MFC中,我们可以找到如下三个宏

DECLARE_MESSAGE_MAP()

BEGINE_MESSAGE_MAP(CLASS, BASSCLASS)

END_MESSAGE_MAP()

 

下面来分析这三个宏

1 DECLARE_MESSAGE_MAP()

作用:为一个消息响应类声明必须的成员变量和成员函数。

#define DECLARE_MESSAGE_MAP()

private:

       static const  AFX_MSGMAP_ENTRY _messageEntries[];//AFX_MSGMAP_ENTRY数组变量

protected:

       static const AFX_MSGMAP messageMap; //afx_msg_map变量

       Virtual const AFX_MSGMAP* GetMessageMap() const;//函数声明

可以看出DECLARE_MESSAGE_MAP()宏中定义了两个静态成员变量和一个重载的虚函数。

AFX_MSGMAP_ENTRY根据题意,可以看出这是一个消息入口(消息和消息函数之间的映射)

Struct AFX_MSGMAP_ENTRY

{

UINT nMessage;//windows message

UINT nCode; //control code or WM_NOTIFY code

UINT nID; //control ID(or 0 for windows messages)

UINT nLastID; //used for entries specifying a range of control id’s

UINT nSig; //signature type(action) or pointer to message#

AFX_PMSG pfn; //routine to call(or special value)

};

再看看AFX_MESSAGE结构

Struct AFX_MSGMAP

{

       Const AFX_MSGMAP* pBaseMap;

       Const AFX_MSGMAP_ENTRY* lpEntries;

};

可见结构体AFX_MSGMAP中定义了两个指针,pBaseMap指向另一个AFX_MSGMAPlpEntries指向一个消息入口表。可以推想,在响应消息时,一定是在lpEntries指向的消息入口表中寻找响应函数,也可能会在pBaseMap指向的结构体中做同样的相应函数寻找操作,重载的虚函数GetMessageMap,可以猜测只是用来返回成员messageMap的地址而已。

 

2 .BEGIN_MESSAGE_MAP(CLASS,BASECLASS)

作用:定义DECLARE_MESSAGE_MAP宏声明的静态变量。

#define BEGIN_MESSAGE_MAP(theClass,baseClass)//theClass:当前类 baseClass:当前类的父类

const AFX_MEGMAP* theClass::GetMessageMap() const

{return &theClass::messageMap;}

AFX_COMDAT const AFX_MSGMAP theClass::messageMap =

{&baseClass::messageMap,&theClass::_messageEntries[0]}

AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[]=

{

BEGIN_MESSAGE_MAP宏有两个参数,theClass表示为当前类,baseClass为当前类的父类。

BEGIN_MESSAGE_MAP宏首先定义了函数GetMessageMap的函数体,如前文所述,直接返回当前类的成员变量messageMap的地址。

Const AFX_MSGMAP* theClass::GetMessageMap() const

{

Return &theClass::messageMap;

}

然后初始化了当前类的成员变量messageMapmessageMappBaseMap指针指向其父类的messageMap成员,lpEntries指针指向当前类的_messageEntries数组的首地址。

AFX_COMDAT const AFX_MSGMAP theClass::messageMap 
     &baseClass::messageMap, &theClass::_messageEntries[0] };

最后,定义了_messageEntries数组初始化代码的开始部分。

    AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] 
     

 第三个宏END_MESSAGE_MAP()

作用:定义_messageEntries数组初始化代码的结束部分。

#define END_MESSAGE_MAP()

{0,0,0,0,AfxSig_end,(AFX_PMSG)0}

};

DECLARE_MESSAGE_MAPEND_MESSAGE_MAP之间还有一些宏,如ON_COMMANDON_WM_CREATE等,这些宏最终都会被生成一条AFX_MSGMAP_ENTRY结构体数据,并成为_messageEntries消息映射表数据的一个元素。我们以常见的ON_COMMAND宏为例。ON_COMMAND宏的源代码为:

#define ON_COMMAND(id, memberFxn) 
     WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSigCmd_v, 
         static_cast<AFX_PMSG> (memberFxn) },

通过以上分析,我们可以得到一个链表式的数据结构,子类的messageMap成员为链表的头节点。链表的每个节点都包含一个消息入口表。MFC的消息系统的标准消息处理函数CCmdTraget::OnCmdMsg正是通过这样一个链表查找到消息的响应函数,并调用该函数来响应消息。