C#注册回调给C++使用
1. C++ 端核心设计:存储回调函数指针
存储回调指针
// MyNativeLib.cpp #include <cstdio> #include <mutex> // 用于线程安全 // 1. 定义函数指针类型(必须与C#委托签名完全一致) typedef int (__cdecl *Callback)(int a, int b); // 2. 全局变量:存储回调指针(初始为空) static Callback g_callback = nullptr; // 3. 互斥锁:防止C#在注册/注销时,C++刚好在调用,导致崩溃 static std::mutex g_mutex;
2. 导出给 C# 调用的注册、注销、触发函数
C++端需要导出几个关键函数,供C#调用。
extern "C" { // 【C#调用】注册回调 __declspec(dllexport) void RegisterCallback(Callback cb) { std::lock_guard<std::mutex> lock(g_mutex); g_callback = cb; printf("C++: Callback registered successfully.\n"); } // 【C#调用】注销回调(非常重要!防止C++持有悬空指针) __declspec(dllexport) void UnregisterCallback() { std::lock_guard<std::mutex> lock(g_mutex); g_callback = nullptr; printf("C++: Callback unregistered.\n"); } // 【C#调用】模拟“C++主动触发事件”,让C++调用C#的回调 // 实际项目中,这个函数可能是被C++内部线程、网络事件、定时器自动调用的 __declspec(dllexport) void TriggerEvent(int a, int b) { // 先加锁拷贝一份,避免在调用期间C#那边注销导致指针失效 Callback temp_cb = nullptr; { std::lock_guard<std::mutex> lock(g_mutex); temp_cb = g_callback; } if (temp_cb != nullptr) { int result = temp_cb(a, b); // 这里正式回调 C# 方法 printf("C++: Callback invoked, result from C# = %d\n", result); } else { printf("C++: Triggered but no callback registered.\n"); } } }
C#使用
// ========== 1. 定义与C++函数指针匹配的委托 ========== // 必须使用 [UnmanagedFunctionPointer] 指定调用约定,与C++端 __cdecl 一致 [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate int CallbackDelegate(int a, int b); // ========== 2. 将委托实例保存为静态字段,防止GC回收 ========== private static CallbackDelegate _callbackInstance; // ========== 3. 导入C++ DLL中的函数 ========== [DllImport("MyNativeLib.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void RegisterCallback(CallbackDelegate cb); [DllImport("MyNativeLib.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void UnregisterCallback(); [DllImport("MyNativeLib.dll", CallingConvention = CallingConvention.Cdecl)] public static extern void TriggerEvent(int a, int b); // ========== 4. C# 回调方法的实现 ========== private static int MyCallbackMethod(int a, int b) { // 注意:此方法可能由C++的任意线程调用 Console.WriteLine($"[C#] Callback invoked with a={a}, b={b} on thread {Thread.CurrentThread.ManagedThreadId}"); // 模拟业务处理 int result = a + b; // 如果需要在UI线程更新界面,需要通过 SynchronizationContext 或 Invoke 封送 // 这里只是演示,不做跨线程操作 return result; } // ========== 5. 主程序 ========== static void Main() { // 注册回调:将方法包装为委托,并保存到静态字段 _callbackInstance = new CallbackDelegate(MyCallbackMethod); RegisterCallback(_callbackInstance); Console.WriteLine("[C#] Callback registered."); // 手动触发一次回调(演示) Console.WriteLine("[C#] Triggering event from C#..."); TriggerEvent(10, 20); // ========== 6. 程序退出前注销回调,防止C++持有悬空指针 ========== UnregisterCallback(); Console.WriteLine("[C#] Callback unregistered."); // (可选)等待C++线程完全结束,如果有的话,可以通过事件或标志位实现 // 这里简单等待一下 Thread.Sleep(500); }

浙公网安备 33010602011771号