PInvoke for C函数返回char *
我试图写一些C#代码调用一个非托pipeDLL的方法。 在dll函数的原型是:
extern "C" __declspec(dllexport) char *foo(void);
在C#中,我第一次使用:
[DllImport(_dllLocation)] public static extern string foo();
它似乎在表面上工作,但在运行时收到内存损坏错误。 我想我指的是正确的记忆,但已经被释放了。
我尝试使用一个名为“P / Invoke Interop Assistant”的PInvoke代码gen实用程序。 它给了我输出:
[System.Runtime.InteropServices.DLLImportAttribute(_dllLocation, EntryPoint = "foo")] public static extern System.IntPtr foo();
它是否正确? 如果是这样,我该如何将此IntPtr转换为C#中的string?
您必须将其作为IntPtr返回。 从PInvoke函数返回System.Stringtypes需要非常小心。 CLR必须将内存从本地表示转移到受pipe理的表示中。 这是一个简单而可预测的操作。
问题来自于如何处理从foo()返回的本机内存。 CLR假定以下两个关于直接返回stringtypes的PInvoke函数
- 本地内存需要被释放
- 本机内存分配给CoTaskMemAlloc
因此,它将封送string,然后在本机内存块上调用CoTaskMemFree。 除非你真的用CoTaskMemAlloc分配这个内存,否则这最多只会导致应用程序崩溃。
为了在这里得到正确的语义,你必须直接返回一个IntPtr。 然后使用Marshal.PtrToString *为了获得一个托pipe的string值。 你可能仍然需要释放本地内存,但这将取决于foo的实现。
您可以使用Marshal.PtrToStringAuto方法。
IntPtr ptr = foo(); string str = Marshal.PtrToStringAuto(ptr);