MFC消息映射BEGIN_MESSAGE_MAP詳解

版權聲明:本文爲博主原創文章,遵循 CC 4.0 by-sa 版權協議,轉載請附上原文出處連接和本聲明。
本文連接:https://blog.csdn.net/luoti784600/article/details/10070939
         MFC的消息映射對於對開發者處理消息可謂十分方便。MFC類繼承衆多,虛函數表佔內存大致使微軟直接不採用虛函數方式。發現《VC++深刻詳解》只大概說了消息映射的原理,沒有詳細介紹其實現,因此寫篇小文章探究下。數組

1、首先在使用消息映射以前,必須先聲明DECLARE_MESSAGE_MAP()緩存

DECLARE_MESSAGE_MAP()是個宏定義,對應的源碼爲:函數

#define DECLARE_MESSAGE_MAP() 
private: 
    static const AFX_MSGMAP_ENTRY _messageEntries[]; 
protected: 
    static AFX_DATA const AFX_MSGMAP messageMap; 
    static const AFX_MSGMAP* PASCAL _GetBaseMessageMap(); 
    virtual const AFX_MSGMAP* GetMessageMap() const; .net

聲明添加了兩個成員變量和兩個成員函數:設計

_messageEntries: 是一個AFX_MSGMAP_ENTRY(定義了消息路由)類型數組,即路由表。指針

struct AFX_MSGMAP_ENTRY
{
    UINT nMessage;    //消息類型
    UINT nCode;       // 控制碼
    UINT nID;         // 控件ID
    UINT nLastID;      // 控件ID範圍, 對於單控件消息處理,與nID相同
    UINT nSig;         // 信號類型
    AFX_PMSG pfn;    //回調函數,即處理函數
};blog

messageMap: 路由信息,包含父類路由信息指針,和本類的路由表指針。繼承

struct AFX_MSGMAP
{
    const AFX_MSGMAP* pBaseMap;        //指向父類的指針
    const AFX_MSGMAP_ENTRY* lpEntries;    //路由表指針
};遞歸

2、接着咱們查看BEGIN_MESSAGE_MAP在.cpp文件中的定義內存

BEGIN_MESSAGE_MAP(CMfc_testApp, CWinApp)
    ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
END_MESSAGE_MAP()

能夠看到BEGIN_MESSAGE_MAP也是一個宏。而後上面的ON_COMMAND也是宏定義,所有展開後代碼爲:

const AFX_MSGMAP* theClass::GetMessageMap() const 

    return &theClass::messageMap; 

const AFX_MSGMAP* PASCAL theClass::_GetBaseMessageMap() 

    return &baseClass::messageMap; 
}
AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = 

    &baseClass::messageMap,                //基類路由信息指針
        &theClass::_messageEntries[0]               //路由表數組地址
}; 
 
AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = 

    {WM_COMMAND,N_COMMAND,(WORD)id,(WORD)id,AfxSig_vv,(AFX_PMSG)&memberFxn },
    {0, 0, 0, AfxSig_end, (AFX_PMSG)0 } 
};

能夠看到,經過宏定義和消息內嵌的方式,已經所有初始化消息路由相關的成員變量和方法,結構以下圖所示:

3、而後消息循環:CWnd::OnWndMsg(位於WINCORE.cpp文件中)

if (message == pMsgCache->nMsg && pMessageMap == pMsgCache->pMessageMap)
{
    //處理在當前類的路由表和緩存命中
}
else
{
    // 當前類路由表和緩存找不到,
    pMsgCache->nMsg = message;
    pMsgCache->pMessageMap = pMessageMap;
    
    //經過pMessageMap = pMessageMap->pBaseMap遞歸往基類深刻查找匹配
 
    for (; pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMap)
    {
        .....
    }
    .....
}

總結:
不得不佩服MS牛人在那個年代已經有那麼先進的設計思想!!!

 ————————————————  版權聲明:本文爲CSDN博主「luoti784600」的原創文章,遵循CC 4.0 by-sa版權協議,轉載請附上原文出處連接及本聲明。 原文連接:https://blog.csdn.net/luoti784600/article/details/10070939/

相關文章
相關標籤/搜索