TTrackBar 缺少 OnStartTrack/OnEndTrack 事件,只能得知最終位置。WM_NCHITTEST 拖動無標題視窗、WM_POWERBROADCAST 電源管理等。解決之道:**繞過 VCL,直接攔截 Windows 訊息**。
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);
};
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);
}
}
| 要點 | 說明 |
|---|---|
定義於 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。MESSAGE_HANDLER 完整名稱避免宏衝突。
掌握訊息攔截,即擁有了「VCL 後門鑰匙」,能實現框架未預見的任何視窗行為定製。