1200字范文,内容丰富有趣,写作的好帮手!
1200字范文 > C#委托实现C++ Dll中的回调函数

C#委托实现C++ Dll中的回调函数

时间:2019-11-01 17:33:42

相关推荐

C#委托实现C++ Dll中的回调函数

from:/ferrycooper/article/details/63261771

很多的Dll都是C和C++写的,那么如果C#想要调用Dll中的函数怎么办,尤其是Dll函数其中一个参数是函数指针的,即里面有回掉函数的用C#怎么实现?

C中的回掉函数在C#中有中特殊的处理方式叫委托,即要实现的回掉函数委托给另一个和它返回值类型以及函数参数类型、数量一样的方法来实现。

一、新建项目Visual C++Win32控制台应用,工程名为CcreateDll,解决方案名为Dlltest

确定—>下一步

应用程序类型选Dll—>完成

新建头文件Ccreate.h,声明导出函数,其中API_DECLSPECintCallPFun(addPcallback,inta,intb)第一个参数为函数指针,内容如下:

[cpp]view plaincopy#pragmaonce#ifndefCcreate_H_#defineCcreatel_H_typedefint(*addP)(int,int);#ifdef_EXPORTING#defineAPI_DECLSPECextern"C"_declspec(dllexport)#else#defineAPI_DECLSPECextern"C"_declspec(dllimport)#endifAPI_DECLSPECintAdd(intplus1,intplus2);API_DECLSPECintmulp(intplus1,intplus2);API_DECLSPECintCallPFun(addPcallback,inta,intb);#endif

头文件有了,在CcreateDll.cpp中include头文件,并实现相关函数。Ccreate.cpp如下

[cpp]view plaincopy//CcreateDll.cpp:定义DLL应用程序的导出函数。//#include"stdafx.h"#include<iostream>#include"Ccreate.h"usingnamespacestd;intAdd(intplus1,intplus2){intadd_result=plus1+plus2;returnadd_result;}intmulp(intplus1,intplus2){intadd_result=plus1*plus2;returnadd_result;}intCallPFun(int(*callback)(int,int),inta,intb){returncallback(a,b);}

函数CallPFun实际就是传入函数指针及其参数,内部直接调用函数指针。

在Release模式下生成CcreateDll工程

生成成功后在解决方案目录的Release文件夹下会看到生成的CcreateDll.dll,使用Dll查看工具可以看到三个导出函数。

二、新建C#控制台工程CsharpCallDll实现调用Dll并使用委托实现回掉。

CsharpCallDll工程Program.cs如下:

[csharp]view plaincopyusingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingSystem.Runtime.InteropServices;namespaceCsharpCallDll{publicclassProgram{[UnmanagedFunctionPointer(CallingConvention.Cdecl)]publicdelegateintDllcallBack(intnum1,intnum2);[DllImport(@"../../../Release/CcreateDll.dll",EntryPoint="Add",SetLastError=true,CharSet=CharSet.Ansi,ExactSpelling=false,CallingConvention=CallingConvention.Cdecl)]externstaticintAdd(inta,intb);[DllImport(@"../../../Release/CcreateDll.dll",EntryPoint="mulp",SetLastError=true,CharSet=CharSet.Ansi,ExactSpelling=false,CallingConvention=CallingConvention.Cdecl)]externstaticintmulp(inta,intb);[DllImport(@"../../../Release/CcreateDll.dll",EntryPoint="CallPFun",SetLastError=true,CharSet=CharSet.Ansi,ExactSpelling=false,CallingConvention=CallingConvention.Cdecl)]publicexternstaticintCallPFun(DllcallBackpfun,inta,intb);//[MarshalAs(UnmanagedType.FunctionPtr)]staticvoidMain(string[]args){inta=3;intb=4;intresult;DllcallBackmycall;mycall=newDllcallBack(Program.CsharpCall);result=Add(a,b);Console.WriteLine("Add返回{0}",result);result=mulp(a,b);Console.WriteLine("mulp返回{0}",result);result=CallPFun(mycall,a,b);Console.WriteLine("dll回掉返回{0}",result);Console.ReadLine();}publicstaticintCsharpCall(inta,intb){returna*a+b*b;}}}

通过DllImport导入相应的Dll并声明Dll中的导出函数,CcreateDll.dll中导出函数CallPFun有三个参数,原型为

[cpp]view plaincopyintCallPFun(int(*callback)(int,int),inta,intb){returncallback(a,b);}

参数1为一个带两个int参数的返回值为int型的函数指针,这里声明一个委托

publicdelegateintDllcallBack(intnum1,intnum2);

该委托可以指向任何带两个int型参数且返回值为int型的方法,这里的CsharpCall方法可以看作是回掉函数的实现。

[csharp]view plaincopypublicstaticintCsharpCall(inta,intb){returna*a+b*b;}

通过DllcallBackmycall;

mycall =newDllcallBack(Program.CsharpCall);

把实际要完成的工作交给CsharpCall去完成。

运行CsharpCallDll,结果如下:

是不是实现了C#委托实现回掉

最后还有如果声明委托时在public delegate int DllcallBack(int num1, int num2);上面没有[UnmanagedFunctionPointer(CallingConvention.Cdecl)]这一句,那么运行时将会出现System.AccessViolationException异常,如下

还有Dll调用约定,CallingConvention.有五种调用方式

CallingConvention= CallingConvention.StdCall

CallingConvention= CallingConvention.Cdecl

CallingConvention= CallingConvention.FastCall

CallingConvention= CallingConvention.ThisCall

CallingConvention= CallingConvention.Winapi

到底使用哪种方式,网上有说"Bydefault, C and C++ use cdecl - but marshalling uses stdcall to match theWindows API."即默认情况下,C和C++使用的Cdecl调用,但编组使用StdCall调用匹配的Windows API,对于FastCall、ThisCall、Winapi这三种调用方式尚不清楚。

这里将CallingConvention= CallingConvention.Cdecl改成CallingConvention = CallingConvention.StdCall,重新运行导致堆栈不对称如下

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。