【问题标题】:Delphi - prevent windows shutdown from tray applicationDelphi - 防止从托盘应用程序关闭Windows
【发布时间】:2016-09-05 09:01:20
【问题描述】:

我正在尝试为我们的系统制作一个小型工具,以防止在我们的软件运行时关闭 Windows。为了使其独立,我制作了一个单独的应用程序,使用this 信息防止关机。

但是,当应用程序最小化到托盘时,Windows 会简单地将其杀死并正常关闭。如果表单是可见的(也就是我从 Form.OnCreate 事件中评论 Application.Minimize 调用),它确实可以防止关机。

如何实现 MainWindow 挂钩以保持活动状态,或者通过其他方式防止系统关闭,并将应用程序隐藏在托盘中?

谢谢。

当前代码:

unit Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, TlHelp32, dateutils, Vcl.AppEvnts, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    TrayIcon1: TTrayIcon;
    ApplicationEvents1: TApplicationEvents;
    procedure FormCreate(Sender: TObject);
    function HookEndSession(var Message: TMessage): Boolean;
    procedure WMQueryEndSession(var Msg : TWMQueryEndSession) ;
         message WM_QueryEndSession;
    procedure ApplicationEvents1Minimize(Sender: TObject);
    procedure ApplicationEvents1Restore(Sender: TObject);
    procedure TrayIcon1DblClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var Form1: TForm1;
var Mutex : THandle;

implementation

{$R *.dfm}



procedure TForm1.WMQueryEndSession(var Msg: TWMQueryEndSession);
begin
  Msg.Result := 0;
end;

function TForm1.HookEndSession(var Message: TMessage): Boolean;
begin
  result := false;
  if Message.Msg = WM_ENDSESSION then begin
    Message.Result := 0;
    result := true;
  end;
end;


procedure TForm1.TrayIcon1DblClick(Sender: TObject);
begin
  WindowState := wsNormal;
  Application.Terminate;
end;

procedure TForm1.ApplicationEvents1Minimize(Sender: TObject);
begin
  Hide();
  WindowState := wsMinimized;
  TrayIcon1.Visible := True;
end;

procedure TForm1.ApplicationEvents1Restore(Sender: TObject);
begin
  Application.Minimize;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Mutex := CreateMutex(nil, True, 'preventWinShutdown');
  if (Mutex = 0) OR (GetLastError = ERROR_ALREADY_EXISTS) then
  Application.Terminate;

  Application.HookMainWindow(HookEndSession);

  TrayIcon1.Hint := 'Windows Shutdown prevented.';
  //Application.Minimize;
end;


end.

【问题讨论】:

    标签: delphi delphi-xe3


    【解决方案1】:

    我手头没有 XE3,但在 XE7 中,TCustomTrayIcon.WindowProc 通过返回 1(等效于 TRUE)显式处理 WM_QUERYENDSESSION,这向 Windows 发出信号以继续注销/关闭/重新启动序列。 您可以覆盖它:

    type
      TTrayIcon = class(Vcl.ExtCtrls.TTrayIcon)
      protected
        procedure WindowProc(var Message: TMessage); override;
      end;
    
    procedure TTrayIcon.WindowProc(var Message: TMessage);
    begin
      case Message.Msg of
        WM_QUERYENDSESSION:
          Message.Result := 0;
        else
          inherited WindowProc(Message);
      end;
    end;
    

    要获得更完整的解决方案,您将在单独的单元中创建一个新类,从 TCustomTrayIcon 继承并重新发布您希望公开的属性和事件,就像 TTrayIcon 所做的那样,在 IDE 中安装组件并在您的任何项目中使用它。

    上面的示例只是一个带有插入器类的快速示例,您可以在 TForm1 之前简单地声明并立即使用,仅在本单元中。

    【讨论】:

      【解决方案2】:

      Ondrej 所说的只是解决方案的一半。

      在 Vista 及更高版本上,您必须使用 ShutdownBlockReasonCreate()。由于以下注意事项,这对您的情况尤其重要:

      Application Shutdown Changes in Windows Vista

      必须阻止关机的应用程序应使用新的关机原因 API

      在 Windows XP 中,Microsoft 建议如果应用程序需要阻止关机,它应该显示自己的 UI 来解释为什么需要这样做,这样用户在关机失败时就不会感到沮丧。如前所述,Windows Vista 将通过显示列出应用程序阻止关闭的所有原因的新 UI 来进一步减少用户在关机失败时的挫败感。

      在 Windows Vista 中,如果您的应用程序必须阻止关闭,除了返回 FALSE 或不响应 WM_QUERYENDSESSION 之外,它应该利用这个新 UI,通过使用简单的 API 为 Windows 提供一个原因字符串来解释它为什么阻止关机。这个 API 很简单:

      BOOL ShutdownBlockReasonCreate(HWND hWnd, LPCWSTR pwszReason);

      BOOL ShutdownBlockReasonDestroy(HWND hWnd);

      BOOL ShutdownBlockReasonQuery(HWND hWnd, LPWSTR pwszBuff, DWORD *pcchBuff);

      本主题后面以及各个 ShutdownBlockReason() 函数的 MSDN 文档中更详细地详细介绍了此 API 的使用。

      再次请注意,此 API 不能取代向 WM_QUERYENDSESSION 返回 FALSE(或延迟响应)以阻止关机的需要。除了使用 API 之外,应用程序还需要执行此操作。向 WM_QUERYENDSESSION 返回 TRUE 的应用程序将在关闭时关闭,无论它们是否使用过 API

      另外请注意,如果您的应用程序没有可见的顶级窗口,则它必须使用此 API 才能成功阻止关机。如果此类应用程序在不使用 API 的情况下阻止关闭,则会自动终止

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-02-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多