深入剖析WTL—WTL消息循環機制詳解
WTL消息循環機制實現了消息過濾和空閒處理機制。
首先看一下CMessageLoop的核心邏輯CMessageLoop.Run()的代碼:
int Run()
for(;;)
bRet = ::GetMessage(&m_msg, NULL, 0, 0);
if(bRet == -1)
if(!PreTranslateMessage(&m_msg))
if(IsIdleMessage(&m_msg))
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)
return m_view.PreTranslateMessage(pMsg);
|
這種消息過濾機制的好處是任何實現了CMessageFilter接口的對象,都可以接受消息過濾。
程序通過AddMessageFilter()和RemoveMessageFilter()把這些對象加入到CMessageLoop中。
空閒處理
空閒處理的機制和消息過濾類似。這裏不再介紹。我們要把主要經歷放在WTL的框架窗口分析上。稍後,我們將進入這部分內容。