delphi 如何确保FormClose过程运行,而不管程序如何退出?

4xy9mtcn  于 2023-10-18  发布在  其他
关注(0)|答案(4)|浏览(177)

在 Delphi 7中,我有一个TMainForm.FormClose过程,用于在程序退出时写出一些状态。这在手动关闭程序时工作正常。然而,我发现如果程序被Windows“强制”退出(例如在需要重新启动的Windows Update之后),则不会调用FormClose过程。
编辑-我是新来的,看起来我不能删除我自己的帖子。经过一番搜索,我找到了a solution

nnsrf1az

nnsrf1az1#

这是真实的困难。如果你在外部杀死一个进程,那就是即时终止。没有机会清理,时期。Windows Update的重新启动通常会通过发送WM_QUERYENDSESSION消息来“正确”关闭程序,但无论出于何种原因,它并不总是有效。特别是,如果你的程序延迟了很长时间(例如,在退出前询问用户是否要保存),关闭代码将终止进程。
因此,如果你想保证它总是调用那个事件处理程序,你必须保证你永远不会使用一个模态对话框或任何其他东西来阻止程序在收到WM_QUERYENDSESSION时立即退出。这可能是更多的麻烦比它的价值。
一个替代方案是做一些类似于Firefox所做的事情:当它还在运行时,将状态数据写入一个临时文件,然后当它重新启动时,检查该文件是否在那里,以及数据是否指示它仍处于“打开”状态。如果是这样,您的程序可以知道它的最后一个化身以某种方式被杀死,并采取任何适当的行动,例如用最后可用的数据更新状态日志(或您正在使用的任何内容)。

slsn1g29

slsn1g292#

上面的一条评论建议我总结我找到的答案(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是否完全正确。如果Inherited过程首先响应Windows,则Windows仍然可以在MyCleanUpProcedure完成之前关闭应用程序。我不确定Inherited对WM_QUERYENDSESSION消息做了什么-我假设它默认允许立即关闭。在我的应用程序中,MyCleanUpProcedure运行得非常快,所以它不会导致Windows显示“Not Responding”对话框,因为没有对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;
ac1kyiln

ac1kyiln3#

随访信息:我不知道继承的过程除了返回“1”之外还做了什么,所以我尝试了return和inherited。首先运行我的关闭过程,然后返回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更新),我的应用程序仍在运行。以下代码已被验证在这种情况下正确工作- MyCleanUpProcedure在我的应用程序关闭之前运行。
我还没有针对应用程序被任务管理器杀死的情况进行测试--这与我的应用程序无关。

3phpmpom

3phpmpom4#

不能保证会调用FormClose。
(详情来自Peter B,
https://groups.google.com/g/borland.public.delphi.objectpascal/c/82AG0_kHonU/m/ft53lAjxWRMJ
通过一个名为“应用程序”的按钮关闭表单。
OnShow来电
毁灭召唤
OnHide打来电话
OnDestroy打电话来
通过调用Form1.Close的按钮关闭表单,在FormClose中使用Action:= caFree:
OnShow来电
OnCloseQuery已调用。
在关闭调用
毁灭召唤
OnHide打来电话
OnDestroy打电话来
通过系统菜单关闭表单:
OnShow来电
OnCloseQuery已调用。
在关闭调用
毁灭召唤
OnHide打来电话
OnDestroy打电话来
通过注销Win NT关闭应用程序:
OnShow来电
OnCloseQuery已调用。
两种解决方案:

  • 从上面的所有代码中调用一个自定义过程,并在该过程中设置一个bool变量。测试它,所以这个过程只被调用一次。把你的清理代码放在那里。
  • 删除析构函数。

相关问题