windows消息队列

消息分为进队消息消息和非进队消息。所谓进队消息就是windows将消息发送到每个线程所专有的队列中,然后由程序自主处理,这种消息基本上是由 用户输入产生(wm_keydown,wm_keyup,wm_char,wm_mouse**,以及 wm_paint,wm_timer,wm_quit)或者是调用postmessage,postthreadmessage产生的消息;所谓的非进队 消息就是直接发送给窗口过程的消息,就是直接调用窗口过程,上述消息以外的一般都是这种类型!

    一个线程一旦建立了至少一个窗口,则系统就为其分配一个消息队列。主要表现形式为系统为其分配一个THREADINFO结构,该结构有四个指针分别指向登 记消息队列,发送消息队列,应答消息队列和虚拟输入队列。如果想将消息放入登记消息队列,可以调用postmessage,或者 postthreadmessage。其余的消息队列主要用于处理如下的事务。当某线程调用sendmessage给别的线程创建的窗口时,发送的消息首 先追加到接收线程的发送消息队列,发送线程处于空闲状态,等待接收线程处理完他的消息返回给发送线程的应答队列,等到后发送线程被唤醒取得应答队列的消息 (就是处理完消息的返回值),继续执行。而虚拟输入队列则是由windows的系统线程RIT(原始输入线程)负责将硬件事件转换成消息添加到对应线程的 虚拟消息队列中。

    处理消息队列的顺序。首先windows绝对不是按队列先进先出的次序来处理的,而是有一定优先级的。优先级通过消息队列的状态标志来实现的。首先最高优 先级的是别的线程发过来的消息(通过sendmessage),其次是处理登记消息队列消息,再次处理QS_QUIT标志,再处理虚拟输入队列,再处理 wm_paint最后是wm_timer!

 

关于消息队列有两种,一种是系统消息队列,另一种是线程消息队列。windows应用程序的运行需要依靠 外部发生的事件来驱动。应用程序通过输入消息来接受输入。操作系统负责监视所有设备并将输入消息放入一个先进先出的队列中,即系统消息队列。接 着,windows从系统消息队列中去走一条消息,确定目的窗口,并将消息送入创建该窗口的消息队列中。

并不是每一个线程都有消息队列,只有当线程调用一个与图形用户界面有关的函数,系统才会为线程分配一个THREADINFO结构,并将这个数据结构 与线程联系起来。该结构记录的各种消息的分类。

对于该结构中,消息分为:

1.登记消息队列(如:PostMessage发送的消息)

2.虚拟输入队列(wm_keyup,wm_mousemove)

3.发送的消息(SendMessage发送的消息)。

4.其他 如wm_paint,wm_timer。

处理消息的算法:

对于windows来说,当调用getMessage或PeekMessage时,按下列顺序从消息队列中获得消息进行处理:

1)首先处理sendMessage发送的消息

2)接着处理PostMessage发送的消息

3)检查是否有WM_QUIT消息

4)处理虚拟消息队列

5)如果有WM_PAINT消息,就处理

6)如果有WM_TIMER消息,就处理

windows处理判断处理顺序时,察看的是标志位(以QS_*描述的一些消息标志),利用这些标志位,来确定是否对应的消息队列中有对应的消息。

 

从线程的队列中提取消息的算法:

 当一个线程调用 GetMessage 或 PeekMessage 时,系统必须检查线程的队列状态的情况,并确定应该处理哪个消息。

        系 统确定线程应该处理的下一个消息的步骤:
(1)
        如果 QS_SENDMESSAGE 标志被设置,系统向相应的窗口过程发送消息。GetMessage 或 PeekMessage 函数在内部进行这种处理,并且在窗口过程处理完消息后不返回到线程,这些函数要等待其他处理的消息;

(2)   如果消息在线程的登记消息队列中,函数 GetMessage 或 PeekMessage 填充传递给他们的
MSG 结构,然后函数返回。这时,线程的消息循环通常调用 DispatchMessage 让相应的窗口过程来处理消息;

(3)   如果 QS_QUIT 标志被设置。GetMessage 或 PeekMessage 返回一个 WM_QUIT 消息并复位QS_QUIT标志;

(4)   如果消息在线程的虚拟输入队列,函数 GetMessage 或 PeekMessage返回硬件输入消息;

(5)   如果 QS_PAINT 标志被设置,GetMessage 或 PeekMessage 为相应的窗口返回一个WM_PAINT 消息;

(6)   如果QS_TIMER 标志被设置,GetMessage 或 PeekMessage 返回一个WM_TIMER消息。

 

Windows消息机制要点

1. 窗口过程
每个窗口会有一个称为窗口过程的回调函数 (WndProc),它带有四个参数,分别为:窗口句柄(Window Handle),消息ID(Message ID),和两个消息参数(wParam, lParam), 当窗口收到消息时系统就会调用此窗口过程来处理消息。(所以叫回调函数)

2 消息类型
1) 系统定义消息(System-Defined Messages)
在SDK中事先定义好的消息,非用户定义的,其范围在[0x0000, 0x03ff]之间, 可以分为以下三类:
1>窗口消息(Windows Message)
与窗口的内部运作有关, 如创建窗口,绘制窗口,销毁窗口等。可以是一般的窗口,也可以是Dialog,控件等。
如:WM_CREATE, WM_PAINT, WM_MOUSEMOVE, WM_CTLCOLOR, WM_HSCROLL...
2>命令消息(Command Message)
与处理用户请求有关, 如单击菜单项或工具栏或控件时, 就会产生命令消息。
WM_COMMAND, LOWORD(wParam)表示菜单项,工具栏按钮或控件的ID。如果是控件, HIWORD(wParam)表示控件消息类型
3> 控件通知(Notify Message)
控件通知消息, 这是最灵活的消息格式, 其Message, wParam, lParam分别为:WM_NOTIFY, 控件ID,指向NMHDR的指针。NMHDR包含控件通知的内容, 可以任意扩展。
2) 程序定义消息(Application-Defined Messages)
用户自定义的消息, 对于其范围有如下规定:
WM_USER: 0x0400-0x7FFF    (ex. WM_USER+10)
WM_APP(winver>4.0): 0x8000-0xBFFF (ex.WM_APP+4)
RegisterWindowMessage: 0xC000-0xFFFF

3 消息队列(Message Queues)
Windows中有两种类型的消息队列
1) 系统消息队列(System Message Queue)
这是一个系统唯一的Queue,设备驱动(mouse, keyboard)会把操作输入转化成消息存在系统队列中,然后系统会把此消息放到目标窗口所在的线程的消息队列(thread-specific message queue)中等待处理
2) 线程消息队列(Thread-specific Message Queue)
每 一个GUI线程都会维护这样一个线程消息队列。(这个队列只有在线程调用GDI函数时才会创建,默认不创建)。然后线程消息队列中的消息会被送到相应的窗 口过程(WndProc)处理.
注意: 线程消息队列中WM_PAINT,WM_TIMER只有在Queue中没有其他消息的时候才会被处理,WM_PAINT消息还会被合并以提高效率。其他所 有消息以先进先出(FIFO)的方式被处理。

4 队列消息(Queued Messages)和非队列消息(Non-Queued Messages)
1)队列消息 (Queued Messages)

消息会先保存在消息队列中,消息循环会从此队列中取消息并分发到各窗口处理
如鼠 标,键盘消息。
2) 非队列消息(NonQueued Messages)
消息会绕过系统消息队列和 线程消息队列直接发送到窗口过程被处理
如: WM_ACTIVATE, WM_SETFOCUS, WM_SETCURSOR, WM_WINDOWPOSCHANGED
注意: postMessage发送的消息是队列消息,它会把消息Post到消息队列中; SendMessage发送的消息是非队列消息, 被直接送到窗口过程处理

5 PostMessage(PostThreadMessage), SendMessage
PostMessage: 把消息放到指定窗口所在的线程消息队列中后立即返回。 PostThreadMessage:把消息放到指定线程的消息队列中后立即返回。
SendMessage: 直接把消息送到窗口过程处理, 处理完了才返回。

6 GetMessage, PeekMessage
PeekMessage会立即返回  可以保留 消息
GetMessage在有消息时返回 会删除消息

7 TranslateMessage, TranslateAccelerator
TranslateMessage: 把一个virtual-key消息转化成字符消息(character message),并放到当前线程的消息队列中,消息循环下一次取出处理。
TranslateAccelerator: 将快捷键对应到相应的菜单命令。它会把WM_KEYDOWN 或 WM_SYSKEYDOWN转化成快捷键表中相应的WM_COMMAND 或WM_SYSCOMMAND消息, 然后把转化后的 WM_COMMAND或WM_SYSCOMMAND直接发送到窗口过程处理, 处理完后才会返回。

8(消息死锁( Message Deadlocks)
假设有线程A和B, 现在有以下下步骤
1) 线程A SendMessage给线程B, A等待消息在线程B中处理后返回
2) 线程B收到了线程A发来的消息,并进行处理, 在处理过程中,B也向线程A SendMessgae,然后等待从A返回。
因为此时, 线程A正等待从线程B返回, 无法处理B发来的消息, 从而导致了/线程A,B相互等待, 形成死锁。多个线程也可以形成环形死锁。
可以使用 SendNotifyMessage或SendMessageTimeout来避免出现死锁。

9 BroadcastSystemMessage
我们一般所接触到的消息都是发送给窗口的, 其实, 消息的接收者可以是多种多样的,它可以是应用程序(applications), 可安装驱动(installable drivers), 网络设备(network drivers), 系统级设备驱动(system-level device drivers)等,
BroadcastSystemMessage 这个API可以对以上系统组件发送消息。

 

 

你可能感兴趣的:(数据结构,windows,timer,command,character,keyboard)