在 P/调用中为固定字符串传递什么

本文关键字:字符串 什么 调用 | 更新日期: 2023-09-27 18:36:50

假设这个C函数:

void do_something(const char* str)

它将字符串存储在某处以供以后参考

此外,我在 C# 中有这个签名来调用这个函数:

[DllImport("NativeLib")]
static extern void do_something(string str);

现在,将字符串传递给此方法时需要做什么:

  • 我是否需要固定字符串(带GCHandle.Alloc())(或者编组器正在创建副本)?
  • 如果我确实需要固定它,我是否传递"原始"字符串(即我传递给GCHandle.Alloc()的字符串)?还是需要传递 GCHandle.AddrOfPinnedObject() 的返回值?
  • 在这种情况下,string正确的数据类型(对于do_something)是否正确?还是我应该改用IntPtr

在 P/调用中为固定字符串传递什么

通过互

操作边界存储指针是一个非常糟糕的主意,请尽一切努力修改 C 代码以复制字符串。

按照投票答案中的建议固定字符串是行不通的,pinvoke 封送器必须将字符串转换为 char*,并在进行本机调用后释放转换后的字符串,从而使指针无效。 您必须自己封送字符串。 将参数声明为 IntPtr 并使用 Marshal.StringToHGlobalAnsi() 创建指针值。

或者使用 Marshal.StringToCoTaskMemAnsi(),它从 COM 堆中分配。 这是你真正的问题,没有很好的方案来释放字符串。 C 代码无法释放字符串,因为它不知道它是如何分配的。 C# 代码无法释放字符串,因为它不知道 C 代码何时使用指针完成。 这就是复制字符串如此重要的原因。 如果只进行几次此调用,则可以忍受内存泄漏。

鉴于非托管代码将存储指针而不是复制字符串,我建议您使用 GCHandle.Alloc() 手动创建字符串的副本并将其作为 Intptr 传递。

然后,您将能够管理传递的内存块的生存期,仅在完成它时释放它(通过 GCHandle)。