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