c# - 在执行 P/Invoke 调用时应在哪些情况下固定参数

标签 c# interop pinvoke

我有一个 DLL,需要从中 P/调用以下 C 方法:

int DAOpen(HANDLE *hOpen, UNIT *flags, void *callback, char *userData)

我提出了以下 C# 签名:

[DllImportAttribute("<libName>", EntryPoint="DAOpen")]  
    static extern  int DAOpen(  
    out IntPtr hOpen,  
    ref uint flags,  
    IntPtr callback,  
    IntPtr userData);

假设 native 代码保留对所有参数的引用的时间长于 P/Invoke 调用的持续时间:

  1. 除了保留 hOpen 的实例之外,我还应该固定它吗?

  2. 我应该保留 flags 变量的引用吗?既然在这种特殊情况下它作为引用传递,我是否也应该固定它?

  3. 我通过以下方式分配我的回调委托(delegate):

    私有(private) IntPtr callBackOnNativeEvents;
    ...
    this.callBackOnNativeEvents = Marshal.GetFunctionPointerForDelegate(
    new CallBack(this.CallBackOnNativeEvents));

    我应该保留对委托(delegate)本身的引用(而不仅仅是指针)吗?我也应该固定它吗?

  4. 最后,我按以下方式定义 userData 参数:

    私有(private) IntPtr userData;
    ...
    string userName = "test";
    this.userData = Marshal.StringToHGlobalAnsi(userName);

    我应该保留对该字符串的引用吗?我也应该钉它吗? API文档指出它将字符串内容复制到非托管内存,但我不确定它是否复制了引用的内容。

最佳答案

  1. 无需固定hOpen,它具有值类型语义。
  2. 如果 DLL 写入由 flags 指向的地址,并且在原始函数返回后执行此操作,那么您需要以一种或另一种方式固定它(并保持其事件和安全)脱离 GC 的控制)。
  3. 回调函数指针已被有效固定。您需要保持对委托(delegate)的引用处于事件状态,但不需要固定它,因为 native thunk is allocated from the unmanged heap .
  4. 您不需要在此处执行任何特殊操作,因为您传递的是 IntPtr 并且其后面的内存已固定。您不需要保持对字符串的引用处于事件状态,因为它与 StringToHGlobalAnsi 返回的 IntPtr 完全断开。它仅具有调用 StringToHGlobalAnsi 时字符串内容的副本。

我不得不说,我仍然怀疑这个 DLL 真的可以做你所说的事情。我怀疑出现了其他问题,您将其错误诊断为 DLL 保留了一次调用中的指针参数,然后在后续调用中修改了它们的内容。我觉得这非常难以置信,但当然只有你才能真正知道。如果我处于您的位置,我只会问 DLL 供应商的问题。

关于c# - 在执行 P/Invoke 调用时应在哪些情况下固定参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9621048/

相关文章:

c# - 使用 C# 作为 C 样式导出库

excel - Interop Excel Automation - 使用服务帐户打开工作簿

从 C++ DLL 调用时,带有参数的 C# 委托(delegate)回调会导致 AccessViolation

c# - 将结构从 C# 传递到非托管代码

c# - DllImport 与 ComImport

javascript - 如何从字符串中提取特定文本。困难的部分是所需的文本会定期更改

c# - 在 WPF 中放大图像

c# - 如何创建通用获取自定义 WebConfig 部分扩展方法

c# - 删除节点时保持结构化琐事

c# - GetActiveObject() 与 GetObject() - MK_E_UNAVAILABLE 错误