?? mfc
字號:
<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>
align=justify>這樣,在進入WinMain函數之前,每個可以響應消息的MFC類都生成了一個消息映射表,程序運行時通過查詢該表判斷是否需要響應某條消息。</P>
<OL>
<P align=justify>
<LI>對消息映射入口表(消息映射數組)的初始化
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -