TN006: 訊息對應
這張便箋說明 MFC 訊息對應功能。
問題
Microsoft Windows 會使用其郵件的設備的視窗類別中實作虛擬的函式。 受限於大量的相關郵件中,為每個 Windows 訊息提供個別的虛擬函式會建立那麼大的 vtable。
由於系統定義的 Windows 訊息的數目隨時間變化,以及訊息對應的應用程式可以定義自己的 Windows 訊息,因為提供的層級的間接取值,以致於無法破壞現有程式碼介面的變更。
概觀
MFC 提供另一種傳統的 windows 程式中用來處理訊息傳送至視窗的 switch 陳述式。 訊息對應到方法可以使視窗所收到一則訊息時,會自動呼叫適當的方法定義。 此訊息對應機能設計成類似虛擬函式,但有不能具有 C++ 虛擬函式的其他優點。
定義訊息對應
DECLARE_MESSAGE_MAP巨集,會宣告三個類別的成員。
私用陣列的AFX_MSGMAP_ENTRY項目稱為_messageEntries。
受保護AFX_MSGMAP結構稱為messageMap ,指到_messageEntries陣列。
A 受保護的虛擬函式呼叫GetMessageMap所傳回的位址messageMap。
此巨集應該放在使用訊息對應的任何類別的宣告。 依照慣例,是在類別宣告結尾處。 例如:
class CMyWnd : public CMyParentWndClass
{
// my stuff...
protected:
//{{AFX_MSG(CMyWnd)
afx_msg void OnPaint();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
這是在建立新的類別時,即 AppWizard 和類別精靈所產生的格式。 / / {{,/ /}} 括號所需的類別精靈。
使用一組訊息對應項目來展開的巨集來定義訊息對應的資料表。 資料表開頭BEGIN_MESSAGE_MAP巨集呼叫,定義的類別,由這個訊息對應處理和未處理的訊息傳遞到父類別。 在資料表結尾為END_MESSAGE_MAP巨集呼叫。
下列兩個巨集呼叫之間會為每則訊息已經處理過此訊息對應項目。 每一個標準的 Windows 訊息有巨集的表單 ON_WM_MESSAGE_NAME ,會產生該訊息的項目。
標準函式簽章已經解壓縮的每個視窗訊息的參數,並提供型別安全為使用中。 這些簽章可能位在宣告中的檔案 Afxwin.h 的 CWnd。 每一個標記],關鍵字afx_msg的分頁。
注意事項 |
---|
類別精靈要求您使用afx_msg在您的訊息對應處理常式宣告中的關鍵字。 |
這些函式簽章是使用簡單的慣例來衍生而來。 函式的名稱永遠開頭"On"。 這後面會有"WM_"移除 Windows 訊息的名稱,以及以大寫表示每個單字的第一個字母。 參數的順序是wParam後面加上LOWORD(lParam) 然後HIWORD(lParam)。 未使用的參數不會傳遞。 任何由 MFC 類別會包裝的控制代碼會轉換成適當的 MFC 物件的指標。 下列範例顯示如何處理WM_PAINT訊息,而且會導致CMyWnd::OnPaint所要呼叫的函式:
BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
//{{AFX_MSG_MAP(CMyWnd)
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
範圍以外的任何函式或類別定義,都必須定義訊息地圖檯。 不應在 extern"C"區塊中。
注意事項 |
---|
類別精靈將會修改之間進行訊息對應項目 / / {{,/ /}} 註解的方括號。 |
使用者定義的 Windows 訊息
使用者自訂的訊息可能包含在訊息對應,使用ON_MESSAGE巨集。 此巨集可接受的訊息數字和表單的方法:
// inside the class declaration
afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
#define WM_MYMESSAGE (WM_USER + 100)
BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
ON_MESSAGE(WM_MYMESSAGE, OnMyMessage)
END_MESSAGE_MAP()
在這個範例中,我們可以建立自訂的郵件,其中包含衍生自標準的 Windows 訊息識別碼的處理常式WM_USER基底的使用者自訂的訊息。 下列範例會示範如何呼叫這個處理常式:
CWnd* pWnd = ...;
pWnd->SendMessage(WM_MYMESSAGE);
使用這種方法的使用者定義訊息的範圍必須介於WM_USER到 0x7fff。
注意事項 |
---|
類別精靈不支援輸入ON_MESSAGE和類別精靈使用者介面的處理常式。您必須手動將其輸入從 Visual C++ 編輯器。類別精靈將會剖析這些項目,並可讓您瀏覽它們] 就像任何其他的訊息對應項目。 |
已註冊的 Windows 訊息
RegisterWindowMessage 函式用來定義新的視窗訊息,保證是唯一在整個系統。 巨集ON_REGISTERED_MESSAGE用來處理這些訊息。 此巨集可接受的名稱, UINT NEAR變數,包含已註冊的 windows 訊息識別碼。 例如
class CMyWnd : public CMyParentWndClass
{
public:
CMyWnd();
//{{AFX_MSG(CMyWnd)
afx_msg LRESULT OnFind(WPARAM wParam, LPARAM lParam);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
static UINT NEAR WM_FIND = RegisterWindowMessage("COMMDLG_FIND");
BEGIN_MESSAGE_MAP(CMyWnd, CMyParentWndClass)
//{{AFX_MSG_MAP(CMyWnd)
ON_REGISTERED_MESSAGE(WM_FIND, OnFind)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
已註冊的 Windows 訊息 ID 變數 (在本例中為 WM_FIND) 必須是NEAR變數是由於方式ON_REGISTERED_MESSAGE的實作。
使用這種方法的使用者自訂訊息的範圍將會在 0xC000 到 0xFFFF 的範圍內。
注意事項 |
---|
類別精靈不支援輸入ON_REGISTERED_MESSAGE和類別精靈使用者介面的處理常式。您必須手動將其輸入文字編輯器] 中。類別精靈將會剖析這些項目,並可讓您瀏覽它們] 就像任何其他的訊息對應項目。 |
命令訊息
功能表和快速鍵的命令訊息會以與訊息對應處理ON_COMMAND巨集。 命令識別碼及一種方法,可接受此巨集。 只有特定WM_COMMAND郵件,其中包含wParam等於指定的命令 ID 由訊息對應項目中指定的方法。 命令處理常式成員函式不採用參數,並傳回void。 巨集都採用下列格式:
ON_COMMAND(id, memberFxn)
命令更新訊息會經由相同的機制,但使用ON_UPDATE_COMMAND_UI巨集改。 命令更新處理常式成員函式採用單一參數,變數的指標, CCmdUI 物件,並傳回void。 巨集有格式
ON_UPDATE_COMMAND_UI(id, memberFxn)
進階的使用者可以使用ON_COMMAND_EX巨集],也就是命令訊息處理常式的延伸的形式。 巨集提供的超集ON_COMMAND功能。 擴充的命令處理常式成員函式都接受一個參數, UINT所包含的命令 ID,並傳回BOOL。 傳回值應該是TRUE ,表示已處理命令。 否則路由將會繼續其他的命令目標物件。
這些表單的範例:
內線 Resource.h (通常是由 Visual C++)
#define ID_MYCMD 100 #define ID_COMPLEX 101
類別宣告中
afx_msg void OnMyCommand(); afx_msg void OnUpdateMyCommand(CCmdUI* pCmdUI); afx_msg BOOL OnComplexCommand(UINT nID);
在訊息對應定義
ON_COMMAND(ID_MYCMD, OnMyCommand) ON_UPDATE_COMMAND_UI(ID_MYCMD, OnUpdateMyCommand) ON_COMMAND_EX(ID_MYCMD, OnComplexCommand)
在實作檔案
void CMyClass::OnMyCommand() { // handle the command } void CMyClass::OnUpdateMyCommand(CCmdUI* pCmdUI) { // set the UI state with pCmdUI } BOOL CMyClass::OnComplexCommand(UINT nID) { // handle the command return TRUE; }
進階的使用者可以使用單一命令處理常式處理一系列的命令: ON_COMMAND_RANGE 或ON_COMMAND_RANGE_EX。 請參閱產品說明文件,如需有關這些巨集。
注意事項 |
---|
類別精靈支援建立ON_COMMAND和ON_UPDATE_COMMAND_UI處理常式,但它不支援建立ON_COMMAND_EX或ON_COMMAND_RANGE處理常式。然而,類別精靈將會剖析,並可讓您瀏覽所有四個命令處理常式的版本。 |
控制項告知訊息
從視窗的子控制項有額外的元他們的訊息中的資訊傳送的訊息對應項目: 控制項的 id。 只有當下列情況皆成立,就會呼叫訊息對應項目中所指定的訊息處理常式:
控制項告知程式碼 (高位文字lParam),例如 BN_CLICKED,符合的訊息對應項目中所指定的告知程式碼。
控制項 ID (wParam) 比對的訊息對應項目中所指定的控制項 ID。
自訂控制項告知訊息可能會使用ON_CONTROL巨集來定義自訂通知程式碼的訊息對應項目。 此巨集有格式
ON_CONTROL(wNotificationCode, id, memberFxn)
進階的使用方式ON_CONTROL_RANGE可以用來處理特定的控制項告知從相同的處理常式之控制項的範圍。
注意事項 |
---|
類別精靈不支援建立ON_CONTROL或ON_CONTROL_RANGE在使用者介面的處理常式。您必須手動將其輸入使用文字編輯器。類別精靈將會剖析這些項目,並可讓您瀏覽它們] 就像任何其他訊息對應項目。 |
使用功能更強大的 Windows 通用控制項 WM_NOTIFY 的複雜控制項告知。 這個版本的 MFC 具有直接支援這個新訊息使用ON_NOTIFY和ON_NOTIFY_RANGE巨集。 請參閱產品說明文件,如需有關這些巨集。