无论程序如何退出,如何确保FormClose过程运行?

时间:2009-03-24 23:02:27

标签: delphi

在Delphi 7中,我有一个TMainForm.FormClose过程,用于在程序退出时写出一些状态。这在手动关闭程序时工作正常。 但是,我发现如果程序被“强制”退出Windows(例如在需要重新启动的Windows Update之后),则不会调用FormClose过程。

编辑 - 我是新来的,看起来我无法删除自己的帖子。经过一番搜索,我找到了a solution

3 个答案:

答案 0 :(得分:8)

这个真的很难。如果你在外部杀死一个进程,那就是即时终止。期间没有机会清理。 Windows Update的重新启动通常通过向它发送WM_QUERYENDSESSION消息来“关闭”程序,但它并不总是起作用。特别是,如果您的程序延迟很长时间(例如,在退出之前询问用户是否要保存),则关闭代码将终止该进程。

因此,如果你想保证它总是调用那个事件处理程序,那么你必须保证你永远不会使用模态对话框或任何阻止程序收到WM_QUERYENDSESSION时立即拯救的东西。这可能比它的价值更麻烦。

一种替代方法是执行与Firefox相似的操作:将状态数据写入临时文件,同时它仍在运行,然后在重新启动时,检查该文件是否存在以及数据是否仍然存在处于“开放”状态。如果是这样,你的程序可以知道它的最后一个化身以某种方式被杀死并采取任何适当的行动,例如用最后可用的数据更新状态日志(或任何你正在使用的)。

答案 1 :(得分:5)

上面的评论建议我总结一下我找到的答案(link)。基本上,它说要为WM_QUERYENDSESSION提供自己的处理程序。这是推荐的代码:

procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
  inherited; { let the inherited message handler respond first }
  {--------------------------------------------------------------------}
  { at this point, you can either prevent windows from closing... }
  { Message.Result:=0; }
  {---------------------------or---------------------------------------}
  { just call the same cleanup procedure that you call in FormClose... }
  MyCleanUpProcedure;
  {--------------------------------------------------------------------}
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  MyCleanUpProcedure;
end;

我不确定在调用MyCleanUpProcedure之前调用Inherited是完全正确的。如果“继承”过程首先响应Windows,则Windows仍可在MyCleanUpProcedure完成之前关闭应用程序。我不确定Inherited对WM_QUERYENDSESSION消息做了什么 - 我假设它默认允许立即关闭。在我的应用程序中,MyCleanUpProcedure运行速度非常快,因此不会导致Windows显示“无响应”对话框,因为没有对WM_QUERYENDSESSION消息的响应。

为了确保我的程序运行完成,程序可能如下所示:

procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
  MyCleanUpProcedure;
  inherited;
end;

或者可能这个?

procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
  MyCleanUpProcedure;
  Message.Result:=1;    // tell Windows it is OK to shut down
end;

答案 2 :(得分:2)

跟进信息: 我不知道继承的过程是否做了除了返回“1”以外的任何事情,所以我尝试了返回和继承。首先运行我的关机程序,然后返回1,然后继承。

procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
  MyCleanUpProcedure;
  Message.Result:=1;  {Signal that it is OK to shut down}
  inherited; { let the inherited message handler respond }
end;

我已经针对系统正在关闭的情况(手动或因为Windows Update)测试了此代码,并且我的应用程序仍在运行。在这种情况下,以下代码已经过验证可以正常工作 - MyCleanUpProcedure在我的应用程序关闭之前运行。

我没有对我的应用程序被任务管理器杀死的情况进行测试 - 这不是我的应用程序的相关用例。