ImageVerifierCode 换一换
格式:DOCX , 页数:11 ,大小:22.08KB ,
资源ID:6165961      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/6165961.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(在函数前面加上WINAPICALLBACK.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

在函数前面加上WINAPICALLBACK.docx

1、在函数前面加上WINAPICALLBACK一直搞不懂为什么在函数前面加上WINAPI、CALLBACK等是什么意思 又不是返回值 为什么加在前面 今天终于知道了这是一个呼叫声明(姑且称之吧)。引子:看看这个函数:int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, LPSTR szCmdLine, int sw) MSG msg;/进行程序的初始化工作 if(!AppInit(hInst,hPrev,sw) return FALSE;/消息循环处理 for(;) while(PeekMessage(&msg, NULL, 0, 0,PM_RE

2、MOVE)/Peek只是查看事件,一般不作任何处理 /Get会做一些例行处理,并且把事件从队列中删除掉(WM_PAINT除外) /通常先peek,看某事件是否存在,再get,进行处理 /未经严格测试:如果你get某个在队列中不存在的事件,程序会陷入等待,但是peek总是立即返回 if(msg.message = WM_QUIT) break; / Leave the PeekMessage while() loop /TranslateAccelerator将WM_KEYDOWN和WM_SYSYKEYDOWN消息翻译成为WM_COMMAND消息,/然后直接将消息送到相关的窗口过程中去,直到消息

3、被处理后才返回值 if(TranslateAccelerator(ghwndApp, ghAccel, &msg) continue; TranslateMessage(&msg); DispatchMessage(&msg); if(msg.message = WM_QUIT) break; / Leave the for() loop WaitMessage();/当本窗口的消息序列中没有消息的时候,将控制权交给其他的线程直到再次有消息进入自己的消息队列中时才返回 / Reached on WM_QUIT message CoUninitialize(); return (int) msg

4、.wParam);别的先别看,现看看这个PASCAL :The _pascal, _fortran, and _syscall calling conventions are no longer supported. You can emulate their functionality by using one of the supported calling conventions and appropriate linker options.WINDOWS.H now supports the WINAPI macro, which translates to the appropria

5、te calling convention for the target. Use WINAPI where you previously used PASCAL or _far _pascal.看来现在用WINAPI来代替己经不用的PASCAL了,那么WINAPI是什么呢?WINAPI:查看WINAPI的定义:(WINDOWS.H)#define WINAPI FAR PASCALWINAPI:Use in place of FAR PASCAL in API declarations. If you are writing a DLL with exported API entry poi

6、nts, you can use this for your own APIs.原来是个宏定义。用法也说到了,你可以使用WINAPI来为自己的API写一个DLL文件(有导出的API入口点的DLL,废话,没有API入口,要DLL干什么?)。消息处理函数就是这么定义的:LONG WINAPI AppWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)在VC+ 6.0中,WINDEF.h#define WINAPI CDECL /=_cdecl#define CALLBACK PASCAL /=_pascal,VC已经不支持直接使用_p

7、ascal了顺便提下CALLBACK:CALLBACK:Use in place of FAR PASCAL in application callback routines such as window procedures and dialog procedures.在BCB(Boland C+ Builder )中:windef.h#define WINAPI _stdcall#define CALLBACK _stdcall具体来说,他们是关于堆栈的一些说明,首先是函数参数压栈顺序,其次是压入堆栈的内容由谁来清除,调用者还是函数自己?简单说明:_cdecl是C/C+和MFC程序默认使用

8、的调用约定,也可以在函数声明时加上_cdecl关键字来手工指定。采用_cdecl约定时,函数参数按照从右到左的顺序入栈,并且由调用函数者把参数弹出栈以清理堆栈。因此,实现可变参数的函数只能使用该调用约定。由于每一个使用_cdecl约定的函数都要包含清理堆栈的代码,所以产生的可执行文件大小会比较大。_cdecl可以写成_cdecl。_stdcall调用约定用于调用Win32 API函数。采用_stdcal约定时,函数参数按照从右到左的顺序入栈,被调用的函数在返回前清理传送参数的栈,函数参数个数固定。由于函数体本身知道传进来的参数个数,因此被调用的函数可以在返回前用一条ret n指令直接清理传递参

9、数的堆栈。_stdcall可以写成_stdcall。_fastcall约定用于对性能要求非常高的场合。_fastcall约定将函数的从左边开始的两个大小不大于4个字节(DWORD)的参数分别放在ECX和EDX寄存器,其余的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的堆栈。_fastcall可以写成_fastcall。特别说明:1. 在默认情况下,采用_cdecl方式,因此可以省略.2. WINAPI一般用于修饰动态链接库中导出函数3. CALLBACK仅用于修饰回调函数4. VC下和BCB下对WINAPI的定义不同,所以不能直接从BCB下调用VC的dll的一个原因了。看来WIN

10、API与DLL关系很密切,所以还应该探讨一下DLL啊。下次说吧。函数调用的几个概念:_stdcall,_cdecl.左通过栈传递,被调用的函数在返回前清理传送参数的内存栈,但不同的是函数名的修饰部分(关于函数名的修饰部分在后面将详细说明)。_stdcall是Pascal程序的缺省调用方式,通常用于Win32Api中,函数采用从右到左的压栈方式,自己在退出时清空堆栈。VC将函数编译后会在函数名前面加上下划线前缀,在函数名后加上和参数的字节数。2、C调用约定(即用_cdecl关键字说明)按从右至左的顺序压参数入栈,由调用者把参数弹出栈。对于传送参数的内存栈是由调用者来维护的(正因为如此,实现可变参

11、数的函数只能使用该调用约定)。另外,在函数名修饰约定方面也有所不同。_cdecl是C和C程序的缺省调用方式。每一个调用它的函数都包含清空堆栈的代码,所以产生的可执行文件大小会比调用_stdcall函数的大。函数采用从右到左的压栈方式。VC将函数编译后会在函数名前面加上下划线前缀。是MFC缺省调用约定。3、_fastcall调用约定是“人”如其名,它的主要特点就是快,因为它是通过寄存器来传送参数的(实际上,它用ECX和EDX传送前两个双字(DWORD)或更小的参数,剩下的参数仍旧自右向左压栈传送,被调用的函数在返回前清理传送参数的内存栈),在函数名修饰约定方面,它和前两者均不同。_fastcal

12、l方式的函数采用寄存器传递参数,VC将函数编译后会在函数名前面加上前缀,在函数名后加上和参数的字节数。4、thiscall仅仅应用于“C+”成员函数。this指针存放于CX寄存器,参数从右到左压。thiscall不是关键词,因此不能被程序员指定。5、nakedcall采用1-4的调用约定时,如果必要的话,进入函数时编译器会产生代码来保存ESI,EDI,EBX,EBP寄存器,退出函数时则产生代码恢复这些寄存器的内容。nakedcall不产生这样的代码。nakedcall不是类型修饰符,故必须和_declspec共同使用。关键字_stdcall、_cdecl和_fastcall可以直接加在要输出的

13、函数前,也可以在编译环境的Setting.C/C+CodeGeneration项选择。当加在输出函数前的关键字与编译环境中的选择不同时,直接加在输出函数前的关键字有效。它们对应的命令行参数分别为/Gz、/Gd和/Gr。缺省状态为/Gd,即_cdecl。要完全模仿PASCAL调用约定首先必须使用_stdcall调用约定,至于函数名修饰约定,可以通过其它方法模仿。还有一个值得一提的是WINAPI宏,Windows.h支持该宏,它可以将出函数翻译成适当的调用约定,在WIN32中,它被定义为_stdcall。使用WINAPI宏可以创建自己的APIs。2)名字修饰约定1、修饰名(Decorationna

14、me)“C”或者“C+”函数在内部(编译和链接)通过修饰名识别。修饰名是编译器在编译函数定义或者原型时生成的字符串。有些情况下使用函数的修饰名是必要的,如在模块定义文件里头指定输出“C+”重载函数、构造函数、析构函数,又如在汇编代码里调用“C”或“C+”函数等。修饰名由函数名、类名、调用约定、返回类型、参数等共同决定。2、名字修饰约定随调用约定和编译种类(C或C+)的不同而变化。函数名修饰约定随编译种类和调用约定的不同而不同,下面分别说明。a、C编译时函数名修饰约定规则:_stdcall调用约定在输出函数名前加上一个下划线前缀,后面加上一个“”符号和其参数的字节数,格式为_functionna

15、menumber。_cdecl调用约定仅在输出函数名前加上一个下划线前缀,格式为_functionname。_fastcall调用约定在输出函数名前加上一个“”符号,后面也是一个“”符号和其参数的字节数,格式为functionnamenumber。它们均不改变输出函数名中的字符大小写,这和PASCAL调用约定不同,PASCAL约定输出的函数名无任何修饰且全部大写。b、C+编译时函数名修饰约定规则:_stdcall调用约定:1、以“?”标识函数名的开始,后跟函数名;2、函数名后面以“YG”标识参数表的开始,后跟参数表;3、参数表以代号表示:X-void,D-char,E-unsignedchar

16、,F-short,H-int,I-unsignedint,J-long,K-unsignedlong,M-float,N-double,_N-bool,.PA-表示指针,后面的代号表明指针类型,如果相同类型的指针连续出现,以“0”代替,一个“0”代表一次重复;4、参数表的第一项为该函数的返回值类型,其后依次为参数的数据类型,指针标识在其所指数据类型前;5、参数表后以“Z”标识整个名字的结束,如果该函数无参数,则以“Z”标识结束。其格式为“?functionnameYG*Z”或“?functionnameYG*XZ”,例如intTest1(char*var1,unsignedlong)-“?Te

17、st1YGHPADKZ”voidTest2()-“?Test2YGXXZ”_cdecl调用约定:规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的“YG”变为“YA”。_fastcall调用约定:规则同上面的_stdcall调用约定,只是参数表的开始标识由上面的“YG”变为“YI”。VC+对函数的省缺声明是_cedcl,将只能被C/C+调用.CB在输出函数声明时使用4种修饰符号/_cdeclcb的默认值,它会在输出函数名前加_,并保留此函数名不变,参数按照从右到左的顺序依次传递给栈,也可以写成_cdecl和cdecl形式。/_fastcall她修饰的函数的参数将尽肯呢感地使用寄

18、存器来处理,其函数名前加,参数按照从左到右的顺序压栈;/_pascal它说明的函数名使用Pascal格式的命名约定。这时函数名全部大写。参数按照从左到右的顺序压栈;/_stdcall使用标准约定的函数名。函数名不会改变。使用_stdcall修饰时。参数按照由右到左的顺序压栈,也可以是_stdcall;VisualC+中函数调用方式浅探转载VisualC+中函数调用方式浅探我们知道在进行函数调用时,有几种调用方法,分为C式,Pascal式。在C和C+中C式调用是缺省的,除非特殊声明。二者是有区别的,下面我们用实例说明一下:1._cdecl:C和C+缺省调用方式例子:voidInput(int&m

19、,int&n);/*相当于void_cdeclInput(int&m,int&n);*/以下是相应的汇编代码:00401068leaeax,ebp-8;取ebp-8地址(ebp-8),存到eax0040106Bpusheax;然后压栈0040106Cleaecx,ebp-4;取ebp-4地址(ebp-4),存到ecx0040106Fpushecx;然后压栈00401070callILT+5(Input)(0040100a);然后调用Input函数00401075addesp,8;恢复栈从以上调用Input函数的过程可以看出:在调用此函数之前,首先压栈ebp-8,然后压栈ebp-4,然后调用函数

20、Input,最后Input函数调用结束后,利用esp+8恢复栈。由此可见,在C语言调用中默认的函数修饰_cdecl,由主调用函数进行参数压栈并且恢复堆栈。下面看一下:地址ebp-8和ebp-4是什么?在VC的VIEW下选debugwindows,然后选Registers,显示寄存器变量值,然后在选debugwindows下面的Memory,输入ebp-8的值和ebp-4的值(或直接输入ebp-8和-4),看一下这两个地址实际存储的是什么值,实际上是变量n的地址(ebp-8),m的地址(ebp-4),由此可以看出:在主调用函数中进行实参的压栈并且顺序是从右到左。另外,由于实参是相应的变量的引用,

21、也证明实际上引用传递的是变量的地址(类似指针)。总结:在C或C+语言调用中默认的函数修饰_cdecl,由主调用函数进行参数压栈并且恢复堆栈,实参的压栈顺序是从右到左,最后由主调函数进行堆栈恢复。由于主调用函数管理堆栈,所以可以实现变参函数。另外,命名修饰方法是在函数前加一个下划线(_).2.WINAPI(实际上就是PASCAL,CALLBACK,_stdcall)例子:voidWINAPIInput(int&m,int&n);看一下相应调用的汇编代码:00401068leaeax,ebp-80040106Bpusheax0040106Cleaecx,ebp-40040106Fpushecx00

22、401070callILT+5(Input)(0040100a)从以上调用Input函数的过程可以看出:在调用此函数之前,首先压栈ebp-8,然后压栈ebp-4,然后调用函数Input,在调用函数Input之后,没有相应的堆栈恢复工作(为其它的函数调用,所以我没有列出)下面再列出Input函数本身的汇编代码:(实际此函数不大,但做汇编例子还是大了些,大家可以只看前和后,中间代码与此例子无关)39:voidWINAPIInput(int&m,int&n)40:00401110pushebp00401111movebp,esp00401113subesp,48h00401116pushebx004

23、01117pushesi00401118pushedi00401119leaedi,ebp-48h0040111Cmovecx,12h00401121moveax,0CCCCCCCCh00401126repstosdwordptredi41:ints,i;42:43:while(1)00401128moveax,10040112Dtesteax,eax0040112FjeInput+0C1h(004011d1)44:45:printf(nPleaseinputthefirstnumberm:);00401135pushoffsetstringnPleaseinputthefirstnumber

24、m.(004260b8)0040113Acallprintf(00401530)0040113Faddesp,446:scanf(%d,&m);00401142movecx,dwordptrebp+800401145pushecx00401146pushoffsetstring%d(004260b4)0040114Bcallscanf(004015f0)00401150addesp,847:48:if(m1)continue;00401153movedx,dwordptrebp+800401156cmpdwordptredx,100401159jgeInput+4Dh(0040115d)004

25、0115BjmpInput+18h(00401128)49:printf(nPleaseinputthefirstnumbern:);0040115DpushoffsetstringnPleaseinputthefirstnumbern.(0042608c)00401162callprintf(00401530)00401167addesp,450:scanf(%d,&n);0040116Amoveax,dwordptrebp+0Ch0040116Dpusheax0040116Epushoffsetstring%d(004260b4)00401173callscanf(004015f0)004

26、01178addesp,851:52:if(n1)continue;0040117Bmovecx,dwordptrebp+0Ch0040117Ecmpdwordptrecx,100401181jgeInput+75h(00401185)00401183jmpInput+18h(00401128)53:54:for(i=1,s=0;i=s)004011B3moveax,dwordptrebp+8004011B6movecx,dwordptreax004011B8cmpecx,dwordptrebp-4004011BBjlInput+0AFh(004011bf)57:break;004011BDj

27、mpInput+0C1h(004011d1)58:else59:printf(mn*(n+1)/2,Pleaseinputagain!n);004011BFpushoffsetstringmn*(n+1)/2,Pleaseinputagai.(00426060)004011C4callprintf(00401530)004011C9addesp,460:004011CCjmpInput+18h(00401128)61:62:004011D1popedi004011D2popesi004011D3popebx004011D4addesp,48h004011D7cmpebp,esp004011D9call_chkesp(004015b0)004011DEmovesp,ebp

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1