PeekMessage、GetMessage的区别
在Windows编程中经常使用这两个函数来处理消息,它们之间的区别就是GetMessage是阻塞的,PeekMessage是非阻塞的。
GetMessage原型如下:BOOL GetMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax);
PeekMessage原型如下:BOOL PeekMessage(LPMSG lpMsg,HWND hWnd,UINT wMsgFilterMin,UINT wMsgFilterMax,UINT wRemoveMsg);
前面4个参数都是一样的,第一个是消息结构指针;第二个是窗口句柄,标识要接收的消息的窗口,如果为NULL,则表示接收属于该应用程序的所有窗口的消息;第三个、第四个分别指定了接收的消息的范围,如果都为0,则接收所有消息,WM_KEYFIRST 和 WM_KEYLAST 常量用于接受所有的键盘消息。 WM_MOUSEFIRST 和 WM_MOUSELAST 常量用于接受所有的鼠标消息。PeekMessage函数的第五个参数指示了PeekMeesage接收过消息之后是否将该消息删除,PM_REMOVE表示删除,PM_NONREMOVE表示不删除。
该函数用于查看应用程序的消息队列,如果其中有消息就将其放入lpMsg所指的结构中,不过,与GetMessage不同的是, PeekMessage函数不会等到有消息放入队列时才返回。同样,如果hWnd为NULL,则PeekMessage获取属于调用该函数应用程序的任一窗口的消息,如果hWnd=-1,那么函数只返回把hWnd参数为NULL的PostAppMessage函数送去的消息。如果 wMsgFilterMin和wMsgFilterMax都是0,则PeekMessage就返回所有可得到的消息。函数获取之后将删除消息队列中的除 WM_PAINT消息之外的其他消息,至于WM_PAINT则只有在其处理之后才被删除。
Windows编程中常用的消息处理函数如下:
1 while(GetMessage(&msg, NULL, 0, 0)) 2 { 3 TranslateMessage(&msg); 4 DispatchMessage(&msg); 5 }
首先,GetMessage从进程的主线程的消息队列中获取一个消息并将它复制到MSG结构,如果队列中没有消息,则GetMessage函数将等待一个消息的到来以后才返回。如果你将一个窗口句柄作为第二个参数传入GetMessage,那么只有指定窗口的的消息可以从队列中获得。GetMessage也可以从消息队列中过滤消息只接受消息队列中落在范围内的消息。这时候就要利用GetMessage/PeekMessage指定一个消息过滤器。这个过滤器是一个消息标识符的范围或者是一个窗体句柄,或者两者同时指定。当应用程序要查找一个后入消息队列的消息是很有用。WM_KEYFIRST 和 WM_KEYLAST 常量用于接受所有的键盘消息。 WM_MOUSEFIRST 和 WM_MOUSELAST 常量用于接受所有的鼠标消息。
TranslateMessage将把两个按键消息WM_KEYDOWN和WM_KEYUP 转换成一个WM_CHAR,不过需要注意的是,消息WM_KEYDOWN,WM_KEYUP仍然将传递给窗口的回调函数。
处理完之后,DispatchMessage函数将把此消息发送给该消息指定的窗口中已设定的回调函数。如果消息是WM_QUIT,则 GetMessage返回0,从而退出循环体。应用程序可以使用PostQuitMessage来结束自己的消息循环。通常在主窗口的 WM_DESTROY消息中调用。
使用PeekMessage函数的消息循环如下:
1 while(true) 2 { 3 if(PeekMessage(&msg, m_hWnd, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE)) 4 { 5 if (msg.message == WM_QUIT) 6 { 7 break; 8 } 9 if(msg.message == WM_KEYDWON && msg.wParam == VK_ESCAPE) 10 { 11 ... 12 } 13 } 14 else 15 { 16 // no message 17 } 18 }
这里我们接受所有的键盘消息,所以就用WM_KEYFIRST 和 WM_KEYLAST作为参数。最后一个参数可以是PM_NOREMOVE 或者 PM_REMOVE,表示消息信息是否应该从消息队列中删除。
所以这段小代码就是判断是否按下了Esc键,如果是就进行处理。
注意:
while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) ;
这行叙述从消息伫列中删除WM_PAINT之外的所有消息。如果伫列中有一个WM_PAINT消息,程式就会永远地陷在while循环中。