SysMac.h)
#define BEGIN_MESSAGE_MAP \
virtual void __fastcall Dispatch(void *Message) \
{ \
switch (((PMessage)Message)->Msg) \
{
#define VCL_MESSAGE_HANDLER(msg, type, meth) \
case msg: \
meth(*((type *)Message)); \
break;
#if !defined(USING_ATL) && !defined(USING_ATLVCL) && !defined(INC_ATL_HEADERS)
#define MESSAGE_HANDLER VCL_MESSAGE_HANDLER
#endif
#define END_MESSAGE_MAP(base) \
default: \
base::Dispatch(Message); \
break; \
} \
}
原始碼:
BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(WM_PAINT, TMessage, OnPaint)
END_MESSAGE_MAP(TForm1)
預處理後展開為:
virtual void __fastcall Dispatch(void *Message)
{
switch (((PMessage)Message)->Msg)
{
case WM_PAINT:
OnPaint(*((TMessage *)Message));
break;
default:
TForm1::Dispatch(Message); // 呼叫父類 Dispatch
break;
}
}
Dispatch 虛擬方法鏈TObject (VCL 根基類)。default: 分支呼叫 BaseClass::Dispatch,形成繼承鏈查找。TObject::Dispatch → DefaultHandler (空實作) → DefWindowProc (透過 MainWndProc)。MESSAGE_HANDLER 宏,與 VCL 衝突。VCL_MESSAGE_HANDLER 專用名稱。MESSAGE_HANDLER 映射為 VCL_MESSAGE_HANDLER。VCL_MESSAGE_HANDLER 避免衝突。type 參數指定訊息結構 (TMessage, TWMMouse, TWMKey 等)。((type *)Message) 強制轉型,編譯期無法檢查,開發者需確保類型匹配。| 機制 | 實現層級 | 效能 | 適用場景 |
|---|---|---|---|
| 事件 (OnClick 等) | 最高層 (元件) | 映射表查找 | 標準 UI 互動 |
| BEGIN_MESSAGE_MAP | 中層 (類別) | switch 分派 O(n) | 無事件對應的訊息、自訂訊息 |
| 重寫 WndProc | 底層 (視窗程序) | 直接分派 O(1) | 高頻訊息、前置過濾、完全控制 |
| TApplication.OnMessage | 應用層 (全域) | 最早攔截 | 全域熱鍵、訊息日誌、跨表單協調 |
protected 區,處理函數放在 private。END_MESSAGE_MAP(TForm) 中正確指定。void __fastcall Handler(TMessage &Msg) 或專用結構引用。Msg.Result 設置返回值,影響後續處理 (如 WM_NCHITTEST)。Dispatch 設置斷點,觀察 Message->Msg 確認訊息到達。OutputDebugString(Format("Dispatch: %x", [Msg.Msg])) 追蹤流向。
理解宏展開原理,就能從「會用」進階到「懂原理」,在疑難雜症時能精準定位訊息分派鏈路。