Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi防止应用程序关闭_Delphi_Shutdown - Fatal编程技术网

Delphi防止应用程序关闭

Delphi防止应用程序关闭,delphi,shutdown,Delphi,Shutdown,我正试图阻止我的应用程序被windows关闭。 该应用程序在windows 8上运行,并用XE6编写。 我尝试了以下代码,但似乎完全被忽略了。为了测试它,我只需通过任务管理器向它发送“结束任务”。 我需要的是一种方法,当应用程序被用户、任务管理器或windows关闭时,让我的应用程序完成它所做的事情。 正常关闭不是问题,这由FormCloseQuery事件处理。但是其他两种方法我都无法使用。在windows XP之前,捕获wm_endsession和wm_queryendsession很容易,从

我正试图阻止我的应用程序被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;
根据to block shutdown,您需要返回
FALSE
以响应
WM\u QUERYENDSESSION

而且,您不能在这个消息处理程序中工作。这项工作必须在别处进行。如果您不及时回复此消息,系统将不会等待您

  • 开始工作前,请调用
    ShutdownBlockReasonCreate
  • 工作时返回
    FALSE
    from
    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调用结果;如果你不这样做,你就不能责怪他们不能正常工作,因为你没有正确地使用他们。