CWnd或者派生類的對(duì)象調(diào)用OnWndMsg搜索本對(duì)象或者基類的消息映射數(shù)組,尋找當(dāng)前消息的消息處理函數(shù)。如果當(dāng)前對(duì)象或者基類處理了當(dāng)前消息,則必定在其中一個(gè)類的消息映射數(shù)組中匹配到當(dāng)前消息的處理函數(shù)。
消息匹配是一個(gè)比較耗時(shí)的任務(wù),為了提高效率,MFC設(shè)計(jì)了一個(gè)消息緩沖池,把要處理的消息和匹配到的消息映射條目(條目包含了消息處理函數(shù)的地址)以及進(jìn)行消息處理的當(dāng)前類等信息構(gòu)成一條緩沖信息,放到緩沖池中。如果以后又有同樣的消息需要同一個(gè)類處理,則直接從緩沖池查找到對(duì)應(yīng)的消息映射條目就可以了。
MFC用哈希查找來(lái)查詢消息映射緩沖池。消息緩沖池相當(dāng)于一個(gè)哈希表,它是應(yīng)用程序的一個(gè)全局變量,可以放512條最新用到的消息映射條目的緩沖信息,每一條緩沖信息是哈希表的一個(gè)入口。
采用AFX_MSG_CACHE結(jié)構(gòu)描述每條緩沖信息,其定義如下:
struct AFX_MSG_CACHE
{
UINT nMsg;
const AFX_MSGMAP_ENTRY* lpEntry;
const AFX_MSGMAP* pMessageMap;
};
nMsg存放消息ID,每個(gè)哈希表入口有不同的nMsg。
lpEnty存放和消息ID匹配的消息映射條目的地址,它可能是this所指對(duì)象的類的映射條目,也可能是這個(gè)類的某個(gè)基類的映射條目,也可能是空。
pMessageMap存放消息處理函數(shù)匹配成功時(shí)進(jìn)行消息處理的當(dāng)前類(this所指對(duì)象的類)的靜態(tài)成員變量messageMap的地址,它唯一的標(biāo)識(shí)了一個(gè)類(每個(gè)類的messageMap變量都不一樣)。
this所指對(duì)象是一個(gè)CWnd或其派生類的實(shí)例,是正在處理消息的MFC窗口對(duì)象。
哈希查找:使用消息ID的值作為關(guān)鍵值進(jìn)行哈希查找,如果成功,即可從lpEntry獲得消息映射條目的地址,從而得到消息處理函數(shù)及其原型。
如何判斷是否成功匹配呢?有兩條標(biāo)準(zhǔn):
第一,當(dāng)前要處理的消息message在哈希表(緩沖池)中有入口;第二,當(dāng)前窗口對(duì)象(this所指對(duì)象)的類的靜態(tài)變量messageMap的地址應(yīng)該等于本條緩沖信息的pMessagMap。MFC通過(guò)虛擬函數(shù)GetMessagMap得到messageMap的地址。
如果在消息緩沖池中沒(méi)有找到匹配,則搜索當(dāng)前對(duì)象的消息映射數(shù)組,看是否有合適的消息處理函數(shù)。
如果匹配到一個(gè)消息處理函數(shù),則把匹配結(jié)果加入到消息緩沖池中,即填寫(xiě)該條消息對(duì)應(yīng)的哈希表入口:
nMsg=message;
pMessageMap=this->GetMessageMap;
lpEntry=查找結(jié)果
然后,調(diào)用匹配到的消息處理函數(shù)。否則(沒(méi)有找到),使用_GetBaseMessageMap得到基類的消息映射數(shù)組,查找和匹配;直到匹配成功或搜尋了所有的基類(到CCmdTarget)為止。
如果最后沒(méi)有找到,則也把該條消息的匹配結(jié)果加入到緩沖池中。和匹配成功不同的是:指定lpEntry為空。這樣OnWndMsg返回,把控制權(quán)返還給AfxCallWndProc函數(shù),AfxCallWndProc將繼續(xù)調(diào)用DefWndProc進(jìn)行缺省處理。
消息映射數(shù)組的搜索在CCmdTarget::OnCmdMsg函數(shù)中也用到了,而且算法相同。為了提高速度,MFC把和消息映射數(shù)組條目逐一比較、匹配的函數(shù)AfxFindMessageEntry用匯編書(shū)寫(xiě)。
const AFX_MSGMAP_ENTRY* AFXAPI
AfxFindMessageEntry(const AFX_MSGMAP_ENTRY* lpEntry,
UINT nMsg, UINT nCode, UINT nID)
第一個(gè)參數(shù)是要搜索的映射數(shù)組的入口;第二個(gè)參數(shù)是Windows消息標(biāo)識(shí);第三個(gè)參數(shù)是控制通知消息標(biāo)識(shí);第四個(gè)參數(shù)是命令消息標(biāo)識(shí)。
對(duì)Windows消息來(lái)說(shuō),nMsg是每條消息不同的,nID和nCode為0。
對(duì)命令消息來(lái)說(shuō),nMsg固定為WM_COMMAND,nID是每條消息不同,nCode都是CN_COMMAND(定義為0)。
對(duì)控制通知消息來(lái)說(shuō),nMsg固定為WM_COMMAND或者WM_NOTIFY,nID和nCode是每條消息不同。
對(duì)于Register消息,nMsg指定為0XC000,nID和nCode為0。在使用函數(shù)AfxFindMessageEntry得到匹配結(jié)果之后,還必須判斷nSig是否等于message,只有相等才調(diào)用對(duì)應(yīng)的消息處理函數(shù)。