P/Invoke导致具有结构和回调参数的方法崩溃
本文关键字:回调 参数 崩溃 方法 结构 Invoke | 更新日期: 2023-09-27 18:26:32
我有一个DLL,我需要从中p/Invoke以下C方法:
int DAOpen(HANDLE *hOpen, UNIT *flags, void *callback, void *userData)
使用p/Invoke Assistant,我得到了以下签名:
[DllImportAttribute("<libName>", EntryPoint="DAOpen")]
static extern int DAOpen(
out IntPtr hOpen,
ref uint flags,
IntPtr callback,
IntPtr userData);
回调参数必须与以下C签名相对应:
void CallBack(
int event,
int socket,
struct _iComStructure *plcom,
void *eventData,
void *myData)
翻译成
delegate void CallBack(
int @event,
int socket,
IntPtr plcom,
IntPtr eventData,
IntPtr myData);
现在,我用以下方式打电话:
void MyCallBack(int @event, int socket, IntPtr plcom, IntPtr eventData, IntPtr myData)
{
// does nothing for now
}
IntPtr hOpen;
uint flags = 0;
CallBack callBack = MyCallBack;
StringBuilder userData = new StringBuilder(userData.ToString());
int rc = DAOpen(
out hOpen,
ref flags,
Marshal.GetFunctionPointerForDelegate(callBack), Marshal.StringToHGlobalAnsi(userData.ToString()));
我对这段代码的问题是,当我执行对DAOpen的调用时,它要么崩溃,要么抛出FatalExecutionEngineError
。我知道这一定是编组错误,但我想不通。。。
谢谢你的帮助!
更新
正如建议的那样,我尝试以以下方式锁定回调:
GCHandle callbackHandle = GCHandle.Alloc(callBack, GCHandleType.Pinned);
我收到一个ArgumentException
,上面写着:
Object contains non-primitive or non-blittable data
如果我不指定GCHandleType(即我得到了一个句柄),它似乎可以正常工作,但当然最初的问题仍然存在。
我有什么理由不能锁定代表吗?
感谢您的投入!
您是否采取了任何措施来确保委托不会被垃圾收集?
在通话过程中可能会触发第0代集合。尝试在调用函数中创建一个局部变量,或者手动地将委托固定在GC句柄中。
更新:
另外,看看呼叫约定本机API中回调的。是stdcall吗?如果没有,则不能使用GetFunctionPointerForDelegate,因为它返回一个指向本机函数的指针,该函数需要stdcall参数。
在这种情况下,使用委托类型并在指定本机调用约定的委托定义上放置"UnmanagedFunctionPointerAttribute",而不是使用intptr。