在 MFC 開發中,消息映射是連接 Windows 作業系統與應用程式邏輯的核心橋樑。雖然 ClassWizard 等工具讓我們能輕鬆添加訊息處理函式,但深入理解其底層實作原理,不僅有助於排查疑難雜症,更能讓我們在需要時靈活擴展框架功能。本文將從 Windows 訊息機制基礎出發,層層剖析 MFC 如何封裝並實現高效的訊息映射與分發。
Windows 程式的輸入皆以「訊息」形式傳遞。依傳遞路徑可分為:
GetMessage/DispatchMessage 迴圈送達視窗程序。依來源分類則有系統訊息(0 ~ WM_USER-1、0x8000 ~ 0xBFFF)與應用程式自訂訊息(WM_USER ~ 0x7FFF、0xC000 ~ 0xFFFF)。後者若需跨程式通訊,應用 RegisterWindowMessage 保證 ID 唯一性。
每筆訊息以 MSG 結構描述:視窗句柄、訊息 ID、兩個 32 位參數、時間戳記、滑鼠座標。視窗程序原型為:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
應用程式在視窗程式內以 switch-case 判別訊息並處理。主迴圈典型寫法:
while (GetMessage(&msg, NULL, 0, 0)) {
if (!TranslateAccelerator(...) && !IsDialogMessage(...)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
MFC 最大的貢獻在於:所有 MFC 視窗共用同一視窗程序(AfxWndProc),開發者無需自行編寫龐大的 switch-case,而是透過「訊息映射」機制,將訊息 ID 與類別成員函式建立對應關係。
CCmdTarget 派生物件尋找處理器。在類別宣告(.h)中:
//{{AFX_MSG(CMyClass)
afx_msg void OnMyMessage();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
在類別實作(.cpp)中:
BEGIN_MESSAGE_MAP(CMyClass, CBaseClass)
ON_MESSAGE(WM_MYMSG, OnMyMessage)
END_MESSAGE_MAP()
void CMyClass::OnMyMessage() { ... }
DECLARE_MESSAGE_MAP 與 IMPLEMENT_MESSAGE_MAP(展開為 BEGIN_MESSAGE_MAP/END_MESSAGE_MAP)是核心巨集,下一篇將深入剖析其內部實作與訊息分發流程。