有時我們需要在應用程式的系統選單(標題列左上角圖示選單)中加入自訂選單項,並為其綁定特定事件。本文結合 Windows API AppendMenu 與 C++ Builder 的 WindowProc 重載機制,實現系統選單的動態擴展與事件響應。
#define IDM_HELP1 1
#define IDM_HELP2 2
#define IDM_REMOVE 3
#define IDM_SEPARATOR1 4
#define IDM_SEPARATOR2 5
void __fastcall TForm1::FormCreate(TObject *Sender) {
HMENU hMenu = GetSystemMenu(this->Handle, FALSE);
HBITMAP hBitmapHelp;
// 新增分隔線與字串選單項
AppendMenu(hMenu, MF_SEPARATOR, IDM_SEPARATOR1, NULL);
AppendMenu(hMenu, MF_STRING, IDM_HELP1, "說明");
AppendMenu(hMenu, MF_SEPARATOR, IDM_SEPARATOR2, NULL);
// 新增位圖選單項
hBitmapHelp = LoadBitmap((void*)HInstance, "HELP"); // 需預先在資源編輯器建立位圖資源
AppendMenu(hMenu, MF_BITMAP, IDM_HELP2, (char*)hBitmapHelp);
// 新增「取消選單」項
AppendMenu(hMenu, MF_STRING, IDM_REMOVE, "取消選單");
}
在表單建構函式中指定自訂訊息處理函式:
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) {
WindowProc = MyWndProc; // 重載視窗程序
}
實作 MyWndProc:
void __fastcall TForm1::MyWndProc(Messages::TMessage &Message) {
HMENU hMenu = GetSystemMenu(this->Handle, FALSE);
if (Message.Msg == WM_SYSCOMMAND) {
switch (Message.WParamLo) {
case IDM_HELP1:
case IDM_HELP2:
ShowMessage("這是一個測試!");
break;
case IDM_REMOVE: {
// 動態移除所有自訂選單項
DeleteMenu(hMenu, IDM_HELP1, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_HELP2, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_REMOVE, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_SEPARATOR1, MF_BYCOMMAND);
DeleteMenu(hMenu, IDM_SEPARATOR2, MF_BYCOMMAND);
break;
}
default:
WndProc(Message); // 預設系統處理
}
} else {
WndProc(Message); // 非系統命令訊息交給基底類別
}
}
GetSystemMenu(hWnd, FALSE) 取得可修改的選單控制代碼。MF_STRING)、位圖 (MF_BITMAP)、分隔線 (MF_SEPARATOR) 等多種類型。TForm 的 WindowProc 屬性指向訊息處理函式,將其指向自訂函式即可攔截 WM_SYSCOMMAND。自訂函式中處理完特定命令後,需呼叫 WndProc(Message) 讓基底類別處理標準系統命令(如最小化、最大化、關閉)。DeleteMenu(hMenu, ID, MF_BYCOMMAND) 依命令 ID 刪除項目。Unit1.h 宣告 MyWndProc 於 public 區段;Unit1.cpp 包含建構函式設定 WindowProc、FormCreate 建立選單、MyWndProc 處理命令。專案在 C++Builder 4.0 下測試通過。
此技術可應用於:快速存取常用功能、動態顯示程式狀態、實現「關於」對話框捷徑等場景,豐富標準視窗的系統選單功能。