1

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

我试过这段代码:

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;

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

4

1 回答 1

6

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至少调整为指示关闭请求的来源,那将是很好的,这样可以轻松处理Query End Session的具体情况。

因此,鉴于我不希望弹出任何提示以响应 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不能通过任务管理器工作的原因是任务管理器不使用与关闭相同的机制。它只是向WM_CLOSE您的应用程序发送一条消息。

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

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

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

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

  1. 从应用程序中的自定义菜单或按钮关闭。
  2. 从标准 Windows 命令关闭:X在右上角,系统菜单或双击左上角,Alt+F4组合键。
  3. 最后从任务管理器关闭。

让这三个人都按照你想要的方式行事有点棘手。

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

最后的想法

我个人觉得“关闭确认”很烦人。当然,我有经常保存的习惯,所以不要冒险丢失数据。

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

当应用程序打开时,始终将其恢复到与关闭时完全相同的状态。

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

是的。也许这过于简单化了,但这个想法在移动设备上运行得非常好。

于 2015-03-06T17:40:23.617 回答