我需要拦截
Windows关闭,并执行一些DB查询,之后我的应用程序将关闭.
我在Windows 10上使用Delphi XE10在FMX项目
我在Windows 10上使用Delphi XE10在FMX项目
我试过的是下面的代码,但它不起作用
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'); 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'); CanClose:=true; finally lista.Free; end; {$ENDIF} end;
只有正常的关闭应用程序,才能正常工作,在FormCloseQuery事件下,但是当Windows关闭时,我的应用程序将关闭而不保存任何数据
解决方法
FormCloseQuery的工作原理是由框架公开的.由于您的邮件处理程序永远不会被调用,所以您的应用程序不会在Windows关闭时保存任何数据.消息处理仅适用于VCL应用程序,fmx应用程序具有与
documented不同的消息传递机制.
简要说明here意味着可以在fmx框架中接收来自OS的通知.但是,我不知道这是否包括关机通知,并且可以设置返回值,因为文档提到的消息对象只能被读取.
直到你知道fmx消息传递机制是如何工作的,如果它满足要求,你可以通过传统方式对你的窗体进行子类化.下面的示例使用SetWindowSubclass.
... protected {$IFDEF MSWINDOWS} procedure CreateHandle; override; procedure DestroyHandle; override; procedure WMQueryEndSession(var Msg: TWMQueryEndSession); message WM_QUERYENDSESSION; procedure WMEndSession(var Msg: TWMEndSession); message WM_ENDSESSION; {$ENDIF} ... implementation {$IFDEF MSWINDOWS} uses FMX.Platform.Win,Winapi.Commctrl; function SubclassProc(Wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM; uIdSubclass: UINT_PTR; RefData: DWORD_PTR): LRESULT; stdcall; var Self: TfMain; Message: TMessage; begin Result := DefSubclassProc(Wnd,Msg,wParam,lParam); case Msg of WM_QUERYENDSESSION,WM_ENDSESSION: begin Self := TfMain(RefData); Message.Msg := Msg; Message.WParam := wParam; Message.LParam := lParam; Message.Result := Result; Self.Dispatch(Message); Result := Message.Result; end; end; end; procedure TfMain.CreateHandle; var Wnd: HWND; begin inherited; Wnd := WindowHandleToPlatform(Self.Handle).Wnd; SetWindowSubclass(Wnd,SubclassProc,1,DWORD_PTR(Self)); end; procedure TfMain.DestroyHandle; var Wnd: HWND; begin Wnd := WindowHandleToPlatform(Self.Handle).Wnd; RemoveWindowSubclass(Wnd,1); inherited; end; procedure TfMain.WMQueryEndSession(var Msg: TWMQueryEndSession); begin // do not call inherited here,there's no inherited handling end; procedure TfMain.WMEndSession(var Msg: TWMEndSession); begin // do not call inherited here,there's no inherited handling end; var ICC: TInitCommonControlsEx; initialization ICC.dwSize := SizeOf(ICC); ICC.dwICC := ICC_STANDARD_CLASSES; InitCommonControlsEx(ICC); {$ENDIF}