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

1 篇文章 0 订阅

从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
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
C#中调用C++编写的DLL时,有时需要使用回调函数,以便C++代码可以调用C#中的函数。以下是一些回调函数相关的注意事项: 1. 在C++中定义回调函数时,需要使用__stdcall或__cdecl修饰符,并将函数指针作为参数传递给C++函数。 2. 在C#中定义回调函数时,需要使用delegate关键字,并指定回调函数的签名。 3. 在C#中使用DllImport特性引用C++编写的DLL时,需要使用UnmanagedFunctionPointer特性指定回调函数的调用约定,以确保C++能够正确调用C#中的回调函数。 4. 在C++中调用C#中的回调函数时,需要将其换为函数指针类型,并使用该指针调用回调函数。 以下是一个简单的示例,演示了如何在C++中调用C#中的回调函数C++ DLL代码: ```cpp typedef void(__stdcall *Callback)(const char*); __declspec(dllexport) void DoSomething(Callback callback) { if (callback != NULL) { callback("Hello from C++!"); } } ``` C#代码: ```csharp delegate void CallbackDelegate(string message); [DllImport("mydll.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool DoSomething(CallbackDelegate callback); static void Main(string[] args) { CallbackDelegate callback = new CallbackDelegate(PrintMessage); DoSomething(callback); } static void PrintMessage(string message) { Console.WriteLine(message); } ``` 在上面的示例中,C++中的DoSomething函数接收一个回调函数指针作为参数,该函数使用指针调用回调函数C#中的DoSomething函数使用CallbackDelegate作为回调函数签名,并使用UnmanagedFunctionPointer特性指定调用约定,Main函数中创建了一个CallbackDelegate对象,并将其传递给DoSomething函数。 希望这个示例对你有所帮助,祝你学习愉快!
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值