user3000 发表于 2012-6-16 06:24:17

Windows消息机制要点, 系统消息的分类

这是本人为学习系统消息时, 在网上搜集的,觉得值得一看. 但似乎没在论坛上找到类似资料?


Windows消息机制要点
1. 窗口过程
每个窗口会有一个称为窗口过程的回调函数(WndProc),
它带有四个参数,分别为:窗口句柄(Window Handle),消息ID(Message ID),和两个消息参数(wParam, lParam), 当窗口收到消息时系统就会调用此窗口过程来处理消息。(所以叫回调函数)
(注: 个人认为可以理解为, 程序窗体响应系统的管理\自动用户操作的处理机制.)


2 消息类型

1) 系统定义消息(System-Defined Messages)
在SDK中事先定义好的消息,非用户定义的,其范围在之间, 可以分为以下三类:
1> 窗口消息(Windows Message)
与窗口的内部运作有关,比如 ----- 创建窗口: WM_CREATE,绘制窗口: WM_PAINT等。可以是一般的窗口,也可以是Dialog,控件等。
还有: 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包含控件通知的内容, 可以任意扩展。
注: NMHDR 的结构可参考: http://baike.baidu.com/view/8062693.htm
或者到 MSDN 上搜索.

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可以对以上系统组件发送消息。


此文发布在多个网址, 我没有去详细去研究到底谁才是原作者了!还请他多多见谅!
这里只发布了前面部分, 后面部分多是C++下面的编程指导, 故没有放上来. 有兴趣请移步这里下载DOC文档:
论坛上的免费通道: http://www.autoitx.com/forum.php?mod=redirect&goto=findpost&pid=447650&ptid=31870
百度网盘上通道:    http://pan.baidu.com/netdisk/singlepublic?fid=390821_2962665475

自己关于AU3注册系统消息的体验1: http://www.autoitx.com/forum.php?mod=viewthread&tid=32879&highlight=
体验2还未考虑好, 想写: GUI控件为什么是从3开始?但毕竟不习惯写文章, 写了一点, 觉得很生涩, 被自己否决掉了.

fhqbbfcu2050 发表于 2012-6-16 16:22:02

这个一定要好好学学看看.....

zerobin 发表于 2012-6-16 19:37:42

特想看消息通知之类的文章。谢谢分享

147988704 发表于 2012-6-17 20:08:45

回帖是一种礼貌

Alam 发表于 2012-6-21 10:07:52

非常感谢楼主的分享!

lvjing79 发表于 2012-6-27 21:38:54

认真学习,不错的资料,多谢分享!

lcm0001 发表于 2013-1-3 19:05:58

好东西占个位置!

au32 发表于 2013-1-10 22:46:01

又学习了好东西

wszhov 发表于 2013-11-13 14:26:32

仔仔细细的看了,收获中

qazwsxedc 发表于 2013-11-14 10:28:33

非常感谢楼主的分享!

qhdpc 发表于 2013-11-14 21:33:49

谢谢楼主分享,下载学习了!

jsdn2000 发表于 2016-12-26 19:53:07

支持楼主,谢谢分享。
页: [1]
查看完整版本: Windows消息机制要点, 系统消息的分类