📄 mfc教程_ 消息映射的实现.htm
字号:
<LI><A name=_Toc445889008></A><A name=_Toc445782411></A>DECLARE_MESSAGE_MAP宏:
<P></P>
<P align=justify>首先,看DECLARE_MESSAGE_MAP宏的内容:</P>
<P align=justify>#ifdef _AFXDLL</P>
<P align=justify>#define<B> DECLARE_MESSAGE_MAP</B>() \</P>
<P align=justify>private: \</P>
<P align=justify>static const AFX_MSGMAP_ENTRY _messageEntries[]; \</P>
<P align=justify>protected: \</P>
<P align=justify>static AFX_DATA const AFX_MSGMAP messageMap; \</P>
<P align=justify>static const AFX_MSGMAP* PASCAL _GetBaseMessageMap(); \</P>
<P align=justify>virtual const AFX_MSGMAP* GetMessageMap() const; \</P>
<P align=justify></P>
<P align=justify>#else</P>
<P align=justify>#define <B>DECLARE_MESSAGE_MAP</B>() \</P>
<P align=justify>private: \</P>
<P align=justify>static const AFX_MSGMAP_ENTRY _messageEntries[]; \</P>
<P align=justify>protected: \</P>
<P align=justify>static AFX_DATA const AFX_MSGMAP messageMap; \</P>
<P align=justify>virtual const AFX_MSGMAP* GetMessageMap() const; \</P>
<P align=justify></P>
<P align=justify>#endif</P>
<P align=justify>DECLARE_MESSAGE_MAP定义了两个版本,分别用于静态或者动态链接到MFC DLL的情形。</P>
<P align=justify></P>
<LI><A name=_Toc445889009></A><A name=_Toc445782412></A>BEGIN_MESSAE_MAP宏
<P></P>
<P align=justify>然后,看BEGIN_MESSAE_MAP宏的内容:</P>
<P align=justify>#ifdef _AFXDLL</P>
<P align=justify>#define BEGIN_MESSAGE_MAP(theClass, baseClass) \</P>
<P align=justify>const AFX_MSGMAP* PASCAL theClass::_GetBaseMessageMap() \</P>
<P align=justify>{ return &baseClass::messageMap; } \</P>
<P align=justify>const AFX_MSGMAP* theClass::GetMessageMap() const \</P>
<P align=justify>{ return &theClass::messageMap; } \</P>
<P align=justify>AFX_DATADEF const AFX_MSGMAP theClass::messageMap = \</P>
<P align=justify>{ &theClass::_GetBaseMessageMap,
&theClass::_messageEntries[0] }; \</P>
<P align=justify>const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \</P>
<P align=justify>{ \</P>
<P align=justify></P>
<P align=justify>#else</P>
<P align=justify>#define BEGIN_MESSAGE_MAP(theClass, baseClass) \</P>
<P align=justify>const AFX_MSGMAP* theClass::GetMessageMap() const \</P>
<P align=justify>{ return &theClass::messageMap; } \</P>
<P align=justify>AFX_DATADEF const AFX_MSGMAP theClass::messageMap = \</P>
<P align=justify>{ &baseClass::messageMap,
&theClass::_messageEntries[0] }; \</P>
<P align=justify>const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = \</P>
<P align=justify>{ \</P>
<P align=justify></P>
<P align=justify>#endif</P>
<P align=justify></P>
<P align=justify>#define END_MESSAGE_MAP() \</P>
<P align=justify>{0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \</P>
<P align=justify>}; \</P>
<P align=justify>对应地,BEGIN_MESSAGE_MAP定义了两个版本,分别用于静态或者动态链接到MFC
DLL的情形。END_MESSAGE_MAP相对简单,就只有一种定义。</P>
<P align=justify></P>
<LI>ON_COMMAND宏
<P></P></LI></OL>
<P align=justify>最后,看ON_COMMAND宏的内容:</P>
<P align=justify>#define ON_COMMAND(id, memberFxn) \</P>
<P align=justify>{\</P>
<DIR>
<P align=justify>WM_COMMAND,\</P>
<P align=justify>CN_COMMAND,\</P>
<P align=justify>(WORD)id,\</P>
<P align=justify>(WORD)id,\</P>
<P align=justify>AfxSig_vv,\</P>
<P align=justify>(AFX_PMSG)memberFxn\</P></DIR>
<P align=justify>};</P>
<OL>
<OL>
<OL>
<OL>
<P align=justify>
<LI><A name=_Toc445889010></A><A name=_Toc445782413></A><A
name=_Toc457298970></A><B>消息映射声明的解释</B>
<P></P></LI></OL></OL></OL></OL>
<P align=justify>在清楚了有关宏的定义之后,现在来分析它们的作用和功能。</P>
<P align=justify>消息映射声明的实质是给所在类添加几个静态成员变量和静态或虚拟函数,当然它们是与消息映射相关的变量和函数。</P>
<OL>
<P align=justify>
<LI>成员变量
<P></P></LI></OL>
<P align=justify>有两个成员变量被添加,第一个是_messageEntries,第二个是messageMap。</P>
<UL>
<P align=justify>
<LI>第一个成员变量的声明:
<P></P></LI></UL>
<DIR>
<P align=justify><B>AFX_MSGMAP_ENTRY _messageEntries[]</B></P></DIR>
<P align=justify>这是一个AFX_MSGMAP_ENTRY<B>
</B>类型的数组变量,是一个静态成员变量,用来容纳类的消息映射条目。一个消息映射条目可以用AFX_MSGMAP_ENTRY结构来描述。</P>
<DIR>
<P align=justify>AFX_MSGMAP_ENTRY结构的定义如下:</P></DIR>
<P align=justify>struct AFX_MSGMAP_ENTRY</P>
<P align=justify>{</P>
<P align=justify>//Windows消息ID</P>
<P align=justify>UINT nMessage;</P>
<P align=justify>//控制消息的通知码</P>
<P align=justify>UINT nCode;</P>
<P align=justify>//Windows Control的ID</P>
<P align=justify>UINT nID;</P>
<P align=justify>//如果是一定范围的消息被映射,则nLastID指定其范围</P>
<P align=justify>UINT nLastID;</P>
<P align=justify></P>
<P align=justify>UINT nSig;//消息的动作标识</P>
<P align=justify>//响应消息时应执行的函数(routine to call (or special value))</P>
<P align=justify>AFX_PMSG pfn; </P>
<P align=justify>};</P>
<DIR>
<P
align=justify>从上述结构可以看出,每条映射有两部分的内容:第一部分是关于消息ID的,包括前四个域;第二部分是关于消息对应的执行函数,包括后两个域。</P></DIR>
<P align=justify>在上述结构的六个域中,pfn是一个指向CCmdTarger成员函数的指针。函数指针的类型定义如下:</P>
<P align=justify>typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);</P>
<P
align=justify>当使用一条或者多条消息映射条目初始化消息映射数组时,各种不同类型的消息函数都被转换成这样的类型:不接收参数,也不返回参数的类型。因为所有可以有消息映射的类都是从CCmdTarge派生的,所以可以实现这样的转换。</P>
<P
align=justify>nSig是一个标识变量,用来标识不同原型的消息处理函数,每一个不同原型的消息处理函数对应一个不同的nSig。在消息分发时,MFC内部根据nSig把消息派发给对应的成员函数处理,实际上,就是根据nSig的值把pfn还原成相应类型的消息处理函数并执行它。</P>
<P align=justify></P>
<UL>
<P align=justify>
<LI>第二个成员变量的声明
<P></P></LI></UL>
<P align=justify><B>AFX_MSGMAP messageMap;</B></P>
<P
align=justify>这是一个AFX_MSGMAP类型的静态成员变量,从其类型名称和变量名称可以猜出,它是一个包含了消息映射信息的变量。的确,它把消息映射的信息(消息映射数组)和相关函数打包在一起,也就是说,得到了一个消息处理类的该变量,就得到了它全部的消息映射数据和功能。AFX_MSGMAP结构的定义如下:</P>
<P align=justify>struct AFX_MSGMAP</P>
<P align=justify>{</P>
<P align=justify>//得到基类的消息映射入口地址的数据或者函数</P>
<P align=justify>#ifdef _AFXDLL</P>
<P align=justify>//pfnGetBaseMap指向_GetBaseMessageMap函数</P>
<P align=justify>const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();</P>
<P align=justify>#else</P>
<P align=justify>//pBaseMap保存基类消息映射入口_messageEntries的地址</P>
<P align=justify>const AFX_MSGMAP* pBaseMap;</P>
<P align=justify>#endif</P>
<P align=justify>//lpEntries保存消息映射入口_messageEntries的地址</P>
<P align=justify>const AFX_MSGMAP_ENTRY* lpEntries;</P>
<P align=justify>};</P>
<P
align=justify>从上面的定义可以看出,通过messageMap可以得到类的消息映射数组_messageEntries和函数_GetBaseMessageMap的地址(不使用MFC
DLL时,是基类消息映射数组的地址)。</P>
<P align=justify></P>
<OL>
<P align=justify>
<LI><B>成员函数</B>
<P></P></LI></OL>
<UL>
<P align=justify>
<LI>_GetBaseMessageMap()
<P></P></LI></UL>
<P align=justify>用来得到基类消息映射的函数。</P>
<P align=justify></P>
<UL>
<P align=justify>
<LI>GetMessageMap()
<P></P></LI></UL>
<P align=justify>用来得到自身消息映射的函数。</P>
<OL>
<OL>
<OL>
<OL>
<P align=justify>
<LI><A name=_Toc445889011></A><A name=_Toc445782414></A><A
name=_Toc457298971></A><B>消息映射实现的解释</B>
<P></P></LI></OL></OL></OL></OL>
<P
align=justify>消息映射实现的实质是初始化声明中定义的静态成员函数_messageEntries和messageMap,实现所声明的静态或虚拟函数GetMessageMap、_GetBaseMessageMap。</P>
<P
align=justify>这样,在进入WinMain函数之前,每个可以响应消息的MFC类都生成了一个消息映射表,程序运行时通过查询该表判断是否需要响应某条消息。</P>
<OL>
<P align=justify>
<LI>对消息映射入口表(消息映射数组)的初始化
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -