消息映射的目的是實現ProcessWindowMessage()。ProcessWindowMessage()函數是窗口函數的關鍵邏輯。
一共有三種消息處理宏,分別對應三類窗口消息——普通窗口消息(如WM_CREATE),命令消息(WM_COMMANS)和通知消息(WM_NOTIFY)。
消息處理宏的目的是將消息和相應的處理函數(該窗口的成員函數)聯繫起來。
· 普通消息處理宏
有兩個這樣的宏:MESSAGE_HANDLER和MESSAGE_RANGE_HANDLER。
第一個宏將一個消息和一個消息處理函數連在一起。第二個宏將一定範圍內的消息和一個消息處理函數連在一起。
消息處理函數通常是下面這樣的:
LRESULT MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled); |
注意最後一個參數bHandled。它的作用是該處理函數是否處理該消息。如果它爲FALSE,消息MAP的其它處理函數會來處理這個消息。
我們看一下MESSAGE_HANDLE的定義:
#define MESSAGE_HANDLER(msg, func) \ if(uMsg == msg) \ { \ bHandled = TRUE; \ lResult = func(uMsg, wParam, lParam, bHandled); \ if(bHandled) \ return TRUE; \ } |
在上面的代碼中,首先判斷是否是想要處理的消息。如果是的,那麼調用第二個參數表示的消息處理函數來處理該消息。
注意bHandled,如果在消息處理函數中設置爲TRUE,那麼,在完成該消息處理後,會進入return TRUE語句,從ProcessWindowMessage()函數中返回。
如果bHandled在調用消息處理函數時,設置爲FALSE,則不會從ProcessWindowMessage中返回,而是繼續執行下去。
· 命令消息處理宏和通知消息處理宏
命令消息處理宏有五個——COMMAND_HANDLER,COMMAND_ID_HANDLER,COMMAND_CODE_HANDLER,COMMAND_RANGE_HANDLER和COMMAND_RANGE_CODE_HANDLER。
通知消息處理宏有五個--NOTIFY_HANDLER,NOTIFY_ID_HANDLER,NOTIFY_CODE_HANDLER,NOTIFY_RANGE_HANDLER和NOTIFY_RANGE_CODE_HANDLER
我們不再詳細分析。
通過上面的分析,我們知道了ATL是怎樣實現窗口函數邏輯的。那麼ATL是怎樣封裝窗口函數的呢?爲了能理解ATL的封裝方法,還必須瞭解ATL中的窗口subclass等技術。我們將在分析完這些技術之後,再分析ATL對窗口消息處理函數的封裝。
我們知道Windows窗口的功能由它的窗口函數指定。通常在創建Windows應用程序時,我們要開發一個窗口函數。通過定義對某些消息的相應來實現窗口的功能。
在每個窗口處理函數的最後,我們一般用下面的語句:
default: return DefWindowProc(hWnd, message, wParam, lParam); |
它的意思是,對於沒有處理的消息,我們將它傳遞給Windows的確省窗口函數。
Windows除了提供這個缺省的窗口函數,還爲某些標準的控制提供了一些預定義的窗口函數。
我們在註冊窗口類的時候,指定了該窗口類的窗口處理函數。
擴展窗口類的功能,就是要改變窗口函數中對某些消息的處理邏輯。
下面我們來看幾種擴展窗口功能的技術,以及看看ATL是怎樣實現的。
派生和CHAIN_MSG_MAP()
很自然,我們會在一個窗口類的基礎上派生另一個。然後通過定義不同的消息處理函數。
下面是一個簡單的實例(該例子摘自MSDN)。
class CBase: public CWindowImpl< CBase > // simple base window class: shuts down app when closed { BEGIN_MSG_MAP( CBase ) MESSAGE_HANDLER( WM_DESTROY, OnDestroy ) END_MSG_MAP() LRESULT OnDestroy( UINT, WPARAM, LPARAM, BOOL& ) { PostQuitMessage( 0 ); return 0; } }; class CDerived: public CBase // derived from CBase; handles mouse button events { BEGIN_MSG_MAP( CDerived ) MESSAGE_HANDLER( WM_LBUTTONDOWN, OnButtonDown ) CHAIN_MSG_MAP( CBase ) // chain to base class END_MSG_MAP() LRESULT OnButtonDown( UINT, WPARAM, LPARAM, BOOL& ) { ATLTRACE( "button down\n" ); return 0; } }; |