需求單純:禁用 WPF 視窗右上角的關閉按鈕 (×),而非攔截關閉邏輯。本文提供呼叫 Win32 GetSystemMenu + EnableMenuItem 的精確實作,並說明 WPF/WinForms 取得視窗句柄的差異。
[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int GetSystemMenu(int hwnd, int revert);
[DllImport("user32", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
private static extern int EnableMenuItem(int menu, int ideEnableItem, int enable);
private const int SC_CLOSE = 0xF060; // 關閉選單項目識別碼
private const int MF_BYCOMMAND = 0x00000000;
private const int MF_GRAYED = 0x00000001; // 灰化 (禁用)
private const int MF_ENABLED = 0x00000002;
public static void Disable(int handle) {
int result = EnableMenuItem(GetSystemMenu(handle, 0), SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
switch (result) {
case MF_ENABLED: break; // 原本啟用,現已禁用
case MF_GRAYED: break; // 原本已禁用
case -1: throw new Exception("The Close menu item does not exist.");
default: break;
}
}
回傳值表示先前狀態,-1 表選單項目不存在 (異常情況)。
| 視窗類型 | 取得句柄代碼 | |
|---|---|---|
| WPF Window | int handle = new WindowInteropHelper(wpfWindow).Handle.ToInt32(); | |
| WinForms Form | int handle = this.Handle.ToInt32(); 或 form.Handle.ToInt32() |
| 特性 | 禁用按鈕 (本文) | 取消關閉 (Closing 事件) |
|---|---|---|
| 視覺效果 | 按鈕灰化不可點擊 | 按鈕正常,點擊後攔截 |
| Alt+F4 | 無效 | 觸發 Closing 可攔截 |
| 工作列右鍵關閉 | 無效 | 觸發 Closing 可攔截 |
| 適用場景 | 嚴格鎖定視窗、Kiosk 模式 | 需確認/儲存/驗證再決定是否關閉 |
若需「確認後再關閉」而非完全禁用,請參考 Closing 事件設定 e.Cancel = true,或使用 Hide 替代 Close (視窗隱藏而非銷毀)。