下载
下载
第3章 消 息 处 理
第1章讨论了M F C 用户界面的基本要素:窗口、窗口类和 C W n d ;第2章讨论了构成M F C
库的其他类,尤其是那些构成 M F C 应用程序内核的类。在本章中,我们将讨论 M F C 类和它们
的窗口怎样进行互相通信的。我们发现有三种类型的消息:窗口、命令 ( C o m m a n d )和控件通
知(Control Notification),并且这些消息既可以发送 ( s e n t ),也可以寄送( p o s t );接着,将跟踪
一个被M F C窗口进程处理的消息;最后,将讨论重定向消息的方法。
3.1 发送或寄送一个消息
第1章已提及,每个窗口使用窗口进程处理发送给它的消息。消息可以来自系统、你的应
用程序或别的应用程序。消息告诉窗口进程执行某个任务 (如初始化自己、绘制或销毁一个窗
口等),或者通知它发生某个事件 (如鼠标正单击窗口)。
系统或应用程序有两种传输消息的方法:发送消息或寄送消息。
3.1.1 发送一个消息
发送一个消息时,直接调用窗口的窗口进程。通信是即时的,直到窗口进程为调用函数
返回一个结果后,应用程序才能继续。
3.1.2 寄送一个消息
寄送一个消息时,把消息发送到拥有那个窗口的应用程序消息队列中。一有空闲,应用
程序就搜索消息队列,并在消息队列中处理消息,即从队列中删除它们,并将它们发送到即
定窗口。通信将可能延迟,直到目标应用程序获得处理消息的时间。调用函数发送消息后即
返回,但结果只是表示消息寄送成功与否,而不是被调用窗口进程的结果 (见图3 - 1 )。
图3-1 发送消息时通信是即时的,而寄送消息时通信可能延迟
3.1.3 发送一个消息与寄送一个消息的比较
鼠标和键盘消息通常是寄送的,而所有其他消息通常都是发送的。在消息队列中,寄送
③当应用程序空闲时,
抽出寄送到队列中
的消息并调用该窗
口的窗口进程
①被发送的消息直接
调用该窗口的窗口
进程
②被寄送的消息延迟在
应用程序消息队列中
消息队列
消息n+1
消息n+2
消息n+3
消息n+4
WndProc
地址
消息泵
窗口对象
的消息接受特殊的鼠标和键盘处理。通常,应该尽量发送一个消息,除非想把动作延迟到所
有鼠标和键盘消息被处理之后。
3.2 怎样使用MFC发送一个消息
用M F C 发送一个消息的方法是,首先,应获取接收消息的 C W n d类对象的指针;然后,调
用C W n d的成员函数SendMessage( )。
L R E S U LT Res=pWnd->SendMessage(UINT Msg, WPARAM wParam, LPARAM lParam);
p W n d指针指向目标 C W n d 类对象。变量 M s g 是消息, w P a r a m 和l P a r a m 变量包含消息的参
数,如鼠标单击哪里或选择了什么菜单项。目标窗口返回的消息结果放在变量 R e s中。发送消
息到一个没有C W n d 类对象的窗口,可以用下列目标窗口的句柄直接调用 Windows API:
L R E S U LT Res=::SendMessage(HWND hWnd , UINT Msg , WPARAM wParam , LPARAM lParam);
这里的h W n d是目标窗口的句柄。
3.3 怎样用MFC寄送一个消息
用M F C 寄送一个消息与发送一个消息几乎相同,但寄送时用 PostMessage( ),而不是用
SendMessage( );返回值R e s 也不一样,R e s 不是一个由目标窗口返回的值,而是一个布尔值,
用来表示消息是否成功地放到消息队列中。
检索一个寄送消息
正常情况下,一旦消息被寄送后,应用程序在后台发送它。但是在特殊情况下,需要你
自己去删除一个消息,例如想在应用程序接收到某种消息之前停止应用程序。有两种方法可
以从应用程序消息队列中删除一个消息,但这两种方法都没有涉及 M F C 。
■ 第一种方法:在不干扰任何事情之下窥视消息队列,看看一个消息是否在那里。
BOOL res=::PeekMessage(LPMSG lpMsg, HWND hWnd, UINT wMsFilterMin, UINT wMsgFilterMax, UINT
w R e m o v e M s g ) ;
■ 第二种方法:实际上是等待,一直等到一个新的消息到达队列为止,然后删除并返回
该消息。
BOOL res=::GetMessage(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax);
在这两种方法中,变量 h W n d 指定要截获消息的窗口,如果该变量设为 N U L L ,所有窗口
消息将被截获。w M s g F i l t e r M i n 和w M s g F i l t e r M a x 变量与SendMessage( )中的变量M s g 相对应,
指定查看消息的范围。如果用“ 0, 0”,则所有的消息都将被截获。如果用 W M _ K E Y F I R S T,
W M _ K E Y L A S T 或W M _ M O U S E F I R S T, WM_MOUSELAST,则所有键盘或鼠标的消息将被截
获。
w R e m o v e M s g 变 量 指 定 PeekMessage( )是 否 应 该 真 正 地 从 队 列 中 删 除 该 消 息 。
(GetMessage( )总是删除消息)。该变量可以取两个值:
■ P M _ R E M O V E,PeekMessage( )将删除消息。
■ P M _ N O R E M O V E,PeekMessage( )将把消息留在队列里,并返回它的一个拷贝。
当然,如果把消息留在消息队列中,然后再次调用 PeekMessage( )查看相同类型的消息,
则将返回完全相同的消息。
第3章 消 息 处 理 33
下载
l p M s g 变量是一个指向M S G结构的指针,M S G 包含检索到的消息。
typedef struct tagMSG {
H W N D h w n d ; // window handle message is intended for
U I N T m e s s a g e ;
W PA R A M w P a r a m ;
L PA R A M l P a r a m ;
D W O R D t i m e ; // the time the message was put in the queue
P O I N T p t ; // the location of the mouse cursor when the
// message was put in the queue
} MSG;
3.4 三种类型的消息
在M F C应用程序中传输的消息有三种类型:窗口消息、命令消息和控件通知。
3.4.1 窗口消息
窗口消息(Window Message)一般与窗口的内部运作有关,如创建窗口、绘制窗口和销毁窗
口等。通常,消息是从系统发送到窗口,或从窗口发送到窗口。
当用S e n d M e s s a g e ( ) 或P o s t M e s s a g e ( ) 发送一个窗口消息时,变量 M e s s a g e 、w P a r a m 和
l P a r a m的格式如下:
M e s s a g e wPa r a m lPa r a m
W M _ X X X 定义的命令 定义的命令
W M _ X X X 可以是许多窗口消息之一,如下列窗口:
■ W M _ C R E AT E ,告诉窗口初始化自己。
■ W M _ PA I N T ,告诉窗口绘制自己。
■ W M _ M O U S E M O V E ,告诉窗口鼠标移经它。
有关某些公共窗口消息,参见附录 B。若需要窗口消息的完全的列表,请参考 M F C文档。
3.4.2 命令消息
命令消息一般与处理用户请求相关,当用户单击一个菜单项或工具栏时,命令消息产生,
并被发送到能处理该请求的类对象 (如,装载文件、编辑文本和保存选项等 )。
当用SendMessage( )或PostMessage( )发送窗口消息时,变量M e s s a g e 、w P a r a m和l P a r a m的
格式如下:
M e s s a g e w P a r a m l P a r a m
W M _ C O M M A N D 0 Command ID 0
Command ID要么是选中菜单项的 I D,要么是被单击的工具栏按钮。注意 Command ID不
能大于一个字长,如果使它大于一个字长,系统就只用 0来填充高位字。某些控件通知也用
W M _ C O M M A N D 消息,区别两种消息的唯一方法是 l P a r a m是否为N U L L 。
3.4.3 控件通知
通常,控件通知在某些重要事件发生时,由控件窗口发送到父窗口,如打开一个组合框。
34 第一部分 基 础 知 识
下载
控件通知为父窗口进一步控制子窗口提供了机会。例如,打开一个组合框时,父窗口可以用
组合框初建时得不到的消息填充它。
控件通知经历了一个演变过程,因而 SendMessage( )的变量M e s s a g e 、w P a r a m和l P a r a m有
三种格式。
1. 第一控件通知格式
第一控件通知格式只是窗口消息的子集。
M e s s a g e w P a r a m l P a r a m
W M _ X X X 定义的命令 定义的命令
W M _ X X X 可以是下面消息中的任何一种:
■ W M _ PA R E N T N O T I F Y 表示一个控件窗口要么已被建立或销毁,要么鼠标已单击了该
窗口。
■ W M _ C T L C O L O R 、W M _ D R AW I T E M、W M _ M E A S U R E I T E M 、W M _ D E L E T E I T E M、
W M _ C H A RTO I T E M、W M _ V K E Y TO I T E M或W M _ C O M PA R E I T E M 都是送往父窗口的
消息,用来绘制自身的控件窗口。
■ W M _ H S C R O L L 或W M _ V S C R O L L由滚动条控件发送,通知父窗口滚动窗口。
2. 第二控件通知格式
第二控件通知格式使用W M _ C O M M A N D消息,与命令消息共享。
M e s s a g e w P a r a m l P a r a m
W M _ C O M M A N D X N _ X X X 控件I D 窗口句柄
l P a r a m 变量用来区分是命令消息还是控件通知。控件通知在 l P a r a m 中有一个有定义的句
柄,用来标识发出通知的控件;而命令消息中 l P a r a m 为N U L L。
X N _ X X X值因发出通知的控件不同而不同,例如, X N _ X X X 值为E N _ C H A N G E,告诉父
窗口显示在编辑框控件中的文本已发生变化。还有其他一些例子列在附录 B中。
3. 第三控件通知格式
第三控件通知格式也是最灵活的通知格式,它用 W M _ N O T I F Y 消息。
M e s s a g e w P a r a m l P a r a m
W M _ N O T I F Y 控件I D 指向N M H D R的指针
l P a r a m 值指向一个结构,该结构包括有关制作该通知的控件的任何内容,而不受空间和
类型的限制,该结构叫做N M H D R。
typedef struct tagNMHDR {
HWND hwndFrom; // Window handle of Control Wi n d o w
// making the notification.
UINT idFrom; // Control ID of Control Wi n d o w
// making the notification.
UINT code; // notification code ex: the user
// has clicked the Control Wi n d o w
} NMHDR;
N M H D R 代表通知消息头(Notification Message Header)。为什么要这个头?因为某些控件
用N M H D R作为头发送一个更大结构的消息,即使那些不知道更大结构内容的函数还是能处理
第3章 消 息 处 理 35
下载