MFC消息映射BEGIN_MESSAGE_MAP详解

来源:互联网 发布:mac下面工具栏不见了 编辑:程序博客网 时间:2024/06/05 16:57

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


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

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

[cpp] view plaincopy
  1. #define DECLARE_MESSAGE_MAP()   
  2. private:   
  3.     static const AFX_MSGMAP_ENTRY _messageEntries[];   
  4. protected:   
  5.     static AFX_DATA const AFX_MSGMAP messageMap;   
  6.     static const AFX_MSGMAP* PASCAL _GetBaseMessageMap();   
  7.     virtual const AFX_MSGMAP* GetMessageMap() const;   
[cpp] view plaincopy
  1.   

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

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

[cpp] view plaincopy
  1. struct AFX_MSGMAP_ENTRY  
  2. {  
  3.     UINT nMessage;    //消息类型  
  4.     UINT nCode;       // 控制码  
  5.     UINT nID;         // 控件ID  
  6.     UINT nLastID;      // 控件ID范围, 对于单控件消息处理,与nID相同  
  7.     UINT nSig;         // 信号类型  
  8.     AFX_PMSG pfn;    //回调函数,即处理函数  
  9. };  

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

[cpp] view plaincopy
  1. struct AFX_MSGMAP  
  2. {  
  3.     const AFX_MSGMAP* pBaseMap;     //指向父类的指针  
  4.     const AFX_MSGMAP_ENTRY* lpEntries;  //路由表指针  
  5. };  

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

[cpp] view plaincopy
  1. BEGIN_MESSAGE_MAP(CMfc_testApp, CWinApp)  
  2.     ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)  
  3. END_MESSAGE_MAP()  

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

[cpp] view plaincopy
  1. const AFX_MSGMAP* theClass::GetMessageMap() const   
  2. {   
  3.     return &theClass::messageMap;   
  4. }   
  5. const AFX_MSGMAP* PASCAL theClass::_GetBaseMessageMap()   
  6. {   
  7.     return &baseClass::messageMap;   
  8. }  
  9. AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap =   
  10. {   
  11.     &baseClass::messageMap,             //基类路由信息指针  
  12.         &theClass::_messageEntries[0]              //路由表数组地址  
  13. };   
  14.   
  15. AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] =   
  16. {   
  17.     {WM_COMMAND,N_COMMAND,(WORD)id,(WORD)id,AfxSig_vv,(AFX_PMSG)&memberFxn },  
  18.     {0, 0, 0, AfxSig_end, (AFX_PMSG)0 }   
  19. };  

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


三、然后消息循环:CWnd::OnWndMsg(位于WINCORE.cpp文件中)

[cpp] view plaincopy
  1. if (message == pMsgCache->nMsg && pMessageMap == pMsgCache->pMessageMap)  
  2. {  
  3.     //处理在当前类的路由表和缓存命中  
  4. }  
  5. else  
  6. {  
  7.     // 当前类路由表和缓存找不到,  
  8.     pMsgCache->nMsg = message;  
  9.     pMsgCache->pMessageMap = pMessageMap;  
  10.       
  11.     //通过pMessageMap = pMessageMap->pBaseMap递归往基类深入查找匹配  
  12.   
  13.     for (; pMessageMap != NULL; pMessageMap = pMessageMap->pBaseMap)  
  14.     {  
  15.         .....  
  16.     }  
  17.     .....  
  18. }  

总结:

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

原文地址:http://blog.csdn.net/luoti784600/article/details/10070939
0 0
原创粉丝点击