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

 

消息過濾



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

int CMessageLoop.Run()	
{		
BOOL bDoIdle = TRUE;		
int nIdleCount = 0;		
BOOL bRet;		
for(;;)		
{	
while(!::PeekMessage(&m_msg, NULL, 0, 0, PM_NOREMOVE) &&
 bDoIdle)			
{		
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的框架窗口分析上。稍後,我們將進入這部分內容。

發佈了3 篇原創文章 · 獲贊 0 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章