Windows 是訊息驅動系統。C++Builder VCL 封裝大多數常用訊息為事件,但處理未封裝訊息、自訂訊息、子類別化視窗程序時,理解底層機制至關重要。本文從訊息循環切入,解析 VCL 分發流程與實戰應用。
AttachThreadInput 可連接)MSG:hwnd, message, wParam, lParam, time, ptMSG msg;
while (GetMessage(&msg, NULL, 0, 0)) { // 0 表示所有視窗
TranslateMessage(&msg); // 虛擬鍵 → 字元訊息 (WM_KEYDOWN → WM_CHAR)
DispatchMessage(&msg); // 分發至視窗程序 (WindowProc)
}
// 簡化版
void TApplication::Run() {
MSG msg;
while (GetMessage(&msg, 0, 0, 0)) {
if (!PreProcessMessage(&msg)) { // VCL 內部預處理 (快捷鍵、提示等)
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
WindowProc 方法 (虛擬函數)TControl::WndProc 為核心分發點MESSAGE_MAP) 將訊息導向特定處理函數// .h
class TMyControl : public TCustomControl {
protected:
void __fastcall WMMouseEnter(TMessage& Msg);
void __fastcall WMCustomMsg(TMessage& Msg);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_MOUSEENTER, TMessage, WMMouseEnter)
MESSAGE_HANDLER(WM_USER + 100, TMessage, WMCustomMsg)
END_MESSAGE_MAP(TControl)
};
OnClick、OnCommand 事件OnItemClick, OnCustomDraw)Paint() 虛擬函數Paint() 而非處理 WM_PAINTconst UINT WM_MY_CUSTOM = WM_USER + 100; // WM_USER (0x0400) 以上為應用程式自用
// 或 RegisterWindowMessage("MyApp_CustomMsg") 取得全域唯一值
| API | 特性 | 用途 |
|---|---|---|
SendMessage | 同步,直接呼叫視窗程序,等待返回 | 需立即結果、跨執行緒同步 |
PostMessage | 非同步,放入佇列,立即返回 | 非阻塞通知、避免死結 |
SendMessageTimeout | 同步帶超時 | 防止目標視窗無回應卡死 |
void __fastcall TMyForm::WMCustomMsg(TMessage& Msg) {
int param1 = Msg.WParam;
int param2 = Msg.LParam;
// 處理邏輯
Msg.Result = 1; // 回傳值
}
// 攔獲現有視窗 (如 Edit 控制項) 的訊息
WNDPROC oldProc = (WNDPROC)SetWindowLongPtr(edit->Handle, GWLP_WNDPROC, (LONG_PTR)NewWndProc);
// 新視窗程序
LRESULT CALLBACK NewWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
if (msg == WM_CHAR) {
// 攔截字元輸入
if (wParam == VK_RETURN) { /* 處理 Enter */ return 0; }
}
return CallWindowProc(oldProc, hwnd, msg, wParam, lParam); // 必須轉發
}
PostMessage(Form->Handle, WM_USER+1, wp, lp) + 主視窗處理TThread::Synchronize() (阻塞) / TThread::Queue() (非阻塞)TThread::Queue 內部用 PostMessage 實現,優先使用| 技巧 | 工具/方法 |
|---|---|
| 訊息追蹤 | Spy++ (Visual Studio)、WinSpector、API Monitor |
| 訊息過濾 | Spy++ 設定過濾條件 (視窗、訊息範圍) |
| 效能分析 | GetMessage 佇列長度監控、PeekMessage 非阻塞檢查 |
| 死結偵測 | SendMessageTimeout 超時、避免跨執行緒 SendMessage |
OnClick, OnKeyDown),降低複雜度RegisterWindowMessage 避免衝突TThread::Queue + Lambda (C++11)TPaintBox + OnPaint 或第三方繪圖引擎 (Skia, Direct2D)訊息機制是 Windows 程式設計的靈魂。C++Builder VCL 以 TApplication::Run() 驅動循環、WndProc 分發、MESSAGE_MAP 對應,將底層 MSG 轉為高層事件。理解這層映射關係,能在需要時精準介入:處理未封裝訊息、實作自訂協定、子類別化第三方控制項、跨執行緒安全通訊。