在哪些情况下,执行P/Invoke调用时应固定参数
本文关键字:调用 参数 Invoke 情况下 执行 | 更新日期: 2023-09-27 18:27:06
我有一个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调用的持续时间:
除了保留
hOpen
的一个实例之外,我还应该固定它吗?我应该保留
flags
变量的引用吗?既然它在这种特殊情况下被作为引用传递,我是否也应该将其固定?我以以下方式分配我的
callback
代表:private IntPtr callBackOnNativeEvents;
...
this.callBackOnNativeEvents = Marshal.GetFunctionPointerForDelegate(
new CallBack(this.CallBackOnNativeEvents));
我应该保留对委托本身的引用(而不仅仅是指针)吗?我应该也把它钉上吗?
最后,我以以下方式定义
userData
参数:private IntPtr userData;
...
string userName = "test";
this.userData = Marshal.StringToHGlobalAnsi(userName);
我应该保留对字符串的引用吗?我应该也把它钉上吗?API文档指出它将字符串内容复制到非托管内存中,但我不确定它是否复制了引用的内容。
- 无需引脚
hOpen
,它具有值类型语义 - 如果DLL写入
flags
指向的地址,并且在原始函数返回后这样做,那么您需要以某种方式固定它(以及保持它的活动性和安全性,使其免受GC的控制) - 回调函数指针已被有效固定。您需要保持对委托的引用处于活动状态,但不需要固定它,因为本机thunk是从未管理的堆中分配的
- 你不需要在这里做任何特别的事情,因为你正在传递一个
IntPtr
,而它后面的内存是固定的。您不需要保持对字符串的引用处于活动状态,因为它与StringToHGlobalAnsi
返回的IntPtr
完全断开连接。它只是在调用StringToHGlobalAnsi
时有一个字符串内容的副本
我不得不说,我仍然不相信这个DLL真的可以做你说它正在做的事情。我怀疑还有其他问题,您错误地诊断为DLL保留了一个调用中的指针参数,然后在随后的调用中修改了它们的内容。我觉得这很难相信,但当然只有你才能真正知道。如果我处于你的位置,我会简单地问DLL供应商的问题。