01、目录
目录
02、简言
想必了解过MFC(windows程序)的都知道,windows的程序全是由消息驱动的。不敢干什么,都是通过各种各样的消息来做一些事。
消息队列(MQ)这一词,可能一眼看去有点很高端的感觉,其实也就是跟队列一样的性质,一个一个消息排队而存。链接了一篇简书上介绍消息队列概念的文章,感兴趣可以看看。其实程序中,我们一般用不上,有个认知就行了。
而今天,我们要聊的两个函数,就是针对这个消息队列而存在的。
- PeekMessage()
- GetMessage()
见明知其意:都有得到消息或者说看消息的意思。
下面我们就来好好聊聊这两个消息函数,结合程序了解如何使用,什么时候用。
03、PeekMessage() Function
微软文档解释:分发传入的发送消息,检查线程消息队列中的已发布消息,并检索消息(如果存在的话)。
3.1 语法(Syntax)
函数原型,C++程序:
BOOL PeekMessageA(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax,
UINT wRemoveMsg
);
3.2 参数(Parameters)
参数解释:
- lpMsg:A pointer to an MSG structure that receives message information.(指向接收消息信息的MSG结构的指针。)
- hWnd:A handle to the window whose messages are to be retrieved. The window must belong to the current thread.(要检索消息的窗口的句柄。窗口必须属于当前线程。)
如果HWND是零, PeekMessage检索属于当前线程的任何窗口的消息,以及当前线程消息队列上的任何消息Hwnd价值是零(见味精结构)。因此,如果hwnd是零,则同时处理窗口消息和线程消息。
如果HWND是-1,PeekMessage仅检索当前线程的消息队列上的消息Hwnd价值是零的线程消息。邮政讯息(当HWND参数是零)或后线程消息.
- wMsgFilterMin:The value of the first message in the range of messages to be examined. Use WM_KEYFIRST (0x0100) to specify the first keyboard message or WM_MOUSEFIRST (0x0200) to specify the first mouse message.(要检查的消息范围中第一条消息的值。使用Wm_KEYFIRST(0x0100)指定第一条键盘消息或Wm_MOUSEFIRST(0x0200)指定第一个鼠标消息。)
如果WMsgFilterMin和WMsgFilterMax都是零,PeekMessage返回所有可用消息(即不执行范围筛选)。
- wMsgFilterMax:The value of the last message in the range of messages to be examined. Use WM_KEYLAST to specify the last keyboard message or WM_MOUSELAST to specify the last mouse message.(要检查的邮件范围中最后一条消息的值。使用WM_KEYLAST指定最后一条键盘消息,或使用WM_MOUSELAST指定最后一条鼠标消息。)
如果WMsgFilterMin和WMsgFilterMax都是零,PeekMessage返回所有可用消息(即不执行范围筛选)。
- wRemoveMsg:Specifies how messages are to be handled. This parameter can be one or more of the following values.(指定如何处理消息。此参数可以是下列一个或多个值。)
value | Meaning |
---|---|
PM_NOREMOVE | 处理后,消息不会从队列中移除。PeekMessage. |
PM_REMOVE | 处理后,消息将从队列中移除。PeekMessage. |
PM_NOYIELD | 防止系统释放等待调用方空闲的线程(请参阅WaitForInputIdle).将此值与PM NOREMOVE或PM去除. |
默认情况下,将处理所有消息类型。若要指定只应处理某些消息,请指定下列一个或多个值。
value | Meaning |
---|---|
PM_QS_INPUT | 处理鼠标和键盘消息。 |
PM_QS_PAINT | 处理绘制消息。 |
PM_QS_POSTMESSAGE | 处理所有已发布的消息,包括计时器和热键。 |
PM_QS_SENDMESSAGE | 处理所有发送的消息。 |
3.3 返回值(Return value)
如果消息可用,则返回值为非零。
如果没有可用的消息,则返回值为零。
04、GetMessage() Function
微软文档解释:从调用线程的消息队列中检索消息。该函数将发送传入的发送消息,直到发布的消息可供检索为止。
4.1 语法(Syntax)
函数原型,C++程序:
BOOL GetMessage(
LPMSG lpMsg,
HWND hWnd,
UINT wMsgFilterMin,
UINT wMsgFilterMax
);
4.2 参数(Parameters)
- lpMsg:A pointer to an MSG structure that receives message information.(指向接收消息信息的MSG结构的指针。)
- hWnd:A handle to the window whose messages are to be retrieved. The window must belong to the current thread.(要检索消息的窗口的句柄。窗口必须属于当前线程。)
如果hWnd为NULL,GetMessage将检索属于当前线程的任何窗口的消息,以及当前线程消息队列中hwnd值为空的任何消息(请参见MSG结构)。因此,如果hWnd为NULL,则同时处理窗口消息和线程消息。
如果hWnd为-1,GetMessage只检索当前线程的消息队列上的消息,该队列的hwnd值为null,即由PostMessage(当hWnd参数为NULL)或PostThreadMessage发送的线程消息。
-
wMsgFilterMin:The value of the first message in the range of messages to be examined. Use WM_KEYFIRST (0x0100) to specify the first keyboard message or WM_MOUSEFIRST (0x0200) to specify the first mouse message.(要检查的消息范围中第一条消息的值。使用Wm_KEYFIRST(0x0100)指定第一条键盘消息或Wm_MOUSEFIRST(0x0200)指定第一个鼠标消息。)
-
wMsgFilterMax:The value of the last message in the range of messages to be examined. Use WM_KEYLAST to specify the last keyboard message or WM_MOUSELAST to specify the last mouse message.(要检查的邮件范围中最后一条消息的值。使用WM_KEYLAST指定最后一条键盘消息,或使用WM_MOUSELAST指定最后一条鼠标消息。)
4.3 返回值(Return value)
如果函数检索的消息不是Wm退出,返回值为非零。
如果函数检索Wm退出消息时,返回值为零。
如果出现错误,则返回值为-1。例如,如果hWnd是无效的窗口句柄或lpMsg是无效指针,则函数将失败。要获得扩展错误信息,请调用GetLastError。
由于返回值可以是非零、零或-1,所以请避免这样的代码:
while (GetMessage( lpMsg, hWnd, 0, 0)) ...
在hWnd是无效参数的情况下,返回值的可能性(例如引用已被销毁的窗口)意味着此类代码可能导致致命的应用程序错误。相反,使用如下代码:
BOOL bRet;
while( (bRet = GetMessage( &msg, hWnd, 0, 0 )) != 0)
{
if (bRet == -1)
{
// handle the error and possibly exit
}
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
05、示例助教
// 普通的消息循环
while( GetMessage(&msg,NULL,0,0) )
{
TranslateMessage(&msg);
DispatchMessage (&msg);
}
return msg.wParam;
// 等价于
while( TRUE )
{
if( PeekMessage(&msg,NULL,0,0,PM_REMOVE) )
{
if(msg.message == WM_QUIT)
{
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
// Other program lines to do some work
}
}
return msg.wParam;
如果 PeekMessage 的返回值为 TRUE,则消息按通常方式进行处理。如果返回值为 FALSE,则在将控制返回给Windows(操作系统) 之前,还可以做一点工作(如显示另一个随机矩形)。
PeekMessage 不能从消息队列中删除 WM_PAINT 消息。
从队列中删除 WM_PAINT 消息的唯一方法是令窗口客户区的失效区域变得有效,这可以用 ValidateRect 和 ValidateRgn 或者 BeginPaint 和 EndPaint 对来完成。
不能使用如下所示的代码来清除消息队列中的所有消息:
while( PeekMessage(&msg,NULL,0,0,PM_REMOVE) );
这条语句从消息队列中删除 WM_PAINT 之外的所有消息。如果队列中有一个 WM_PAINT 消息,程序就会永远地陷在 while 循环中。
了解完了两个函数的基本概念知识,现在结合下面在网上Copy的例子,感受下吧。
#include <windows.h>
#include <stdlib.h> // for the rand function
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
void DrawRectangle (HWND) ;
int cxClient, cyClient ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("RandRect") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Random Rectangles"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
//用于替换的部分
while (TRUE)
{
if (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break ;
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
else
DrawRectangle (hwnd) ;
}
//用于替换的部分
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM
lParam)
{
switch (iMsg)
{
case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
}
void DrawRectangle (HWND hwnd)
{
HBRUSH hBrush ;
HDC hdc ;
RECT rect ;
if (cxClient == 0 || cyClient == 0)
return ;
SetRect (&rect, rand () % cxClient, rand () % cyClient,
rand () % cxClient, rand () % cyClient) ;
hBrush = CreateSolidBrush (
RGB (rand () % 256, rand () % 256, rand () % 256)) ;
hdc = GetDC (hwnd) ;
FillRect (hdc, &rect, hBrush) ;
ReleaseDC (hwnd, hdc) ;
DeleteObject (hBrush) ;
}
以上程序用PeekMessage函数实现,在应用程序消息队列没有消息时,随机生成的矩形
将坚持不懈地画下去。当有消息产生时,PeekMessage函数获取并派发消息出去,然后
继续画随机生成的矩形。
下面部分代码用于替换WinMain函数中“用于替换的部分”的代码。
while (TRUE)
{
if (GetMessage (&msg, NULL, 0, 0))
{
if (msg.message == WM_QUIT)
break ;
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
DrawRectangle (hwnd) ;
}
else
break;
}
替换后,应用程序产生一个消息(鼠标移动、改变窗体大小等),在窗体内画一个随
机生成的矩形,无消息产生时,窗体无变化。
06、总结
PeekMessage与GetMessage的对比:
-
相同点:PeekMessage函数与GetMessage函数都用于查看应用程序消息队列,有消息时将队列中的消息派发出去。
-
不同点:无论应用程序消息队列是否有消息,PeekMessage函数都立即返回,程序得以继续执行后面的语句(无消息则执行其它指令,有消息时一般要将消息派发出去,再执行其它指令)。
GetMessage函数只有在消息对立中有消息时返回,队列中无消息就会一直等,直至下一个消息出现时才返回。在等的这段时间,应用程序不能执行任何指令。
从他们的不同点上来看,PeekMessage函数有点像“乞丐行乞”,有你就施舍点,没有也不强求。GetMessage函数有点像“强盗打劫”,有你得给,没有我就等你什么时候有了再给,这段时间我什么都不干,我就等你。
上述Code是借鉴网上的一个例子,概念是部分来源微软文档,外加自己组织了一点语言。
今天的文章【MFC】PeekMessage() 与GetMessage() 消息函数分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/61917.html