深入剖析WTL—WTL消息循環機制詳解

深入剖析WTL—WTL消息循環機制詳解 

WTL消息循環機制實現了消息過濾和空閒處理機制。

消息過濾



首先看一下CMessageLoop的核心邏輯CMessageLoop.Run()的代碼:

int Run()
{
   BOOL bDoIdle = TRUE;
   int nIdleCount = 0;
   BOOL bRet;
    for(;;)
   {
    while(bDoIdle && !::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE))
    {
     if(!OnIdle(nIdleCount++))
      bDoIdle = FALSE;
    }
     bRet = ::GetMessage(&m_msg, NULL, 0, 0);
     if(bRet == -1)
    {
     ATLTRACE2(atlTraceUI, 0, _T("::GetMessage returned -1 (error)/n"));
     continue;   // error, don't process
    }
    else if(!bRet)
    {
     ATLTRACE2(atlTraceUI, 0, _T("CMessageLoop::Run - exiting/n"));
     break;   // WM_QUIT, exit message loop
    }
     if(!PreTranslateMessage(&m_msg))
    {
     ::TranslateMessage(&m_msg);
     ::DispatchMessage(&m_msg);
    }
     if(IsIdleMessage(&m_msg))
    {
     bDoIdle = TRUE;
     nIdleCount = 0;
    }
   }
    return (int)m_msg.wParam;
}


在上面的代碼中,有三個需要注意的地方。

消息循環中,首先調用PeekMessage()判斷消息隊列中是否有消息。如果沒有,則調用OnIdle()函數。這就是調用空閒處理。

第二個注意點是,如果有消息,則調用GetMessage()得到消息。然後做判斷,如果是錯誤返回,則對消息並不進行處理。然後再判斷是否是WM_QUIT消息,如果是,則退出消息循環,從而結束該界面線程。

接下來是第三個注意點。在TranslateMessage()消息之前,調用了成員函數PreTranslateMessage()。這爲在TranslateMessage()之前對消息進行處理提供了機會。

PreTranslateMessage()會遍歷CMessageLoop中所有CMessageFilterd對象的PreTranslateMessage()函數,直到其中一個返回爲TRUE或它們都返回爲FALSE。當有一個返回爲TRUE時,即對消息處理了,那麼,就不再調用TranslateMessage(),而是進入下一個循環。

這種消息過濾機制提供了一種在不同窗口之間傳遞消息的機制。

CMessageFilter是一個C++的接口,即只定義了抽象虛擬函數。

class CMessageFilter {
public:
 virtual BOOL PreTranslateMessage(MSG* pMsg) = 0;
};


這樣,任何類想要實現消息過濾,只需實現這個接口。在C++中就採用繼承。然後再實現PreTranslateMessage()函數即可。

ATL/WTL App Wizard生成的框架窗口中實現PreTranslateMessage()的代碼如下:

BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
{
if(CFrameWindowImpl<CMainFrame>::PreTranslateMessage(pMsg))
   return TRUE;
 return m_view.PreTranslateMessage(pMsg);
}


這種消息過濾機制的好處是任何實現了CMessageFilter接口的對象,都可以接受消息過濾。

程序通過AddMessageFilter()和RemoveMessageFilter()把這些對象加入到CMessageLoop中。

空閒處理



空閒處理的機制和消息過濾類似。這裏不再介紹。我們要把主要經歷放在WTL的框架窗口分析上。稍後,我們將進入這部分內容。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章