MFC的消息響應機制詳解:程序員
1.MFC是Windows下程序設計的最流行的一個類庫,可是該類庫比較龐雜,尤爲是它的消息映射機制,更是涉及到不少低層的東西,接下來詳細講解。編程
2.在講解MFC的消息響應以前先講解一下SDK的消息響應: SDK下的消息機制實現windows
講解一下SDK下咱們是如何進行Windows的程序開發的。通常來講,Windows的消息都是和線程相對應的。即Windows會把消息發送給和該消息相對應的線程。數組
在SDK的模式下,程序是經過GetMessage函數從和某個線程相對應的消息隊列裏面把消息取出來並放到一個特殊的結構裏面,一個消息的結構是一個以下的STRUCTURE。app
typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
}MSG;框架
說明一下結構體裏的內容:函數
1)hwnd表示和窗口過程相關的窗口的句柄。spa
2)message表示消息的ID號。操作系統
3)wParam和lParam表示和消息相關的參數。線程
4)time表示消息發送的時間。
5)pt表示消息發送時的鼠標的位置。
再用TranslateMessage函數用來把虛鍵消息翻譯成字符消息並放到響應的消息隊列裏面,最後DispatchMessage函數把消息分發到相關的窗口過程。
而後窗口過程根據消息的類型對不一樣的消息進行相關的處理。在SDK編程過程當中,用戶須要在窗口過程當中分析消息的類型和跟消息一塊兒的參數的含義,作不一樣的處理,
相對比較麻煩,而MFC把消息調用的過程給封裝起來,使用戶可以經過ClassWizard方便的使用和處理Windows的各類消息。
3.MFC的消息實現機制
在MFC的框架結構下,咱們能夠清晰的看到,能夠進行消息處理的類的頭文件裏面都會含有DECLARE_MESSAGE_MAP()宏,這裏主要進行消息映射和消息處理函數的聲明。
能夠進行消息處理的類的實現文件裏通常都含有以下的結構。
BEGIN_MESSAGE_MAP(CInheritClass, CBaseClass)
END_MESSAGE_MAP()
1)全部可以進行消息處理的類都是基於CCmdTarget類的,也就是說CCmdTarget類是全部能夠進行消息處理類的父類。CCmdTarget類是MFC處理命令消息的基礎和核心。
2)同時MFC定義了下面的兩個主要結構:
AFX_MSGMAP_ENTRY
struct AFX_MSGMAP_ENTRY
{
UINT nMessage; // windows message
UINT nCode; // control code or WM_NOTIFY code
UINT nID;
UINT nLastID;
UINT nSig;
AFX_PMSG pfn;
};
其中AFX_MSGMAP_ENTRY結構包含了一個消息的全部相關信息:
1)nMessage爲Windows消息的ID號。
2)nCode爲控制消息的通知碼。
3)nID爲Windows控制消息的IDnLastID表。
4)若是是一個指定範圍的消息被映射的話,nLastID用來表示它的範圍。nSig表示消息的動做標識。
5)AFX_PMSG pfn 它其實是一個指向和該消息相應的執行函數的指針。
AFX_MSGMAP
struct AFX_MSGMAP
{
#ifdef _AFXDLL
const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
#else
const AFX_MSGMAP* pBaseMap;
#endif
const AFX_MSGMAP_ENTRY* lpEntries;
};
FX_MSGMAP主要做用是兩個:
1)用來獲得基類的消息映射入口地址。
2)獲得自己的消息映射入口地址。
實際上,MFC把全部的消息一條條填入到AFX_MSGMAP_ENTRY結構中去,造成一個數組,該數組存放了全部的消息和與它們相關的參數。
同時經過AFX_MSGMAP能獲得該數組的首地址,同時獲得基類的消息映射入口地址,這是爲了當自己對該消息不響應的時候,就調用其基類的消息響應。
分析一下MFC是如何讓窗口過程來處理消息的,實際上全部MFC的窗口類都經過鉤子函數_AfxCbtFilterHook截獲消息,而且在鉤子函數_AfxCbtFilterHook中把窗口過程設定爲
AfxWndProc。原來的窗口過程保存在成員變量m_pfnSuper中。
在MFC框架下,通常一個消息的處理過程是這樣的,如下做爲說明:
函數AfxWndProc接收Windows操做系統發送的消息。
函數AfxCallWndProc調用CWnd類的方法WindowProc進行消息處理。注意AfxWndProc和AfxCallWndProc都是AFX的API函數。而WindowProc已是CWnd的一個方法。
因此能夠注意到在WindowProc中已經沒有關於句柄或者是CWnd的參數了。
方法WindowProc調用方法OnWndMsg進行正式的消息處理,即把消息派送到相關的方法中去處理。消息是如何派送的呢?實際上在CWnd類中都保存了一個AFX_MSGMAP的
結構,而在AFX_MSGMAP結構中保存有全部咱們用ClassWizard生成的消息的數組的入口,咱們把傳給OnWndMsg的message和數組中的全部的message進行比較,
找到匹配的那一個消息。實際上系統是經過函數AfxFindMessageEntry來實現的。找到了那個message,實際上咱們就獲得一個AFX_MSGMAP_ENTRY結構,
而咱們在上面已經提到AFX_MSGMAP_ENTRY保存了和該消息相關的全部信息,其中主要的是消息的動做標識和跟消息相關的執行函數。
而後咱們就能夠根據消息的動做標識調用相關的執行函數,而這個執行函數實際上就是經過ClassWizard在類實現中定義的一個方法。
這樣就把消息的處理轉化到類中的一個方法的實現上。
舉一個簡單的例子,好比在View中對WM_LButtonDown消息的處理就轉化成對以下一個方法的操做。
void CInheritView::OnLButtonDown(UINT nFlags, CPoint point)
{
handler code here and/or call default
CView::OnLButtonDown(nFlags, point);
}
注意這裏CView::OnLButtonDown(nFlags, point)實際上就是調用CWnd的Default()方法。 而Default()方法所作的工做就是調用DefWindowProc對消息進行處理。
這其實是調用原來的窗口過程進行缺省的消息處理。
若是OnWndMsg方法沒有對消息進行處理的話,就調用DefWindowProc對消息進行處理。這是其實是調用原來的窗口過程進行缺省的消息處理。因此若是正常的消息處理的
話,MFC窗口類是徹底脫離了原來的窗口過程,用本身的一套體系結構實現消息的映射和處理。即先調用MFC窗口類掛上去的窗口過程,再調用原先的窗口過程。而且用戶面
對和消息相關的參數再也不是死板的wParam和lParam,而是和消息類型具體相關的參數。
好比和消息WM_LbuttonDown相對應的方法OnLButtonDown的兩個參數是nFlags和point。nFlags表示在按下鼠標左鍵的時候是否有其餘虛鍵按下,point更簡單,
就是表示鼠標的位置。
同時MFC窗口類消息傳遞中還提供了兩個函數,分別爲WalkPreTranslateTree和PreTranslateMessage。咱們知道利用MFC框架生成的程序,都是從CWinApp開始執行的,
而CWinapp實際繼承了CWinThread類。在CWinThread的運行過程當中會調用窗口類中的WalkPreTranslateTree方法。
而WalkPreTranslateTree方法實際上就是從當前窗口開始查找願意進行消息翻譯的類,直到找到窗口沒有父類爲止。
在WalkPreTranslateTree方法中調用了PreTranslateMessage方法。實際上PreTranslateMessage最大的好處是咱們在消息處理前能夠在這個方法裏面先作一些事情。
舉一個簡單的例子:
好比咱們但願在一個CEdit對象裏,把全部的輸入的字母都以大寫的形式出現。咱們只須要在PreTranslateMessage方法中判斷message是否爲WM_CHAR,
若是是的話,把wParam(表示鍵值)由小寫字母的值該爲大寫字母的值就實現了這個功能。
繼續上面的例子,根據咱們對MFC消息機制的分析,咱們很容易獲得除了上面的方法,咱們至少還能夠在另外兩個地方進行操做。
a.在消息的處理方法裏面即OnChar中,固然最後咱們再也不調用CEdit::OnChar(nChar, nRepCnt, nFlags),而是直接調用DefWindowProc(WM_CHAR,nChar,MAKELPARAM
(nRepCnt,nFlags))。
由於從咱們上面的分析能夠知道CEdit::OnChar(nChar, nRepCnt, nFlags)實際上也就是對DefWindowProc方法的調用。
b.咱們能夠直接重載DefWindowProc方法,對message類型等於WM_CHAR的,直接修改nChar的值便可。
4.今天就寫這些,明天繼續,程序員們要想要精通代碼,最主要的方式之一就是要多練習,多調試,這樣面對bug的時候才能臨危不動。
改變本身,從如今作起-----------久館