C++注入回调函数到C# Dll

本文探讨了从C++向C#注入回调函数的方法,通过定义C#中的委托和C++中的函数指针,利用C++/CLI进行封装转换,实现了跨语言的回调功能。文中详细介绍了具体步骤和代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

从C#注入回调函数到C++编写的Dll中网上可以看到很多方法,但是反过来就麻烦多了。
回调函数的本质就是传递一个函数地址给相应的函数进行处理。所以C++往C#中注入回调函数,所需要解决的问题就是,C++的函数要怎么传到C#中。
从网上找到的资料来看,虽然都是从C#往C++ DLL中传入回调,但是可以得到的一点启示就是,C#的委托可以用来跟C++进行通信。 所以我们可以利用委托来实现这个操作。

C#的编写如下

namespace CSharp
{
    public class program
    {
    	public delegate void ProgressCallback(int num);
        public void registerCallBackFuncktion(ProgressCallback func)
        {
            func(0);
        }
    }
}

这里我们所声明的委托,就是用来进行通信用的。registerCallBackFuncktion用来给外面进行回调函数的注册。当然在项目中,并不会在注册函数内直接调用回调,都是在别处调用,此处无伤大雅。
比较有趣的就是C++中的写法了。

typedef void (*funcType) (int);
public ref class CFunc{
public:
	CFunc(funcType f) : f(f) {};
	void func(int num) {
		f(num);
	}
private:
	funcType f;
};

void registerCallBackFuncktion(funcType ft) {
	CFunc ^cf = gcnew CFunc(ft);
	program::ProgressCallback ^func = gcnew program::ProgressCallback(cf, &CFunc::func);
	program ^pro = gcnew program();
	pro->registerCallBackFuncktion(func);
}

如上述代码所见,我们不能直接将函数指针传递给C#的委托,需要用一个类封起来。
对于这个用来封装函数指针的类,还需要记住,需要使用关键字ref修辞,这样才是一个可以被托管的类。至于ref加上这一关键词的类与原先的类的区别,可以查看这篇文章
将其封装好了之后,我们需要在注入的地方前,将我们的函数gcnew出来,再与封装好的成员函数,一起传递给C#的委托,这里类似于构造函数参数。
这是最简单的一种情况了,如果C#用到了泛型的话,其实也并没有麻烦多少。

public delegate T3 CallBackText<in T1, in T2, out T3>(T1 arg1, T2 arg2);
public void Generic(CallBackText<string, string, string> func)
{
  	 Console.WriteLine(func("arg1", "arg2"));
}

我们在C#中,需要回调这么一个泛型委托。
C++/CLI中我们可以这么实现调用

typedef std::string (*FuncType) (std::string arg1, std::string arg2);
ref class RFunc {
public:
	RFunc(FuncType f) : f(f) {};
	System::String^ func(System::String ^arg1, System::String ^arg2) {
		const char* fir = (const char*)(Marshal::StringToHGlobalAnsi(arg1)).ToPointer();
		const char* sec = (const char*)(Marshal::StringToHGlobalAnsi(arg2)).ToPointer();
		std::string res = f(std::string(fir), std::string(sec));
		return gcnew String(res.c_str());
	}
private:
	FuncType f;
};
std::string test() {
		RFunc ^rf = gcnew RFunc(func);
		Func<String ^, String ^, String ^> ^action = gcnew Func<String ^, String ^, String ^>(rf, &RFunc::func);
		func(action);
}

一切就跟C#一样顺其自然。需要额外注意的就是gcnew出来的东西,需要指定类型就可以了。这里我们可以用一切在C#中可以使用的类型。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值