回调函数

窗口过程函数原型如下:

LRESULT CALLBACK WindowProc(
  HWND hwnd,      // handle to window
  UINT uMsg,      // message identifier
  WPARAM wParam,  // first message parameter
  LPARAM lParam   // second message parameter
);

关键字CALLBACK定义的函数为回调函数,它实际上是一个宏:#define CALLBACK    __stdcall

而__stdcall是一种调用约定。

1,回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数。
在新建一个窗口程序时,必须要经过一下四个步骤:设计一个窗口类、注册窗口类、创建窗口、显示及更新窗口

设计窗口类的API原型为:

typedef struct _WNDCLASS { 
    UINT       style; 
    WNDPROC    lpfnWndProc; 
    int        cbClsExtra; 
    int        cbWndExtra; 
    HINSTANCE  hInstance; 
    HICON      hIcon; 
    HCURSOR    hCursor; 
    HBRUSH     hbrBackground; 
    LPCTSTR    lpszMenuName; 
    LPCTSTR    lpszClassName; 
} WNDCLASS, *PWNDCLASS; 

注册窗口类的时候需要传入一个窗口过程的指针,WNDPROC   A 32-bit pointer to a window procedure,所以WindowProc就是一个回调函数。

程序在调用一个函数(function)时(通常指api).相当于程序(program)呼叫(Call)了一个函数(function)关系表示如下:
                   call(调用)
      program     --------------------→       dll

程序在调用一个函数时,将自己的函数的地址作为参数传递给程序调用的函数时(那么这个自己的函数称回调函数).需要回调函数的 DLL 函数往往是一些必须重复执行某些操作的函数.关系表示如下:

                  call(调用)
      program     --------------------→       dll
         ↑                                  ¦
         ¦_______________________________¦
                 callback(回调)

2,调用约定

函数的调用约定主要决定函数参数的入栈顺序和谁来清除栈中的参数问题。

当高级语言函数被编译成机器码时,有一个问题就必须解决:因为CPU没有办法知道一个函数调用需要多少个、什么样的参数。即计算机不知道怎么给这个函数传递参数,传递参数的工作必须由函数调用者和函数本身来协调。为此,计算机提供了一种被称为栈的数据结构来支持参数传递。函数调用时,调用者依次把参数压栈,然后调用函数,函数被调用以后,在堆栈中取得数据,并进行计算。函数计算结束以后,或者调用者、或者函数本身修改堆栈,使堆栈恢复原装。在参数传递中,有两个很重要的问题必须得到明确说明:

函数调用后,由谁来把堆栈恢复原状?

函数的返回值放在什么地方?

一般情况下,VC编译器中project->setting->c/c++->code generation->call convention下面可以修改调用约定

回调函数一般是__stdcall,它是标准c调用约定,标准调用约定的函数在它们返回到调用者之前,都会从堆栈中移除掉参数,这也是Pascal的标准约定。名字修饰是前面加下划线,后面加@+参数大小,如_fun@number

__cdecl是c/c++调用约定,是调用者负责清理堆栈,而不是被调用函数。它是调用者来清除堆栈,所以对被调用函数的参数个数没有明确的限制,支持可变参数。但由于由被调函数清除堆栈,多以程序较大。它的名字修饰约定是在前面加下划线,如_fun。在这里我们应该要考虑类似于像scanfprintf这样的函数,这里我们应该明白这两个函数的参数都是可变的,如果参数不固定的话,在被调用函数内就无法知道参数究竟使用了多少个字节,所以为了实现可变参数,我们必须要在被调函数执行之后我们才知道参数究竟用了多少字节,所以我们在调用者来进行堆栈平衡操作。

不同环境下可以强制使用。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值