Win编程里的消息循环:pumpmessage、peekMessage

  这是在浏览器项目实际遇到了消息循环的问题,因此在这里简陋的写上一笔,为的是给自己个印象。

  下面要介绍的函数都是在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需要合并处理,只有在合并处理之后才会被删除),也可以显式地保留之。

  关于消息循环,现就介绍我用到的三个函数,应该还会加的。