MFC消息映射
1.消息映射的产生
为了解决传统窗口函数的缺点(需要程序员了解许多窗口消息;许多窗口的窗口函数大部分消息处理相同;switch语句逐一判断窗口发生的消息,使编译代码的效率非常低),MFC引入了消息映射的概念。
消息映射实际上是采用一张表(消息映射表),将消息标识和消息处理函数存储在其中,当调用窗口函数处理消息时,窗口函数搜索消息映射表,就可以调用消息映射表中对应消息的消息处理函数。MFC就采用了上述的消息映射机制,它提供了一个消息映射的基类CCmdTarget,在CCmdTarget类中提供了一个消息映射表,以后与消息有关的类都应是CCmdTarget的派生类。这样,基类的消息映射表就可以与派生类的消息映射表连接起来。消息处理可以按着从派生类到基类的顺序搜索消息映射表。
2.消息映射表
为了构建消息映射表,MFC的设计者们提供了两个数据结构AFX_MSGMAP_ENTRY和AFX_MSGMAP。
struct AFX_MSGMAP_ENTRY
{
UINT nMessage; //表示消息标识
UINT nCode; //控制代码或WM_NOTIFY通知代码
UINT nID; //控件ID,如果是窗口消息,nID为0
UINT nLastID; //表示一定范围的命令中的最后一个命令或控件ID,用于将一组命令映射到同一个消息处理函数中
UINT nSig; //表示小溪成员的签名代码
AFX_PMSG pfn; //表示消息处理函数
};
其中AFX_PMSG的原型为:typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);
问:对于不同的消息,其消息处理函数的参数个数、参数类型一般也不会相同,而在AFX_MSGMAP_ENTRY结构中,则定义了同意的消息处理函数pfn。那么如何通过pfn调用不同参数签名的函数呢?
答:在MFC内部定义了一个用于转换消息处理函数的联合体MessageMapFunctions。该联合体的作用是将统一的消息处理函数的指针转换为特定的形式。AFX_MSGMAP_ENTRY结构中的pfn函数指针通过联合体MessageMapFunctions巧妙的转换为特定形式的函数指针,AFX_MSGMAP_ENTRY结构中的nSig成员的作用——根据该成员的不同取值,AFX_MSGMAP_ENTRY结构中的pfn函数指针会转换为不同的函数指针形式。
struct AFX_MSGMAP
{
#ifdef _AFXDLL
const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
#else
const AFX_MSGMAP* pBaseMap;//指向基类的消息映射表
#endif
const AFX_MSGMAP_ENTRY* lpEntries;//表示指向一个AFX_MSGMAP_ENTRY结构数组。
};
可以看出,AFX_MSGMAP_ENTRY结构和AFX_MSGMAP结构构成了一张链表,MFC就是借助于这两个数据结构构成了一张大的消息网。
MFC在组建消息映射表的时候,还定义了3个宏:DECLARE_MESSAGE_MAP、BEGIN_MESSAGE_MAP、END_MESSAGE_MAP。
#define DECLARE_MESSAGE_MAP()
protected:
static const AFX_MSGMAP* PASCAL GetThisMessageMap();
virtual const AFX_MSGMAP* GetMessageMap() const;
#define BEGIN_MESSAGE_MAP(theClass, baseClass)
const AFX_MSGMAP* theClass::GetMessageMap() const
{ return GetThisMessa