一尘不染

用于返回char的C函数的PInvoke

c#

我正在尝试编写一些从非托管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转换为字符串?


阅读 220

收藏
2020-05-19

共1个答案

一尘不染

您必须将此作为IntPtr返回。从PInvoke函数返回System.String类型需要非常小心。CLR必须将内存从本机表示形式转移到托管表示形式。这是一个容易且可预测的操作。

但是,问题在于如何处理从foo()返回的本机内存。CLR假设以下两个有关直接返回字符串类型的PInvoke函数的项目

  1. 本机内存需要释放
  2. 本机内存是通过CoTaskMemAlloc分配的

因此,它将封送字符串,然后在本机内存blob上调用CoTaskMemFree。除非您实际上使用CoTaskMemAlloc分配了此内存,否则充其量只会导致应用程序崩溃。

为了在此处获得正确的语义,您必须直接返回IntPtr。然后使用Marshal.PtrToString
*以获得托管的String值。您可能仍然需要释放本机内存,但这将取决于foo的实现。

2020-05-19