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

BCB 攔截 Windows 訊息實戰:修改系統選單、擴展 TrackBar 事件

     編輯:VC 教學

痛點:VCL 封裝的缺口

  • 無法修改表單系統選單(新增/移除項目、圖示、擁有者繪製)。
  • TTrackBar 缺少 OnStartTrack/OnEndTrack 事件,只能得知最終位置。
  • 其他:WM_NCHITTEST 拖動無標題視窗、WM_POWERBROADCAST 電源管理等。

解決之道:**繞過 VCL,直接攔截 Windows 訊息**。

標準攔截步驟(表單級)

1. 標頭檔宣告

class TForm1 : public TForm
{
__published: ...
private:
    // 訊息處理函數宣告
    void __fastcall WMSysCommand(TMessage &Message);
    void __fastcall WMHScroll(TMessage &Message);
protected:
    // 訊息映射表
    BEGIN_MESSAGE_MAP
        MESSAGE_HANDLER(WM_SYSCOMMAND, TMessage, WMSysCommand)
        MESSAGE_HANDLER(WM_HSCROLL,    TMessage, WMHScroll)
    END_MESSAGE_MAP(TForm)
public:
    __fastcall TForm1(TComponent* Owner);
};

2. 實作檔定義

void __fastcall TForm1::WMSysCommand(TMessage &Message)
{
    // 攔截系統選單命令
    if (Message.WParam == SC_ABOUT) { // 假設新增「關於」項目
        ShowMessage("自訂系統選單項目被點擊");
        Message.Result = 0;
        return;
    }
    // 其他交給預設處理
    DefaultHandler(Message);
}

void __fastcall TForm1::WMHScroll(TMessage &Message)
{
    TTrackBar *tb = dynamic_cast(ControlAtPos(Mouse->CursorPos, true));
    if (tb && (Message.WParam & 0xFFFF) == TB_THUMBTRACK) {
        // 滑塊拖動中
        if (!tb->Tag) { // 首次
            tb->Tag = 1;
            OnStartTrack(tb); // 自訂事件
        }
    }
    else if (tb && ((Message.WParam & 0xFFFF) == TB_ENDTRACK)) {
        tb->Tag = 0;
        OnEndTrack(tb); // 自訂事件
    }
    DefaultHandler(Message); // 保證 TrackBar 正常更新
}

進階:修改系統選單完整範例

void __fastcall TForm1::FormCreate(TObject *Sender)
{
    HMENU hSysMenu = GetSystemMenu(Handle, FALSE);
    // 1. 新增分隔線
    AppendMenu(hSysMenu, MF_SEPARATOR, 0, NULL);
    // 2. 新增自訂項目
    AppendMenu(hSysMenu, MF_STRING, IDM_MY_ABOUT, "關於我的程式(&A)...");
    AppendMenu(hSysMenu, MF_STRING, IDM_MY_SETTINGS, "設定(&S)...");
}

// 3. 在 WMSysCommand 處理
void __fastcall TForm1::WMSysCommand(TMessage &Message)
{
    switch (Message.WParam & 0xFFF0) {
        case IDM_MY_ABOUT:
            ShowMessage("版本 1.0.0");
            break;
        case IDM_MY_SETTINGS:
            ShowSettingsDialog();
            break;
        default:
            DefaultHandler(Message);
    }
}

關鍵技術細節

MESSAGE_HANDLER 宏
要點說明
定義於 SysMac.h,展開為 switch-case 分派
訊息結構基本 TMessage 含 Msg, WParam, LParam, Result;特定訊息有專用結構(如 TWMMouse)
DefaultHandler呼叫 DefWindowProc,確保系統預設行為(如視窗移動、TrackBar 更新)
WParam & 0xFFF0系統命令高 12 位為命令 ID,低 4 位保留
跨進程攔截需 SetWindowsHookEx(WH_CALLWNDPROC/GETMESSAGE, ...) + DLL 注入

常見錯誤與修正

  • ❌ 忘記呼叫 DefaultHandler → 視窗無法移動、TrackBar 不更新。
    ✅ 除非明確要完全取代系統行為,否則必須呼叫。
  • ❌ 在訊息處理器中做耗時操作。
    ✅ 僅做輕量判斷/標記,重度邏輯 PostMessage 給自己或丟入工作佇列。
  • ❌ 使用 VCL_MESSAGE_HANDLER 卻引用 ATL。
    ✅ 專案含 ATL 時改用 MESSAGE_HANDLER 完整名稱避免宏衝突。

訊息攔截流程圖

掌握訊息攔截,即擁有了「VCL 後門鑰匙」,能實現框架未預見的任何視窗行為定製。

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