在Delphi 7中,我有一个TMainForm.FormClose过程,用于在程序退出时写出一些状态.这在手动关闭程序时工作正常.但是,我发现如果程序被"强制"退出Windows(例如在需要重新启动的Windows Update之后),则不会调用FormClose过程.
编辑 - 我是新来的,看起来我无法删除自己的帖子.经过一番搜索,我找到了解决方案.
这个真的很难.如果你在外部杀死一个进程,那就是即时终止.期间没有机会清理.Windows Update的重新启动通常通过向它发送WM_QUERYENDSESSION消息来"关闭"程序,但它并不总是起作用.特别是,如果您的程序延迟很长时间(例如,在退出之前询问用户是否要保存),则关闭代码将终止该进程.
因此,如果你想保证它总是调用那个事件处理程序,你必须保证你永远不会使用模态对话框或任何阻止程序收到WM_QUERYENDSESSION时立即拯救的东西.这可能比它的价值更麻烦.
一种替代方法是执行与Firefox相似的操作:将状态数据写入临时文件,同时它仍在运行,然后在重新启动时,检查该文件是否存在,以及数据是否表明它仍在"打开"状态.如果是这样,你的程序可以知道它的最后一个化身以某种方式被杀死并采取任何适当的行动,例如用最后可用的数据更新状态日志(或任何你正在使用的).
上面的评论表明我总结了我找到的答案(链接).基本上,它说要为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;
Run Code Online (Sandbox Code Playgroud)
我不确定在调用MyCleanUpProcedure之前调用Inherited是完全正确的.如果"继承"过程首先响应Windows,则Windows仍可在MyCleanUpProcedure完成之前关闭应用程序.我不确定Inherited对WM_QUERYENDSESSION
消息做了什么- 我认为它默认允许立即关闭.在我的应用程序中,MyCleanUpProcedure运行速度非常快,因此不会导致Windows显示"无响应"对话框,因为没有响应WM_QUERYENDSESSION
消息.
为了确保我的程序运行完成,可能程序应如下所示:
procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
MyCleanUpProcedure;
inherited;
end;
Run Code Online (Sandbox Code Playgroud)
或者可能这个?
procedure TForm1.WMQueryEndSession(var Message: TWMQueryEndSession);
begin
MyCleanUpProcedure;
Message.Result:=1; // tell Windows it is OK to shut down
end;
Run Code Online (Sandbox Code Playgroud)