透過巨集定義了解MFC的訊息響應機制

2021-06-02 00:28:06 字數 3218 閱讀 7724

訊息系統是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 表示的是訊息響應函式,只是乙個標記...