MFC消息映射BEGIN_MESSAGE_MAP详解

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/luoti784600/article/details/10070939
         MFC的消息映射对于对开发者处理消息可谓十分方便。MFC类继承众多,虚函数表占内存大导致微软直接不采用虚函数方式。发现《VC++深入详解》只大概说了消息映射的原理,没有详细介绍其实现,所以写篇小文章探究下。

一、首先在使用消息映射之前,必须先声明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; 

声明添加了两个成员变量和两个成员函数:

_messageEntries: 是一个AFX_MSGMAP_ENTRY(定义了消息路由)类型数组,即路由表。

struct AFX_MSGMAP_ENTRY
{
    UINT nMessage;    //消息类型
    UINT nCode;       // 控制码
    UINT nID;         // 控件ID
    UINT nLastID;      // 控件ID范围, 对于单控件消息处理,与nID相同
    UINT nSig;         // 信号类型
    AFX_PMSG pfn;    //回调函数,即处理函数
};

messageMap: 路由信息,包含父类路由信息指针,和本类的路由表指针。

struct AFX_MSGMAP
{
    const AFX_MSGMAP* pBaseMap;        //指向父类的指针
    const AFX_MSGMAP_ENTRY* lpEntries;    //路由表指针
};

二、接着我们查看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 } 
};

可以看到,通过宏定义和消息内嵌的方式,已经全部初始化消息路由相关的成员变量和方法,结构如下图所示:

三、然后消息循环: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/

转载于:https://my.oschina.net/u/3874841/blog/3094290

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值