首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> Delphi

Delphi 程式阻止使用者關機/登出/重啟:WM_QUERYENDSESSION 訊息攔截實作

     編輯:Delphi

前言

Windows 關機/登出/重啟時,會向所有視窗發送 WM_QUERYENDSESSION 訊息詢問「是否允許結束工作階段」。應用程式回傳 0 (False) 即可取消關機,回傳 1 (True) 表示同意。本文示範在 Delphi 中攔截此訊息實作「防關機」功能,適用於關鍵監控程式、不可中斷的資料處理任務等場景。

核心實作

1. 宣告訊息處理函數

type
  TForm1 = class(TForm)
  private
    procedure WMQueryEndSession(var Msg: TMessage); message WM_QUERYENDSESSION;
  public
    { Public declarations }
  end;

2. 實作攔截邏輯

procedure TForm1.WMQueryEndSession(var Msg: TMessage);
begin
  // 回傳 0 (False) 告訴系統:不同意結束工作階段 → 取消關機/登出
  Msg.Result := 0;
  
  // 可選:顯示提示、記錄日誌、詢問使用者確認
  // if MessageDlg('確定要取消關機嗎?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then
  //   Msg.Result := 1
  // else
  //   Msg.Result := 0;
end;

3. 完整單元程式碼

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;

type
  TForm1 = class(TForm)
  private
    { Private declarations }
    procedure WMQueryEndSession(var Msg: TMessage); message WM_QUERYENDSESSION;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.WMQueryEndSession(var Msg: TMessage);
begin
  // 直接阻止關機
  Msg.Result := 0;
end;

end.

進階:條件式允許關機

type
  TForm1 = class(TForm)
  private
    FCriticalTaskRunning: Boolean;
    procedure WMQueryEndSession(var Msg: TMessage); message WM_QUERYENDSESSION;
  public
    property CriticalTaskRunning: Boolean read FCriticalTaskRunning write FCriticalTaskRunning;
  end;

procedure TForm1.WMQueryEndSession(var Msg: TMessage);
begin
  if FCriticalTaskRunning then
  begin
    // 關鍵任務執行中,阻止關機並提示
    Msg.Result := 0;
    // 可選:閃爍視窗、播放聲音、顯示非模態提示
    FlashWindow(Handle, True);
    // 記錄日誌
    Log('關機被攔截: 關鍵任務執行中');
  end
  else
  begin
    // 無關鍵任務,允許關機
    Msg.Result := 1;
  end;
end;

相關訊息區別

訊息階段可否取消用途
WM_QUERYENDSESSION詢問階段✅ 可取消 (回傳 0)應用程式決定是否允許關機
WM_ENDSESSION通知階段❌ 不可取消系統已決定關機,執行清理儲存
WM_CLOSE視窗關閉✅ 可取消使用者點擊視窗關閉按鈕

處理 WM_ENDSESSION 執行最終清理

type
  TForm1 = class(TForm)
  private
    procedure WMEndSession(var Msg: TMessage); message WM_ENDSESSION;
  end;

procedure TForm1.WMEndSession(var Msg: TMessage);
begin
  if Msg.WParam = 1 then // TRUE: 系統確實要關機
  begin
    // 最後機會:儲存設定、關閉資料庫、釋放硬體資源
    SaveSettings;
    CloseDatabase;
    ReleaseHardware;
  end;
  inherited;
end;

注意事項與最佳實務

  • 濫用風險:長期阻止關機會惱怒使用者、導致系統更新無法安裝、筆電無法休眠。僅在真正關鍵任務期間啟用。
  • 使用者體驗:提供視覺回饋 (托盤圖示閃爍、氣球提示) 告知使用者為何無法關機。
  • 服務程式替代:真正需要持續運行的後台任務,應開發為 Windows Service,而非 GUI 程式阻止關機。
  • ShutdownBlockReasonCreate (Vista+):現代 API 提供更友善的阻止關機方式,可在關機對話框顯示自訂原因字串。
    uses ShellApi;
    ShutdownBlockReasonCreate(Handle, '正在處理關鍵資料,請稍候...');
    // 任務完成後
    ShutdownBlockReasonDestroy(Handle);
  • 測試方法:編譯執行程式,嘗試「開始 → 關機」或 Win+X → 關機,觀察是否被攔截。

結語

WM_QUERYENDSESSION 是 Delphi 程式參與 Windows 關機協商的標準介面。回傳 0 即可攔截關機,但這是一把雙面刃。現代應用應優先考慮 Windows Service 架構處理長期任務,或使用 ShutdownBlockReasonCreate 提供使用者可見的阻止原因。GUI 程式阻止關機應作為最後手段,且必須嚴格限制啟用條件與時間。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved