欢迎来到天天文库
浏览记录
ID:59357615
大小:39.50 KB
页数:5页
时间:2020-09-04
《如何让类的成员函数作为回调函数.doc》由会员上传分享,免费在线阅读,更多相关内容在教育资源-天天文库。
1、如何让类的成员函数作为回调函数为什么类(class)的成员函(memberfunction)数不能作为回调函数(callbackfunction)首先来看看回调函数有怎样的特点。windows中,回调函都显式(explicit)使用CALLBACK修饰符(decorator)修饰(decorated)。实际上CALLBACK就是_stdcall参数传递方式(callingconvention)的宏定义。MSDN中对__stdcall做了如下定义:The__stdcallcallingconventionisusedtocallWin32APIfunctions.Thecalle
2、ecleansthestack,sothecompilermakesvarargfunctions__cdecl.Functionsthatusethiscallingconventionrequireafunctionprototype.ElementImplementationArgument-passingorderRighttoleft.Argument-passingconventionByvalue,unlessapointerorreferencetypeispassed.Stack-maintenanceresponsibilityCalledfunctionp
3、opsitsownargumentsfromthestack.Name-decorationconventionAnunderscore()isprefixedtothename.Thenameisfollowedbytheatsign(@)followedbythenumberofbytes(indecimal)intheargumentlist.Therefore,thefunctiondeclaredasintfunc(inta,doubleb)isdecoratedasfollows:_func@12Case-translationconventionNone其中心思想
4、是,__stdcall修饰的函数,参数从右至左依次压入堆栈,被调用者(callee)负责平衡堆栈(cleanalsocalled‘stackunwindinghandling’)。下面来看看类的成员函数有怎样的特点。在VC++中,所有类的成员函数在定义的时候都被隐式(implicit)定义为__thiscall参数传递方式。在MSDN中对__thiscall做了如下定义:The__thiscallcallingconventionisusedonmemberfunctionsandisthedefaultcallingconventionusedbyC++memberfunct
5、ionsthatdonotusevariablearguments.Under__thiscall,thecalleecleansthestack,whichisimpossibleforvarargfunctions.Argumentsarepushedonthestackfromrighttoleft,withthethispointerbeingpassedviaregisterECX,andnotonthestack,onthex86architecture.其中心思想是,__thiscall修饰的函数参数从右至左依次压入堆栈,被调用者负责平衡堆栈。之后是与C语言所有参
6、数传递方式均不相同的一点:成员函数所在类的this指针被存入ecx寄存器(这个特性只针对Intelx86架构)。对比之后,我们发现类成员函数不能作为回调函数的主要原因在于类成员函数使用__thiscal参数传递方式,因此需要调用者(caller)通过ecx寄存器提供类对象的指针。而回调函数使用__stdcall参数传递方式,不具备这个特点。如何让类成员函数成为回调函数根据第一节对回调函数与类成员函数各自特点的分析。不难发现,只要能想办法在类成员函数被调用之前设置好ecx寄存器,就能在__stdcall调用的基础上模拟出一个完好的__thiscall调用。如何提前设置ecx寄存器
7、呢?我们知道函数调用实际是通过汇编指令(oprand)’call函数地址’完成的。因此我们可以提供一个中间函数。当回调发生时,先调用中间函数,再在中间函数执行过程中设置ecx寄存器,当ecx设置好后jmp到类成员函数去(注意:这里是jmp不是call)。当执行到类的成员函数时,函数上下文(functioncontext)就和__thiscall所产生的完全一样了。如何制作这个中间函数呢?普通的函数是不行的。主要因为在vc++debug版本的代码中要使用ecx寄存器做堆栈溢出检测(stacko
此文档下载收益归作者所有