MFC消息响应机制 q

MFC消息响应机制分析
1 引言
微软公司提供的MFC基本类库(Microsoft Foundation Classes),是进行可视化编程时使用最为流行的一个类

库。MFC封装了大部分Windows API函数和Windows控件,使得程序的开发变得简单,极大的缩短了程序的开发

周期。MFC独创的Document/View框架结构,能够将管理数据的代码和显示数据的程序代码分开,并且设计了

一套方便的消息映射和命令传递机制,方便程序员的开发使用。其中消息映射机制本身比较庞大和复杂,对

它的分析和了解无疑有助于我们写出更为合理的高效的程序。这里我们分析一下MFC的消息映射机制,以了解

MFC是如何对Windows的消息加以封装,方便用户的开发。
2 SDK下的消息机制实现
首先,简单回顾一下SDK下我们是如何进行Windows的程序开发的。Windows程序的运行是依靠外部发生的事件

来驱动的,事件由操作系统捕捉,以消息的形式进入消息队列,然后通过消息循环从队列中不断取出消息,

送到对应的窗口过程里处理。相对于DOS程序,Windows是以WinMain作为程序的入口点,以下就是一个简化的

Win32程序的主体,通过while语句实现消息循环:
WinMain(…)
{
   MSG msg;
   RegisterClass(…);           // 注册窗口类
   CreateWindow(…);            // 创建窗口
   ShowWindow(…);              // 显示窗口
   UpdateWindow(…);
   While(GetMessage(&msg,…)){   // 消息循环
TranslateMessage(…);
DispatchMessage(…);
}
return msg.wParam;
}
其中,msg代表消息,程序是通过GetMessage函数从和某个线程相对应的消息队列里面把消息取出来并放到消

息变量msg里面。然后TranslateMessage函数用来把键盘消息转化并放到响应的消息队列里面,最后

DispatchMessage函数把消息分发到相关的窗口过程去处理。窗口过程根据消息的类型对不同的消息进行相关

的处理。在SDK编程过程中,用户需要在窗口过程中分析消息的类型及其参数的含义,然后做不同的处理,相

对比较麻烦;而MFC把消息调用的过程给封装起来,使用户能够通过ClassWizard方便的使用和处理Windows的

各种消息。
3 MFC中的消息映射机制
在MFC的框架结构下,“消息映射”是通过巧妙的宏定义,形成一张消息映射表格来进行的。这样一旦消息发

生,Framework就可以根据消息映射表格来进行消息映射和命令传递。
首先在需要进行消息处理的类的头文件(.H)里,都会含有DECLARE_MESSAGE_MAP()宏,声明该类拥有消息映

射表格:
class CscribbleDoc:public Cdocument
{
    …
DECLARE_MESSAGE_MAP()
};
然后在类应用程序文件(.CPP)实现这一表格
BEGIN_MESSAGE_MAP(CInheritClass, CBaseClass)
          //{{AFX_MSG_MAP(CInheritClass)
         ON_COMMAND(ID_EDIT_COPY,OnEditCopy)
         ………
          //}}AFX_MSG_MAP
END_MESSAGE_MAP()
----这里主要进行消息映射的实现,把它和消息处理函数联系在一起。其中出现三个宏,第一个宏是

BEGIN_MESSAGE_MAP有两个参数,分别是拥有消息表格的类,及其父类。第二个宏是ON_COMMAND,指定命令消

息的处理函数名称。第三个宏是END_MESSAGE_MAP()作为结尾符号。中间的奇怪符号//}}和//{{,是

ClassWizard产生的,对程序无影响。
观察DECLARE_MESSAGE_MAP的定义:
#define DECLARE_MESSAGE_MAP () \
private: \
static const AFX_MESSAGE_ENTRY _messageEntries[]; \
protected: \
static AFX_DATA const AFX_MSGMAP messageMap; \
virtual const AFX_MSGMAP* GetMessageMap() const; \
里面又包含了MFC新定义的两个数据结构,如下:
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)
};
和AFX_MSGMAP
struct AFX_MSGMAP
{
          const AFX_MSGMAP* pBaseMap;
          const AFX_MSGMAP_ENTRY* lpEntries;
};
其中AFX_MSGMAP_ENTRY结构包含了一个消息的所有相关信息,而AFX_MSGMAP主要作用有两个,一是用来得到基

类的消息映射入口地址。二是得到本身的消息映射入口地址。
实际上,MFC把所有的消息一条条填入到AFX_MSGMAP_ENTRY结构中去,形成一个数组,该数组存放了所有的消

息和与它们相关的参数。同时通过AFX_MSGMAP能得到该数组的首地址,同时得到基类的消息映射入口地址。

当本身对该消息不响应的时候,就可以上溯到基类的消息映射表寻找对应的消息响应。
现在我们来分析MFC是如何让窗口过程来处理消息的,实际上所有MFC的窗口类都通过钩子函数

_AfxCbtFilterHook截获消息,并且在钩子函数_AfxCbtFilterHook中把窗口过程设定为AfxWndProc。原来的

窗口过程保存在成员变量m_pfnSuper中。
在MFC框架下,一般一个消息的处理过程是这样的。
(1)函数AfxWndProc接收Windows操作系统发送的消息。
(2)函数AfxWndProc调用函数AfxCallWndProc进行消息处理,这里一个进步是把对句柄的操作转换成对CWnd对

象的操作。
(3)函数AfxCallWndProc调用CWnd类的方法WindowProc进行消息处理。
(4)WindowProc调用OnWndMsg进行正式的消息处理,即把消息派送到相关的方法中去处理。在CWnd类中都保存

了一个AFX_MSGMAP的结构,而在AFX_MSGMAP结构中保存有所有我们用ClassWizard生成的消息的数组的入口,

我们把传给OnWndMsg的message和数组中的所有的message进行比较,找到匹配的那一个消息。实际上系统是

通过函数AfxFindMessageEntry来实现的。找到了那个message,实际上我们就得到一个AFX_MSGMAP_ENTRY结

构,而我们在上面已经提到AFX_MSGMAP_ENTRY保存了和该消息相关的所有信息,其中主要是消息的动作标识

和相关的执行函数。然后我们就可以根据消息的动作标识调用相关的执行函数,而这个执行函数实际上就是

通过ClassWizard在类实现中定义的一个方法。这样就把消息的处理转化到类中的一个方法的实现上。
(5)如果OnWndMsg方法没有对消息进行处理的话,就调用DefWindowProc对消息进行处理。这是实际上是调用

原来的窗口过程进行缺省的消息处理。 所以如果正常的消息处理的话,MFC窗口类是完全脱离了原来的窗口

过程,用自己的一套体系结构实现消息的映射和处理。即先调用MFC窗口类挂上去的窗口过程,再调用原先的

窗口过程。用户面对的消息参数将不再是固定的wParam和lParam,而是和消息类型具体相关的参数。比如和消

息WM_LButtonDown相对应的方法OnLButtonDown的两个参数是nFlags和point。nFlags表示在按下鼠标左键的

时候是否有其他虚拟键按下,point更简单,就是表示鼠标的位置。同时MFC窗口类消息传递中还提供了两个

函数,分别为WalkPreTranslateTree和PreTranslateMessage。我们知道利用MFC框架生成的程序,都是从

CWinApp开始执行的,而CWinapp实际继承了CWinThread类。在CWinThread的运行过程中会调用窗口类中的

WalkPreTranslateTree方法。而WalkPreTranslateTree方法实际上就是从当前窗口开始查找愿意进行消息翻

译的类,直到找到窗口没有父类为止。在WalkPreTranslateTree方法中调用了PreTranslateMessage方法。实

际上PreTranslateMessage最大的好处是我们在消息处理前可以在这个方法里面先做一些事情。举一个简单的

例子,比如我们希望在一个CEdit对象里,把所有的输入的字母都以大写的形式出现。我们只需要在

PreTranslateMessage方法中判断message是否为WM_CHAR,如果是的话,把wParam(表示键值)由小写字母的值

该为大写字母的值就实现了这个功能。
4 小结
MFC通过巧妙的宏定义把消息调用的过程给封装起来,使用户能够通过ClassWizard方便的使用和处理Windows

的各种消息。通过对MFC消息映射机制的分析,不仅能够使我们更好的使用MFC类库,同时,对于我们自己设

计程序框架和类,无疑也有相当大的帮助。

时间: 2024-10-17 04:18:13

MFC消息响应机制 q的相关文章

MFC消息响应机制分析

---- 摘要: ---- MFC是Windows下程序设计的最流行的一个类库,但是该类库比较庞杂,尤其是它的消息映射机制,更是涉及到很多低层的东西,我们在这里,对它的整个消息映射机制进行了系统的分析,可以帮助程序开发人员对MFC的消息映射机制有一个比较透彻的了解. ---- 关键词:面向对象 消息映射 MFC 程序设计 一.引言---- VC++的MFC类库实际上是Windows下C++编程的一套最为流行的类库.MFC的框架结构大大方便了程序员的编程工作,但是为了更加有效.灵活的使用MFC编程

MFC中消息响应机制

由于视类窗口始终覆盖在框架类窗口之上,因此所有操作,包括鼠标单击.鼠标移动等操作都只能由视类窗口捕获.一个MFC消息响应函数在程序中有三处相关信息:函数原型.函数实现和以及用来关联消息和消息响应函数的宏. (1)在消息响应函数的原型代码中,函数声明的前部有一个afx_msg限定符,也是一个宏,该宏表明这个函数是一个消息响应函数的声明. (2)消息映射宏:在视图类的源文件中,BEGIN_MESSAGE_MAP()和 END_MASSAGE_MAP()这两个宏之间定义了消息映射表,例如对于画线,其中

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

在MFC软件开发中,界面操作或者线程之间通信都会经常用到消息,通过对消息的处理实现相应的操作.比较典型的过程是,用户操作窗口,然后有消息产生,送给窗口的消息处理函数处理,对用户的操作做出响应. 一.什么是消息?  窗口消息一般由三个部分组成:1.一个无符号整数,是消息值:2.消息附带的WPARAM类型的参数:3.消息附带的LPARAM类型的参数.其实,我们一般所说的消息是侠义上的消息值,也就是一个无符号整数,经常被定义为宏. 二.什么是消息映射机制?  MFC使用一种消息映射机制来处理消息,在应

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

VS2010/MFC编程入门之五(MFC消息映射机制概述)-软件开发-鸡啄米 http://www.jizhuomi.com/software/147.html     上一讲鸡啄米为大家简单分析了MFC应用程序框架,这一讲是关于MFC消息映射机制的内容.        前面已经说过,Windows应用程序是消息驱动的.在MFC软件开发中,界面操作或者线程之间通信都会经常用到消息,通过对消息的处理实现相应的操作.比较典型的过程是,用户操作窗口,然后有消息产生,送给窗口的消息处理函数处理,对用户的

c++对MFC消息映射机制和运行时类型识别的理解

对MFC消息映射机制和运行时类型识别的理解 对MFC消息映射机制的理解 MFC中派生于Cobject的每个类都有一个消息映射表,所有MFC窗口都有一个同样的窗口过程AfxWndProc(),AfxWndProc的参数列表中有一个是窗口句柄,在AfxWndProc函数中将句柄(HWND)转换成了窗口指针(CWnd*),通过这个窗口指针就可以获得该窗口的消息映射表.对于WM_COMMAND这类特殊消息,将依据C++的虚函数多态机制来决定调用哪个类的函数. 对MFC运行时类型识别的理解 定义一个CRu

MFC消息映射机制详解

 MFC消息映射机制: 在每个能接收和处理消息的类中,定义一个消息与消息处理函数的映射表,即消息映射表.MFC有一个窗口句柄与C++对象指针的映射表,当窗口收到消息时,消息的第一个参数指明了该消息与哪个窗口句柄相关,通过映射表找到C++对象指针,然后将这个指针传递给应用程序框架窗口类的基类,基类调用WindowProc函数(在wincore.cpp文件中),这是一个虚函数,函数内部调用OnWndMsg函数,消息处理就是在这个函数内完成的,该函数也在wincore.cpp中.OnWndMsg函

MFC消息映射机制

1 消息循环所在的函数 CWinApp::Run 2  消息类别 <1>Windows Messages WM_XX前缀开头,但是除了WM_COMMAND消息外. <2>Control Notifications 包含来自控件或者子窗口发给父窗口的 WM_COMMAND的通知消息. <3>Command Messages 菜单,工具栏按钮,快捷键 3 消息的发送和接受 CWinApp::Run函数接受消息并且将他们分派到合适的窗口,大多数命令消息时被发送到主框架窗口.接

C++MFC编程笔记day02 MFC消息映射机制、菜单资源使用

机制3:MFC消息映射机制: 类内声明,类外定义宏,绑定消息处理函数 派生自CCmdTarget 类内声明宏:DECLARE_MESSAGE_MAP() 类外添加实现宏: BEGIN_MESSAGE_MAP(类名,父类名) END_MESSAGE_MAP() //数据结构 struct AFX_MSGMAP_ENTRY { UINT nMessage;   // 消息ID UINT nCode;      // 通知码 UINT nID;        // 控件ID或消息 UINT nLast

自制MFC消息响应定位器+原理分析

mfc里面有张消息映射表(MESSAGE_MAP),消息都是通过这张表来分发到相应函数里的. 这个是我自制的定位器,从vc6.0到现在的2013生成的mfc都可以用,全静态扫描并已处理动态基址. 下面来看MESSAGE_MAP结构: struct AFX_MSGMAP_ENTRY{        UINT nMessage;           UINT nCode;                 UINT nID;                     UINT nLastID;