從 VC++ 轉向 C# 開發時,視窗訊息處理機制的差異常令人困惑。VC++ 依賴 PreTranslateMessage 與 WindowProc 處理訊息迴路,而 C# 採用事件導向模型,並提供 Control.WndProc 覆寫作為底層攔截點。本文對比兩者架構與用法。
BOOL CMyDialog::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->hwnd == GetSafeHwnd())
{
if (pMsg->message == WM_MOUSEMOVE)
{
m_tooltip.RelayEvent(pMsg);
}
// 其他預處理...
}
return CDialog::PreTranslateMessage(pMsg);
}
// 訊息對應表
BEGIN_MESSAGE_MAP(CMyDialog, CDialog)
ON_WM_PAINT()
ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()
PreTranslateMessage:在訊息分派給視窗程序前攔截,常用於工具提示、快速鍵、輸入法處理。WindowProc (透過訊息對應表) :處理標準視窗訊息。大多數情況直接訂閱事件:
this.button1.Click += Button1_Click;
this.KeyDown += Form1_KeyDown;
需攔截未封裝為事件的訊息 (如 WM_HOTKEY, WM_DEVICECHANGE) 時:
protected override void WndProc(ref Message m)
{
const int WM_HOTKEY = 0x0312;
if (m.Msg == WM_HOTKEY)
{
// 處理熱鍵
return; // 已處理,不再傳遞
}
base.WndProc(ref m); // 交由基類處理其他訊息
}
public class MyFilter : IMessageFilter
{
public bool PreFilterMessage(ref Message m)
{
// 返回 true 表示已處理,過濾掉該訊息
return false;
}
}
// 註冊
Application.AddMessageFilter(new MyFilter());
| 特性 | VC++ (MFC) | C# (WinForms) |
|---|---|---|
| 預處理入口 | PreTranslateMessage | IMessageFilter.PreFilterMessage |
| 視窗程序 | WindowProc + 訊息對應表 | Control.WndProc 覆寫 |
| 常用訊息封裝 | 需自行處理 | 事件模型 |
| 訊息結構 | MSG (含 hwnd, message, wParam, lParam) | Message 結構體 |
WndProc 處理 WM_HOTKEY, WM_DEVICECHANGE。IMessageFilter 並 Application.AddMessageFilter。BeginInvoke 或 Task.Run。C# 將訊息迴路封裝為事件與虛擬方法,降低開發複雜度。理解 IMessageFilter、WndProc、事件三層機制,能靈活應對從簡單 UI 互動到底層系統訊息的各種需求。