MFC消息机制

何谓消息、消息处理函数、消息映射?
消息简单的说就是指通过输入设备向程序发出指令要执行某个操作。具体的某个操作是你的一系列代码。称为消息处理函数。

在SDK中消息其实非常容易理解,当窗口建立后便会有一个函数(窗口处理函数)开始执行一个消息循环,我们还可以清楚的看到消息处理的脉络。一个switch case语句就可以搞定,消息循环直到遇到WM_QUIT消息才会结束,其余的消息均被拦截后调用相应的处理函数。

但在封装了API的MFC中,消息似乎变的有些复杂了,我们看不到熟悉的switch case语句了,取而代之的是一个叫消息映射的东西。为什么MFC要引入消息映射机制,你可以想象一下,在现在的程序开发活动中,你的一个程序是否拥有多个窗体,主窗口就算只有一个,那菜单、工具条、控件这些都是子窗口,那我们需要写多少个switch case,并且还要为每个消息分配一个消息处理函数,这样做是多么的复杂呀。因此MFC采用了一种新的机制。利用一个数组,将窗口消息和相对应的消息处理函数进行映射,你可以理解成这是一个表。这种机制就是消息映射。这张表在窗口基类CWnd定义,派生类的消息映射表如果你没有动作它是空的,也就是说如果你不手工的增加消息处理函数,则当派生窗口接受一个消息时会执行父类的消息处理函数。这样做显然是高效的。

MFC提供的消息结构
同时MFC定义了下面的两个主要结构:
AFX_MSGMAP_ENTRY
struct AFX_MSGMAP_ENTRY{
UINT nMessage;   // Windows消息的ID号
UINT nCode;  // 控制消息的通知
UINT nID;    // Windows控制消息的ID
UINT nLastID;   //表示是一个指定范围的消息被映射的范围
UINT nSig;  //表示消息的动作标识
AFX_PMSG pfn;    // 指向消息处理函数的指针
};
AFX_MSGMAP
struct AFX_MSGMAP{
#ifdef _AFXDLL
const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
#else
const AFX_MSGMAP* pBaseMap;
#endif
const AFX_MSGMAP_ENTRY* lpEntries;
};
///AFX_MSGMAP可以得到基类的消息映射入口地址和得到本身的消息映射入口地址。

MFC下一个消息的处理过程是一般是这样的。
1、_AfxCbtFilterHook截获消息(这是一个钩子函数)
2、_AfxCbtFilterHook把窗口过程设定为AfxWndProc。
3、函数AfxWndProc接收Windows操作系统发送的消息。
4、函数AfxWndProc调用函数AfxCallWndProc进行消息处理。
5、函数AfxCallWndProc调用CWnd类的方法WindowProc进行消息处理。

如何添加自己的消息?
我们已经了解了WINDOW的消息机制,如何加入我们自己的消息呢?好我们来看
一个标准的消息处理程序是这个样子的
在 CWnd 类中预定义了标准 Windows 消息 (WM_XXXX  WM是WINDOW MESSAGE的缩写) 的默认处理程序。类库基于消息名命名这些处理程序。例如,WM_PAINT 消息的处理程序在 CWnd 中被声明为:
afx_msg void OnPaint();
afx_msg 关键字通过使这些处理程序区别于其他 CWnd 成员函数来表明 C++ virtual 关键字的作用。但是请注意,这些函数实际上并不是虚拟的,而是通过消息映射实现的。我们在本文的一开始便说明了为什么要这样做。
所有能够进行消息处理的类都是基于CCmdTarget类的,也就是说CCmdTarget类是所有可以进行消息处理类的父类。CCmdTarget类是MFC处理命令消息的基础和核心。

若要重写基类中定义的处理程序,只需在派生类中定义一个具有相同原型的函数,并创建此处理程序的消息映射项。我们通过ClassWizard可以建立大多数窗口消息或自定义的消息,通过ClassWizard可以自动建立消息映射,和消息处理函数的框架,我们只需要把我们要做的事情填空,添加你要做的事情到处理函数。这个非常简单,就不细说了。但是也许我们需要添加一些ClassWizard不支持的窗口消息或自定义消息,那么就需要我们亲自动手建立消息映射和消息处理的框架,通常步骤如下:
第一步:定义消息。Microsoft推荐用户自定义消息至少是WM_USER+100,因为很多新控件也要使用WM_USER消息。
#define WM_MYMESSAGE (WM_USER + 100)

第二步:实现消息处理函数。该函数使用WPRAM和LPARAM参数并返回LPESULT。
LPESULT CMainFrame::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
// TODO: 处理用户自定义消息,填空就是要填到这里。
return 0;
}
第三步:在类头文件的AFX_MSG块中说明消息处理函数:
// {{AFX_MSG(CMainFrame)
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
第四步:在用户类的消息块中,使用ON_MESSAGE宏指令将消息映射到消息处理函数中。
ON_MESSAGE( WM_MYMESSAGE, OnMyMessage )

可以看出,用户自定义的消息和我们通过ClassWizard添加的消息一样,都是利用了ON_MESSAGE宏,建立的消息映射。

其实消息类别可以分成多种,上面说的只是其中之一。有三种主要的消息类别:(以下部分摘自MSDN)
1、Windows 消息
此类消息主要包括以前缀 WM_ 开头的消息,WM_COMMAND 除外。Windows 消息由窗口和视图处理。此类消息往往带有用于确定如何处理消息的参数。
2、控件通知
此类消息包括从控件和其他子窗口发送到其父窗口的 WM_COMMAND 通知消息。例如,当用户在编辑控件 (Edit Control) 中执行可能更改文本的操作后,该编辑控件 (Edit Control) 将向其父级发送包含 EN_CHANGE 控件通知代码的 WM_COMMAND 消息。该消息的窗口处理程序以某种适当的方式响应此通知消息,例如在控件中检索该文本。
框架像传送其他 WM_ 消息一样传送控件通知消息。但是有一个例外的情况,即当用户单击按钮时由按钮发送的 BN_CLICKED 控件通知消息。该消息被作为命令消息特别处理,并像其他命令一样传送。
3、命令消息
此类消息包括用户界面对象(菜单、工具栏按钮和快捷键)发出的 WM_COMMAND 通知消息。框架处理命令的方式与处理其他消息不同,可以使用更多种类的对象处理命令。
Windows 消息和控件通知消息由窗口来处理(窗口是从 CWnd 类派生的类的对象)。包括 CFrameWnd、CMDIFrameWnd、CMDIChildWnd、CView、CDialog 以及从这些基类派生的您自己的类。这些对象封装了 HWND——Windows 窗口的句柄。
命令消息可以由范围更广的对象(文档、文档模板以及应用程序对象本身)处理,而不仅仅由窗口和视图处理。当某一命令直接影响到某个特定对象时,应当让该对象处理此命令。例如,“文件”菜单中的“打开”命令在逻辑上与应用程序相关联:该应用程序接收到此命令时会打开指定的文档。因此“打开”命令的处理程序是应用程序类的成员函数。

命令消息我们比较常见的便是菜单项和工具条了,大家可以看到他的消息映射宏和窗口消息不太一样,一般的形式是这样的
ON_COMMAND(id,memberFxn)
第一个参数是命令ID,一个ID号对应一个消息处理,当然你可以让多个ID共用一个处理函数。常见的应用例如:菜单项打开文档的ID和工具条按钮打开文档的ID同时使用一个处理函数,或者直接将它们的ID设成相同的。

还有一种消息叫通知消息。例如树型控件的等一些复杂的控件在单击后需要传递更多的信息,例如光标的位置和当前项的一个结构,所以MFC为控件的每个通知消息也定义了一个宏,它长成了这个样子:
ON_CONTROL(EN_CHANGE,id,memberFxn)

还有很多种消息存在于MFC,宏定义有区别,大家可以触类旁通。

窗口消息有上百个。你可以从MSDN上查到WM_开头的,或者查看CWnd的成员函数,会给你列出很多,别忘了还有很多非窗口消息。雷神无法一一列出,也没有必要。大家查一下就行了。不过对一些常用的、新的控件消息和特殊的通知消息我还是把他们列出几个表,大家做个参考吧。

MFC中处理消息的顺序

1.     AfxWndProc()接收消息,寻找消息所属的CWnd对象,然后调用AfxCallWndProc( )。

2.     AfxCallWndProc()存储消息(消息标识符和消息参数)供未来参考,然后调用WindowProc( )。

3.     WindowProc()发送消息给OnWndMsg( ),如果消息未被处理,则发送给DefWindowproc( )。

4.     OnWndMsg()首先按字节对消息进行排序,对于WM_COMMAND消息,调用OnCommand()消息响应函数;对于WM_NOTIFY消息调用OnNotify()消息响应函数。任何被遗漏的消息将是标准消息。OnWndMsg()函数搜索类的消息映像,以找到一个能处理任何窗口消息的处理函数。如果OnWndMsg()函数不能找到这样的处理函数的话,则把消息返回到WindowProc()函数,由它将消息发送给DefWindowProc()函数。

5.     OnCommand()查看这是不是一个控件通知(lParam参数不为NULL),如果它是,OnCommand()函数会试图将消息映射到制造通知的控件;如果它不是一个控件通知,或者控件拒绝映射的消息,OnCommand()就会调用OnCmdMsg()函数。

6.     OnNotify( )也试图将消息映射到制造通知的控件;如果映射不成功,OnNotify( )就调用相同的OnCmdMsg( )函数。

7.     根据接收消息的类,OnCmdMsg()函数将在一个称为命令传递(Command Routing)的过程中潜在的传递命令消息和控件通知。例如:如果拥有该窗口的类是一个框架类,则命令和控件通知消息也被传递到视图和文档类,并为该类寻找一个消息处理函数。

MFC中创建窗口的顺序

1.     PreCreateWindow()是一个重载函数,在窗口被创建前,可以在该重载函数中改变创建参数(可以设置窗口风格等等)。

2.     PreSubclassWindow()也是一个重载函数,允许首先子分类一个窗口OnGetMinMaxInfo()为消息响应函数,响应的是WM_GETMINMAXINFO消息,允许设置窗口的最大或者最小尺寸。

3.     OnNcCreate()也是一个消息响应函数,响应WM_NCCREATE消息,发送消息以告诉窗口的客户区即将被创建。

4.     OnNcCalcSize()也是消息响应函数,响应WM_NCCALCSIZE消息,作用是允许改变窗口客户区大小。

5.     OnCreate()也是消息响应函数,响应WM_CREATE消息,发送消息告诉一个窗口已经被创建。

6.     OnSize()也是消息响应函数,响应WM_SIZE消息,发送该消息以告诉该窗口大小已经发生变化。

7.     OnMove()也是消息响应函数,响应WM_MOVE消息,发送此消息说明窗口在移动。

8.     OnChildNotify()为重载函数,作为部分消息映射被调用,告诉父窗口即将被告知一个窗口刚刚被创建。

MFC中打开模态对话框的顺序

1.     DoModal()是重载函数,重载DoModal()成员函数。

2.     PreSubclassWindow()也是重载函数,允许首先子分类一个窗口。

3.     OnCreate()是消息响应函数,响应WM_CREATE消息,发送此消息以告诉一个窗口已经被创建。

4.     OnSize()也是消息响应函数,响应WM_SIZE消息,发送此消息以告诉窗口大小发生变化。

5.     OnMove()也是消息响应函数,响应WM_MOVE消息,发送此消息以告诉窗口正在移动。

6.     OnSetFont()也是消息响应函数,响应WM_SETFONT消息,发送此消息以允许改变对话框中控件的字体。

7.     OnInitDialog()也是消息响应函数,响应WM_INITDIALOG消息,发送此消息以允许初始化对话框中的控件,或者是创建新控件。

8.     OnShowWindow()也是消息响应函数,响应WM_SHOWWINDOW消息,该函数被ShowWindow()函数调用。

9.     OnCtlColor()也是消息响应函数,响应WM_CTLCOLOR消息,被父窗口发送已改变对话框或对话框上面控件的颜色。

10. OnChildNotify()是重载函数,作为WM_CTLCOLOR消息的结果发送。

MFC中关闭模态对话框的顺序

1.     OnClose()是消息响应函数,响应WM_CLOSE消息,当"关闭"按钮被单击的时候,该函数被调用。

2.     OnKillFocus()也是消息响应函数,响应WM_KILLFOCUS消息,当一个窗口即将失去键盘输入焦点以前被发送。

3.     OnDestroy()也是消息响应函数,响应WM_DESTROY消息,当一个窗口即将被销毁时,被发送。

4.     OnNcDestroy()也是消息响应函数,响应WM_NCDESTROY消息,当一个窗口被销毁以后被发送。

5.     PostNcDestroy()也是重载函数,作为处理OnNcDestroy()函数的最后动作被CWnd调用。

MFC中打开非模态对话框的顺序

1.     PreSubclassWindow()是重载函数,允许用户首先子分类一个窗口。

2.     OnCreate()是消息响应函数,响应WM_CREATE消息,发送此消息以告诉一个窗口已经被创建。

3.     OnSize()也是消息响应函数,响应WM_SIZE消息,发送此消息以告诉窗口大小发生变化。

4.     OnMove()也是消息响应函数,响应WM_MOVE消息,发送此消息以告诉窗口正在移动。

5.     OnSetFont()也是消息响应函数,响应WM_SETFONT消息,发送此消息以允许改变对话框中控件的字体。

MFC中关闭非模态对话框的顺序

1.     OnClose()是消息响应函数,响应窗口的WM_CLOSE消息,当关闭按钮被单击的时候发送此消息。

2.     OnDestroy()也是消息响应函数,响应窗口的WM_DESTROY消息,当一个窗口将被销毁时发送此消息。

3.     OnNcDestroy()也是消息响应函数,响应窗口的WM_NCDESTROY消息,当一个窗口被销毁后发送此消息。

4.     PostNcDestroy()是重载函数,作为处理OnNcDestroy()函数的最后动作,被CWnd调用。

时间: 2024-10-01 18:34:29

MFC消息机制的相关文章

MFC消息响应机制分析

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

MFC框架剖析和消息机制

即便是基于MFC的应用程序,建立窗口类也是会遵循如下的过程: 设计窗口类->注册窗口类->生成窗口->显示窗口->更新窗口->消息循环->消息路由到窗口过程函数处理.下面就剖析一下在MFC中是如何完成上述过程的. (1)每个应用程序都有且仅有一个应用类的全局变量theApp,全局变量先于WinMain函数进行处理. (2)WinMain函数体在APPMODUL.CPP文件中,定义如下: extern "C" int WINAPI _tWinMain(

MFC消息响应机制 q

MFC消息响应机制分析 1 引言微软公司提供的MFC基本类库(Microsoft Foundation Classes),是进行可视化编程时使用最为流行的一个类 库.MFC封装了大部分Windows API函数和Windows控件,使得程序的开发变得简单,极大的缩短了程序的开发 周期.MFC独创的Document/View框架结构,能够将管理数据的代码和显示数据的程序代码分开,并且设计了 一套方便的消息映射和命令传递机制,方便程序员的开发使用.其中消息映射机制本身比较庞大和复杂,对 它的分析和了

windows消息机制(MFC)

windows消息机制(MFC) 消息分类与消息队列 Windows中,消息使用统一的结构体(MSG)来存放信息,其中message表明消息的具体的类型, 而wParam,lParam是其最灵活的两个变量,为不同的消息类型时,存放数据的含义也不一样. time表示产生消息的时间,pt表示产生消息时鼠标的位置. 按照类型,Windows将消息分为: (0) 消息ID范围 系统定义消息ID范围:[0x0000, 0x03ff]用户自定义的消息ID范围: WM_USER: 0x0400-0x7FFF 

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的消息机制

MFC的消息循环(::GetMessage,::PeekMessage)消息泵(CWinThread::PumpMessage)和MFC的消息在窗口之间的路由是两件不同的事情 分两个步骤完成: 1 "消息派送":非对话框程序(MFC Doc/View架构)和对话框程序略有不同,但原理相差不大.但除了少数的消息例如WM_QUIT,所有消息的派送流程基本一致.2 "消息路由":其中消息分有3种类型,各类型的路由过程不一样.非对话框程序和对话框程序的处理相同. 消息派送消

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软件开发中,界面操作或者线程之间通信都会经常用到消息,通过对消息的处理实现相应的操作.比较典型的过程是,用户操作窗口,然后有消息产生,送给窗口的消息处理函数处理,对用户的