C#/C++ 回调作为 NULL 传递

Posted

技术标签:

【中文标题】C#/C++ 回调作为 NULL 传递【英文标题】:C#/C++ Callback Passed as NULL 【发布时间】:2014-12-02 14:32:58 【问题描述】:

我在将回调函数从 C# 传递到 C++ 非托管 DLL 时遇到了一些问题。运行程序时,DLL 接收 NULL 而不是回调。

回调函数定义为

typedef void(__cdecl *CallbackFunction)();

C++ 函数定义为

__declspec(dllexport) void __cdecl StreamData(unsigned char *Buffer, unsigned int BufferSize, unsigned long Points,
 unsigned short AveragingPower, CallbackFunction BufferUpdated);

C# 回调和函数委托定义为

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void BufferUpdatedCallback();

[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
private delegate void StreamDataDelegate(byte[] Buffer, uint BufferSize, ulong Points,
 ushort AveragingPower, BufferUpdatedCallback BufferUpdated);

C++ 函数确实可以正常工作,因为我已经从 C++ 控制台应用程序对其进行了测试,并且它可以正常工作。在 C# 中,我可以通过Marshal.GetFunctionPointer(Delegate d) 获取回调委托的指针,但是当我在程序进入 StreamData 函数时单步执行程序时,指针在 DLL 中变为 NULL。 DLL 和 C# 委托的调用约定是一致的。

我错过了一些非常基本的东西吗?有人知道解决问题的方法吗?

更新

如果 unsigned long Points 参数从 DLL 和 C# 中删除,则函数正常工作,否则回调为 NULL。

【问题讨论】:

【参考方案1】:

C++ 编译器中的 unsigned long 是 32 位整数类型。但是,您声明为 ulong,一种 64 位类型。这导致的参数未对齐使委托在 C++ 代码中看起来像 NULL,它正在读取该 ulong 变量的高 32 位。

您必须在 Points 参数的 [DllImport] 声明中使用 uint

【讨论】:

【参考方案2】:

试试这个:

私有委托 void StreamDataDelegate(ref byte[] Buffer, uint BufferSize, ulong Points, ushort AveragingPower, BufferUpdatedCallback BufferUpdated);

【讨论】:

数组不是问题,我已经检查过了。

以上是关于C#/C++ 回调作为 NULL 传递的主要内容,如果未能解决你的问题,请参考以下文章

将非托管方法作为回调传递给托管 C++/CLI 类

Ruby - 将方法作为回调传递给 DLL 库

从本机 c 代码 (JNI) 为 Java 中的回调函数传递多个参数

如何实现类的成员函数作为回调函数

JNI 回调传递给 C

如何将回调对象从 Swift 传递到 Objective C 类并用作回调?