C#的Native Callback
有时候需要C#调用C/C++库,如果是异步调用必然涉及回调函数,本文记录一下C#如何调用C++以及如何处理Native的回调。首先生成Windows下的动态库 DLL可以参考: 《演练:创建和使用自己的动态链接库 (C++)》 ,由于是在Windows环境,所以没有做关于平台区分的宏定义。
Windows下生成动态库DLL,也就是导出操作:
1#pragma once
2
3typedef int(__stdcall* func_notice)(int, int);
4
5extern "C" {
6 __declspec(dllexport) void __stdcall my_print();
7
8 __declspec(dllexport) int __stdcall calc_add(int a, int b);
9
10 __declspec(dllexport) void __stdcall setNotice(func_notice func);
11}
使用动态库DLL,也就是导入操作:
1#pragma once
2
3typedef int(__stdcall* func_notice)(int, int);
4
5extern "C" {
6 __declspec(dllimport) void __stdcall my_print();
7
8 __declspec(dllimport) int __stdcall calc_add(int a, int b);
9
10 __declspec(dllimport) void __stdcall setNotice(func_notice func);
11}
func_notice 是一个函数指针,即是定义的回调函数。头文件定义了,具体实现如下(就简单实现一下):
1#include <stdio.h>
2#include "calc.h"
3
4func_notice call_back = NULL;
5
6void my_print()
7{
8 printf("my_print exec..\n");
9}
10
11int calc_add(int a, int b)
12{
13 printf("calc_add exec.. a = %d, b = %d\n", a, b);
14 if (call_back) {
15 printf("call_back exec..\n");
16 call_back(a + 10, b + 10);
17 }
18 return a + b;
19}
20
21void setNotice(func_notice func)
22{
23 call_back = func;
24}
本地使用测试一下,测试没问题就通过C#来调用。
1#include "calc.h"
2#include <iostream>
3
4int my_func(int a, int b) {
5 printf("my_func callback success! a = %d, b = %d\n", a, b);
6 return 0;
7}
8
9int main()
10{
11 setNotice(my_func);
12 my_print();
13
14 printf("calc_add -> %d", calc_add(50, 100));
15
16 return 0;
17}
C# 如何使用调用DLL(同样的DLL和exe放在同一个文件夹底下):
1using System;
2using System.Runtime.InteropServices;
3
4namespace CSCallTest
5{
6 class Program
7 {
8 // 定义回调方法
9 public static int CallBackFunction(int a, int b)
10 {
11 Console.WriteLine("C++ call me, a = " + a + ", b = " + b);
12 return a + b;
13 }
14
15 static void Main(string[] args)
16 {
17 DllImportX.CallbackDel callback = CallBackFunction;
18 DllImportX.my_print();
19 DllImportX.setNotice(callback);
20 int calcAdd = DllImportX.calc_add(20, 90);
21 Console.WriteLine("calcAdd = " + calcAdd);
22 }
23 }
24
25
26 public class DllImportX
27 {
28 [DllImport("call_test.dll", EntryPoint = "my_print",
29 CallingConvention = CallingConvention.StdCall)]
30 public static extern void my_print();
31
32
33 [DllImport("call_test.dll", EntryPoint = "calc_add",
34 CallingConvention = CallingConvention.StdCall)]
35 public static extern int calc_add(int a, int b);
36
37
38 [DllImport("call_test.dll", EntryPoint = "setNotice",
39 CallingConvention = CallingConvention.StdCall)]
40 public static extern void setNotice(CallbackDel callback);
41
42 // 定义委托
43 public delegate int CallbackDel(
44 [MarshalAs(UnmanagedType.I4)] int a,
45 [MarshalAs(UnmanagedType.I4)] int b
46 );
47 }
48}
UnmanagedType.XXX 对应表格,类型需要对应,参考地址 UnmanagedType Enum
参考资料: