这是在浏览器项目实际遇到了消息循环的问题,因此在这里简陋的写上一笔,为的是给自己个印象。
下面要介绍的函数都是在CWinThread这个类里的,而且我遇到的都是在int CWinThread::Run()函数里的。给出一段代码,以方便分析:
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
do{
// pump message, but quit on WM_QUIT
if (!PumpMessage())
return ExitInstance();
// reset "no idle" state after pumping "normal" message
if (IsIdleMessage(&m_msgCur)){
bIdle = TRUE;
lIdleCount = 0;
}
} while (::PeekMessage(&m_msgCur, NULL, NULL, NULL, PM_NOREMOVE));
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
从上面这段代码里可以看出,核心的就是PumpMessage()函数、IsIdleMessage(...)和PeekMessage(...)。下面先分析PumpMessage函数:
1.PumpMessage()函数可以翻译为消息泵,顾名思义,是获取消息并将其放到消息队列的,其核心代码如下两行:
MSG msg;
while(GetMessage(&msg, hwnd, 0, 0)){
//由于篇幅限制,省略了一些预编译的代码
TranslateMessage(&msg);
DispatchMessage(&msg);
// do stuff
}
很容易可以看出,这是Win32编程的核心内容啊:映射(翻译)消息、分发消息。当然,这个处理起来是有点难度的,所以msdn上建议advanced coder用这个函数。这也是循环的出口,当接受到信息为WM_QUIT时,该函数返回false,这样便退出do ...while。
2.IsIdleMessage(para)//下面完全按中文mfc网站说明写的
如果避免在产生指定的消息以后调用OnIdle函数,则应重载这个函数。当产生重复的鼠标消息和闪烁光标消息之后,这个函数的缺省实现并不调用OnIdle。
如果应用程序创建了一个短的定时器,OnIdle将被频繁调用,导致性能上的问题。为了改善这种应用程序的性能,重载应用程序的CWinApp派生类中的IsIdleMessage消息,按照如下方式检测WM_TIMER消息:
BOOL CMyApp::IsIdleMessage( MSG* pMsg ){
if (!CWinApp::IsIdleMessage(pMsg) || pMsg->message == WM_TIMER) return FALSE;
else return TRUE;
}
按照这种方式处理WM_TIMER消息可以改善那些使用短定时器的应用程序的性能。
3.PeekMessage(param,param,param,param,param)//下面这些参考了网友的文章
WinCE/Win32:该函数从进程消息队列中检索一个消息,并将该消息(如果存在的话)赋值给指定的消息结构。PeekMessage函数跟GetMessage函数不同之处在于:PeekMessage不会等待消息,而是不间断地访问消息队列,不管消息队列的目前状态如何。
其函数原型为:
BOOL PeekMessage(
LPMSG IpMsg, // 检索到的消息
HWND hWnd, // 窗口指向
UINT wMSGfilterMin,// 消息范围的下界限参数
UINT wMsgFilterMax,// 上界限参数
UINT wRemoveMsg // 消息在被检索之后要如何处理
);
对于最后一个参数,即wRemoveMsg:消息被检索后如何处理, 此参数可取下列值之一:
PM_NOREMOVE:消息被PeekMessage处理后,不要除掉;
PM_REMOVE:消息被PeekMessage处理后,需要除掉;
PM_NOYIELD:跟PM_NOREMOVE或PM_REMOVE相结合使用,此标志防止系统释放任何正在等待被调用的线程;
默认设置下处理所有类型的消息,若要求只处理某些消息,则指定一个或多个下列值:
PM_QS_INPUT:Windows 98/Me, Windows 2000/XP,处理鼠标和键盘消息。
PM_QS_PAINT:Windows 98/Me, Windows 2000/XP,处理画图消息。
PM_QS_POSTMESSAGE:Windows 98/Me, Windows 2000/XP,处理所有被投递的消息,包括timers 和 hotkeys。
PM_QS_SENDMESSAGE:Windows 98/Me, Windows 2000/XP,处理所有发送的消息。
PeekMessage在检索应用程序的消息队列时,如果其中有消息就将其放入lpMsg(如下所示的函数原型的声明中)所指的结构中,同时PeekMessage函数不会等到有消息放入队列时才返回。同样,如果hWnd为NULL,则PeekMessage检索对象为进程的消息队列;如果hWnd = -1,那么函数只检索消息队列中hWnd参数为NULL的PostThreadMessage函数投递的消息;如果 wMsgFilterMin和wMsgFilterMax都是0,则PeekMessage就检索所有有效消息;对一个消息在完成检索之后,可以显式地删除之(WM_PAINT例外,因为WM_PAINT需要合并处理,只有在合并处理之后才会被删除),也可以显式地保留之。
关于消息循环,现就介绍我用到的三个函数,应该还会加的。