如何区分UI关闭和使用Delphi强制关机

时间:2015-03-05 19:03:54

标签: delphi shutdown delphi-xe4 application-shutdown

如果用户尝试关闭应用程序,我想显示“关闭查询”确认对话框。如果系统关闭或任务或进程正在从任务管理器结束,我只想清理并关闭。

我试过这段代码:

private
procedure WMEndSession(var Message: TWMEndSession); message WM_ENDSESSION;

...

procedure TxxxForm.WMEndSession(var Message: TWMEndSession);
begin
  gShuttingDown := Message.EndSession;
end;

...

procedure TxxxForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  Application.ProcessMessages;
  if gShuttingDown then
    CanClose := True
  else
    CanClose := MessageDlg('Are you sure you want to stop the close?', mtConfirmation,
       [mbYes, mbNO], 0) = mrYes;
end;

弹出确认显示我是否关闭程序或从任务管理器终止进程。

1 个答案:

答案 0 :(得分:3)

WM_QUERYENDSESSION是要处理的正确消息。这是在WM_ENDSESSION之前发送的,根据以下VCL代码,您可以看到WMQueryEndSession立即调用CloseQuery

procedure TCustomForm.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
  Message.Result := Integer(CloseQuery);
end;

可以认为上述实现是VCL代码中的一个小错误,因为正如WM_QUERYENDSESSION文档所述(强调我的):

  

每个应用程序应在收到此消息后立即返回TRUE或FALSE ,并推迟任何清理操作,直到收到WM_ENDSESSION消息。
  应用程序可以显示一个用户界面,提示用户在关机时获取信息,但不推荐五秒后,系统会显示有关阻止关闭的应用程序的信息,并允许用户终止它们。例如,Windows XP显示一个对话框,而Windows Vista显示一个完整的屏幕,其中包含有关阻止关闭的应用程序的其他信息。如果您的应用程序必须阻止或推迟系统关闭,请使用ShutdownBlockReasonCreate功能。有关详细信息,请参阅关闭Windows Vista的更改。

如果用户无法响应在5秒内弹出的对话框,则他们必须 终止 应用或取消关机。不幸的是,由于CloseQuery通常用于提示用户,所以这样做并不是一个好主意 注意:这在Vista之前是完全可以接受的,上面的代码可能更像是一个遗留问题。但是,如果CloseQuery至少被调整以指示关闭请求的来源,那么将很容易处理查询结束会话的具体情况。

所以鉴于我不想在响应WM_QUERYENDSESSION时弹出任何提示,我实际上会做以下事情:

procedure TxxxForm.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
  Message.Result := 1;
  { Do not call inherited bc VCL may prevent/delay shutdown via 
    calls to: CloseQuery and CallTerminateProcs (in older 
    versions of Delphi).
    As per Vista requirements, this should not be done. Use
    ShutdownBlockReasonCreate and ShutdownBlockReasonDestroy to
    control when shutdown is allowed. }
end;

转到问题的第二部分。
以上原因不能通过任务管理器对 End Task 起作用,因为任务管理器不使用与shutdown相同的机制。它只是向您的应用程序发送WM_CLOSE消息。

因此,您的应用程序的行为方式与“正常”关闭时的行为方式完全相同。事实上,您可以尝试使用记事本:

  • 打开记事本
  • 输入一些文字
  • 转到任务管理器,然后单击记事本的结束任务
  • 您将看到记事本将提示确认,任务管理器将显示一个对话框,记事本正在等待用户的响应。 (至少在Win7中。)

但是,如果希望/需要在从任务管理器关闭时阻止提示,则可以执行此操作。但是代码必须处理许多特殊情况,并且在所有版本的Windows上可能不会以完全相同的方式运行。 (所以你必须问自己,这是否值得付出努力。)

你必须至少满足3种情况:

  1. 从应用程序中的自定义菜单或按钮关闭。
  2. 从标准Windows命令关闭:右上角的 X ,系统菜单或双击左上角, Alt + F4 组合键。
  3. 最后从任务管理器关闭。
  4. 让所有3个人按照你想要的方式行事会变得有点棘手。

    • 选项3发送WM_CLOSE。因此,您必须在没有提示的情况下关闭“默认”行为。并使用Flag启用提示。通过这种方式,选项3可以“静默地”关闭。
    • 选项2首先发送WM_SYSCOMMAND SC_CLOSE后跟WM_CLOSE。因此,您可以设置Flag以响应第一条消息。因此,您的用户将收到提示。
    • 选项1最有可能通过调用Close来实现。但为了确保您获得提示,您必须先设置Flag
    • 如果您的用户选择不关闭该应用,请不要忘记清除您的Flag

    最后的想法

    我个人认为“近距离确认”非常烦人。当然,我习惯经常保存,所以不要冒着丢失数据的风险。

    基本上,提示关闭的唯一合理理由是防止未保存数据的意外数据丢失。如果您遵循此规则,您可以创建更愉快的用户体验:

      

    当应用程序打开时,请务必将其恢复为 与其关闭时所处的完全相同的状态

    即。如果文档有未保存的数据,请将其存储在临时文件中。当应用程序重新打开时,文档将自动置于关机状态下的“编辑”状态。

    是的。也许这只是过于简单化了,但这个想法在移动设备上非常适用。