C++ Builder 的 VCL 將大多數常見 Windows 消息封裝為事件(OnClick、OnKeyDown 等),但系統定義的消息數百種,VCL 無法面面俱到。當需處理 WM_NCHITTEST、WM_DEVICECHANGE 等未封裝消息時,必須使用訊息映射表直接掛接回呼函數。
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(消息ID, 消息結構型別, 處理函數名)
// 可多行
END_MESSAGE_MAP(基底類別名)
消息結構型別:VCL 依消息定義不同結構,通用型別為 TMessage:struct TMessage {
unsigned int Msg; // 消息 ID
long WParam;
long LParam;
long Result; // 回傳值,影響後續處理
};
目標:建立無標題列(bsDialog + 隱藏 WS_CAPTION)視窗,滑鼠在用戶區按下即可拖動。
CreateParams)// MainForm.h - private 區
void __fastcall CreateParams(TCreateParams &Params);
// MainForm.cpp
void __fastcall TForm1::CreateParams(TCreateParams &Params)
{
TForm::CreateParams(Params); // 先呼叫基底實作
Params.Style &= ~WS_CAPTION; // 移除標題列樣式
}
// MainForm.h - public 區
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_NCHITTEST, TMessage, WMNchitTest)
END_MESSAGE_MAP(TForm)
// private 區
void __fastcall WMNchitTest(TMessage &Message);
WM_NCHITTEST 處理邏輯void __fastcall TForm1::WMNchitTest(TMessage &Message)
{
// 僅在左鍵按下時偽裝為標題列命中
if (GetAsyncKeyState(VK_LBUTTON) < 0)
Message.Result = HTCAPTION; // 告訴系統:游標在標題列
else
Message.Result = HTCLIENT; // 否則為用戶區
}
GetAsyncKeyState 回傳負值表示高位被設定(鍵盤/滑鼠按下),即時反映實體按鍵狀態,不受消息佇列延遲影響。
環境:C++ Builder 3 / Windows 98。按 F9 執行,滑鼠在視窗任意處按住左鍵即可拖動。程式未提供關閉機制,可自行加入 TPopupMenu 實作。
TMessage.Result 是關鍵:設定後可改變系統後續行為(如拖動判斷)。CreateParams 是調整視窗建立參數(樣式、擴充樣式、類別名等)的標準切入點。