delphi - 如何在 VCL 项目上获取 Fmx 项目中的 Windows 关闭事件作为 WM_QUERYENDSESSION 和 WM_ENDSESSION ?

标签 delphi firemonkey

我需要拦截 Windows 关闭,并执行一些数据库查询,然后我的应用程序将关闭。 我在 Windows 10 下的 FMX 项目中使用 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 关闭时,我的应用程序将关闭而不保存任何数据

最佳答案

FormCloseQuery 之所以有效,是因为它是由框架公开的。当 Windows 关闭时,您的应用程序不会保存任何数据,因为您的消息处理程序永远不会被调用。消息处理仅适用于 VCL 应用程序,fmx 应用程序具有不同的消息传递机制,如 documented .

简要说明here意味着可以从 fmx 框架中的操作系统接收通知。但是我不知道这是否包括关闭通知以及是否可以设置返回,因为文档提到消息对象是只读的。

在您了解 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, SubclassProc, 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}

关于delphi - 如何在 VCL 项目上获取 Fmx 项目中的 Windows 关闭事件作为 WM_QUERYENDSESSION 和 WM_ENDSESSION ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39807377/

相关文章:

delphi - TApplication.MainFormOnTaskbar 版本要求

delphi - 在运行时检测 GPU 是否支持 Pixel Shader 2.0 (Firemonkey)

delphi - 通过设置透明颜色来剪切火猴形状的一部分不起作用?

ios - 添加 XSuperObject 时项目无法在 iOS 中启动

delphi - TListBox弹性滚动效果

delphi - 基于无约束泛型类型创建对象实例

delphi - 我可以更改 Delphi XE2 中 watch 的顺序吗?

delphi - 如何在Delphi中正确使用IFileOperation删除文件夹中的文件

ios - TFileStream.Create 在具有某些设备语言的 iOS 上失败

delphi - xul.dll和图像中的异常未在delphi应用程序内的gecko浏览器中显示