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函数

  1. 本地内存需要被释放
  2. 本机内存分配给CoTaskMemAlloc

因此,它将封送string,然后在本机内存块上调用CoTaskMemFree。 除非你真的用CoTaskMemAlloc分配这个内存,否则这最多只会导致应用程序崩溃。

为了在这里得到正确的语义,你必须直接返回一个IntPtr。 然后使用Marshal.PtrToString *为了获得一个托pipe的string值。 你可能仍然需要释放本地内存,但这将取决于foo的实现。

您可以使用Marshal.PtrToStringAuto方法。

 IntPtr ptr = foo(); string str = Marshal.PtrToStringAuto(ptr);