C# C++互操作回调
C# C++ Interop callback
我最近一直在修补C#以C++互操作,特别是设置一个从C++DLL调用的回调函数。
namespace TomCSharpDLLImport
{
class Program
{
public delegate void TomDelegate(int a, int b);
[DllImport("TomDllNative.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void GetData();
[DllImport("TomDllNative.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetCallback(TomDelegate aCallback);
static void Main(string[] args)
{
TomDelegate lTD = new TomDelegate(Program.TomCallback);
SetCallback(lTD); //Sets up the callback
int thread = Thread.CurrentThread.ManagedThreadId;
GetData(); //This calls the callback in unmanaged code
while (true) ;
}
//Callback function which is called from the unmanaged code
public static void TomCallback(int a, int b)
{
Console.WriteLine("A: {0} B: {1}", a, b);
int thread = Thread.CurrentThread.ManagedThreadId;
}
}
}
我的问题是,当程序控件进入 TomCallback 函数时,我希望它会在 Main 中命中 while(true) 循环。但是,程序只是退出。我无法完全理解这种行为,我的一部分认为这是预期的,但我的一部分本来希望它继续下去。
我期待的...
- 调用 GetData() 函数
- GetData 函数调用回调
- 回调函数返回给 GetData
- GetData 返回回 main()
然而,这并不完全正确。
有人会好心地解释一下发生了什么。
为了节省空间,我没有发布非托管代码,但是如果需要,我很乐意发布
编辑:我打开了非托管调试(完全忘记这样做),现在我看到了崩溃。
运行时检查失败 #0 - ESP 的值未在函数调用中正确保存。 这通常是调用使用一个调用约定声明的函数的结果,该函数指针声明了不同的调用约定。
本机代码,因为这是崩溃的地方
#include "stdafx.h"
typedef void (*callback_function)(int, int);
extern "C" __declspec(dllexport) void SetCallback(callback_function aCallback);
extern "C" __declspec(dllexport) void GetData();
callback_function gCBF;
__declspec(dllexport) void SetCallback(callback_function aCallback)
{
gCBF = aCallback;
}
__declspec(dllexport) void GetData()
{
gCBF(1, 2);
}
必须
使用IntPtr Marshal.GetFunctionPointerForDelegate(Delegate d)
方法。
你使用 SetCallback() 和 System.Delegate 作为参数是错误的。
来得及
SetCallback(Marshal.GetFunctionPointerForDelegate(lTD));
并将 SetCallback 重新声明为
/// StdCall is crucial here
[DllImport("TomDllNative.dll", CallingConvention = CallingConvention.StdCall)]
public static extern void SetCallback(IntPtr aCallback);
我遇到了与 OP 完全相同的问题(相同的错误消息)。接受的答案根本没有帮助,甚至@TomP89在评论中也承认了这一点。
这并不奇怪,因为错误消息指示传递的回调函数的调用约定是错误的,而假定的解决方案会更改传递回调的函数的调用约定,如果库导出的是 cdecl 函数,则会导致堆栈不平衡(这是 Win32 API 外部所有函数的默认情况)。
事实证明,.Net 默认假定任何委托的调用约定为"stdcall"。通常,非托管代码将采用与其导出函数相同的调用约定(在本例中为我的:"cdecl")。
所以真正的解决方案(最终对我有用)是将回调的调用约定更改为"cdecl"。这个问题显示了如何实现这一点,简而言之:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void TomDelegate(int a, int b);
相关文章:
- 架构决策:返回std::future还是提供回调
- 正在为Xtensa simcall函数编写回调函数
- 如何在C++中使用非静态成员函数作为回调函数
- FLTK:按下哪个按钮 - 将数字传递给按钮的回调 (lambda)
- 在简单示例中,Python3 + ctypes 回调会导致内存泄漏
- 用于在回调中调用解析器的设计模式
- 如何使用C++对象的成员函数作为 C 样式回调?
- Java从C++回调到C++回调
- 如何将成员函数作为回调参数传递给需要"typedef-ed"自由函数指针的函数?
- 如何读取 C++ SAFEARRAY**,该 SAFEARRAY** 是 COM 互操作的结果,其中 C# 返回值为
- 从不同的 cpp 调用回调函数会导致bad_function_call
- pcap_handler回调仅在使用 NPCAP v0.9991 时包含空数据包
- 不带轮询的 SDL2 事件回调
- 如何使用软化工具包从 OPC UA 服务器异步读取操作回调中的数据值响应中获取 NodeId 详细信息
- ASIO IO完成回调订单与实际IO操作的顺序
- 如何使用GLUT的回调操作数据
- C# C++互操作回调
- 无法找出错误原因 跨线程操作从回调到 C# C++无效
- c# / c++回调类(不是函数)互操作
- c++与c#的互操作,传递回调给c++函数