Delphi阻止应用程序关闭

Gui*_*doG 6 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;
Run Code Online (Sandbox Code Playgroud)

更新

将消息结果更改为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;
Run Code Online (Sandbox Code Playgroud)

Dav*_*nan 10

根据阻止关闭的文档,您需要返回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;
Run Code Online (Sandbox Code Playgroud)

然后执行工作的代码需要ShutdownBlockReasonCreate在工作开始之前调用,ShutdownBlockReasonDestroy当工作结束时,并确保Working上面使用的属性True在工作期间进行评估.

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

如果你被送到目前为止WM_ENDSESSION已经太晚了.系统正在下降.

为了测试它,我只需通过任务管理器向其发送"结束任务".

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

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


Ser*_*yuz 6

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

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

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