VC MFC訊息對映機制詳解

2021-07-22 13:25:34 字數 4729 閱讀 8701

windows程式和mfc程式是靠訊息驅動的,他們對於訊息的處理本質上是相同的。只是windows程式對於訊息處理的過程十分清晰明了,mfc程式則掩蓋了訊息處理的過程,以訊息對映的方式呈現在開發者面前,使得開發訊息的處理十分簡單。用多了mfc就想對它的訊息對映機制有乙個本質的了解,下面將對訊息對映做詳細的分析。當然,在分析mfc訊息對映之前首先對windows程式的訊息處理過程進行乙個簡單的描述。

1、windows應用程式訊息處理

windows程式都維護有自己的訊息佇列,儲存了佇列訊息(當然也有非佇列訊息,它們直接發給視窗),並用過訊息迴圈對訊息進行處理。訊息迴圈首先通過getmessage取得訊息並從佇列中移走,對於加速鍵會呼叫translateaccelerator函式,對其進行翻譯和處理,如果處理成功就不在呼叫translatemessage。如果不是加速鍵,就進行訊息的轉換和派發,讓目的視窗的視窗過程來處理訊息。示例**:

[cpp]view plain

copy

print?

// 主訊息迴圈:

while

(getmessage(&msg, null, 0, 0))  

}  真正處理訊息的是所謂的視窗過程(lresult callback wndproc(hwnd hwnd, uint message, wparam wparam, lparam lparam)),這個函式的引數記錄了過程對應的視窗、訊息的id以及引數,在其內部開發者可以實現自己需要的訊息處理功能。那訊息分發是如何傳送給視窗過程的呢?我們知道視窗建立過程中有乙個註冊視窗類的步驟,如下:

[cpp]view plain

copy

print?

atom

myregisterclass(

hinstance

hinstance)  

相信你看到這段**就會立即明了!

2、mfc訊息對映

mfc視窗使用同一視窗過程,通過訊息對映隱藏了訊息處理的過程,更加詳細點是隱藏了,那訊息對映如何實現的呢?

首先,我們先對mfc的訊息對映做乙個簡單介紹。mfc為了實現訊息對映在響應訊息的類內部自動做了如下兩方面的處理:

a、訊息對映宣告和實現

在類的定義(標頭檔案)裡,新增宣告訊息對映的巨集declare_message_map,在類的實現(原始檔)裡,通過

begin_message_map和end_message_map()實現訊息對映。

b、訊息響應函式的宣告和實現

當通過classwizard新增訊息響應函式時就會自動新增函式的宣告和實現,**如下:

宣告: 

[cpp]view plain

copy

print?

//}afx_msg

declare_message_map()  

對映: 

[cpp]view plain

copy

print?

begin_message_map(ctestdialog, cdialog)  

//}afx_msg_map

end_message_map()  

實現: 

[c-sharp]view plain

copy

print?

void

ctestdialog::onpaint()   

void

ctestdialog::ontimer(uint nidevent)     

僅僅這些工作就能實現對訊息處理的簡化嗎?當然,我們需要對這幾步有更深入的**!首先,需要了解的是訊息對映的宣告和實現。訊息對映宣告的**如下:  

[cpp]view plain

copy

print?

#define declare_message_map() /

protected

: /  

static

const

afx_msgmap* pascal getthismessagemap(); / 

// 獲得當前類和基類的對映資訊

virtual

const

afx_msgmap* getmessagemap() 

const

; /     

// 實際上呼叫了上乙個函式

訊息對映實現的**如下:

[cpp]view plain

copy

print?

#define begin_message_map(theclass, baseclass) /              // 訊息對映開始

ptm_warning_disable /                                    // pragma巨集的處理,無關係

const

afx_msgmap* theclass::getmessagemap() 

const

/      

// 獲得自身和基類的函式對映表 

/                        

// 入口位址

const

afx_msgmap* pascal theclass::getthismessagemap() / 

// 獲得自身函式對映表入口位址

/      // 體的最後乙個元素,標誌結束

}; /  

static

const

afx_msgmap messagemap = /                

// 訊息對映變數(包含基類)

; /  

return

&messagemap; /                                  

// 返回訊息變數 

}/  

ptm_warning_restore                                  // pragma巨集的處理,無關係 

對於訊息對映宣告和實現需要特別說明四點:

a、靜態變數:訊息對映實體陣列afx_msgmap_entry _messageentries ——記錄了當前類的所有訊息對映。每乙個訊息是乙個陣列成員,afx_msgmap_entry 的定義如下: 

[c-sharp]view plain

copy

print?

struct

afx_msgmap_entry  

;  

從上述結構可以看出,每條對映有兩部分的內容:第一部分是關於訊息id的,包括前四個域;第二部分是關於訊息對應的執行函式,包括後兩個域,pfn是乙個指向ccmdtarger成員函式的指標。函式指標的型別定義如下:

typedef void (afx_msg_call ccmdtarget::*afx_pmsg)(void);

當使用一條或者多條訊息對映條目初始化訊息對映陣列時,各種不同型別的訊息函式都被轉換成這樣的型別:不接收引數,也不返回引數的型別。因為所有可以有訊息對映的類都是從ccmdtarge派生的,所以可以實現這樣的轉換。nsig是乙個標識變數,用來標識不同原型的訊息處理函式,每乙個不同原型的訊息處理函式對應乙個不同的nsig。在訊息分發時,mfc內部根據nsig把訊息派發給對應的成員函式處理,實際上,就是根據nsig的值把pfn還原成相應型別的訊息處理函式並執行它。

b、靜態變數:訊息對映資訊變數afx_msgmap messagemap——記錄了當前類和基類的訊息對映實體陣列的入口位址。afx_msgmap結構的定義如下: 

[cpp]view plain

copy

print?

struct

afx_msgmap  

;  

c、訊息對映實體陣列:從begin_message_map和end_message_map巨集定義來看,使用者新增的訊息對映實體會自動加入到_messageentries陣列中,在這裡實現了對訊息對映實體陣列的初始化。

d、虛函式getmessagemap:之所以設定成虛函式,就是為了實現多型,使當前類和基類能夠呼叫正確的訊息對映實體陣列。

通過上面對訊息對映巨集的解析,我可以清晰的了解到三個巨集通過兩個靜態變數把類和基類、把訊息和對應的訊息處理函式關聯起來,這種關聯保證了訊息處理的順序(當前類->基類),保證了訊息能夠正確的找到對應的函式。

講到這裡,總感覺少點什麼。仔細想想這種對映是有啦,但是什麼激發了這樣對映(就像windows程式的視窗過程是有啦,是誰呼叫了這個過程使得每乙個訊息都能夠實現自己的功能、達到想要的目的呢?)?——訊息迴圈。通過訊息迴圈派發訊息到視窗,視窗類的會呼叫有關函式查詢訊息對映實體陣列,首先查詢當前類的再查詢基類的,查詢到後就會呼叫相應的訊息處理函式,如果沒有查到相應的處理函式程式會自動呼叫預設處理函式!

至於mfc具體是怎樣實現訊息的派送的,請參考:這篇文章清晰的闡釋了mfc訊息分發的原理和訊息的部分傳遞過程!

mfc的完整傳遞過程(從訊息迴圈開始到訊息處理函式)有待以後熟悉,畢竟mfc封裝的太好以至於不那麼好理解,同時給予文件的應用程式和基於對話方塊的應用程式也是不一樣。

VC MFC訊息對映機制詳解

windows程式和mfc程式是靠訊息驅動的,他們對於訊息的處理本質上是相同的。只是windows程式對於訊息處理的過程十分清晰明了,mfc程式則掩蓋了訊息處理的過程,以訊息對映的方式呈現在開發者面前,使得開發訊息的處理十分簡單。用多了mfc就想對它的訊息對映機制有乙個本質的了解,下面將對訊息對映做...

VC MFC的訊息對映機制

對映機制的原理 windows 下的程式包括 windows 系統都是基於訊息機制的。mfc訊息對映機制的具體實現方法是 在每個能接收和處理訊息的類中,定義乙個訊息和訊息響應函式的靜態對照表,即訊息對映表 在訊息對映表中,訊息與對應的訊息處理函式指標是成對出現的。某個類能處理的所有訊息及其對應的訊息...

訊息對映機制

大家看的出下面程式的錯誤嗎?include include message.h class myframe public cframewnd myframe afx msg void onexit afx msg void onlbuttondown uint nflags,cpoint point...