MFC的消息映射機制
=================================================================================================
MFC將消息分為以下三種類型:
(1)標準消息:除WM_COMMAND之外,所有以WM_開頭的消息,從CWnd派生的類,都可以接收到這類消息。
(2)命令消息:來自菜單、加速鍵或工具欄按鈕的消息。這類消息都以WM_COMMAND呈現(xiàn)。在MFC中,通過菜單項的標識(ID)來區(qū)分不同的命令消息;在SDK中,通過消息的wParam參數(shù)識別。從CCmdTarget派生的類,都可以接收到這類消息。
(3)通告消息:由控件產(chǎn)生的消息,例如,按鈕的單擊,列表框的選擇等均產(chǎn)生此類消息,為的是向其父窗口(通常是對話框)通知事件的發(fā)生。這類消息也是以WM_COMMAND形式呈現(xiàn)。從CCmdTarget派生的類,都可以接收到這類消息。
某個窗口產(chǎn)生一個消息,該消息中的第一個參數(shù)就是與這個窗口有關(guān)的句柄,由于VC++系統(tǒng)在后臺維護了一個句柄和指針的映射關(guān)系,因此就可以從這個句柄找到對應的指針,然后將指針傳遞給基類,消息循環(huán)的最終結(jié)果都會歸結(jié)為調(diào)用基類(窗口類的基類也就是CWnd類)中的WindowProc函數(shù),下面詳細的分析了MFC對消息的處理過程:
MFC對于各類消息都是先交由一個“Afx(即應用程序框架函數(shù))”LRESULT CALLBACK AfxWndProc<for all CWnd's and derived classes>來處理;
然后再調(diào)用LRESULT AFXAPI AfxCallWndProc(CWnd* pWnd, HWND hWnd, UINT nMsg, WPARAM wParam = 0, LPARAM lParam = 0)<Official way to send message to a CWnd>;
然后再調(diào)用LRESULT CWnd::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)<main WindowProc implementation>;
然后再調(diào)用BOOL CWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult);在OnWndMsg函數(shù)中會針對不同的消息類型進行不同的處理,對于命令消息它會交由BOOL OnCommand(WPARAM wParam, LPARAM lParam)來處理;對于通告消息,會交由BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)來處理;需要說明的一點是不論是命令消息還是通告消息,最終都會調(diào)用OnCmdMsg函數(shù)。如果消息不是命令消息或通告消息,即為標準消息,則會最終到一個switch結(jié)構(gòu)中去尋找,如果在OnWndMsg中未能響應消息,則交由默認的消息處理函數(shù)LRESULT CWnd::DefWindowProc(UINT nMsg, WPARAM wParam, LPARAM lParam)<Default CWnd implementation>。
在OnWndMsg函數(shù)中的case結(jié)構(gòu)中有很多類似于這樣的語句:lResult = (this->*mmf.pfn_is)((LPTSTR)lParam);根據(jù)多態(tài)性,這里面的this指針往往都是指向基類的,例如CMainFrame或CXXXView類等的對象,這里面的mmf.pfn_is是一個指向函數(shù)的指針,因此執(zhí)行這句話調(diào)用消息處理的入口就會遵循先到子類中查找是否存在這樣的消息處理函數(shù),如果子類沒有,才會上溯到基類中去尋找。
=================================================================================================
自定義消息:#define UM_XXXX WM_USER+X;聲明消息響應函數(shù)原型afx_msg void OnXXXX();添加消息映射ON_MESSAGE(UM_XXXX,OnXXXX);編寫消息響應函數(shù)代碼;使用SendMessage或者PostMessage函數(shù)發(fā)送消息。
GetMessage會等待消息處理完畢后再取出下一條消息;PeekMessage只會窺視一下即將取出的下一條消息,而不會做任何與消息處理有關(guān)的工作。
CWnd::SendMessage會發(fā)送消息,并等待消息返回,在程序執(zhí)行過程中使用該函數(shù),就相當于把消息響應函數(shù)的函數(shù)體插放到當前程序體中;CWnd::PostMessage會發(fā)送消息,但是不會等待消息處理完成后才返回,這個函數(shù)會立刻返回,它只是在消息隊列的頭部放置了一個新的消息,至于這個消息多會兒被響應就是系統(tǒng)底層消息循環(huán)的事情了。
=================================================================================================
這里要提到的這個觀點太過于經(jīng)典了,因此一定要好好領(lǐng)會,永遠不能忘記。
MFC的消息相應是通過將產(chǎn)生的消息放置到一個消息隊列中,然后由系統(tǒng)不停的從隊列的頭部取出消息進行響應和執(zhí)行,由于消息響應在一個時刻只能響應一個消息,而不能同時響應若干個消息,因此只有等待當前的消息處理完成后才能夠進行下一個消息的響應,因此如果我們希望在響應完一個消息之后(也就是在程序中表現(xiàn)為執(zhí)行完一個消息響應函數(shù)的函數(shù)體之后)再去做另外一件工作,那就可以在當前的消息響應函數(shù)中發(fā)送一個消息,在這個發(fā)送出去的消息的響應函數(shù)中去做那些工作就可以了。而這個發(fā)送的消息可以是我們自定義的消息。
=================================================================================================
posted on 2008-02-23 19:14 so true 閱讀(526) 評論(0) 編輯 收藏 所屬分類: C&C++