【问题标题】:String marshalling and memory management字符串编组和内存管理
【发布时间】:2021-07-28 14:50:56
【问题描述】:

假设我在库中导出了以下 C++ 函数:

void foo(const wchar_t* text);

以及使用该函数的 C# 代码:

[DllImport("bla.dll")]
static extern void foo([MarshalAs(UnmanagedType.LPWStr)] string text);

void Bar()
{
    string s = "hello";
    foo(s);
}
  1. 当我调用foo 时.net marshaller 是否复制字符串或指针是否指向s 的缓冲区?
  2. 如果值被复制,什么时候清理?
  3. 我必须自己清理吗(大概在foo内部)?
  4. 如果是,我该如何清理内存?

如果text 编组为:

  1. UnmanagedType.LPWStr
  2. UnmanagedType.BStr

【问题讨论】:

  • 无副本,.net 字符串与 const wchar_t* 兼容。 BSTR 需要被复制,marshaller 处理它并在调用后销毁副本。

标签: c# c++ pinvoke marshalling


【解决方案1】:
  1. .net marshaller 是在我调用 foo 时复制字符串还是指针指向 s 的缓冲区?

按值传递 LPWSTR 的特定情况意味着托管字符串被固定并由本机代码直接使用,see here。在所有其他情况下,将复制字符串 see here

  1. 如果值被复制,什么时候清理?

编组器在函数调用返回后进行任何释放。

如果文本编组为:

  1. UnmanagedType.LPWStr
  2. UnmanagedType.BStr

最终的行为是相同的,在函数调用返回后传递给本机函数的指针无效。在 LPWStr 的情况下,它将指向与托管字符串使用的内存相同的内存(可能在本机函数返回后移动),对于 BStr,它将指向由编组器分配的临时缓冲区(将在本机函数返回)。

如果您需要本机函数来获取指针的所有权,您需要传入一个IntPtr,它指向您以合适的方式分配给自己的一些内存(也许通过调用一些本机代码,也许通过使用AllocHGlobal 等)。指针需要您手动释放,或者使用相同的机制由本机代码释放。

【讨论】:

    猜你喜欢
    • 2011-10-22
    • 1970-01-01
    • 2013-06-17
    • 2010-10-11
    • 2013-04-16
    • 1970-01-01
    • 1970-01-01
    • 2011-01-06
    • 2017-01-31
    相关资源
    最近更新 更多