12

我有托盘应用程序。

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

但是,如果 Windows 由于 Windows 关闭而试图关闭我的应用程序,我不想将我的应用程序移动到托盘中,而是关闭它。

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

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

谢谢!

4

2 回答 2

16

如果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;
于 2012-05-24T22:07:54.177 回答
9

您的问题源于使用OnCloseQuerywhich 是错误的事件。Remy 的回答解释了如何解决默认 VCL 结束会话消息处理阻止 Windows 关机的问题。而这又是由事件中的设置CanClose引起FalseOnCloseQuery

该解决方法将完成工作,但有一种更简单的方法来处理这个问题。与其阻止表单关闭,不如让它继续关闭。完全删除您的OnCloseQuery活动。将其替换为OnClose事件。

procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caNone;
  Visible := False;
end;

当主窗体关闭时,这段相当琐碎的代码足以使您的应用程序最小化到托盘。

于 2012-05-24T21:29:11.137 回答