深入剖析WTL框架(二)

 

ATL的消息處理宏

消息映射的目的是實現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;
   }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章