我有一个调用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类型的标头.
更重要的是,如果我在返回CPP代码之前添加以下行,我也可以在C#代码中获得正确的retstring:
ret2 = L"1?2?3?4?5";
但是当我在C DLL中返回ret2时,返回的C#中的字符串似乎已损坏.在我的检查中,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 dd dd dd ….”.
我只能注意到ret2比ret1长 – ret2有几百个WCHAR.
有任何想法吗? Thx提前.
解决方法
我总是会使用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#marshaller能够使用与分配它的C代码相同的分配器来释放字符串.