MFC消息映射BEGIN

xiaoxiao2021-02-28  92

 MFC的消息映射对于对开发者处理消息可谓十分方便。MFC类继承众多,虚函数表占内存大导致微软直接不采用虚函数方式。发现 《VC++深入详解》只大概说了消息映射的原理,没有详细介绍其实现,所以写篇小文章探究下。

一、首先在使用消息映射之前,必须先声明DECLARE_MESSAGE_MAP()

DECLARE_MESSAGE_MAP()是个宏定义,对应的源码为:

[cpp] view plain copy print ? #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;    #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; [cpp] view plain copy print ?   

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

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

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

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

[cpp] view plain copy print ? struct AFX_MSGMAP  {      const AFX_MSGMAP* pBaseMap;     //指向父类的指针      const AFX_MSGMAP_ENTRY* lpEntries;  //路由表指针  };   struct AFX_MSGMAP { const AFX_MSGMAP* pBaseMap; //指向父类的指针 const AFX_MSGMAP_ENTRY* lpEntries; //路由表指针 };

二、接着我们查看BEGIN_MESSAGE_MAP在.cpp文件中的定义

[cpp] view plain copy print ? BEGIN_MESSAGE_MAP(CMfc_testApp, CWinApp)      ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)  END_MESSAGE_MAP()   BEGIN_MESSAGE_MAP(CMfc_testApp, CWinApp) ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew) END_MESSAGE_MAP()

可以看到BEGIN_MESSAGE_MAP也是一个宏。然后上面的ON_COMMAND也是宏定义,全部展开后代码为:

[cpp] view plain copy print ? 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 }   };   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文件中)

[cpp] view plain copy print ? if (message == pMsgCache->nMsg && pMessageMap == pMsgCache->pMessageMap)  {      //处理在当前类的路由表和缓存命中  }  else  {      // 当前类路由表和缓存找不到,      pMsgCache->nMsg = message;      pMsgCache->pMessageMap = pMessageMap;            //通过pMessageMap = pMessageMap->pBaseMap递归往基类深入查找匹配        for (; pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMap)      {          .....      }      .....  }   if (message == pMsgCache->nMsg && pMessageMap == pMsgCache->pMessageMap) { //处理在当前类的路由表和缓存命中 } else { // 当前类路由表和缓存找不到, pMsgCache->nMsg = message; pMsgCache->pMessageMap = pMessageMap; //通过pMessageMap = pMessageMap->pBaseMap递归往基类深入查找匹配 for (; pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMap) { ..... } ..... } 总结:

不得不佩服MS牛人在那个年代已经有那么先进的设计思想!!!

转载请注明原文地址: https://www.6miu.com/read-52041.html

最新回复(0)