【问题标题】:Prevent Windows 10 from automatically restarting after an update programmatically以编程方式阻止 Windows 10 在更新后自动重启
【发布时间】:2017-07-13 14:24:43
【问题描述】:

问题:有没有一种程序化方式可以防止 Windows 10 在更新后自动重启?

我们致力于在 Windows 中运行的“关键任务”软件。一般来说,如果 Windows 自动更新中断了我们的流程,这很糟糕,因为这可能意味着报废材料的损失(您不能停止并稍后恢复,工作必须从头到尾不间断地工作)。

过去,我们可以通过让我们的软件安装程序在 Windows 注册表中设置一个参数(在用户安装程序的同意下)来解决这个问题,以防止在用户登录时自动更新后自动重新启动。因此,不是自动更新,而是通知用户有更新需要重新启动,并在他们准备好时单击按钮。这适用于 Windows Vista、7 和 8/8.1。但是,对于最新的 Windows 10(我正在使用 Creators 的更新),该参数似乎不再起作用,因为我观察到我的计算机经历了自动更新,我知道注册表项已经生效。

在我的研究中,我发现似乎是一个希望的地方,可以选择一个设置,Windows 将为用户提供安排更新的机会,而不是在 Windows 认为合适的时候自动执行更新(信息here)。但是,我不确定如何以编程方式设置 Windows,以便安排更新的选项成为默认选项。

是否有编程方式来设置 Windows 10(最好以友好的方式)使其不会自动重启?

【问题讨论】:

  • 这是使用组策略和域策略完成的。它不需要代码。在域中控制更新很容易 - 设置和配置更新服务以根据需要缓存和分发更新
  • 换句话说 - 我必须在我的域中手动强制更新
  • 这不是您应该尝试设置的策略。这是运行您的程序的机器的系统管理员的东西。
  • @PanagiotisKanavos,我不想完全打败它。我希望对其进行设置,以便它会提示用户安排时间自动更新,而不是 Windows 只是在感觉时一次这样做。我们还要求管理员安装程序/用户在安装我们的软件时更改此设置(否则,如果他们单击“否”,我们将不理会它)。至于您关于“关键任务”和 Internet 连接的问题......有些所有者想要两者,以便他们可以远程监控他们的机器。
  • ...NoAutoRebootWithLoggedOnUsers 似乎仍在 1703 上工作。但是,这可能取决于其他配置设置,例如 WSUS。

标签: c# windows delphi winapi restart


【解决方案1】:

尝试关闭阻止原因 API。 ShutdownBlockReasonCreate

API 文档以 CD 刻录为例,但同样适用于您的“关键任务”流程。

应用程序应在开始执行不可中断的操作时调用此函数,例如刻录 CD 或 DVD。操作完成后,调用ShutdownBlockReasonDestroy函数表示可以关闭系统。

请注意,文档专门提到了用户关闭,但我不明白为什么它也不应该适用于更新重启。

注意:记得检查功能是否成功;并在进程完成时销毁 Shutdown Reason。


根据您的评论,您似乎需要使用 Windows API 例程的帮助。我建议您在适当的库中声明外部函数。 (但您可以毫无顾虑地在同一个单元中进行测试。)

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

以下演示如何使用 API。注意:注意错误检查。我已经演示了如何获取错误信息。你用它做什么取决于你。

要指出的另一件重要的事情(在 cmets 中重复)是您不应该阻塞主线程。有关详细信息,请参阅这些更改首次在 Vista 中引入时的 Microsoft 文档here

procedure TForm1.JobStartClick(Sender: TObject);
var
  LErr: Cardinal;
begin
  ListBox1.Items.Add('Attempting to block shutdown:');
  if (not ShutdownBlockReasonCreate(Application.MainForm.Handle, 
      'Super Critical Job')) then
  begin
    LErr := GetLastError;
    ListBox1.Items.Add('... failed: ' + SysErrorMessage(LErr));
    //Probably not safe to start your job in this case, but perhaps you
    //choose to give it a shot anyway.
    Exit;
  end;
  ListBox1.Items.Add('... success');

  FJobRunning := True;
  //Start the job.
  //However, NB do not run the job here.
  //If it takes a long time and is not asynchronous, you should probably
  //run your job on a separate thread.   ***Do not block the main thread
  //  otherwise Windows will still kill your app for not responding***
end;

procedure TForm1.JobEndClick(Sender: TObject);
var
  LErr: Cardinal;
begin
  if (not FJobRunning) then Exit;
  //End the job.
  //Again, do not block the main thread, so perhaps this is rather something
  //to do after you already know the job is done.
  FJobRunning := False;

  ListBox1.Items.Add('Allow shutdown');
  if (not ShutdownBlockReasonDestroy(Application.MainForm.Handle)) then
  begin
    LErr := GetLastError;
    ListBox1.Items.Add('... failed: ' + SysErrorMessage(LErr));
  end;
end;

//Declare the handler for the WM_QUERYENDSESSION message as follows.
//procedure WMQueryEndSession(var AMsg : TWMQueryEndSession); message WM_QUERYENDSESSION;
procedure TForm1.WMQueryEndSession(var AMsg: TWMQueryEndSession);
begin
  ListBox1.Items.Add('WMQueryEndSession');
  if (FJobRunning) then
    //NB: This is very important.
    //You still need to confirm that your application wants to block
    //shutdown whenever you receive this message.
    AMsg.Result := 0
  else
    inherited;
end;

【讨论】:

  • ...我不知道,Windows 对那些自动重启可能非常...痴迷...。但这绝对值得一试。
  • @Craig Young,我在 Delphi 从事这个项目,但无权访问“ShutdownBlockReasonCreate”。但是,我确实找到了其他东西“WMQueryEndSession”here。我试过了,它可以正常关机或重启你认为这会阻止自动更新的重启吗(没有方便的更新来测试:))?
  • @Andre72127 首先,如果您使用Delphi,为什么要标记C#?其次,我的建议适用于德尔福。如果尚未为您声明它们,您可能不知道如何调用 Windows API 函数?我已经用应该让你继续前进的信息更新了我的答案。但我强烈建议您熟悉如何在 Delphi 中更有效地使用 Windows API。 (以及与此相关的其他外部 DLL。)
  • 终于!我终于可以将此标记为答案了!它在 Windows 10 Build 1909 中运行良好。最糟糕的情况是用户的帐户被锁定,您只需重新登录即可返回应用程序。将出现一条横幅,说明该应用中断了 Windows 更新重新启动,但您可以重新安排。
【解决方案2】:

注册表项HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings 包含两个条目:ActiveHoursStartActiveHoursEnd。根据需要在程序中更改这些条目以禁止重新启动。这样,您可以控制在程序运行时不重新启动。请注意,您需要提升权限才能更改这些设置。

【讨论】:

  • 应用修改这些设置肯定是错误的。
  • @DavidHeffernan,嗯,我有一个正在运行的服务,它完全可以做到这一点。相反,当我没有坐在它前面时,MS 强迫我的系统崩溃任何正在运行的程序(尤其是正在运行的虚拟机)肯定是错误的。并且:不,它之前不会发出关闭消息,我可以拦截并做出反应。实际上我正在重新启动,但在我可以控制它的时候。
  • 在你的机器上很好。不在别人的机器上。
  • @DavidHeffernan,OP 提到他得到了用户的同意。至少在任务运行时禁止更新是用户承认的实际目标。之前的方法已经不行了。我的回答显示了一个可行的选择。问题不在于自动更新是好是坏——在这种情况下,它可能已经被删除了。
猜你喜欢
  • 2016-03-09
  • 1970-01-01
  • 1970-01-01
  • 2010-09-18
  • 1970-01-01
  • 2011-03-09
  • 1970-01-01
  • 1970-01-01
  • 2018-04-08
相关资源
最近更新 更多