Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 检测Windows是否关闭或应用程序是否尝试从系统菜单关闭(WM_close)_Delphi_Tray - Fatal编程技术网

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

Delphi 检测Windows是否关闭或应用程序是否尝试从系统菜单关闭(WM_close),delphi,tray,Delphi,Tray,我正在做托盘申请 Onj FormCloseQuery我检查程序是否应该转到托盘,而不是关闭它,我把它放在托盘中(CanClose:=False) 但如果Windows因为Windows关闭而试图关闭我的应用程序,我不想将我的应用程序移动到任务栏中,而是想关闭它 Win7终止我的应用程序,但XP未关闭,因为我的应用程序仍在任务栏中 如何检测Windows是否处于某种“关闭”模式 谢谢 您的问题源于使用了OnCloseQuery,这是一个错误的事件。Remy的回答解释了如何解决Windows关机被

我正在做托盘申请

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

但如果Windows因为Windows关闭而试图关闭我的应用程序,我不想将我的应用程序移动到任务栏中,而是想关闭它

Win7终止我的应用程序,但XP未关闭,因为我的应用程序仍在任务栏中

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


谢谢

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

这种变通方法可以完成工作,但有一种更简单的方法来处理这个问题。 与其阻止窗体关闭,不如让它继续并关闭。完全删除
OnCloseQuery
事件。将其替换为
OnClose
事件

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

当主窗体关闭时,这一微不足道的代码足以使您的应用程序最小化到托盘中。

如果响应
WM\u QUERYENDSESSION
消息触发
OnCloseQuery
事件,则设置
CanClose=False
将导致消息返回
False

在XP和更早版本上,这将取消Windows关机。到目前为止,任何收到
WM_QUERYENDSESSION
消息的应用程序都将收到
WM_ENDSESSION
消息,其
wParam
值设置为
FALSE
告诉这些应用程序自行终止。这就是为什么你的应用会进入任务栏,在Windows关闭期间不会退出

Microsoft在Windows Vista中更改了此行为,因此应用程序无法再通过
WM\u QUERYENDSESSION
取消Windows关机。这就是为什么Windows Vista及更高版本将终止您的应用程序。如果应用程序需要故意停止Windows关机,则会引入全新的API

这在MSDN上有记录:

要执行要求的操作,必须直接截获
WM\u QUERYENDSESSION
消息,以便确定是否由于Windows关闭而调用了
OnCloseQuery
。例如:

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;

您是否试图捕获该消息?我已将我的注释移动到一个答案。这是因为您的代码未使用
OnCloseQuery
事件。它使用的是
OnClose
事件,它与
WM\u QUERYENDSESSION
消息没有关联,比如
OnCloseQuery
is。@Remy是的,我的理解有点慢,不是吗?!在这里,OnClose似乎是正确的解决方案。卷入结束会话消息毫无意义。我需要WM_QUERYENDSESSION和WM_ENDSESSION-触发WM_CLOSE时,我已经使用OnCanCloseQuery将程序放入托盘中。不,您不需要。您只需要此答案中的代码作为主窗体的OnClose事件。摆脱OnCloseQuery,这是问题的根源。就这么简单。我们的应用程序也做同样的事情。我的使用一个两行事件处理程序。你也可以。你不需要知道它的用户是单击关闭按钮还是Windows关闭。当Windows关闭时,应用程序将运行其OnClose事件并使其主窗体不可见。然后它将被终止。然后窗户就会掉下来。你真的不需要做更多的事情了。我很抱歉继续说下去,但我真的相信这是更好更简单的选择。大卫,你和雷米的解决方案是一样的。我所需要的就是这些消息——以及系统何时发送它们。你们两个都帮了我,我给了你们额外的帮助,但雷米是以回答的形式做的,所以我接受了帮助。但这两种解决方案是相同的。想法(逻辑)几乎是一样的。不,我的答案非常不同。可能您还没有刷新页面。你在谈论我的评论。我相信这个答案中的雷米密码比你需要的要复杂得多。是的,我说的是你的建议,而不是答案。我不能用你们写的这个代码做任何事情,因为我已经用了相同的代码来检测关闭,而不是停止程序,我把它放进了任务栏。我需要其他事件,然后WM_关闭-我需要结束会话,甚至因为Win在退出时触发它。使用你的代码,我无法使diff Dod Close按钮显示此消息或赢得关机