我有一个 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 调用的持续时间:
除了保留
hOpen
的实例之外,我还应该固定它吗?我应该保留
flags
变量的引用吗?既然在这种特殊情况下它作为引用传递,我是否也应该固定它?我通过以下方式分配我的
回调
委托(delegate):私有(private) IntPtr callBackOnNativeEvents;
...
this.callBackOnNativeEvents = Marshal.GetFunctionPointerForDelegate(
new CallBack(this.CallBackOnNativeEvents));
我应该保留对委托(delegate)本身的引用(而不仅仅是指针)吗?我也应该固定它吗?
最后,我按以下方式定义
userData
参数:私有(private) IntPtr userData;
...
string userName = "test";
this.userData = Marshal.StringToHGlobalAnsi(userName);
我应该保留对该字符串的引用吗?我也应该钉它吗? API文档指出它将字符串内容复制到非托管内存,但我不确定它是否复制了引用的内容。
最佳答案
- 无需固定
hOpen
,它具有值类型语义。 - 如果 DLL 写入由
flags
指向的地址,并且在原始函数返回后执行此操作,那么您需要以一种或另一种方式固定它(并保持其事件和安全)脱离 GC 的控制)。 - 回调函数指针已被有效固定。您需要保持对委托(delegate)的引用处于事件状态,但不需要固定它,因为 native thunk is allocated from the unmanged heap .
- 您不需要在此处执行任何特殊操作,因为您传递的是
IntPtr
并且其后面的内存已固定。您不需要保持对字符串的引用处于事件状态,因为它与StringToHGlobalAnsi
返回的IntPtr
完全断开。它仅具有调用StringToHGlobalAnsi
时字符串内容的副本。
我不得不说,我仍然怀疑这个 DLL 真的可以做你所说的事情。我怀疑出现了其他问题,您将其错误诊断为 DLL 保留了一次调用中的指针参数,然后在后续调用中修改了它们的内容。我觉得这非常难以置信,但当然只有你才能真正知道。如果我处于您的位置,我只会问 DLL 供应商的问题。
关于c# - 在执行 P/Invoke 调用时应在哪些情况下固定参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9621048/