首页 理论教育解码消息映射机制|MFC视频教程

解码消息映射机制|MFC视频教程

【摘要】:②“//{{AFX_MSG”下面的代码,是用来管理以“WM_”开头的Windows消息映射函数的。消息映射函数,就是MFC自动把每个消息分离出来,并关联到一个类成员函数上。它是另一类回调函数,和消息回调映射函数类似。基于以上宏定义,把消息映射关联代码替换成原型后会发现ON_WM_MOUSEMOVE是WM_MOUSEMOVE消息和OnMouseMove成员函数地址的关联。4)解密消息映射宏定义。messageMap结构体主要是建立和处理基类消息和派生类消息之间的关系。

要想透彻地解析类向导自动生成的代码,首先必须有一定的C++语法基础,比如,了解构造函数、静态成员变量和静态成员函数等基础知识。

1)类向导专用的注释代码。

在MyDlg.h和MyDlg.cpp中,都有一些以“//{{AFX_”开头的注释代码,并且这些注释代码颜色都变成灰色了。虽然注释代码不参与编译,但是也不要随便删除这些注释代码,因为这些代码是类向导生成的。类向导(ClassWizard)用于代码管理的3种标志如下。

①“//{{AFX_DATA”下面的代码,是用来管理关联成员变量使用的,后面会介绍到。

②“//{{AFX_MSG”下面的代码,是用来管理以“WM_”开头的Windows消息映射函数的。消息映射函数,就是MFC自动把每个消息分离出来,并关联到一个类成员函数上。例如,OnMouseMove和OnPaint等。

③“//{{AFX_VIRTUAL”下面的代码,是用来管理重写基类虚函数的。它是另一类回调函数,和消息回调映射函数类似。在MFC的窗口类中有两类回调函数,一种是消息映射回调函数,另一种是虚函数回调函数。

在类向导(ClassWizard)的消息列表(Messages)中,可以创建两类成员函数,后半部分以“WM_”开头的是窗口消息函数,前半部分不是以“WM_”开头的那些就是虚函数。两种方式创建的函数,分别通过“//{{AFX_MSG”和“//{{AFX_VIRTUAL”注释代码来管理,如图3-60所示。

978-7-111-46378-8-Chapter03-83.jpg

图3-60 类向导代码

2)关联窗口消息与成员函数的桥梁,即BEGIN_MESSAGE_MAP和END_MESSAGE_MAP。

每次在ClassWizard中建立一个消息映射函数后,在窗口类源代码(.cpp)文件中,就会在BEGIN_MESSAGE_MAP和END_MESSAGE_MAP之间添加一行代码。这些代码是关联Windows消息和消息映射函数的桥梁,例如,ON_WM_MOUSEMOVE()和ON_WM_PAINT(等)。

978-7-111-46378-8-Chapter03-84.jpg

3)下面通过查看和替换这些宏定义的方式,来解析这些代码消息关联代码的含义。

选中ON_WM_MOUSEMOVE或者ON_WM_PAINT代码,单击鼠标右键,在弹出的快捷菜单中,选择“Go To Definition Of xxx”命令,或者按<F12>键,查看此类宏定义的原型。

978-7-111-46378-8-Chapter03-85.jpg

基于以上宏定义,把消息映射关联代码替换成原型后会发现ON_WM_MOUSEMOVE是WM_MOUSEMOVE消息和OnMouseMove成员函数地址的关联。ON_WM_PAINT是WM_PAINT消息和OnPaint成员函数地址的关联。而且每一个关联都是用“{…},”的格式包裹起来,其形式类似于结构体数组初始化。如果解析清楚BEGIN_MESSAGE_MAP这些宏定义,那么秘密就被揭晓了。(www.chuimin.cn)

978-7-111-46378-8-Chapter03-86.jpg

4)解密消息映射宏定义(以下消息机制代码解析难度较大,对于C++语言基础较弱者可以忽略)。

替换DECLARE_MESSAGE_MAP宏。这个宏定义是窗口类头文件.h的类声明的结尾处。在源代码窗口中,选中DECLARE_MESSAGE_MAP后按<F12>键查看定义。

978-7-111-46378-8-Chapter03-87.jpg

替换这个宏定义之后,类内新增了一个成员函数的声明和两个静态成员变量的声明。这三行代码不是新增的代码而是一直就存在于类内的,只不过被DECLARE_MESSAGE_MAP宏掩盖了而已。

978-7-111-46378-8-Chapter03-88.jpg

静态成员变量_messageEntries是一个结构体数组,数组元素类型是AFX_MSGMAP_ENTRY结构体。选中AFX_MSGMAP_ENTRY再按<F12>键去查看其结构体定义。这就是把消息类型nMessage和成员函数的地址pfn关联起来的结构体。

978-7-111-46378-8-Chapter03-89.jpg

按照以上方法继续查看BEGIN_MESSAGE_MAP的宏定义。

978-7-111-46378-8-Chapter03-90.jpg

978-7-111-46378-8-Chapter03-91.jpg

BEGIN_MESSAGE_MAP是一个带2个参数的宏定义,实际参数在窗口类源代码中指定。例如,BEGIN_MESSAGE_MAP(CMyDlg,CDialog)。要替换这个有参数的宏定义,必须将CMyDlg替换到宏定义中的所有theClass,而把CDialog替换到宏定义中的所有baseClass。

978-7-111-46378-8-Chapter03-92.jpg

其中BEGIN_MESSAGE_MAP产生了一个成员函数GetMessageMap的函数体,还产生一个静态成员变量messageMap的结构体定义。messageMap结构体主要是建立和处理基类消息和派生类消息之间的关系。最后还提供了静态成员变量_messageEntries结构体数组的初始化语句的起始部分。

END_MESSAGE_MAP提供的是_messageEntries结构体数组初始化语句中的最后一个元素,是一个空的AFX_MSGMAP_ENTRY结构体对象。END_MESSAGE_MAP()最后一行是一个大括号和分号,结束了结构体数组_messageEntries的初始化语句。