一.引言
vc++的mfc類庫實際上是windows下c++程式設計的一套最為流行的類庫。mfc的框架結構大大方便了程式設計師 的程式設計工作,但是為了更加有效、靈活的使用mfc程式設計,了解mfc的體系結構往往可以使程式設計工作事半功倍。它合理的封裝了win32 api函式,並設計了一套方便的訊息對映機制。但這套機制本身比較龐大和複雜,對它的分析和了解無疑有助於我們寫出更為合理的高效的程式。這裡我們簡單的 分析mfc的訊息響應機制,以了解mfc是如何對windows的訊息加以封裝,方便使用者的開發。
二.sdk下的訊息機制實現
這裡簡單的回顧一下sdk下我們是如何進行windows的程式開發的。一般來說,windows的訊息都是和執行緒 相對應的。即windows會把訊息傳送給和該訊息相對應的執行緒。在sdk的模式下,程式是通過getmessage函式從和某個執行緒相對應的訊息佇列裡 面把訊息取出來並放到乙個特殊的結構裡面,乙個訊息的結構是乙個如下的structure。
typedef struct tagmsg msg;
其中hwnd表示和視窗過程相關的視窗的控制代碼,message表示訊息的id號,wparam和lparam表示和訊息相關的引數,time表示訊息傳送的時間,pt表示訊息傳送時的滑鼠的位置。
然 後translatemessage函式用來把虛鍵訊息翻譯成字元訊息並放到響應的訊息佇列裡面,最後dispatchmessage函式把訊息分發到相 關的視窗過程。然後視窗過程根據訊息的型別對不同的訊息進行相關的處理。在sdk程式設計過程中,使用者需要在視窗過程中分析訊息的型別和跟訊息一起的引數的含 義,做不同的處理,相對比較麻煩,而mfc把訊息呼叫的過程給封裝起來,使使用者能夠通過classwizard方便的使用和處理windows的各種消 息。
三.mfc的訊息實現機制
我們可以看到,在mfc的框架結構下,可以進行訊息處理的類的標頭檔案裡面都會含有declare_message_map()巨集,這裡主要進行訊息對映和訊息處理函式的宣告。可以進行訊息處理的類的實現檔案裡一般都含有如下的結構。
begin_message_map(cinheritclass, cbaseclass)
//}afx_msg_map
end_message_map()
這裡主要進行訊息對映的實現和訊息處理函式的實現。
所有能夠進行訊息處理的類都是基於ccmdtarget類的,也就是說ccmdtarget類是所有可以進行訊息處理類的父類。ccmdtarget類是mfc處理命令訊息的基礎和核心。
同時mfc定義了下面的兩個主要結構:
afx_msgmap_entry
struct afx_msgmap_entry
;和afx_msgmap
struct afx_msgmap
;其中afx_msgmap_entry結構包含了
乙個訊息的所有相關資訊,其中
nmessage為windows訊息的id號
ncode為控制訊息的通知碼
nid為windows控制訊息的id
nlastid表示如果是乙個指定範圍的訊息被對映的話,
nlastid用來表示它的範圍。
nsig表示訊息的動作標識
afx_pmsg pfn 它實際上是乙個指向
和該訊息相應的執行函式的指標。
而afx_msgmap主要作用是兩個,一:用來得到基類的訊息對映入口位址。二:得到本身的訊息對映入口位址。
實 際上,mfc把所有的訊息一條條填入到afx_msgmap_entry結構中去,形成乙個陣列,該陣列存放了所有的訊息和與它們相關的引數。同時通過 afx_msgmap能得到該陣列的首位址,同時得到基類的訊息對映入口位址,這是為了當本身對該訊息不響應的時候,就呼叫其基類的訊息響應。
現 在我們來分析mfc是如何讓視窗過程來處理訊息的,實際上所有mfc的視窗類都通過鉤子函式_afxcbtfilterhook截獲訊息,並且在鉤子函式 _afxcbtfilterhook中把視窗過程設定為afxwndproc。原來的視窗過程儲存在成員變數m_pfnsuper中。
所以在mfc框架下,一般乙個訊息的處理過程是這樣的。
函式afxwndproc接收windows作業系統傳送的訊息。
函式afxwndproc呼叫函式afxcallwndproc進行訊息處理,這裡乙個進步是把對控制代碼的操作轉換成對cwnd物件的操作。
函 數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)
注 意這裡cview::onlbuttondown(nflags, point)實際上就是呼叫cwnd的default()方法。 而default()方法所做的工作就是呼叫defwindowproc對訊息進行處理。這實際上是呼叫原來的視窗過程進行預設的訊息處理。
如果onwndmsg方法沒有對訊息進行處理的話,就呼叫defwindowproc對訊息進行處理。這是實際上是呼叫原來的視窗過程進行預設的訊息處理。
所以如果正常的訊息處理的話,mfc視窗類是完全脫離了原來的視窗過程,用自己的一套體系結構實現訊息的對映和處 理。即先呼叫mfc視窗類掛上去的視窗過程,再呼叫原先的視窗過程。並且使用者面對和訊息相關的引數不再是死板的wparam和lparam,而是和訊息類 型具體相關的引數。比如和訊息wm_lbuttondown相對應的方法onlbuttondown的兩個引數是nflags和point。nflags 表示在按下滑鼠左鍵的時候是否有其他虛鍵按下,point更簡單,就是表示滑鼠的位置。
通過對mfc類庫的分析和了解,不僅能夠使我們更好的使用mfc類庫,同時,對於我們自己設計和實現框架和類,無疑也有相當大的幫助。
MFC中訊息響應機制
由於視類視窗始終覆蓋在框架類視窗之上,因此所有操作,包括滑鼠單擊 滑鼠移動等操作都只能由視類視窗捕獲。乙個mfc訊息響應函式在程式中有三處相關資訊 函式原型 函式實現和以及用來關聯訊息和訊息響應函式的巨集。1 在訊息響應函式的原型 中,函式宣告的前部有乙個afx msg限定符,也是乙個巨集,該巨集表...
MFC訊息響應機制(一)
由於視類視窗始終覆蓋在框架類視窗之上,因此所有操作,包括滑鼠單擊 滑鼠移動等操作都只能由視類視窗捕獲。乙個mfc訊息響應函式在程式中有三處相關資訊 函式原型 函式實現和以及用來關聯訊息和訊息響應函式的巨集。1 在訊息響應函式的原型 中,函式宣告的前部有乙個afx msg限定符,也是乙個巨集,該巨集表...
MFC 訊息機制
windows應用程式是通過訊息驅動的,在mfc軟體開發時,進行介面操作經常要用到訊息,通過訊息對應的處理函式來實現響應的操作。比如,使用者操作視窗,就會產生訊息,送給對應的訊息處理函式進行處理,對使用者的操作做出一些反應。mfc使用訊息對映機制來處理訊息,具體表現就是訊息和訊息處理函式一一對應的訊...