MFC的设计者们在设计MFC时,紧紧把握一个目标,那就是尽可能使得MFC的代码要小,速度尽可能快。为了这个目标,他们使用了许多技巧,其中很多技巧体现在宏的运用上,实现MFC的消息映射的机制就是其中之一。 
  同MFC消息映射机制有关的宏有下面几个: 
  DECLARE_MESSAGE_MAP()宏 
  BEGIN_MESSAGE_MAP(theClass, baseClass)和END_MESSAGE_MAP()宏 
  弄懂MFC消息映射机制的最好办法是将找出一个具体的实例,将这些宏展开,并找出相关的数据结构。 
  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; / 
  virtual const AFX_MSGMAP* GetMessageMap() const; / 
从上面的定义可以看出,DECLARE_MESSAGE_MAP()作下面三件事: 
  定义一个长度不定的静态数组变量_messageEntries[]; 
  定义一个静态变量messageMap; 
  定义一个虚拟函数GetMessageMap(); 
在DECLARE_MESSAGE_MAP()宏中,涉及到MFC中两个对外不公开的数据结构 
AFX_MSGMAP_ENTRY和AFX_MSGMAP。为了弄清楚消息映射,有必要考察一下这两个数据结构的定义。 
  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 nSig; // signature type (action) or pointer to message # 
   AFX_PMSG pfn; // routine to call (or special value) 
  };

typedef void (AFX_MSG_CALL CCmdTarget::*AFX_PMSG)(void);

结构中各项的含义注释已经说明得很清楚了,这里不再多述,从上面的定义你是否看出,AFX_MSGMAP_ENTRY结构实际上定义了消息和处理此消息的动作之间的映射关系。因此静态数组变量_messageEntries[]实际上定义了一张表,表中的每一项指定了相应的对象所要处理的消息和处理此消息的函数的对应关系,因而这张表也称为消息映射表。再看看AFX_MSGMAP的定义。 
  (2)AFX_MSGMAP的定义 
  struct AFX_MSGMAP 
  { 
   const AFX_MSGMAP* pBaseMap; 
   const AFX_MSGMAP_ENTRY* lpEntries; 
   };

不难看出,AFX_MSGMAP定义了一单向链表,链表中每一项的值是一指向消息映射表的指针(实际上就是_messageEntries的值)。通过这个链表,使得在某个类中调用基类的的消息处理函数很容易,因此,“父类的消息处理函数是子类的缺省消息处理函数”就“顺理成章”了。在后面的“MFC窗口的消息处理”一节中会对此作详细的讲解。

  BEGIN_MESSAGE_MAP()和END_MESSAGE_MAP()

  它们的定义如下: 
  #define BEGIN_MESSAGE_MAP(theClass, baseClass) / 
  const AFX_MSGMAP* theClass::GetMessageMap() const / 
  { return &theClass::messageMap; } / 
  AFX_COMDAT AFX_DATADEF const AFX_MSGMAP theClass::messageMap = / 
  { &baseClass::messageMap, &theClass::_messageEntries[0] }; / 
  AFX_COMDAT const AFX_MSGMAP_ENTRY theClass::_messageEntries[] = / 
  { / 
   #define END_MESSAGE_MAP() / 
   {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } / 
   }; /
对应BEGIN_MESSAGE_MAP()的定义可能不是一下子就看得明白,不过不要紧,举一例子就很清楚了。对于BEGIN_MESSAGE_MAP(CView, CWnd),VC预编译器将其展开成下面的形式: 
  const AFX_MSGMAP* CView::GetMessageMap() const 
  {  
   return &CView::messageMap;  
   } 
  AFX_COMDAT AFX_DATADEF const AFX_MSGMAP CView::messageMap = 
  {  
   &CWnd::messageMap,  
   &CView::_messageEntries[0]  
  }; 
  AFX_COMDAT const AFX_MSGMAP_ENTRY CView::_messageEntries[] = 
  { 
  至于END_MESSAGE_MAP()则不过定义了一个表示映射表结束的标志项,我想大家对于这种简单的技巧应该是很熟悉的,无需多述。 
到此为止,我想大家也已经想到了象ON_COMMAND这样的宏的具体作用了,不错它们只不过定义了一种类型的消息映射项,看看ON_COMMAND的定义: 
  #define ON_COMMAND(id, memberFxn) / 
  { WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)&memberFxn }, 
   根据上面的定义,ON_COMMAND(ID_FILE_NEW, OnFileNew)将被VC预编译器展开 
   如下: 
  {WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSig_vv,  
  (AFX_PMSG)&OnFileNew}, 
到此,MFC的消息映射机制已经清楚了,现在提出并解答两个问题以作为对这一节的小结。

  为什么不直接使用虚拟函数实现消息处理函数呢?这是一个GOOD QUESTION。前面已经说过,MFC的设计者们在设计MFC时有一个很明确的目标,就是使得“MFC的代码尽可能小,速度尽可能快”,如果采用虚拟函数,那么对于所有的窗口消息,都必须有一个与之对应的虚拟函数,因而对每一个从CWnd派生的类而言,都会有一张很大的虚拟函数表vtbl。但是在实际应用中,一般只对少数的消息进行处理,大部分都交给系统缺省处理,所以表中的大部分项都是无用项,这样做就浪费了很多内存资源,这同MFC设计者们的设计目标是相违背的。当然,MFC所使用的方法只是解决这类问题的方式之一,不排除还有其他的解决方式,但就我个人观点而言,这是一种最好的解决方式,体现了很高的技巧性,值得我们学习。

MFC的消息映射机制揭秘的更多相关文章

  1. MFC编程入门之五(MFC消息映射机制概述)

    在MFC软件开发中,界面操作或者线程之间通信都会经常用到消息,通过对消息的处理实现相应的操作.比较典型的过程是,用户操作窗口,然后有消息产生,送给窗口的消息处理函数处理,对用户的操作做出响应. 一.什 ...

  2. VS2010/MFC编程入门之五(MFC消息映射机制概述)

    VS2010/MFC编程入门之五(MFC消息映射机制概述)-软件开发-鸡啄米 http://www.jizhuomi.com/software/147.html 上一讲鸡啄米为大家简单分析了MFC应用 ...

  3. VS2010-MFC(MFC消息映射机制概述)

    转自:http://www.jizhuomi.com/software/147.html 前面已经说过,Windows应用程序是消息驱动的.在MFC软件开发中,界面操作或者线程之间通信都会经常用到消息 ...

  4. MFC的消息响应机制说明

    MFC的快速理解: 1.MFC的设计者们在设计MFC时,有一个主要的方向就是尽可能使得MFC的代码要小,速度尽可能快.为了这个方向,工程师们使用了许多技巧,主要表现在宏的运用上,实 现MFC的消息映射 ...

  5. MFC消息映射机制以及画线功能实现

    ---此仅供用于学习交流,切勿用于商业用途,转载请注明http://www.cnblogs.com/mxbs/p/6213404.html. 利用VS2010创建一个单文档标准MFC工程,工程名为Dr ...

  6. MFC消息映射机制

    1.MFC应用框架主要类之间的关系 MFC自动生成的框架中重要的类有:C-App.CMainFrame.C-Doc和C-View. 其他的类如CClassView.CFileView等都是在框架窗口( ...

  7. 图解MFC基本框架(深入消息映射机制)

    首先,先看整体的消息流向图: 上图解释: 起点是消息循环,在winmain函数中(mfc中winmain函数是隐含的调用的,在app全局对象构造完后紧接着调用winmain函数),while循环中不断 ...

  8. MFC中消息响应机制

    由于视类窗口始终覆盖在框架类窗口之上,因此所有操作,包括鼠标单击.鼠标移动等操作都只能由视类窗口捕获.一个MFC消息响应函数在程序中有三处相关信息:函数原型.函数实现和以及用来关联消息和消息响应函数的 ...

  9. MFC的消息反射机制

    1.消息反射解释: 父窗口将子窗口发给它的通知消息,首先反射回子窗口进行处理(即给子窗口一个机会,让子窗口处理此消息),这样通知消息就有机会能被子窗口自身进行处理. 2.MFC中引入消息反射的原因: ...

随机推荐

  1. png的格式及像素存储分析

    从图片的数据块存储方式来看png分两种 1.索引色模式存储.png8的索引色透明就采取该种方式.该种方式是将颜色存在png的可选模块调色板中,调色板的色彩存储格式为RGB(各1byte).而图片的数据 ...

  2. Three Swaps DFS

    E. Three Swaps time limit per test 1 second memory limit per test 256 megabytes input standard input ...

  3. 用elasticsearch索引mongodb数据

    参照网页:单机搭建elasticsearch和mongodb的river 三个步骤: 一,搭建单机replicSet二,安装mongodb-river插件三,创建meta,验证使用 第一步,搭建单机m ...

  4. Android_Dialog_设置Dialog窗体的大小

    /** * 设置Dialog窗体的大小 */ private void setWindowSize() { DisplayMetrics dm = new DisplayMetrics(); Wind ...

  5. 深入了解Nginx之Nginx与Python(1)

    6 Python和Nginx 6.1 简介FastCGI FastCGI(Fast Common Gateway Interface)是基于CGI上的改进,是CGI的一种演变产物.虽然目的是保持同样的 ...

  6. [Git]自译《Git版本控制管理》——1.介绍(二)_Git诞生

    译者前言:      本系列译文为作者利用业余时间翻译,有些疏漏与翻译不到位的地方敬请谅解.      不过也很希望各位读者能给出中肯的建议.      方括号的注释,如[1][2]为译者注.     ...

  7. (Problem 22)Names scores

    Using names.txt (right click and 'Save Link/Target As...'), a 46K text file containing over five-tho ...

  8. 转: 模块化开发框架seajs简介

    JavaScript模块化开发库之SeaJSSeaJS由国内的牛人lifesinger开发.目前版本是1.1.1,源码不到1500行,压缩后才4k,质量极高.这篇会讲述SeaJS的一些基本用法,不会面 ...

  9. 图的DFS递归和非递归

    看以前写的文章: 图的BFS:http://www.cnblogs.com/youxin/p/3284016.html DFS:http://www.cnblogs.com/youxin/archiv ...

  10. 51cto运维培训课程

    线路图: Linux运维架构师 基础提高篇(120课时) 基础提高篇(240课时) Linux系统基础及系统管理 Shell编程入门及进阶 linux安全管理和企业级安全防范策略 企业级集群/存储专题 ...