我需要拦截Windows关机,并执行一些DB查询,在此之前,我的应用程序将关闭。我在FMX项目中使用Windows 10下的 Delphi XE10***
我尝试的是下面的代码,但它不工作
private
{ Private declarations }
{$IFDEF MSWINDOWS}
procedure WMQueryEndSession(var Msg: TWMQueryEndSession); message WM_QUERYENDSESSION;
procedure WMEndSession(var Msg : TWMQueryEndSession); message WM_ENDSESSION ;
{$ENDIF}
end;
procedure TfMain.WMQueryEndSession(var Msg: TWMQueryEndSession);
var
lista:TStringList;
begin
{$IFDEF MSWINDOWS}
try
lista:=TStringList.Create;
lista.Add(FOrmatDateTime('DD/MM/YYYY HH:NN:SS',now)+' event WMQueryEndSession');
Lista.SaveToFile(froot+formatdatetime('YYMMDDHHNNSSZZZ',now)+'.log');
SincroClose();
lista.Add(FOrmatDateTime('DD/MM/YYYY HH:NN:SS',now)+' Done');
Lista.SaveToFile(froot+formatdatetime('YYMMDDHHNNSSZZZ',now)+'.log');
finally
lista.Free;
end;
{$ENDIF}
inherited;
end;
procedure TfMain.WMEndSession(var Msg: TWMQueryEndSession);
var
lista:TStringList;
begin
{$IFDEF MSWINDOWS}
try
lista:=TStringList.Create;
lista.Add(FOrmatDateTime('DD/MM/YYYY HH:NN:SS',now)+' WMEndSession');
Lista.SaveToFile(froot+formatdatetime('YYMMDDHHNNSSZZZ',now)+'.log');
SincroClose();
lista.Add(FOrmatDateTime('DD/MM/YYYY HH:NN:SS',now)+' Done');
Lista.SaveToFile(froot+formatdatetime('YYMMDDHHNNSSZZZ',now)+'.log');
finally
lista.Free;
end;
{$ENDIF}
inherited;
end;
procedure TfMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
var lista:TStringList;
begin
{$IFDEF MSWINDOWS}
CanClose:=false;
try
lista:=TStringList.Create;
lista.Add(FOrmatDateTime('DD/MM/YYYY HH:NN:SS',now)+' FormCloseQuery');
Lista.SaveToFile(froot+formatdatetime('YYMMDDHHNNSSZZZ',now)+'.log');
SincroClose();
lista.Add(FOrmatDateTime('DD/MM/YYYY HH:NN:SS',now)+' Done');
Lista.SaveToFile(froot+formatdatetime('YYMMDDHHNNSSZZZ',now)+'.log');
CanClose:=true;
finally
lista.Free;
end;
{$ENDIF}
end;
在FormCloseQuery事件下,只有正常关闭应用程序才能正常工作,但当Windows关闭时,我的应用程序将关闭而不保存任何数据
3条答案
按热度按时间mwngjboj1#
FormCloseQuery
可以工作,因为它是由框架公开的。当Windows关闭时,应用程序不保存任何数据,因为永远不会调用消息处理程序。消息处理仅适用于VCL应用程序,fmx应用程序的消息传递机制与documented不同。这里的简要说明意味着可以在fmx框架中接收来自OS的通知。然而,我不知道这是否包括关机通知,以及是否可以设置您的返回,因为文档提到消息对象是只读的。
在您发现fmx消息传递机制是如何工作的并且如果它满足要求之前,您可以通过常规方法子类窗体的窗口。下面的示例使用
SetWindowSubclass
。kdfy810k2#
在最近的版本中,Windows在这方面有一些变化-即。回到Windows XP。此外, Delphi 窗口由应用程序管理的方式已经改变,以便更好地处理其他操作系统的变化,FMX中的情况再次不同。
WM_QUERYENDSESSION现在只发送到顶层窗口。如果您的应用程序是一个VCL应用程序,并且
MainFormOnTaskbar
设置为 TRUE,那么您的应用程序主窗体是一个顶级窗口,应该会收到该消息。如果MainFormOnTaskbar
设置为 FALSE,或者如果您的窗体不是主窗体(尽管名称如此),则它不是顶级窗口,不会收到消息。如果您的应用程序使用FMX,那么您将需要在
FMX.Platform.Win
WindowService中查找,以确定主窗体的父级是如何确定的。基于对[XE 4] FMX源代码的检查,在这个领域(相对于VCL),事情似乎已经倒退,这里有一些丑陋的代码气味。这方面的细节导致的问题是,从Vista开始,WM_QUERYENDSESSION不再发送到没有任何可见顶层窗口的应用程序。即使您的主窗体是顶级窗口,如果在Windows关闭时它不可见,则这可能是您没有收到消息的原因。
如果问题是您的窗口不是应用程序中的顶级窗口,那么这里应该有足够的信息,至少可以让您找出原因。
在VCL应用程序中,将主窗体设置为任务栏窗口应该可以解决这个问题。我不知道在FMX应用程序中是否有类似的方法来解决这个问题。
如果你有一个有效的顶层窗口,问题是你的顶层窗口(有时)不可见,那么你需要找到一些其他的机制来挂钩到关闭进程,但应该注意的是,任何依赖于其他进程的行为都需要考虑到这些其他进程本身可能正在关闭,可能不可用。
当然,所有这些都是高度特定于Windows关机通知的。如果你打算用你的FMX应用程序支持其他平台,那么你需要在那里以不同的方式处理关机行为,假设FMX不提供跨平台关机通知解决方案(否则你会使用它,不是吗?).
(And如果你实际上只针对Windows,那么你到底为什么要使用FMX?)
lstz6jyr3#
答案很可能是迟来的,但那些将来会面对这个问题的人,那么……表单有一个OnSaveState事件,它只在WM_ENDSESSION事件上调用。是的,默认情况下会处理。WM_QUERYENDSESSION事件也是一样的,但是默认情况下传递1(启用会话终止)。只能通过复制FMX.Platform.Win.pas模块并自行修改来覆盖它