将std :: string从C ++ DLL返回到c#程序 - >为RtlFreeHeap指定的无效地址

时间:2021-09-07 06:56:58

In a function in my C++ DLL, I'm returning a std::string to my c# application. It pretty much looks like this:

在我的C ++ DLL中的一个函数中,我将一个std :: string返回给我的c#应用程序。它几乎看起来像这样:

std::string g_DllName = "MyDLL";

extern "C" THUNDER_API const char* __stdcall GetDLLName()
{
    return g_DllName.c_str();
}

But when my C# code calls this function, I get this message in my output window:

但是当我的C#代码调用此函数时,我在输出窗口中收到此消息:

Invalid Address specified to RtlFreeHeap( 00150000, 0012D8D8 )

The function declaration in c# looks like this:

c#中的函数声明如下所示:

[DllImport("MyDll", EntryPoint = "GetDLLName")]
    [return: MarshalAs(UnmanagedType.LPStr)]
    public static extern string GetDLLName();

From what I've been able to find online, sometimes this message appears when there's an inconsistency between which version of new(debug or release, etc) is being used with delete. But I'm not sure if that is what is going on in my case. So I'm not sure exactly what's causing it. Maybe the MashallAs might have something to do with it?

从我在网上找到的内容来看,当有新版本(调试或发布等)与删除一起使用时,有时会出现此消息。但我不确定这是不是我的情况。所以我不确定究竟是什么导致了它。也许MashallAs可能与它有关?

Any ideas?

Thanks!

1 个解决方案

#1


I managed to find the issue. It was the way the C# definition was done. From what I can understand, using the MarshallAs(UnmanagedType.LPStr) in combination with the string return type makes it so that it'll attempt to free the string when its done. But because the string comes from the C++ DLL, and most likely a totally different memory manager, it fails. And even if it didn't fail, I don't want it to be freed anyway.

我设法找到了这个问题。这是C#定义的完成方式。根据我的理解,将MarshallAs(UnmanagedType.LPStr)与字符串返回类型结合使用,使得它在完成后将尝试释放字符串。但是因为字符串来自C ++ DLL,并且很可能是完全不同的内存管理器,所以它失败了。即使它没有失败,我也不希望它被释放。

The solution I found was to change the C# declaration to this (the C++ code is unchanged):

我发现的解决方案是将C#声明更改为此(C ++代码保持不变):

[DllImport("MyDll", EntryPoint = "GetDLLName")]
public static extern IntPtr GetDLLName();

So this makes it so that it just returns a pointer to the string data. And then to change it to a string, pass it to Marshal.PtrToStringAnsi()

所以这使得它只返回一个指向字符串数据的指针。然后将其更改为字符串,将其传递给Marshal.PtrToStringAnsi()

return Marshal.PtrToStringAnsi(GetDLLName());

And that gets wrapped into another function for cleanliness.

这包含在另一个清洁功能中。

I found the solution from this page: http://discuss.fogcreek.com/dotnetquestions/default.asp?cmd=show&ixPost=1108

我从这个页面找到了解决方案:http://discuss.fogcreek.com/dotnetquestions/default.asp?cmd = show &ixPost = 1108

#1


I managed to find the issue. It was the way the C# definition was done. From what I can understand, using the MarshallAs(UnmanagedType.LPStr) in combination with the string return type makes it so that it'll attempt to free the string when its done. But because the string comes from the C++ DLL, and most likely a totally different memory manager, it fails. And even if it didn't fail, I don't want it to be freed anyway.

我设法找到了这个问题。这是C#定义的完成方式。根据我的理解,将MarshallAs(UnmanagedType.LPStr)与字符串返回类型结合使用,使得它在完成后将尝试释放字符串。但是因为字符串来自C ++ DLL,并且很可能是完全不同的内存管理器,所以它失败了。即使它没有失败,我也不希望它被释放。

The solution I found was to change the C# declaration to this (the C++ code is unchanged):

我发现的解决方案是将C#声明更改为此(C ++代码保持不变):

[DllImport("MyDll", EntryPoint = "GetDLLName")]
public static extern IntPtr GetDLLName();

So this makes it so that it just returns a pointer to the string data. And then to change it to a string, pass it to Marshal.PtrToStringAnsi()

所以这使得它只返回一个指向字符串数据的指针。然后将其更改为字符串,将其传递给Marshal.PtrToStringAnsi()

return Marshal.PtrToStringAnsi(GetDLLName());

And that gets wrapped into another function for cleanliness.

这包含在另一个清洁功能中。

I found the solution from this page: http://discuss.fogcreek.com/dotnetquestions/default.asp?cmd=show&ixPost=1108

我从这个页面找到了解决方案:http://discuss.fogcreek.com/dotnetquestions/default.asp?cmd = show &ixPost = 1108