MFC的消息处理机制由两部分组成:CCmdTarget类和消息映射表。
- 窗口消息构成
所有的窗口消息由3部分组成
UINT Msg,
WPARAM wParam,
LPARAM lParam
- 为神马不用虚函数来处理消息?
因为,虚函数是使用类的虚函数表实现的,每个派生类都会带一个虚函数表的拷贝。虚函数表中的每个入口都是一个4字节指针,这样每个类对象就会在虚函数表中带来大量的额外字节。同时,窗口消息的个数和种类随时会发生变化,在消息改变时,使用虚函数实现的消息机制容易导致代码的废弃
- 消息机制内幕
MFC的消息映射技术由两部分组成:CCmdTarget类 和 消息映射表。CCmdTarget是所有接受窗口消息和命令对象的基类,为了接受消息,类必须从CCmdTarget派生。消息映射表是将窗口消息与处理消息的类成员函数关联起来的机制。消息映射表数据结构和消息映射宏是消息映射系统的另外的两个重要的方面。
(a) 两个消息映射表数据结构
AFX_MSGMAP_ENTRY 消息映射项 ( 见afxwin.h )
- struct AFX_MSGMAP_ENTRY
- {
- UINT nMessage; // windows message
- UINT nCode; // 控件代码或WM_NOTIFY代码,MFC 3.0新增
- UINT nID; // 产生消息的控件ID(0代表Windows消息)
- UINT nLastID; // 用来指定控件ID范围,MFC 3.0新增
- UINT_PTR nSig; // signature type (action) or pointer to message #
- AFX_PMSG pfn; // 消息处理函数
- };
AFX_MSGMAP 消息映射表 ( 见afxwin.h )
- struct AFX_MSGMAP
- {
- const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)(); // 指向基类映射表项的指针
- const AFX_MSGMAP_ENTRY* lpEntries; // 消息映射表
- };
(b) 消息映射宏
MFC提供了三个宏来产生消息映射表:DECLARE_MESSAGE_MAP、BEGIN_MESSAGE_MAP、END_MESSAGE_MAP。要在类中使用消息映射表,最基本的办法是在类声明中包含DECLARE_MESSAGE_MAP (.h文件),在类实现体中包含BEGIN_MESSAGE_MAP、END_MESSAGE_MAP和消息映射信息(.cpp文件)
DECLARE_MESSAGE_MAP ( 见afxwin.h )
- #define DECLARE_MESSAGE_MAP() /
- protected: /
- static const AFX_MSGMAP* PASCAL GetThisMessageMap(); /
- virtual const AFX_MSGMAP* GetMessageMap() const; /
定义了两个Protect函数,GetThisMessageMap用于返回本类中的消息映射表指针,GetMesssageMap是个虚函数
BEGIN_MESSAGE_MAP ( 见afxwin.h )
- #define BEGIN_MESSAGE_MAP(theClass, baseClass) /
- const AFX_MSGMAP* theClass::GetMessageMap() const /
- { return GetThisMessageMap(); } /
- const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() /
- { /
- typedef theClass ThisClass; /
- typedef baseClass TheBaseClass; /
- static const AFX_MSGMAP_ENTRY _messageEntries[] = /
- {
GetMessageMap 和 GetThisMessageMap函数的实现,在GetThisMessageMap中一个函数中定义了两个函数静态变量:_messageEntries 表示所有的消息映射项、messageMap表示消息映射表(见下)
END_MESSAGE_MAP ( 见afxwin.h )
- #define END_MESSAGE_MAP() /
- {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } /
- }; /
- static const AFX_MSGMAP messageMap = /
- { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; /
- return &messageMap; /
- }
BEGIN_MESSAGE_MAP 和 END_MESSAGE_MAP之间的内容是一系列消息映射表的入口宏。这些宏扩展后可以填充类的消息映射表_messageEntries。MFC定义的各种消息映射表入口宏,见下表
(3)MFC定义各种消息映射表入口宏
消息类型 | 宏形式 | 参数 |
预定义窗口消息 | ON_WM_XXXX | None |
命令 | ON_COMMAND | Command Id, Handler Name |
命令ID的范围 | ON_COMMAND_RANGE | Start ID, End ID, Handler Name |
更新命令 | ON_UPDATE_COMMAND_UI | Commnad Id, Handler Name |
用于更新的命令ID的范围 | ON_UPDATE_COMMAND_UI_RANGE | Start ID, End ID, Handler Name |
控件通知 | ON_XXXX | Control Id, Handler Name |
控件ID范围 | ON_CONTROL_RANGE | Notify Code、Start ID、End ID、Handler Name |
用户定义的消息 | ON_MESSAGE | User-defined Message ID, Handler Name |
注册的窗口消息 | ON_REGISTERED_MESSAGE | Registered message ID variable, Handler Name |