訊息系統是mfc的重要組成部分。mfc的訊息響應機制並不複雜,而且mfc的開發環境 visual studio來供了非常好的自動化工具,自動生成**。mfc也定義了豐富的巨集來簡化訊息響應的**。這使得很多初學者都能快速開發出基於訊息響應機制的應用程式。然後也正是這些帶來方便的巨集,使很多人摸不著頭腦。當不小心的**操作使自動化工具不好用的時候,看著那一組更像是一堆的巨集,很多人只好一頭霧水。
要想真正了解mfc的訊息機制,必需弄清楚這些巨集。好在原始碼面前無秘密,我們將從這些巨集的原始碼著手,逐步分析、了解、並學習mfc的訊息響應及對映機制。
第乙個巨集:declare_message_map()
作用:為乙個訊息響應類宣告必需的成員變數和成員函式。
我們在視窗類、應用程式類、文件類、檢視類、以及這些類的子類的定義中,都能看到declare_message_map()巨集,通常被自動化工具宣告在類的最後部分,如: //
生成的訊息對映函式
protected
:declare_message_map()
};declare_message_map()
巨集定義如下(在dll型別和windows程式型別下,定義會有不同,本文只分析非dll型別,下同):
#define
declare_message_map()
private
: static
const
afx_msgmap_entry _messageentries;
protected
: static
const
afx_msgmap messagemap;
virtual
const
afx_msgmap
*getmessagemap()
const
;
可以看到,巨集declare_message_map()定義了兩個靜態成員變數,並過載了乙個虛函式。下面分析一下這三個成員:
_messageentries被定義為乙個afx_msgmap_entry型別的陣列。結構體afx_msgmap_entry的定義如下:
struct
afx_msgmap_entry;
通過檢視源**中的注釋,可以看出afx_msgmap_entry定義了乙個訊息入口,或者說定義了乙個訊息到函式的對映關係。nmessage和ncode確定一條訊息的內容,nid和nlastid確定了一條訊息的**,而nsig和pfn確定了訊息的響應函式和呼叫方式。
通過對訊息響應過程的原始碼分析可知,nsig事實上是一系列編碼,每一種編碼代表一種響應函式的型別,包括返回值、引數資訊等。在響應訊息的時候,將把pfn指向的函式指標強制型別轉換為nsig代表的函式型別,然後再呼叫。
pfn的型別afx_pmsg定義如下,意為ccmdtarget的成員函式:
typedef
void (afx_msg_call ccmdtarget::*afx_pmsg)(void);
由此我們可以得出:靜態成員_messageentries為是乙個訊息到函式的對映表,或叫訊息入口表。通過查詢此表,可以找到訊息的響應函式。
declare_message_map()巨集宣告的另乙個靜態成員變數messagemap被定義為afx_msgmap型別。afx_msgmap定義如下:
struct
afx_msgmap;
struct
afx_msgmap;
可見結構體afx_msgmap中定義了兩個指標,pbasemap指向另乙個afx_msgmap,lpentries指向乙個訊息入口表。可以推想,在響應訊息時,一定是在lpentries指向的訊息入口表中尋找響應函式,也可能會在pbasemap指向的結構體中做同樣的響應函式尋找操作。
至於declare_message_map()巨集過載的虛函式getmessagemap,可以猜測只是用來返回成員messagemap的位址而已。因為getmessagemap是虛函式,所以系統只要通過呼叫訊息響應類的基類ccmdtarget類的getmessagemap函式,便可以找到最後一級子類的訊息對映資訊。我們將在接下來對其它幾個巨集的分析中得到相同的結論。
第二個重要的巨集:begin_message_map
作用:定義declare_message_map巨集宣告的靜態變數。
begin_message_map定義的源**如下:
#define
begin_message_map(theclass, baseclass)
const
afx_msgmap
*theclass::getmessagemap()
const
afx_comdat
const
afx_msgmap theclass::messagemap
=
; afx_comdat
const
afx_msgmap_entry theclass::_messageentries
=
然後初始化了當前類的成員變數messagemap。messagemap的pbasemap指標指向其父類的messagemap成員,lpentries指標指向當前類的_messageentries陣列的首位址。
afx_comdat
const
afx_msgmap theclass::messagemap
= ;
最後,定義了_messageentries陣列初始化**的開始部分。
afx_comdat
const
afx_msgmap_entry theclass::_messageentries
=
};
在declare_message_map和end_message_map之間還有一些巨集,如on_command、on_wm_create等,這些巨集最終都會被生成一條afx_msgmap_entry結構體資料,並成為_messageentries訊息對映表資料的乙個元素。我們以常見的on_command巨集為例。on_command巨集的源**為:
#define
on_command(id, memberfxn)
, 通過以上分析,我們可以得到乙個鍊錶式的資料結構,子類的messagemap成員為鍊錶的頭節點。鍊錶的每個節點都包含乙個訊息入口表。mfc的訊息系統的標準備訊息處理函式ccmdtarget::oncmdmsg正是通過這樣乙個鍊錶查詢到訊息的響應函式,並呼叫該函式來響應訊息。
MFC 訊息對映表 及 相關巨集定義
mfc 中通過通過不同於sdk的switch的方法來處理windows訊息,由訊息對映表 message map 和虛函式多型來處理指定的窗體訊息 宣告乙個訊息對映表 message map 在能處理訊息的類中中新增巨集 declare message map 注 深入淺出 mfc中有更詳盡系統的概...
MFC 訊息對映表 及 相關巨集定義
mfc相關技術說明 可參閱msdn mfc tno 5 mfc 中通過通過不同於sdk的switch的方法來處理windows訊息,由訊息對映表 message map 和虛函式多型來處理指定的窗體訊息 宣告乙個訊息對映表 message map 在能處理訊息的類中中新增巨集 declare mes...
在MFC中新增自定義訊息響應
第 一 在標頭檔案定義訊息字元,n必須大於0,因為wm user以前的用於windows內部定義 define wm my message wm user n 第二 在要響應訊息的窗體的標頭檔案新增 afx msg void onmymessage afx msg 表示的是訊息響應函式,只是乙個標記...