我试图阻止我的应用程序被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;
答案 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任务管理器不提供强制关闭应用程序的附加对话框,但在应用程序拒绝关闭时立即执行此操作。