MFC的消息映射
Windows操作系統采用消息驅動機制,即以消息來驅動應用程序的運行。如果說窗口是用戶操作的接口,消息就是流過這個接口的血液。MFC的消息映射與處理機制是其精華所在,相比之下其他語言如c#、VB等提供給開發者的消息處理方式顯得格外局促和僵化。
MFC中的窗口封裝類CWnd為各種窗口消息定義了對應的虛擬函數(如OnkeyDown(),Onpaint()等),而一個消息處理調度函數WindowProc()為響應各種窗口消息,調用相應的虛擬函數進行處理,例如WM_KEYDOWN消息到來,就調用Onkeydown()虛函數進行處理。如果派生類需要特殊處理某個消息(系類的處理不能滿足需要),重載相應的虛函數即可。這種消息處理機制在MFC沒有誕生之前,被認為是顯而易見的。
但這種處理機制存在明顯的缺陷。因為如果基類定義了虛擬函數,系統要為基類和每個派生類分別建立一張虛擬函數表,其中每個虛擬函數有4字節的入口地址,無論派生類是否重載了某個虛函數。要為100個以上的窗口消息都定義相應的虛函數,成本是可觀的。另外,不可能為所有菜單、按鈕的命令消息都定義處理函數,并且控件的通知消息、反射消息也是不可以預知的。在這種機制下,處理不可預知的命令和通知消息,只能像WIN32API編程那樣,使用繁瑣的switch-case語句。所以,由于以上種種原因,MFC沒有采用虛擬函數機制,而是新創了所謂的消息映射機制。
消息映射就是在基類中建立一張窗口消息和消息處理函數的映射表(以數組形式存儲),將大部分窗口消息和處理消息的對應關系存儲在該表中。注意,這些處理函數雖然也是基類為每個窗口消息分別定義的,但是他們并不是虛函數。基類(如CWnd)為大部分窗口消息定義了處理函數,并建立了二者之間的映射關系,這些處理函數通常對消息進行常規處理或默認處理。而派生類的初始消息映射表是空的,如果派生類需要對某個消息進行特殊處理,它可以定義一個新的消息處理函數,并在自己的映射表中添加一項,存儲該消息和該函數的對應關系。這里也有一個消息處理跳讀函數,它是CWnd::OnWndMsg()。針對某個消息,該函數首先在當前派生類的消息映射表中尋找對應的處理函數,不成功就向上尋找父類的映射表,直到成功或者搜索完基類為止。如果最終沒有發現對應的處理函數,則執行系統級的默認處理。
基類沒有為命令、通知等不可預知的消息定義處理函數,但是能夠根據需要,將他們添加在派生類的消息映射表中。當消息到來時,存儲在該表中的相應處理函數的入口地址(函數指針)就被提取、調用。
雖然建立消息映射表的方法顯得機械,但這些機械的工作可以由類向導來完成,類向導不僅能夠建立消息映射項目,還能為消息處理函數生成框架。只有少數類向導不支持的窗口消息或自定義消息,才必須勞煩程序員動手。
總結
- 上一篇: typeof 数据类型转换
- 下一篇: 理解SetCapture、Release