在MFC中,我們可以找到如下三個宏
DECLARE_MASSAGE_MAP()
BEGINE_MASSAGE_MAP(CLASS, BASSCLASS)
END_MASSAGE_MAP()
下面來分析這三個宏
1 DECLARE_MESSAGE_MAP()
作用:為一個訊息響應類聲明必需的成員變數和成員函數。
#define DECLARE_MESSAGE_MAP()
private:
static const AFX_MSGMAP_ENTRY _messageEntries[];
protected:
static const AFX_MSGMAP messageMap;
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_PTR 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_MSGMAP,lpEntries指向一個訊息入口表。可以推想,在響應訊息時,一定是在lpEntries指向的訊息入口表中尋找響應函數,也可能會在pBaseMap指向的結構體中做同樣的響應函數尋找操作(有點不理解)。重載的虛函數GetMessageMap,可以猜測只是用來返回成員messageMap的地址而已 2 BEGIN_MESSGAE_MAP(CLASS, BASECLASS)
作用:定義DECLARE_MESSAGE_MAP宏聲明的靜態變數。#define BEGIN_MESSAGE_MAP(theClass, baseClass)
const AFX_MSGMAP* 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表示為當前類,bassClass為當前類的父類。
BEGIN_MESSAGE_MAP宏首先定義了函數GetMessageMap的函數體,如前文所述,直接返回當前類的成員變數messageMap的地址。
const AFX_MSGMAP* theClass::GetMessageMap() const
{ return &theClass::messageMap; }
然後初始化了當前類的成員變數messageMap。messageMap的pBaseMap指標指向其父類的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_MAP和END_MESSAGE_MAP之間還有一些宏,如ON_COMMAND、ON_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的訊息系統的標準備訊息處理函數CCmdTarget::OnCmdMsg正是通過這樣一個鏈表尋找到訊息的響應函數,並調用該函數來響應訊息。