首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

C++Builder 訊息處理機制深度解析:從 Windows 訊息循環到 VCL 封裝與自訂訊息實戰

     編輯:VC 教學

前言

Windows 是訊息驅動系統。C++Builder VCL 封裝大多數常用訊息為事件,但處理未封裝訊息、自訂訊息、子類別化視窗程序時,理解底層機制至關重要。本文從訊息循環切入,解析 VCL 分發流程與實戰應用。

一、Windows 訊息驅動核心

系統訊息佇列與應用程式佇列

  • 系統佇列:接收硬體輸入 (鍵盤/滑鼠)、系統事件
  • 每個執行緒擁有獨立應用程式佇列 (AttachThreadInput 可連接)
  • 訊息結構 MSG:hwnd, message, wParam, lParam, time, pt

標準訊息循環

MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) { // 0 表示所有視窗
    TranslateMessage(&msg);  // 虛擬鍵 → 字元訊息 (WM_KEYDOWN → WM_CHAR)
    DispatchMessage(&msg);   // 分發至視窗程序 (WindowProc)
}

二、VCL 訊息封裝與分發架構

1. TApplication::Run() 內部實現

// 簡化版
void TApplication::Run() {
    MSG msg;
    while (GetMessage(&msg, 0, 0, 0)) {
        if (!PreProcessMessage(&msg)) { // VCL 內部預處理 (快捷鍵、提示等)
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
}

2. 視窗程序鏈:DefWindowProc → WndProc → 子類別化

  • 每個 VCL 控制項擁有 WindowProc 方法 (虛擬函數)
  • TControl::WndProc 為核心分發點
  • 訊息對應表 (MESSAGE_MAP) 將訊息導向特定處理函數

3. 訊息對應巨集

// .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)
};

三、關鍵訊息處理流程

命令訊息 (WM_COMMAND)

  • 選單項目、按鈕點擊、加速鍵觸發
  • VCL 轉為 OnClick、OnCommand 事件

通知訊息 (WM_NOTIFY)

  • 通用控制項 (ListView, TreeView, ToolBar) 狀態變化
  • VCL 封裝為特定事件 (OnItemClick, OnCustomDraw)

繪圖訊息 (WM_PAINT / WM_ERASEBKGND)

  • VCL 雙重緩衝、Paint() 虛擬函數
  • 自訂繪圖覆寫 Paint() 而非處理 WM_PAINT

四、自訂訊息實戰

1. 定義自訂訊息常數

const UINT WM_MY_CUSTOM = WM_USER + 100; // WM_USER (0x0400) 以上為應用程式自用
// 或 RegisterWindowMessage("MyApp_CustomMsg") 取得全域唯一值

2. 發送/張貼訊息

API特性用途
SendMessage同步,直接呼叫視窗程序,等待返回需立即結果、跨執行緒同步
PostMessage非同步,放入佇列,立即返回非阻塞通知、避免死結
SendMessageTimeout同步帶超時防止目標視窗無回應卡死

3. 接收端處理

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); // 必須轉發
}

六、跨執行緒訊息傳遞

  • 背景執行緒 → 主執行緒 UI 更新:PostMessage(Form->Handle, WM_USER+1, wp, lp) + 主視窗處理
  • VCL 安全方式:TThread::Synchronize() (阻塞) / TThread::Queue() (非阻塞)
  • TThread::Queue 內部用 PostMessage 實現,優先使用

七、效能與除錯技巧

技巧工具/方法
訊息追蹤Spy++ (Visual Studio)、WinSpector、API Monitor
訊息過濾Spy++ 設定過濾條件 (視窗、訊息範圍)
效能分析GetMessage 佇列長度監控、PeekMessage 非阻塞檢查
死結偵測SendMessageTimeout 超時、避免跨執行緒 SendMessage

八、現代化建議

  • 優先使用 VCL 事件模型 (OnClick, OnKeyDown),降低複雜度
  • 自訂訊息用 RegisterWindowMessage 避免衝突
  • 跨執行緒用 TThread::Queue + Lambda (C++11)
  • 大量自訂繪圖改用 TPaintBox + OnPaint 或第三方繪圖引擎 (Skia, Direct2D)

結語

訊息機制是 Windows 程式設計的靈魂。C++Builder VCL 以 TApplication::Run() 驅動循環、WndProc 分發、MESSAGE_MAP 對應,將底層 MSG 轉為高層事件。理解這層映射關係,能在需要時精準介入:處理未封裝訊息、實作自訂協定、子類別化第三方控制項、跨執行緒安全通訊。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved