當使用者啟動關機/重開機/登出時,Windows 會向所有最上層視窗發送 `WM_QUERYENDSESSION` 訊息。應用程式可透過回傳值決定是否允許:
此機制設計用於:資料未儲存提醒、關鍵作業進行中 (備份、燒錄、資料庫交易)、自動更新安裝階段等場景。
class TForm1 : public TForm {
__published:
TCheckBox* CheckBox1; // 控制是否允許關機
private:
void __fastcall OnWMQueryEndSession(TMessage& Message);
protected:
BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(WM_QUERYENDSESSION, TMessage, OnWMQueryEndSession)
END_MESSAGE_MAP(TForm)
public:
__fastcall TForm1(TComponent* Owner);
};
void __fastcall TForm1::OnWMQueryEndSession(TMessage& Message) {
// 使用者勾選核取方塊表示允許關機
if (CheckBox1->Checked) {
Message.Result = 1; // 同意關機
} else {
Message.Result = 0; // 拒絕關機
// 可選:顯示提示訊息 (需非模態,避免阻塞系統關機逾時)
// Application->MessageBox("關鍵作業進行中,暫不允許關機!", "系統鎖定", MB_OK | MB_ICONWARNING);
}
}
class TCriticalOperationGuard {
static bool s_operationInProgress;
public:
static void Begin() { s_operationInProgress = true; }
static void End() { s_operationInProgress = false; }
static bool IsBusy() { return s_operationInProgress; }
};
// 在 WM_QUERYENDSESSION 中
void __fastcall TForm1::OnWMQueryEndSession(TMessage& Message) {
Message.Result = TCriticalOperationGuard::IsBusy() ? 0 : 1;
}
void __fastcall TForm1::OnWMQueryEndSession(TMessage& Message) {
SYSTEMTIME st; GetLocalTime(&st);
AnsiString log = Format("關機嘗試: %02d/%02d/%04d %02d:%02d:%02d - %s",
ARRAYOFCONST((st.wMonth, st.wDay, st.wYear, st.wHour, st.wMinute, st.wSecond,
CheckBox1->Checked ? "允許" : "攔截")));
LogToFile(log); // 自訂日誌函數
Message.Result = CheckBox1->Checked ? 1 : 0;
}
void __fastcall TForm1::OnWMQueryEndSession(TMessage& Message) {
// lParam 低位元組:ENDSESSION_LOGOFF (0x80000000) 表示登出
// 無法直接區分關機 vs 重開機,需配合 WM_ENDSESSION 或系統事件日誌
if (Message.LParam & ENDSESSION_LOGOFF) {
// 使用者登出
Message.Result = AllowLogoff() ? 1 : 0;
} else {
// 關機或重開機
Message.Result = AllowShutdown() ? 1 : 0;
}
}
Windows 7+ 提供 Application Recovery and Restart 機制,比攔截關機更優雅:
// 註冊復原回呼
RegisterApplicationRecoveryCallback(RecoveryCallback, NULL, 30000, 0);
// 註冊重新啟動命令列
RegisterApplicationRestart(L"/restart", 0);
// 復原回呼範例
DWORD WINAPI RecoveryCallback(LPVOID lpParam) {
// 儲存未完成工作、狀態資訊
SaveUnsavedData();
// 通知系統復原完成
ApplicationRecoveryFinished(TRUE);
return 0;
}
優點:系統自動重新啟動應用、還原視窗狀態、不阻塞關機流程、使用者體驗更佳。
| 測試案例 | 預期結果 |
|---|---|
| 開始功能表 → 關機 | 視核取方塊狀態允許/攔截 |
| Ctrl+Alt+Del → 關機 | 同前 |
| 命令列 `shutdown /s /t 0` | 同前 |
| 遠端桌面 → 登出 | 攔截登出 (若實作區分邏輯) |
| 強制關機 (長按電源鍵 / `shutdown /f`) | 應用程式被終止,無法攔截 |
| 關鍵作業進行中 (旗標=true) | 攔截關機,日誌記錄 |
攔截 `WM_QUERYENDSESSION` 是防止使用者誤關機的經典技術,但**必須謹慎使用**。現代 Windows 版本嚴格限制回應時間,且使用者擁有強制關機權限。建議採用「旗標控制 + 非阻塞日誌 + ARR 機制」組合策略:關鍵作業期間設定旗標攔截正常關機,同時註冊復原回呼確保資料不遺失,提供最佳的資料保護與使用者體驗平衡。