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(即我得到了一个句柄),它似乎可以正常工作,但当然最初的问题仍然存在。

我有什么理由不能锁定代表吗?

感谢您的投入!

P/Invoke导致具有结构和回调参数的方法崩溃

您是否采取了任何措施来确保委托不会被垃圾收集?

在通话过程中可能会触发第0代集合。尝试在调用函数中创建一个局部变量,或者手动地将委托固定在GC句柄中。

更新:

另外,看看呼叫约定本机API中回调的。是stdcall吗?如果没有,则不能使用GetFunctionPointerForDelegate,因为它返回一个指向本机函数的指针,该函数需要stdcall参数。

在这种情况下,使用委托类型并在指定本机调用约定的委托定义上放置"UnmanagedFunctionPointerAttribute",而不是使用intptr。