开发学院软件开发VC 深度解析VC中的消息(下) 阅读

深度解析VC中的消息(下)

 2009-10-27 20:31:17 来源:WEB开发网   
核心提示:前面,我们分析了消息的基本理论和基本的函数及用法,深度解析VC中的消息(下),接下来,我们将进一步讨论消息传递在MFC中的实现,是一个public属性的;与之对应的是在实现部分(.cpp)增加了一章消息映射表,内容如下:BEGIN_MESSAGE_MAP(当前类, 当前类的基类)//{{AFX_MSG_MAP(CMai

前面,我们分析了消息的基本理论和基本的函数及用法,接下来,我们将进一步讨论消息传递在MFC中的实现。

MFC消息的处理实现方式

初看MFC中的各种消息,以及在头脑中根深蒂固的C++的影响,我们可能很自然的就会想到利用C++的三大特性之一:虚拟机制来实现消息的传递,但是经过分析,我们看到事情并不是想我们想象的那样,在MFC中消息是通过一种所谓的消息映射机制来处理的。

为什么呢?在潘爱民老师翻译的《Visual C++技术内幕》(第4版)中给出了详细的原因说明,我再简要的说一遍。在CWnd类中大约有110个消息,还有其它的MFC的类呢,算起来消息太多了,在C++中对程序中用到的每一个派生类都要有一个vtable,每一个虚函数在vtable中都要占用一个4字节大小的入口地址,这样一来,对于每个特定类型的窗口或控件,应用程序都需要一个440KB大小的表来支持虚拟消息控件函数。

如果说上面的窗口或控件可以勉强实现的话,那么对于菜单命令消息及按钮命令消息呢?因为不同的应用程序有不同的菜单和按钮,我们怎么处理呢?在MFC库的这种消息映射系统就避免了使用大的vtable,并且能够在处理常规Windows消息的同时处理各种各样的应用程序的命令消息。

说白了,MFC中的消息机制其实质是一张巨大的消息及其处理函数的一一对应表,然后加上分析处理这张表的应用框架内部的一些程序代码.这样就可以避免在SDK编程中用到的繁琐的CASE语句。

MFC的消息映射的基类CCmdTarget

如果你想让你的控件能够进行消息映射,就必须从CCmdTarget类中派生。CCmdTarget类是MFC处理命令消息的基础、核心。MFC为该类设计了许多成员函数和一些成员数据,基本上是为了解决消息映射问题的,所有响应消息或事件的类都从它派生,例如:应用程序类、框架类、文档类、视图类和各种各样的控件类等等,还有很多。

不过这个类里面有2个函数对消息映射非常重要,一个是静态成员函数DispatchCmdMsg,另一个是虚函数OnCmdMsg。

DispatchCmdMsg专门供MFC内部使用,用来分发Windows消息。OnCmdMsg用来传递和发送消息、更新用户界面对象的状态。

CCmdTarget对OnCmdMsg的默认实现:在当前命令目标(this所指)的类和基类的消息映射数组里搜索指定命令消息的消息处理函数。

这里使用虚拟函数GetMessageMap得到命令目标类的消息映射入口数组_messageEntries,然后在数组里匹配命令消息ID相同、控制通知代码也相同的消息映射条目。其中GetMessageMap是虚拟函数,所以可以确认当前命令目标的确切类。

如果找到了一个匹配的消息映射条目,则使用DispachCmdMsg调用这个处理函数;

如果没有找到,则使用_GetBaseMessageMap得到基类的消息映射数组,查找,直到找到或搜寻了所有的基类(到CCmdTarget)为止;

如果最后没有找到,则返回FASLE。

每个从CCmdTarget派生的命令目标类都可以覆盖OnCmdMsg,利用它来确定是否可以处理某条命令,如果不能,就通过调用下一命令目标的OnCmdMsg,把该命令送给下一个命令目标处理。通常,派生类覆盖OnCmdMsg时,要调用基类的被覆盖的OnCmdMsg。

在MFC框架中,一些MFC命令目标类覆盖了OnCmdMsg,如框架窗口类覆盖了该函数,实现了MFC的标准命令消息发送路径。必要的话,应用程序也可以覆盖OnCmdMsg,改变一个或多个类中的发送规定,实现与标准框架发送规定不同的发送路径。例如,在以下情况可以作这样的处理:在要打断发送顺序的类中把命令传给一个非MFC默认对象;在新的非默认对象中或在可能要传出命令的命令目标中。

消息映射的内容

通过ClassWizard为我们生成的代码,我们可以看到,消息映射基本上分为2大部分:

在头文件(.h)中有一个宏DECLARE_MESSAGE_MAP(),他被放在了类的末尾,是一个public属性的;与之对应的是在实现部分(.cpp)增加了一章消息映射表,内容如下:

  BEGIN_MESSAGE_MAP(当前类, 当前类的基类)

     //{{AFX_MSG_MAP(CMainFrame)

     消息的入口项

     //}}AFX_MSG_MAP

     END_MESSAGE_MAP()

但是仅是这两项还远不足以完成一条消息,要是一个消息工作,必须有以下3个部分去协作:

1.在类的定义中加入相应的函数声明;

2.在类的消息映射表中加入相应的消息映射入口项;

3.在类的实现中加入相应的函数体;

1 2  下一页

Tags:深度 解析 VC

编辑录入:爽爽 [复制链接] [打 印]
[]
  • 好
  • 好的评价 如果觉得好,就请您
      0%(0)
  • 差
  • 差的评价 如果觉得差,就请您
      0%(0)
赞助商链接