本文轉(zhuǎn)自:
http://blog.csdn.net/welcome_ck/article/details/236259何謂消息、消息處理函數(shù)、消息映射?
消息簡(jiǎn)單的說就是指通過輸入設(shè)備向程序發(fā)出指令要執(zhí)行某個(gè)操作。具體的某個(gè)操作是你的一系列代碼。稱為消息處理函數(shù)。在SDK中消息其實(shí)非常容易理解,當(dāng)窗口建立后便會(huì)有一個(gè)函數(shù)(窗口處理函數(shù))開始執(zhí)行一個(gè)消息循環(huán),我們還可以清楚的看到消息處理的脈絡(luò)。一個(gè)switch case語(yǔ)句就可以搞定,消息循環(huán)直到遇到WM_QUIT消息才會(huì)結(jié)束,其余的消息均被攔截后調(diào)用相應(yīng)的處理函數(shù)。但在封裝了API的MFC中,消息似乎變的有些復(fù)雜了,我們看不到熟悉的switch case語(yǔ)句了,取而代之的是一個(gè)叫消息映射的東西。為什么MFC要引入消息映射機(jī)制,你可以想象一下,在現(xiàn)在的程序開發(fā)活動(dòng)中,你的一個(gè)程序是否擁有多個(gè)窗體,主窗口就算只有一個(gè),那菜單、工具條、控件這些都是子窗口,那我們需要寫多少個(gè)switch case,并且還要為每個(gè)消息分配一個(gè)消息處理函數(shù),這樣做是多么的復(fù)雜呀。因此MFC采用了一種新的機(jī)制。利用一個(gè)數(shù)組,將窗口消息和相對(duì)應(yīng)的消息處理函數(shù)進(jìn)行映射,你可以理解成這是一個(gè)表。這種機(jī)制就是消息映射。這張表在窗口基類CWnd定義,派生類的消息映射表如果你沒有動(dòng)作它是空的,也就是說如果你不手工的增加消息處理函數(shù),則當(dāng)派生窗口接受一個(gè)消息時(shí)會(huì)執(zhí)行父類的消息處理函數(shù)。這樣做顯然是高效的。
MFC提供的消息結(jié)構(gòu)
同時(shí)MFC定義了下面的兩個(gè)主要結(jié)構(gòu):
AFX_MSGMAP_ENTRY
struct AFX_MSGMAP_ENTRY{
UINT nMessage; // Windows消息的ID號(hào)
UINT nCode; // 控制消息的通知
UINT nID; // Windows控制消息的ID
UINT nLastID; //表示是一個(gè)指定范圍的消息被映射的范圍
UINT nSig; //表示消息的動(dòng)作標(biāo)識(shí)
AFX_PMSG pfn; // 指向消息處理函數(shù)的指針
};
AFX_MSGMAP
struct AFX_MSGMAP{
#ifdef _AFXDLL
const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
#else
const AFX_MSGMAP* pBaseMap;
#endif
const AFX_MSGMAP_ENTRY* lpEntries;
};
///AFX_MSGMAP可以得到基類的消息映射入口地址和得到本身的消息映射入口地址。
MFC下一個(gè)消息的處理過程是一般是這樣的。
1、_AfxCbtFilterHook截獲消息(這是一個(gè)鉤子函數(shù))
2、_AfxCbtFilterHook把窗口過程設(shè)定為AfxWndProc。
3、函數(shù)AfxWndProc接收Windows操作系統(tǒng)發(fā)送的消息。
4、函數(shù)AfxWndProc調(diào)用函數(shù)AfxCallWndProc進(jìn)行消息處理。
5、函數(shù)AfxCallWndProc調(diào)用CWnd類的方法WindowProc進(jìn)行消息處理。
如何添加自己的消息?
我們已經(jīng)了解了WINDOW的消息機(jī)制,如何加入我們自己的消息呢?好我們來看
一個(gè)標(biāo)準(zhǔn)的消息處理程序是這個(gè)樣子的
在 CWnd 類中預(yù)定義了標(biāo)準(zhǔn) Windows 消息 (WM_XXXX WM是WINDOW MESSAGE的縮寫) 的默認(rèn)處理程序。類庫(kù)基于消息名命名這些處理程序。例如,WM_PAINT 消息的處理程序在 CWnd 中被聲明為:
afx_msg void OnPaint();
afx_msg 關(guān)鍵字通過使這些處理程序區(qū)別于其他 CWnd 成員函數(shù)來表明 C++ virtual 關(guān)鍵字的作用。但是請(qǐng)注意,這些函數(shù)實(shí)際上并不是虛擬的,而是通過消息映射實(shí)現(xiàn)的。我們?cè)诒疚牡囊婚_始便說明了為什么要這樣做。
所有能夠進(jìn)行消息處理的類都是基于CCmdTarget類的,也就是說CCmdTarget類是所有可以進(jìn)行消息處理類的父類。CCmdTarget類是MFC處理命令消息的基礎(chǔ)和核心。
若要重寫基類中定義的處理程序,只需在派生類中定義一個(gè)具有相同原型的函數(shù),并創(chuàng)建此處理程序的消息映射項(xiàng)。我們通過ClassWizard可以建立大多數(shù)窗口消息或自定義的消息,通過ClassWizard可以自動(dòng)建立消息映射,和消息處理函數(shù)的框架,我們只需要把我們要做的事情填空,添加你要做的事情到處理函數(shù)。這個(gè)非常簡(jiǎn)單,就不細(xì)說了。但是也許我們需要添加一些ClassWizard不支持的窗口消息或自定義消息,那么就需要我們親自動(dòng)手建立消息映射和消息處理的框架,通常步驟如下:
第一步:定義消息。Microsoft推薦用戶自定義消息至少是WM_USER+100,因?yàn)楹芏嘈驴丶惨褂肳M_USER消息。
#define WM_MYMESSAGE (WM_USER + 100)
第二步:實(shí)現(xiàn)消息處理函數(shù)。該函數(shù)使用WPRAM和LPARAM參數(shù)并返回LPESULT。
LPESULT CMainFrame::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
// TODO: 處理用戶自定義消息,填空就是要填到這里。
return 0;
}
第三步:在類頭文件的AFX_MSG塊中說明消息處理函數(shù):
// {{AFX_MSG(CMainFrame)
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
第四步:在用戶類的消息塊中,使用ON_MESSAGE宏指令將消息映射到消息處理函數(shù)中。
ON_MESSAGE( WM_MYMESSAGE, OnMyMessage )
可以看出,用戶自定義的消息和我們通過ClassWizard添加的消息一樣,都是利用了ON_MESSAGE宏,建立的消息映射。
其實(shí)消息類別可以分成多種,上面說的只是其中之一。有三種主要的消息類別:(以下部分摘自MSDN)
1、Windows 消息
此類消息主要包括以前綴 WM_ 開頭的消息,WM_COMMAND 除外。Windows 消息由窗口和視圖處理。此類消息往往帶有用于確定如何處理消息的參數(shù)。
2、控件通知
此類消息包括從控件和其他子窗口發(fā)送到其父窗口的 WM_COMMAND 通知消息。例如,當(dāng)用戶在編輯控件 (Edit Control) 中執(zhí)行可能更改文本的操作后,該編輯控件 (Edit Control) 將向其父級(jí)發(fā)送包含 EN_CHANGE 控件通知代碼的 WM_COMMAND 消息。該消息的窗口處理程序以某種適當(dāng)?shù)姆绞巾憫?yīng)此通知消息,例如在控件中檢索該文本。
框架像傳送其他 WM_ 消息一樣傳送控件通知消息。但是有一個(gè)例外的情況,即當(dāng)用戶單擊按鈕時(shí)由按鈕發(fā)送的 BN_CLICKED 控件通知消息。該消息被作為命令消息特別處理,并像其他命令一樣傳送。
3、命令消息
此類消息包括用戶界面對(duì)象(菜單、工具欄按鈕和快捷鍵)發(fā)出的 WM_COMMAND 通知消息。框架處理命令的方式與處理其他消息不同,可以使用更多種類的對(duì)象處理命令。
Windows 消息和控件通知消息由窗口來處理(窗口是從 CWnd 類派生的類的對(duì)象)。包括 CFrameWnd、CMDIFrameWnd、CMDIChildWnd、CView、CDialog 以及從這些基類派生的您自己的類。這些對(duì)象封裝了 HWND——Windows 窗口的句柄。
命令消息可以由范圍更廣的對(duì)象(文檔、文檔模板以及應(yīng)用程序?qū)ο蟊旧恚┨幚恚粌H僅由窗口和視圖處理。當(dāng)某一命令直接影響到某個(gè)特定對(duì)象時(shí),應(yīng)當(dāng)讓該對(duì)象處理此命令。例如,“文件”菜單中的“打開”命令在邏輯上與應(yīng)用程序相關(guān)聯(lián):該應(yīng)用程序接收到此命令時(shí)會(huì)打開指定的文檔。因此“打開”命令的處理程序是應(yīng)用程序類的成員函數(shù)。
命令消息我們比較常見的便是菜單項(xiàng)和工具條了,大家可以看到他的消息映射宏和窗口消息不太一樣,一般的形式是這樣的
ON_COMMAND(id,memberFxn)
第一個(gè)參數(shù)是命令I(lǐng)D,一個(gè)ID號(hào)對(duì)應(yīng)一個(gè)消息處理,當(dāng)然你可以讓多個(gè)ID共用一個(gè)處理函數(shù)。常見的應(yīng)用例如:菜單項(xiàng)打開文檔的ID和工具條按鈕打開文檔的ID同時(shí)使用一個(gè)處理函數(shù),或者直接將它們的ID設(shè)成相同的。
還有一種消息叫通知消息。例如樹型控件的等一些復(fù)雜的控件在單擊后需要傳遞更多的信息,例如光標(biāo)的位置和當(dāng)前項(xiàng)的一個(gè)結(jié)構(gòu),所以MFC為控件的每個(gè)通知消息也定義了一個(gè)宏,它長(zhǎng)成了這個(gè)樣子:
ON_CONTROL(EN_CHANGE,id,memberFxn)
還有很多種消息存在于MFC,宏定義有區(qū)別,大家可以觸類旁通。
窗口消息有上百個(gè)。你可以從MSDN上查到WM_開頭的,或者查看CWnd的成員函數(shù),會(huì)給你列出很多,別忘了還有很多非窗口消息
其他鏈接:
http://blog.csdn.net/liufei_learning/article/details/5903287 http://www.cnblogs.com/lantionzy/archive/2009/10/10/1580428.html