我正在尝试编写一些从非托管DLL调用方法的C#代码。dll中的函数原型为:
extern "C" __declspec(dllexport) char *foo(void);
在C#中,我首先使用:
[DllImport(_dllLocation)] public static extern string foo();
它似乎在表面上起作用,但是在运行时出现内存损坏错误。我认为我指的是碰巧是正确的但已经被释放的内存。
我尝试使用称为“ P / Invoke Interop Assistant”的PInvoke代码生成实用程序。它给了我输出:
[System.Runtime.InteropServices.DLLImportAttribute(_dllLocation, EntryPoint = "foo")] public static extern System.IntPtr foo();
它是否正确?如果是这样,如何在C#中将此IntPtr转换为字符串?
您必须将此作为IntPtr返回。从PInvoke函数返回System.String类型需要非常小心。CLR必须将内存从本机表示形式转移到托管表示形式。这是一个容易且可预测的操作。
但是,问题在于如何处理从foo()返回的本机内存。CLR假设以下两个有关直接返回字符串类型的PInvoke函数的项目
因此,它将封送字符串,然后在本机内存blob上调用CoTaskMemFree。除非您实际上使用CoTaskMemAlloc分配了此内存,否则充其量只会导致应用程序崩溃。
为了在此处获得正确的语义,您必须直接返回IntPtr。然后使用Marshal.PtrToString *以获得托管的String值。您可能仍然需要释放本机内存,但这将取决于foo的实现。