检测Windows关闭或应用程序是否尝试从系统菜单关闭(WM_CLOSE)

Iva*_*ark 11 delphi tray

我有托盘应用程序.

Onj FormCloseQuery我检查程序是否应该转到托盘而不是关闭它我把它放在托盘中(CanClose:= False)

但是,如果Windows由于Windows关闭而尝试关闭我的应用程序,我希望不将我的应用程序移动到托盘中,而是关闭它.

Win7终止我的应用程序,但XP没有关闭,因为我的应用程序仍然在托盘中.

如何检测Windows是否处于某种"关闭"模式?

谢谢!

Rem*_*eau 14

如果OnCloseQuery在响应WM_QUERYENDSESSION消息时触发事件,则设置CanClose=False将导致消息返回FALSE.

在XP及更早版本中,这将取消Windows关闭.到目前为止,任何收到WM_QUERYENDSESSION消息的应用程序都会收到一条WM_ENDSESSION消息,其wParam值设置为FALSE告知这些应用程序不要自行终止.这就是您的应用程序进入托盘并在Windows关闭期间不退出的原因.

Microsoft在Windows Vista中更改了此行为,因此应用程序无法再取消Windows关闭WM_QUERYENDSESSION.这就是Windows Vista及更高版本将终止您的应用程序的原因.如果应用程序需要故意停止Windows关闭,则会引入全新的API.

这在MSDN上有记录:

应用程序关闭Windows Vista中的更改

要执行您要求的操作,您必须WM_QUERYENDSESSION直接拦截消息,以便确定是否OnCloseQuery因Windows关闭而被调用.例如:

type
  TForm1 = class(TForm)
  private
    procedure WMQueryEndSession(var Message: TWMQueryEndSession); message WM_QUERYENDSESSION;
    procedure WMEndSession(var Message: TWMEndSession); message WM_ENDSESSION;
  end;

var
  ShuttingDown: Boolean = False;

procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
  ShuttingDown := True;
  inherited;
end;

procedure TForm1.WMEndSession(var Message: TWMEndSession);
begin
  ShuttingDown := Message.EndSession;
  inherited;
end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := ShuttingDown;
  if not ShuttingDown then
  begin
    // your Tray logic here ...
  end;
end;
Run Code Online (Sandbox Code Playgroud)


Dav*_*nan 9

您的问题源于使用OnCloseQuery哪个是错误的事件.Remy的答案解释了如何解决Windows关闭被默认VCL结束会话消息处理阻止的问题.而这又是通过设置造成的CanClose,以FalseOnCloseQuery事件.

这种解决方法将完成工作,但有一个更简单的方法来处理这个.不要让表格停止关闭,而是让它继续前进并关闭.OnCloseQuery完全删除您的活动.将其替换为OnClose事件.

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caNone;
  Visible := False;
end;
Run Code Online (Sandbox Code Playgroud)

这个相当简单的代码足以让您的应用程序在主窗体关闭时最小化到托盘.

  • 您无需知道其用户是单击关闭按钮还是Windows关闭.当Windows关闭时,您的应用程序将运行其OnClose事件并使其主窗体不可见.然后它将被终止.然后Windows会崩溃.你真的不需要做更多的事情.我很抱歉继续这个,但我真的相信这是更好,更简单的选择. (2认同)