C#调用C++中回调函数资料整理.docx
- 文档编号:29148695
- 上传时间:2023-07-20
- 格式:DOCX
- 页数:37
- 大小:37.86KB
C#调用C++中回调函数资料整理.docx
《C#调用C++中回调函数资料整理.docx》由会员分享,可在线阅读,更多相关《C#调用C++中回调函数资料整理.docx(37页珍藏版)》请在冰豆网上搜索。
C#调用C++中回调函数资料整理
C#调用C++回调函数的问题
2008年10月24日virus
12下一页
C++的回调函数中有一个参数是,是返回一个字符串,原则如下:
typedef void (*TDataEvent)(char *AData ,int ALen);
其中char *AData是从DLL中返回一个字符串,串的内存已经在DLL中分配了
下面中我在C#中定义的委托
public delegate void TDataEvent(Byte[] AData, int ALen);
下面是回调函数的设置代码:
Event = new clReceivelDllPoxy.TDataEvent(getDate);
ReceDllPoxy.AddServer(1024, Event, 2);
其中 Event是上面委托的实例,我定义成一个成员这样就不会被自己释放
下面是C#中回调函数的实现
public void getDate(byte[] AData, int ALen)
{
//发现每次回调是 AData只有一个字节
}
下面转载一个别人的代码,谢谢
usingSystem;
usingSystem.Collections.Generic;
usingSystem.Text;
usingSystem.Runtime.InteropServices;
usingSystem.Reflection;
usingSystem.Reflection.Emit;
namespaceAppDllTest
{
/**////
///非托管动态调用基类,基类不能直接使用,需要实现FunTable()的虚函数
///
publicabstractclassclDllBasePoxy
{
//-装入DLL---------
publicboolOpen(stringdllFileName)
{
Hand=LoadLibrary(dllFileName);
if(Hand==0)
{
returnfalse;
}
FunSet(GetFunTable());
returntrue;
}
//-关闭DLL---
publicboolClose()
{
returnFreeLibrary(Hand)!
=0;
}
publicabstractstring[]GetFunTable();//函数对应表由外部代理类通过GetFunTable来设置
//调用Windows32下的Kernele32库中的装入函数来完成对非托管DLL的引用-------#region//调用Windows32下的Kernele32库中的装入函数来完成对非托管DLL的引用-------
//--------------------------------------------------------------
[DllImport("Kernel32")]
privatestaticexternintGetProcAddress(inthandle,Stringfuncname);
[DllImport("Kernel32")]
privatestaticexternintLoadLibrary(Stringfuncname);
[DllImport("Kernel32")]
privatestaticexternintFreeLibrary(inthandle);
privateintHand=0;//DLL的句柄
privatestaticDelegateGetAddress(intdllModule,stringfunctionname,Typet)//把指针转变成C#的代理
{
intaddr=GetProcAddress(dllModule,functionname);
if(addr==0)
{
returnnull;
}
else
{
returnMarshal.GetDelegateForFunctionPointer(newIntPtr(addr),t);
}
}
//--关联代理和DLL中的函数-----------
privateboolFunSet(string[]aFun)
{
Typetp=this.GetType();
string[]Value;
for(inti=0;i { Value=aFun[i].Split(',');//"Box,TBox,_Box"第一项是代理的实例名,第二项是代理的定义名,第三项是DLL中的函数名 if(Value.Length==3) { FieldInfofi=tp.GetField(Value[0].Trim()); //找实例 Typetype=tp.GetNestedType(Value[1].Trim());//找尾托 if(fi! =null&&type! =null) { fi.SetValue(this,GetAddress(Hand,Value[2].Trim(),type));//创建关联 } } } returntrue; } #endregion } publicclassclDllPoxy: clDllBasePoxy { publicoverridestring[]GetFunTable() { string[]FunTable=newstring[]{ "GetFixParamCount,TGetFixParamCount,_GetFixParamCount", "GetFixParam,TGetFixParam,_GetFixParam" }; returnFunTable; } //--输出函数---------------------------------------------- publicTGetFixParamCountGetFixParamCount; publicTGetFixParamGetFixParam; //--代理描述---------------------------------------------- publicdelegateintTGetFixParamCount(); //获取固定参数个数 publicdelegateboolTGetFixParam(intAIndex,byte[]AOutBuf);//固定参数 } /**//// ///C#动态调用托管DLL的基类-------------- /// publicclassclNetDllPoxy { //--装入动态库---------- publicboolOpen(stringdllFileName,stringclassName) { FAsembly=Assembly.LoadFrom(dllFileName); if(FAsembly==null) { returnfalse; } Typetype=FAsembly.GetTypes()[0];//第一个对应的名字空间当成是调用的名字空间 FDllName=dllFileName; FClassName=className; if(type! =null) { FNameSpace=type.Namespace; } returntrue; } //--设置Dll中的函数范围--------- publicvoidSetArea(stringnameSpace,stringclassName) { FNameSpace=nameSpace; FClassName=className; } //--调用指定的方法,注: 方法的所有参数都转化成对象类型 publicobjectInvoke(stringfunName,object[]ObjArray_Parameter) { try { Type[]types=FAsembly.GetTypes(); foreach(Typetpintypes) { if(tp.Namespace==FNameSpace&&tp.Name==FClassName) { MethodInfometInfo=tp.GetMethod(funName); if(metInfo! =null) { objectobj=Activator.CreateInstance(tp);//创建类对象 if(obj! =null) { returnmetInfo.Invoke(obj,ObjArray_Parameter); } } } } } catch {} returnnull; } privateAssemblyFAsembly;//Dll的程序集 privatestringFDllName; privatestringFNameSpace; privatestringFClassName; } } C#回调函数 C#回调函数应用示例,形象比喻方法助理解,整理了一个简单的例子来说明回调函数的用法: namespaceCallBackFunction { classProgram { staticvoidMain(string[]args) { Programprog=newProgram();//在静态函数Main中调用非静态方法时,必须先实例化该类对象,方可调用GetSum方法 SumClasssc=newSumClass();//实例化SumClass类 intresult=sc.SumAll(prog.GetSum); Console.WriteLine(result.ToString()); } privateintGetSum(inta,intb) { return(a+b); } } classSumClass { publicdelegateintSum(intnum1,intnum2); publicintSumAll(Sumsum) { //可以进行些别的操作 returnsum(1,2);//调用传入函数的一个引用 } //可以封装更多的业务逻辑方法 } } 这个例子非常的简单,假设SumClass类是一个被封装好的,实现某种业务逻辑的类. 其中包含一个委托(delegate)Sum返回值为int型,有两个int型的参数. 还包括一个返回值为int方法SumAll,注意这个方法的参数,是Sum类型的参数,也可以理解为是一个函数的引用(这个函数就是回调函数).作为参数的sum,可以说是某个函数的引用,这个函数返回值为int,并提供两个整型参数.现在大概可以理解了吧? 所谓委托可以被看作是一组方法签名相同的函数的引用的"类",其每一个实例都是符合该方法签名的函数的一个引用.在该方法中可以进行一些操作,并调用传进来的函数引用(sum),而此时sum这个方法内的具体业务逻辑是怎样的并不清楚,SumClass就充当了一个接口的作用,这时接口就需要调用SumClass类的客户端来通过定义一个"回调函数"来实现其具体功能了. 再看Program类,这个类其实就是调用SumClass这个类的一个"客户端". 先来看GetSum这个方法,返回值为int,接受两个int型的参数...如果前面说的你都明白了,那么你一定很清楚GetSum就是作为客户端的"回调函数"用来作为参数的.这个函数实现了两个参数是相加并返回其和的业务逻辑. 在Main函数中,调用SubClass类的SubAll方法,将Programe类的GetSum方法的引用作为参数传递到SubAll方法中,也就是在SubAll中调用GetSum这个相加两个参数的方法,将1和2相加返回3,并将result(3)输出到屏幕上. 通常情况下SubClass类会被封装到DLL中,而参数类型即为一个委托,传入此委托的一个实例(回调函数)来帮助SubClass实现其业务逻辑. 最后再举一个生活中的例子帮助大家来理解: 一天你老婆让你去市场买菜,而你因为偷懒就让你的儿子去买,把菜买回来了你直接将菜交给老婆.而老婆只是想要菜,并不关心菜是谁买的.第二天你老婆让你去买米,结果你又交由儿子处理.第三天老婆让去买肉,可怜的儿子再次被你叫去了... 从这些事情我们可以抽象出一个类来. 这个类就是实现不管老婆让你去做什么,你都叫儿子去代劳.那么我们就可以定义一个"让儿子去做"这样的委托.然后传入"买菜","买肉"等函数进来,这些函数就是回调函数.这样不论老婆需要"买菜","买肉"或者其他任何的事情,都可以通过你这个类来完成 c#调用c++带有回调函数方法的实现 目前正在做的一个项目,大部分数据来源都是通过调用c++函数得到的,此时就遇到一个这次要说的问题。 如c++函数有个定时器,会定时调用我们c#的某个函数并把数据传给c#,让c#把数据显示到界面上,在c++中有个回调函数指针的概念,只需要某个 函数在调用定时器函数时传入一个函数指针就能达到目的,但C#中没有函数指针的概念,我们该怎样来实现呢。 其实说到回调函数,大家应该能想到c#中的委托,虽然名字不一样,但在各自的语言范畴都能实现相似的功能。 所以我们就可以大胆的尝试下,把c#中的委托传给 c++,看c++是否能够承认它就是回调函数。 首先用c++写一个带有回调函数的方法Test,在此省略。 接着,在c#中调用, 如: [DllImport("Test.dll",ChartSet.Ansi,EntryPoint="ReadMyVideo",ExactSpelling=false,CallingConvertion=CallingConvertion.StdCall)] privatestaticexternvoidTest(stringfileName,CallbackDelegatecallback); 复制代码 接下来我们再定义一个委托: publicdelegatevoidCallbackDelegate([marshalAs(UnmanagedType.LPArray,SizeConst=8010)]byte[]buffer,intcount); publicstaticCallbackDelegatecallback; 复制代码 注: 说明一下,在给c++传入数组参数时,必须得用[marshalAs(UnmanagedType.LPArray,SizeConst=8010)]处理一下,相当于是告诉c++,c#传入的是一个长度为8010的数组类型,如果不写这句话的话,你回调函数接收到的参数将只有一条数据。 接下来看看怎样来调用: 在调用时,我们得先写一个接受c++传回参数的方法,即我们传入委托的实现方法。 privatevoidCallBackFunction([marshalAs(UnmanagedType.LPArray,SizeConst=8010)]byte[]buffer,intcount) { ...//处理c++传过来的数据s } 复制代码 一切工作准备完毕之后,我们来进行最后一步操作把 publicvoidGetData() { callback=CallBackFunction; ReadMyVideo("",callback); } 复制代码 经过验证,委托就是c++要的回调函数。 C#调用C++dll中含有回调函数地实现方法! 2007-08-0313: 23 Ifyouhavethe callback usingstdcalllike typedeflong(CALLBACK *MRBNOTIFY)(longmsg,constchar*msgtxt,constvoid*userParam); (orcompilersettings) youcouldusecodelikethis: //=============================================================================== publicdelegateintMRBNOTIFY(intmsg,stringmsgtxt, IntPtr userParam); publicdelegateintMRBPROXYAUTH( IntPtr userParam,stringauth); publicdelegateintMRBHTTPAUTH( IntPtr userParam,stringscheme,stringrealm,stringauth); [StructLayout(LayoutKind.Sequential,Pack=1, CharSet=CharSet.Ansi)] public struct MRBSESSIONINFO { publicstringbaseDir; publicMRBNOTIFYnotify; publicMRBPROXYAUTHproxyAuth; publicMRBHTTPAUTHhttpAuth; publicstringhttpUserAgent; publicstringuserParam; publicintflags; publicstringurl; publicinttimeout; } classInteropWithCbInStruct { [DllImport("YourDll.dll", CharSet=CharSet.Ansi)] publicstaticexternvoidfnTest([In]refMRBSESSIONINFOi); [STAThread] staticvoidMain(string[]args) { MRBSESSIONINFOi; i.baseDir="dir"; i.notify=newMRBNOTIFY(InteropWithCbInStruct.MrbNotify); i.proxyAuth=null;//todo: MRBPROXYAUTH i.httpAuth=null;//todo: MRBHTTPAUTH i.httpUserAgent="agent"; i.userParam="usr"; i.flags=0; i.url="url"; i.timeout=77; fnTest(refi); Console.WriteLine("end."); } publicstaticintMrbNotify(intmsg,stringmsgtxt, IntPtr userParam) { Console.WriteLine("! MrbNotifymsg: {0}msgtxt: {1}userParam: {2}",msg,msgtxt,userParam); return88; } } //=============================================================================== 例二 //////回调函数---------- /// [StructLayout(LayoutKind.Sequential,Pack=1,CharSet=CharSet.Ansi)] publicstructSNAP_INFO { /// /// 标示当前工作的图像卡的句柄。 /// publicinthcg; /// /// 标示当前工作的图像卡的序号(从1开始) ///
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C# 调用 C+ 调函 资料 整理