在開發背景服務、系統盤應用或特殊 UI 需求時,常需要隱藏主視窗在任務列的按鈕。本文詳細解析兩種核心方法:ShowWindow 動態隱顯與 WS_EX_TOOLWINDOW 風格永久移除,並說明其原理、優缺點與最佳實踐。
// 隱藏任務列圖示
ShowWindow(Application->Handle, SW_HIDE);
// 重新顯示任務列圖示
ShowWindow(Application->Handle, SW_SHOW);
Application->Handle 是 VCL 應用程式物件的隱藏視窗句柄(類別名 TApplication),任務列按鈕實際綁定此視窗而非主表單。SW_HIDE 將該視窗設為不可見,任務列隨之移除按鈕。
SetForegroundWindow)會導致圖示重現TApplication 視窗可能影響 MessageBox、對話方塊的父視窗關係,導致對話框顯示異常WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
// 1. 獲取當前擴展風格
DWORD dwExStyle = GetWindowLong(Application->Handle, GWL_EXSTYLE);
// 2. 添加 WS_EX_TOOLWINDOW 標誌
dwExStyle |= WS_EX_TOOLWINDOW;
// 3. 設置新風格
SetWindowLong(Application->Handle, GWL_EXSTYLE, dwExStyle);
try {
Application->Initialize();
Application->CreateForm(__classid(TForm1), &Form1);
Application->Run();
}
catch (Exception &exception) {
Application->ShowException(&exception);
}
return 0;
}
WS_EX_TOOLWINDOW (0x00000080) 標記視窗為「工具視窗」,Windows Shell 承諾:
MessageBox, OpenDialog) 父視窗仍為 Application->Handle,可能顯示位置異常若需「隱藏 Application 視窗,但主表單有自己的任務列按鈕」:
WINAPI WinMain(...) {
// 隱藏 Application 視窗
ShowWindow(Application->Handle, SW_HIDE);
// 讓主表單成為獨立任務列項目
DWORD dwExStyle = GetWindowLong(Form1->Handle, GWL_EXSTYLE);
dwExStyle |= WS_EX_APPWINDOW;
SetWindowLong(Form1->Handle, GWL_EXSTYLE, dwExStyle);
Application->Initialize();
Application->CreateForm(__classid(TForm1), &Form1);
Form1->Show(); // 手動顯示,因 Application->Run 會自動 ShowMainForm
Application->Run();
return 0;
}
需配合修改 TCustomForm.WMSysCommand 防止最小化時觸發 Application 隱藏邏輯 (見 VCL 源碼 Forms.pas)。
| 場景 | 推薦方案 | 關鍵點 |
|---|---|---|
| 系統盤常駐程式 | WS_EX_TOOLWINDOW + NotifyIcon | 主表單隱藏,僅托盤圖示交互 |
| 無 UI 後台服務 | WS_EX_TOOLWINDOW | 完全無視窗,配合 Service 模式更佳 |
| 臨時隱藏主視窗 | ShowWindow(SW_HIDE) | 短暫操作,完成後 SW_SHOW 恢復 |
| 需正常標題列但無任務列按鈕 | WS_EX_TOOLWINDOW + 自繪 NC 區 | 處理 WM_NCPAINT, WM_NCHITTEST, WM_NCCALCSIZE |
| 主表單獨立任務列項 | WS_EX_APPWINDOW + 修正 VCL 最小化邏輯 | 複雜度高,建議考慮獨立進程設計 |
BorderStyle = bsNone 自繪標題列;2) 或不設此風格,改用 ShowWindow(Application->Handle, SW_HIDE) 並接受其非持久性。Application->Handle 為父視窗居中。解決:使用 Form1->ShowModal() 代替 MessageBox,或手動設置對話框位置。TService 類別 (C++ Builder Enterprise) 或純 API CreateService,以 SERVICE_WIN32_OWN_PROCESS 類型安裝,由 SCM 管理生命週期。