Delphi防止应用程序关闭
我正试图阻止我的应用程序被windows关闭。 该应用程序在windows 8上运行,并用XE6编写。 我尝试了以下代码,但似乎完全被忽略了。为了测试它,我只需通过任务管理器向它发送“结束任务”。 我需要的是一种方法,当应用程序被用户、任务管理器或windows关闭时,让我的应用程序完成它所做的事情。 正常关闭不是问题,这由FormCloseQuery事件处理。但是其他两种方法我都无法使用。在windows XP之前,捕获wm_endsession和wm_queryendsession很容易,从vista开始,您需要使用ShutDownBlockReasonCreate,它返回true,但似乎无论如何都不起作用Delphi防止应用程序关闭,delphi,shutdown,Delphi,Shutdown,我正试图阻止我的应用程序被windows关闭。 该应用程序在windows 8上运行,并用XE6编写。 我尝试了以下代码,但似乎完全被忽略了。为了测试它,我只需通过任务管理器向它发送“结束任务”。 我需要的是一种方法,当应用程序被用户、任务管理器或windows关闭时,让我的应用程序完成它所做的事情。 正常关闭不是问题,这由FormCloseQuery事件处理。但是其他两种方法我都无法使用。在windows XP之前,捕获wm_endsession和wm_queryendsession很容易,从
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;
根据to block shutdown,您需要返回FALSE
以响应WM\u QUERYENDSESSION
而且,您不能在这个消息处理程序中工作。这项工作必须在别处进行。如果您不及时回复此消息,系统将不会等待您
- 开始工作前,请调用
李>ShutdownBlockReasonCreate
- 工作时返回
fromFALSE
。处理此邮件时不要工作。马上回来李>WM\u QUERYENDSESSION
- 工作完成后,请调用
李>关机blockreasondestroy
WM_QUERYENDSESSION
的处理程序可以如下所示:
procedure TMainForm.WMQueryEndSession(var Msg: TWMQueryEndSession);
begin
if Working then
Msg.Result := 0
else
inherited;
end;
然后,执行工作的代码需要在工作开始之前调用ShutdownBlockReasonCreate
,在工作结束时调用ShutdownBlockReasonDestroy
,并确保在工作期间上述使用的Working
属性的计算结果为True
如果你的工作阻塞了主线程,那么你就有麻烦了。主线程必须响应,否则系统将不会等待您。把工作放在一个线程中通常是前进的方向。如果主窗口不可见,则无法阻止关机。详情如下:
如果你一直被发送到WM_ENDSESSION
,那就太晚了。不管发生什么情况,这个系统都会崩溃
为了测试它,我只需通过任务管理器向它发送“结束任务”
这与关机阻塞无关。测试关机阻塞的方法是注销。如果用户坚持要终止您的进程,那么您对此无能为力。Sertac的回答详细说明了这一点
最后,忽略API调用的返回值也是非常糟糕的形式。不要那样做 您的代码似乎被完全忽略,因为您没有测试它。您通过任务管理器向其发送“结束任务”,您发布的代码仅在系统关闭时有效 Windows 8的不同之处似乎在于任务管理器的行为方式。在Windows 8之前,任务管理器中的结束任务将首先尝试优雅地关闭应用程序(发送
WM_CLOSE
),这是您正在使用OnCloseQuery
处理的。但当应用程序拒绝关闭时,任务管理器将提供强制结束流程的建议。这是你无法处理的。如果从任务管理器中选择“结束流程”,则相同
Windows 8任务管理器不提供用于强制关闭应用程序的附加对话框,但在应用程序拒绝关闭时会立即执行此操作。此外,“如果应用程序响应WM_QUERYENDSESSION或WM_ENDSESSION超时,Windows将终止它。”因此您的“睡眠(45000);//在此处完成工作”将导致此超时。我试着返回真值,但没什么区别。如果没有sleep命令,它仍然无法工作。返回TRUE并重新启动ShutDownBlockReasonDestroy不起作用。我尝试了我能想到的每一种组合,尝试了使用谷歌找到的不同代码,但似乎没有任何效果。您是否有一个工作示例?我手头可能没有示例代码,但我已经成功地使用了这些API。很明显,他们不是恶作剧,我不明白你为什么认为他们是。您是否希望ms添加不起作用的API?我将问题编辑为更符合您建议的代码。仍然不起作用,我会做错什么。我说他们在那里做恶作剧,因为他们似乎什么都没做,这是讽刺。也许如果我能看看你的工作示例,我可以找出我在这里做错了什么?看。你不能说这些函数是“恶作剧”。检查
ShutDownBlockReasonCreate
的返回值,如果返回false,请使用GetLastError
查找失败原因。如果不检查返回值以找出其原因,则不能说“API不工作”。如果我从按钮调用该函数,则无法在WMQueryEndSession中检查结果,因为应用程序在我检查其值之前关闭。>“要测试它,我只需通过任务管理器向其发送“结束任务”即可。”>这与您正在测试的代码无关,您的应用程序窗口将不会通过此测试发送WM_QUERYENDSESSION、WM_ENDSESSION消息。您可以使用OutputDebugString
查看函数结果,并在IDE的消息窗口中查看它,即使在您的应用程序从IDE运行结束后也是如此。始终检查API调用结果;如果你不这样做,你就不能责怪他们不能正常工作,因为你没有正确地使用他们。