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

时间:2012-03-08 16:22:00

标签: c# interop pinvoke

我有一个DLL,我需要P / Invoke以下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);

假设本机代码保留对所有参数的引用的持续时间超过P / Invoke调用的持续时间:

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

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

  3. 我是按照以下方式分配我的callback代表:

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

    我应该保留对委托本身的引用(不仅仅是指针)吗?我也应该把它钉住吗?

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

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

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

1 个答案:

答案 0 :(得分:2)

  1. 无需固定hOpen,它具有值类型语义。
  2. 如果DLL写入flags指向的地址,并且在原始函数返回后执行此操作,那么您需要以某种方式将其固定(以及保持其活着并且远离离合器GC)。
  3. 回调函数指针已被有效固定。您需要保持对委托的引用,但您不需要固定它,因为native thunk is allocated from the unmanged heap
  4. 你不需要在这里做任何特别的事情,因为你传递的是IntPtr并且后面的内存是固定的。您无需保持对字符串的引用,因为它与IntPtr返回的StringToHGlobalAnsi完全断开连接。它只是在调用StringToHGlobalAnsi时的字符串内容的副本。
  5. 我不得不说,我仍然不相信这个DLL真的可以做你说它正在做的事情。我怀疑你错误诊断的其他东西是错误的,因为DLL从一个调用中保留指针参数,然后在后续调用期间修改它们的内容。我觉得特别难以置信,但当然只有你才能真正了解。如果我在你的位置,我只会询问DLL供应商的问题。