Windows 消息机制
编写Windows程序有两年了,但当别人问起Windows消息机制总觉得很难形容清楚。在这篇中,集合了很多我从网络中搜集来的一些知识,这里只是汇总一下。
我们编写的Windows程序是以事件为驱动,消息机制为基础的。对于每一个正在执行的Windows应用程序,Windows为其建立一个“消息队列”,即应用程序队列,用来存放该程序可能创建的各种窗口的消息。应用程序中含有一段称作“消息循环”的代码,用来从消息队列中检索这些消息并把它们分发到相应的窗口函数中。
一、消息循环
首先我们来看一下Windows消息循环。
while(GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
MSG结构在头文件中定义如下:
typedef struct tagMSG
{
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG, *PMSG;
其数据成员的具体意义如下:
hwnd:消息将要发送到的那个窗口的句柄,用这个参数可以决定让哪个窗口接收消息。
message:消息号,它唯一标识了一种消息类型。每种消息类型都在Windows文件进行了预定义。
wParam:一个32位的消息参数,这个值的确切意义取决于消息本身。
lParam:同上。
time:消息放入消息队列中的时间,在这个域中写入的并非当时日期,而是从Windows启动后所测量的时间值。Windows用这个域来使用消息保持正确的顺序。
pt:消息放入消息队列时的鼠标坐标。
消息循环以GetMessage调用开始,它从消息队列中取出一个消息。然后解释和分发消息。
二、消息类型
消息主要分为两种:一是系统定义消息;二是自定义消息。
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
三、队列化消息和非队列化消息
消息被分成队列化消息和非队列化消息。
队列化消息是由Windows放入程序消息队列中的。在程序的消息循环中,重新传回并分配给窗口消息处理程序。非队列化消息是在Windows的窗口过程中直接发送给窗口的消息处理程序。简单的说,队列化的消息被发送给消息队列,而非队列化的消息则发送给窗口消息处理程序。在任何情况下,窗口消息处理程序都将获得窗口的所有消息——包括队列化的和非队列化的。窗口消息处理程序是窗口的消息中心。队列化消息基本上是使用者输入的结果,如WM_KEYDOWN、WM_KEYUP、WM_CHAR、WM_MOUSEMOVE、WM_LBUTTONDOWN 、WM_TIMER、WM_PAINT、WM_QUIT。非队列化消息则是其他消息。在许多情况下,非队列化的消息来自呼叫特定的windows函数。
四、SendMessage与PostMessage的区别
SendMessage与PostMessage是在编程过程中使用频率较高的两个函数。
SendMessage是同步的操作,它将消息发送给窗口,除非消息处理完毕,否则该函数不会返回。其返回值表示其他程序处理消息后的返回值。
PostMessage是异步的操作,将一个消息放到与指定窗口创建的线程相关的消息队列中,不等线程处理消息就返回。其返回值表示PostMessage是否执行成功。
五、GetMessage和PeekMessage的区别
区别一:
peekmessage不管消息队列里有没有消息都会马上返回,有消息返回消息,没消息返回空值,
getmessage等待到有消息的时候才返回,
区别二:
peekmessage可以根据参数决定是否将消息保留在队列中,
PM_NOREMOVE:该参数指示保留消息
PM_REMOVE:该参数指示移去消息
而getmessage获得消息后回把消息从消息队列中删去。
PeekMessage是一个异步的操作,而GetMessage则是一个同步的操作。
六、TranslateMessage
功能描述:将虚拟键消息转换为字符消息。字符消息被送到调用线程的消息队列中,在下一次线程调用函数GetMessage或PeekMessage时被读出。
返回值:
如果消息被转换(即,字符消息被送到线程的消息队列中),返回非零值。
如果消息是 WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, 或 WM_SYSKEYUP,返回非零值,不考虑转换。
如果消息没有转换(即,字符消息没被送到线程的消息队列中),返回值是零。
备注:
TranslateMessage函数不修改由参数lpMsg指向的消息。
TtanslateMessage仅为那些由键盘驱动器映射为ASCII字符的键产生WM_CHAR消息。
如果应用程序为其它用途而处理虚拟键消息,不应调用TranslateMessage函数。例如,如果TranslateAccelerator函数返回一个非零值,则应用程序将不调用TranslateMessage函数。
Windows CE:Windows CE不支持扫描码或扩展键标志,因此,它不支持由TranslateMessage函数产生的WM_CHAR消息中的lKeyData参数(lParam)16-24的取值。
TranslateMessage函数只能用于转换由GetMessage或PeekMessage函数接收到的消息。
出处没有记载,简单汇总
posted on 2009-04-29 08:02
Sandy 阅读(870)
评论(0) 编辑 收藏 引用 所属分类:
Windows Mobile