Delphi阻止应用程序关闭

时间:2014-08-27 20:17:31

标签: delphi shutdown

我试图阻止我的应用程序被Windows关闭。 该应用程序在Windows 8上运行并以XE6编写。 我尝试了下面的代码,但它似乎完全被忽略了。为了测试它,我只需发送"结束任务"通过任务管理器。 我需要的是一种方法,让我的应用程序完成它在用户关闭应用程序时所执行的操作,由Windows关闭的任务管理器完成。 正常关闭不是问题,这由FormCloseQuery事件处理。但是其他两种方法我无法开始工作。直到windows XP,通过捕获wm_endsession和wm_queryendsession很容易,从vista开始你需要使用ShutDownBlockReasonCreate,它返回true但似乎无论如何都不起作用。

procedure WMQueryEndSession(var Msg : TWMQueryEndSession); message WM_QUERYENDSESSION;
procedure WMEndSession(var Msg: TWMEndSession); message WM_ENDSESSION;

function ShutdownBlockReasonCreate(hWnd: HWND; Reason: LPCWSTR): Bool; stdcall; external user32;
function ShutdownBlockReasonDestroy(hWnd: HWND): Bool; stdcall; external user32;


procedure TForm1.WMEndSession(var Msg: TWMEndSession);
begin
  inherited;

  Msg.Result := lresult(False);
  ShutdownBlockReasonCreate(Handle, 'please wait while muting...');
  Sleep(45000); // do your work here
  ShutdownBlockReasonDestroy(Handle);
end;

procedure TForm1.WMQueryEndSession(var Msg: TWMQueryEndSession);
begin
  inherited;
  Msg.Result := lresult(False);
  ShutdownBlockReasonCreate(Handle, 'please wait while muting...');
  Sleep(45000); // do your work here
  ShutdownBlockReasonDestroy(Handle);
end;

更新

将消息结果更改为true并删除睡眠不会改变任何内容。

procedure TForm1.WMEndSession(var Msg: TWMEndSession);
begin
  inherited;
  Msg.Result := lresult(True);
  ShutdownBlockReasonDestroy(Application.MainForm.Handle);
  ShutdownBlockReasonCreate(Application.MainForm.Handle, 'please wait while muting...');
end;

procedure TForm1.WMQueryEndSession(var Msg: TWMQueryEndSession);
begin
  inherited;
  Msg.Result := lresult(True);
  ShutdownBlockReasonDestroy(Application.MainForm.Handle);
  ShutdownBlockReasonCreate(Application.MainForm.Handle, 'please wait while muting...');
end;

2 个答案:

答案 0 :(得分:8)

根据阻止关闭的documentation,您需要返回FALSE以响应WM_QUERYENDSESSION

还有什么,你不能在这个消息处理程序中工作。这项工作必须在别处进行。如果您没有及时回复此消息,系统将不会等你。

  • 开始工作前请致电ShutdownBlockReasonCreate
  • 同时从FALSE返回WM_QUERYENDSESSION。在处理此消息时不要工作。马上回来。
  • 完成工作后,请致电ShutdownBlockReasonDestroy

WM_QUERYENDSESSION的处理程序可能如下所示:

procedure TMainForm.WMQueryEndSession(var Msg: TWMQueryEndSession);
begin
  if Working then
    Msg.Result := 0
  else
    inherited;
end;

然后执行工作的代码需要在工作开始之前调用ShutdownBlockReasonCreate,在工作结束时调用ShutdownBlockReasonDestroy,并确保上面使用的Working属性求值为{ {1}}在工作期间。

如果您的工作阻止主线程,那么您就遇到了麻烦。主线必须是响应式的,否则系统不会等你。将工作放在一个线程中往往是前进的方向。如果您的主窗口不可见,那么您将无法阻止关机。详细信息请参见此处:http://msdn.microsoft.com/en-us/library/ms700677.aspx

如果你被发送到True,那就太晚了。系统正在下降。

  

为了测试它我只是发送"结束任务"通过任务管理器。

这与关机阻止无关。测试关闭阻止的方法是注销。如果用户坚持要求杀死您的流程,那么您无能为力。 Sertac的答案详细介绍了这一点。

最后,忽略API调用的返回值也是非常差的形式。不要这样做。

答案 1 :(得分:6)

您的代码似乎完全被忽略了,因为您没有对其进行测试。你发送"结束任务"通过任务管理器,您发布的代码仅在系统关闭时才有效。

Windows 8的不同之处似乎是任务管理器的行为方式。在Windows 8之前,任务管理器的结束任务将首先尝试正常关闭应用程序(发送WM_CLOSE),然后使用OnCloseQuery进行处理。但是当应用程序拒绝关闭时,任务管理器将强制结束该过程。这个,你无法处理。如果您选择"结束流程"来自任务经理。

Windows 8任务管理器不提供强制关闭应用程序的附加对话框,但在应用程序拒绝关闭时立即执行此操作。