我有一个调用C++ DLL的C#应用​​程序。

在C#中,我的代码如下:

[DllImport(@"111.dll", CharSet = CharSet.Unicode)]
public extern static String Func1(String arg);
......
String arg = "test text";
String retstring = Func1(arg);

在CPP中,我的功能定义如下:
extern "C"
{
__declspec(dllexport) LPWSTR Func1(LPWSTR arg)
{
          ....
          LPWSTR ret1 = L"1?2?3?4?5";
          LPWSTR ret2 = SomeActualFunction(arg);
          retturn ret1; // return ret2;
     }
}

如果我在C++的Func1()中返回ret1,则一切正常。在VS2008的内存窗口中,我可以看到正确的Unicode二进制文件。在C++中,ret1的二进制文件是

“31 00 3f 00 32 00 3f 00 33 00 3f 00 34 00 3f 00 35 00”

,在C#中retstring的二进制文件是

“28 67 a3 f7 fe 07 00 00 0a 00 00 00 09 00 00 00 31 00 3f 00 32 00 3f 00 33 00 3f 00 34 00 3f 00 35 00”

。我认为C#二进制文件

“28 67 a3 f7 fe 07 00 00 0a 00 00 00 09 00 00 00”

是System.String类型的 header 。

而且,如果在CPP代码返回之前添加以下行,我也可以在C#代码中获得正确的重新字符串:
ret2 = L"1?2?3?4?5";

但是,当我在C++ DLL中返回ret2时,C#中返回的字符串ret似乎已损坏。根据我的检查,C++ DLL中的二进制文件是正确的Unicode。但是C#代码中retstring的二进制文件是

“28 67 a3 f7 fe 07 00 00 0a 00 00 00 09 00 00 00 dd dd dd dd dd dd dd ....”。

我只能注意到ret2比ret1长-ret2有数百个WCHAR。

有任何想法吗?提前谢谢。

最佳答案

我将始终为此使用BSTR,因为它使内存分配/取消分配的职责透明化。

C++

#include <comutil.h>
BSTR GetSomeText()
{
    return ::SysAllocString(L"Greetings from the native world!");
}

C#
[DllImport(@"test.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string GetSomeText();

您没有说明如何分配字符串,但是一旦使用动态分配的字符串,就需要解决该问题。 BSTR的伟大之处在于它使用共享的COM分配器,该分配器使C#编码可以使用与分配该字符串的C++代码相同的分配器来分配该字符串。

10-06 07:28
查看更多