MFC消息映射機制分析論文
時間:2022-03-17 05:31:00
導語:MFC消息映射機制分析論文一文來源于網(wǎng)友上傳,不代表本站觀點,若需要原創(chuàng)文章可咨詢客服老師,歡迎參考。
摘要:mfc以層次結構組織起來,比較龐雜,尤其是它的消息映射機制,更是涉及到很多底層的東西。本文通過對整個消息映射機制進行系統(tǒng)的分析,可以幫助程序開發(fā)人員更好地了解MFC,進行可視化編程。
關鍵詞:消息驅動;消息映射;MFC程序設計
1引言
微軟公司提供的MFC基本類庫(MicrosoftFoundationClasses),是進行可視化編程時使用最為流行的一個類庫。MFC封裝了大部分WindowsAPI函數(shù)和Windows控件,使得程序的開發(fā)變得簡單,極大的縮短了程序的開發(fā)周期。MFC獨創(chuàng)的Document/View框架結構,能夠將管理數(shù)據(jù)的代碼和顯示數(shù)據(jù)的程序代碼分開,并且設計了一套方便的消息映射和命令傳遞機制,方便程序員的開發(fā)使用。其中消息映射機制本身比較龐大和復雜,對它的分析和了解無疑有助于我們寫出更為合理的高效的程序。這里我們分析一下MFC的消息映射機制,以了解MFC是如何對Windows的消息加以封裝,方便用戶的開發(fā)。
2SDK下的消息機制實現(xiàn)
首先,簡單回顧一下SDK下我們是如何進行Windows的程序開發(fā)的。Windows程序的運行是依靠外部發(fā)生的事件來驅動的,事件由操作系統(tǒng)捕捉,以消息的形式進入消息隊列,然后通過消息循環(huán)從隊列中不斷取出消息,送到對應的窗口過程里處理。相對于DOS程序,Windows是以WinMain作為程序的入口點,以下就是一個簡化的Win32程序的主體,通過while語句實現(xiàn)消息循環(huán):
WinMain(…)
{
MSGmsg;
RegisterClass(…);//注冊窗口類
CreateWindow(…);//創(chuàng)建窗口
ShowWindow(…);//顯示窗口
UpdateWindow(…);
While(GetMessage(&msg,…)){//消息循環(huán)
TranslateMessage(…);
DispatchMessage(…);
}
returnmsg.wParam;
}
其中,msg代表消息,程序是通過GetMessage函數(shù)從和某個線程相對應的消息隊列里面把消息取出來并放到消息變量msg里面。然后TranslateMessage函數(shù)用來把鍵盤消息轉化并放到響應的消息隊列里面,最后DispatchMessage函數(shù)把消息分發(fā)到相關的窗口過程去處理。窗口過程根據(jù)消息的類型對不同的消息進行相關的處理。在SDK編程過程中,用戶需要在窗口過程中分析消息的類型及其參數(shù)的含義,然后做不同的處理,相對比較麻煩;而MFC把消息調用的過程給封裝起來,使用戶能夠通過ClassWizard方便的使用和處理Windows的各種消息。
3MFC中的消息映射機制
在MFC的框架結構下,“消息映射”是通過巧妙的宏定義,形成一張消息映射表格來進行的。這樣一旦消息發(fā)生,F(xiàn)ramework就可以根據(jù)消息映射表格來進行消息映射和命令傳遞。
首先在需要進行消息處理的類的頭文件(.H)里,都會含有DECLARE_MESSAGE_MAP()宏,聲明該類擁有消息映射表格:
classCscribbleDoc:publicCdocument
{
…
DECLARE_MESSAGE_MAP()
};
然后在類應用程序文件(.CPP)實現(xiàn)這一表格
BEGIN_MESSAGE_MAP(CInheritClass,CBaseClass)
//{{AFX_MSG_MAP(CInheritClass)
ON_COMMAND(ID_EDIT_COPY,OnEditCopy)
………
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
----這里主要進行消息映射的實現(xiàn),把它和消息處理函數(shù)聯(lián)系在一起。其中出現(xiàn)三個宏,第一個宏是BEGIN_MESSAGE_MAP有兩個參數(shù),分別是擁有消息表格的類,及其父類。第二個宏是ON_COMMAND,指定命令消息的處理函數(shù)名稱。第三個宏是END_MESSAGE_MAP()作為結尾符號。中間的奇怪符號//}}和//{{,是ClassWizard產生的,對程序無影響。
觀察DECLARE_MESSAGE_MAP的定義:
#defineDECLARE_MESSAGE_MAP()
private:
staticconstAFX_MESSAGE_ENTRY_messageEntries[];
protected:
staticAFX_DATAconstAFX_MSGMAPmessageMap;
virtualconstAFX_MSGMAP*GetMessageMap()const;
里面又包含了MFC新定義的兩個數(shù)據(jù)結構,如下:
AFX_MSGMAP_ENTRY
structAFX_MSGMAP_ENTRY
{
UINTnMessage;//windowsmessage
UINTnCode;//controlcodeorWM_NOTIFYcode
UINTnID;//controlID(or0forwindowsmessages)
UINTnLastID;//usedforentriesspecifyingarangeofcontrolid''''s
UINTnSig;//signaturetype(action)orpointertomessage#
AFX_PMSGpfn;//routinetocall(orspecialvalue)
};
和AFX_MSGMAP
structAFX_MSGMAP
{
constAFX_MSGMAP*pBaseMap;
constAFX_MSGMAP_ENTRY*lpEntries;
};
其中AFX_MSGMAP_ENTRY結構包含了一個消息的所有相關信息,而AFX_MSGMAP主要作用有兩個,一是用來得到基類的消息映射入口地址。二是得到本身的消息映射入口地址。
實際上,MFC把所有的消息一條條填入到AFX_MSGMAP_ENTRY結構中去,形成一個數(shù)組,該數(shù)組存放了所有的消息和與它們相關的參數(shù)。同時通過AFX_MSGMAP能得到該數(shù)組的首地址,同時得到基類的消息映射入口地址。當本身對該消息不響應的時候,就可以上溯到基類的消息映射表尋找對應的消息響應。
現(xiàn)在我們來分析MFC是如何讓窗口過程來處理消息的,實際上所有MFC的窗口類都通過鉤子函數(shù)_AfxCbtFilterHook截獲消息,并且在鉤子函數(shù)_AfxCbtFilterHook中把窗口過程設定為AfxWndProc。原來的窗口過程保存在成員變量m_pfnSuper中。
在MFC框架下,一般一個消息的處理過程是這樣的。
(1)函數(shù)AfxWndProc接收Windows操作系統(tǒng)發(fā)送的消息。
(2)函數(shù)AfxWndProc調用函數(shù)AfxCallWndProc進行消息處理,這里一個進步是把對句柄的操作轉換成對CWnd對象的操作。
(3)函數(shù)AfxCallWndProc調用CWnd類的方法WindowProc進行消息處理。
(4)WindowProc調用OnWndMsg進行正式的消息處理,即把消息派送到相關的方法中去處理。在CWnd類中都保存了一個AFX_MSGMAP的結構,而在AFX_MSGMAP結構中保存有所有我們用ClassWizard生成的消息的數(shù)組的入口,我們把傳給OnWndMsg的message和數(shù)組中的所有的message進行比較,找到匹配的那一個消息。實際上系統(tǒng)是通過函數(shù)AfxFindMessageEntry來實現(xiàn)的。找到了那個message,實際上我們就得到一個AFX_MSGMAP_ENTRY結構,而我們在上面已經(jīng)提到AFX_MSGMAP_ENTRY保存了和該消息相關的所有信息,其中主要是消息的動作標識和相關的執(zhí)行函數(shù)。然后我們就可以根據(jù)消息的動作標識調用相關的執(zhí)行函數(shù),而這個執(zhí)行函數(shù)實際上就是通過ClassWizard在類實現(xiàn)中定義的一個方法。這樣就把消息的處理轉化到類中的一個方法的實現(xiàn)上。
(5)如果OnWndMsg方法沒有對消息進行處理的話,就調用DefWindowProc對消息進行處理。這是實際上是調用原來的窗口過程進行缺省的消息處理。所以如果正常的消息處理的話,MFC窗口類是完全脫離了原來的窗口過程,用自己的一套體系結構實現(xiàn)消息的映射和處理。即先調用MFC窗口類掛上去的窗口過程,再調用原先的窗口過程。用戶面對的消息參數(shù)將不再是固定的wParam和lParam,而是和消息類型具體相關的參數(shù)。比如和消息WM_LButtonDown相對應的方法OnLButtonDown的兩個參數(shù)是nFlags和point。nFlags表示在按下鼠標左鍵的時候是否有其他虛擬鍵按下,point更簡單,就是表示鼠標的位置。同時MFC窗口類消息傳遞中還提供了兩個函數(shù),分別為WalkPreTranslateTree和PreTranslateMessage。我們知道利用MFC框架生成的程序,都是從CWinApp開始執(zhí)行的,而CWinapp實際繼承了CWinThread類。在CWinThread的運行過程中會調用窗口類中的WalkPreTranslateTree方法。而WalkPreTranslateTree方法實際上就是從當前窗口開始查找愿意進行消息翻譯的類,直到找到窗口沒有父類為止。在WalkPreTranslateTree方法中調用了PreTranslateMessage方法。實際上PreTranslateMessage最大的好處是我們在消息處理前可以在這個方法里面先做一些事情。舉一個簡單的例子,比如我們希望在一個CEdit對象里,把所有的輸入的字母都以大寫的形式出現(xiàn)。我們只需要在PreTranslateMessage方法中判斷message是否為WM_CHAR,如果是的話,把wParam(表示鍵值)由小寫字母的值該為大寫字母的值就實現(xiàn)了這個功能。
4小結
MFC通過巧妙的宏定義把消息調用的過程給封裝起來,使用戶能夠通過ClassWizard方便的使用和處理Windows的各種消息。通過對MFC消息映射機制的分析,不僅能夠使我們更好的使用MFC類庫,同時,對于我們自己設計程序框架和類,無疑也有相當大的幫助。
參考文獻:
[1]侯俊杰著,深入淺出MFC(第2版)[M].湖北:華中科技大學出版社,2001.5
[2]DavidJ.Kruglinski著,VisualC技術內幕(第五版)[M].北京:北京希望電子出版社,2001.1
- 上一篇:市企業(yè)工資清算工作通知
- 下一篇:國有土地使用權出讓通知