MFC消息类型——理论(转载)
扫描二维码
随时随地手机看文章
Windows系统是一个消息驱动的操作系统,消息是应用程序与操作系统交互的手段。消息的产生来源于系统事件和用户事件,Windows用消息来调入和关闭应用程序。例如在关机操作中,Windows给所有正在运行的应用程序发出一个关机的消息,通知它们退出内存,此时,应用程序用响应消息的方法来回应。MFC通过封装的方式提供对大部分消息处理的接口。本章将围绕消息分类、发送、接收、处理以及重定向等内容展开讨论。
1.1
消息分类从不同的角度,有如下几种分类方式。
从消息的发送途径上看,可以分为队列消息和非队列消息。
从消息的来源来看,可以分为系统消息和自定义消息。
从对消息的处理上看,可以分为窗口消息、命令消息和控件通知。
本节主要分类介绍各种消息的特点。在介绍消息的分类之前,先了解一下消息的结构。
1.1.1
消息结构消息是系统或用户定义的一些UINT常量值,在Windows中,用一个结构类型表示消息的UINT常量值和与该消息相关的其他信息,它的具体定义如下:
typedef struct tagMSG {// 消息结构
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG;
该结构共有6个成员,其各个成员含义具体如下。
hwnd成员:该成员是一个句柄,它标识了将要接收此消息的窗口。
message成员:该成员是消息号,为无符号整形UINT,在系统或者应用中是一个预定义的常量,它是消息的标识符。
wParam成员:该成员在MFC中一般作为常用的消息参数,它携带message消息的附加信息,依据message的具体值有所不同。
lParam成员:该成员和wParam成员的作用类似,在MFC中一般作为常用的消息参数,它携带message消息的附加信息,依据message的具体值有所不同。
time成员:该成员是一个时间值,标识消息被发送时的时间。
pt成员:该成员指定了消息被发送时光标的位置,单位是屏幕坐标。
说明
在基于MFC的应用开发中,一般并不需要所有的成员参数,正如文中所说的,一般只用wParam和lParam就基本满足需要了。
1.1.2
队列消息和非队列消息Windows为当前运行的每个Windows程序维护一个“消息队列”。当通过鼠标或者键盘发生输入事件后,Windows将事件转换为一个“消息”,并将消息放入程序的消息队列中。而队列消息是指由Windows放入程序的消息队列中的消息,在程序消息循环中,队列消息被重新传回并分配给窗口过程。非队列消息是指在Windows调用窗口时直接传送给窗口过程的消息。也就是说,队列消息被“发送”给消息队列,而非队列消息则“发送”给窗口过程。由此可以发现,窗口过程是窗口消息的处理场所。
1.队列消息队列消息大都是用户输入的结果,如击键(WM_KEYDOWN和WM_KEYUP消息)、字符(WM_CHAR)消息、移动鼠标(WM_MOUSEMOVE消息)以及单击鼠标(WM_ LBUTTONDOWN和WM_LBUTTONUP等消息)等。队列消息还包括时钟消息(WM_ TIMER)、重画消息(WM_PAINT)和退出消息(WM_QUIT)等。
2.非队列消息大部分消息都是非队列消息。此类消息大部分来自特定的Windows函数,如当调用UpdateWindow时,Windows将给调用此函数窗口的窗口过程发送WM_PAINT;当调用DestroyWindow时,Windows将给调用此函数窗口的窗口过程发送WM_DESTROY等。
1.1.3
系统消息和自定义消息
Windows消息是预定义的一些UINT常量值,它对系统本身用到的消息进行了定义,为了实现额外的消息,系统为开发人员预留了消息定义的接口,这样,当需要使用系统以外的消息时,可以使用该接口进行定义自己的消息。
系统消息ID的范围是从0~WM_USER-1,或0X8000~0XBFFF;应用程序消息从WM_USER(0XC000)~0XFFFF,或0XC000~0XFFFF;WM_USER~0XFFFF范围的消息由应用程序自己使用;0XC000~0XFFFF范围的消息用来和其他应用程序通信,为了保证ID的唯一性,使用::RegisterWindowMessage来获取该范围的消息ID。
1.1.4
窗口消息窗口消息(Window Message)是由操作系统和控制其他窗口的窗口所使用的消息,它一般与窗口的内部运作有关,如创建窗口、绘制窗口和销毁窗口等。通常,消息是从系统发送到窗口,或从窗口发送到窗口。此类消息的参数Message、wParam和lParam的格式如表1所示。
表1 窗口消息参数
消息
参数wParam
参数lParam
WM_XXX
定义的命令
定义的命令
1.1.5
命令消息命令消息是一种特殊的窗口消息,它从一个窗口发送到另一个窗口,以处理来自用户的请求。当用户单击一个菜单项、工具栏或者使用加速键时,将会产生命令消息,并被发送到能处理该请求的类对象。此类消息的参数Message、wParam和lParam的格式如表6-2所示。
表2 命令消息参数
消息
参数wParam
参数lParam
WM_COMMAND
0
CommandID
0
其中wParam的高字为0,低字为CommandID,这个命令ID要么是选中菜单项的ID,要么是被单击的工具栏按钮。需要注意的是,低字CommandID不能大于一个字长,如果它大于一个字长,则系统就只用0来填充高位字。某些控件通知也用WM_COMMAND消息,区别两种消息的唯一方法是lParam是否为NULL。
1.1.6 控件通知
控件通知类似于命令消息,当用户与控件窗口交互时,这一类消息就从控件窗口发送到其主窗口。但是,这种消息的目的并不在于处理用户命令,而是为了让主窗口能够更新控件的状态,如加载并显示更多的数据。通常,在发生某些重要事件时,该消息由控件窗口发送到父窗口,它为父窗口进一步控制子窗口提供了机会。
控件通知经历了一个演变过程,它所使用的消息形式有窗口消息形式、命令消息形式及WM_NOTIFY消息形式等3种形式,下面分别予以介绍。
1.窗口消息形式
这种形式的控件通知是窗口消息的子集,因此,它的消息参数具有和窗口消息一致的格式,这里不再列出。
2.命令消息形式
这种形式的控件通知使用WM_COMMAND消息,虽然它与命令消息共享参数,但是,它的消息参数有了另外的含义。它的消息参数Message、wParam和lParam的格式如表6-3所示。
表6-3 命令消息参数
消息
参数wParam
参数lParam
WM_COMMAND
XN_XXX
控件ID
窗口句柄
其中lParam用来标识是命令消息还是控件通知。如果是命令消息,则lParam为NULL,而如果是控件通知,则lParam值是一个句柄,用来标识发出该通知的控件。
而wParam中的高字的XN_XXX值随发出通知控件的不同而变化。例如,XN_XXX值为EN_CHANGE,告诉父窗口显示在编辑框控件中的文本已发生变化。而其低字则标识了发出该通知的控件,即控件ID。
3.WM_NOTIFY消息形式
这种形式的控件通知使用WM_NOTIFY消息。老版本的Windows控件一般都使用命令消息形式发送通知。然而,标准的32位wParam和lParam消息参数所能提供的信息对于通用控件的需求来说是不够的,因此,通过引入WM_NOTIFY这种新的消息来解决“带宽”的问题。
在这种形式的消息所携带的参数中,wParam标识控件ID,而lParam是一个指向结构的指针,该结构可以是NMHDR或者是包含NMHDR的更大结构,但是后者以NMHDR作为它的第一个成员。需要注意的是,既然NMHDR是某个更大结构的第一个成员,那么指向这个结构的指针就可以用作NMHDR*类型或者指向那个更大结构的指针,当然,这取决于怎么去映射它。
说明
通常情况下,lParam指向一个比NMHDR更大的结构,因此,在使用过程中,通常需要进行映射。不过当用类向导对WM_NOTIFY消息进行响应时,它会自动设为一个合适的指针。仅有少数的通知,例如通用通知(通知消息以NM_打头)和工具提示控件的TTN_SHOW和TTN_POP通知才是实际使用NMHDR结构。所以,通常也将NMHDR称作通知消息头(Notification Message Header,具体定义参见MSDN)。标准Windows控件如编辑控件、组合框控件、列表框控件、按钮控件、滚动条控件以及静态控件等并不发送WM_NOTIFY消息。
第一类消息(消息ID从0到WM_USER–1)是系统消息;
第二类消息(消息ID从WM_USER到0x7FFF)是供窗口类内部使用的自定义消息;
第三类消息(消息ID从0x8000到0xBFFF)是供应用程序内部使用的自定义消息;
第四类消息(消息ID从0xC000到0xFFFF)是供应用程序之间使用的自定义消息;
第五类消息(消息ID大于0xFFFF)是目前保留起来的供将来使用的消息,无定义;