我有一个DLL,我需要P / Invoke以下C方法:
int DAOpen(HANDLE *hOpen, UNIT *flags, void *callback, void *userData)
使用P / Invoke助手,我想出了以下签名:
[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 :(得分:2)
您是否已采取任何措施确保代表不被垃圾收集?
您可以在通话期间触发第0代收藏。 尝试在调用函数中创建局部变量, 或者手动将代表固定在GC句柄中。
<强>更新强>
另外,请查看调用约定 本机API中的回调。它是stdcall吗? 如果没有,则不能使用GetFunctionPointerForDelegate 返回指向期望stdcall参数的本机函数的指针。
在这种情况下,使用委托类型并在委托定义上放置一个“UnmanagedFunctionPointerAttribute”,而不是我们的intptr,它指定了本机调用约定。