4

我使用 C++ 编写了一个本地服务应用程序,但我找不到正确的方法来注册预关闭通知(对于晚于 Windows XP 的操作系统)。我相信自 Vista 以来已经添加了 SERVICE_CONTROL_PRESHUTDOWN 通知,但是当您调用 SetServiceStatus 时,我们是否需要指定:

dwServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_PRESHUTDOWN;

或者

dwServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PRESHUTDOWN;
4

4 回答 4

10

如果您的服务编码正确,则您不能同时接受关闭和预关闭。文档明确说明了这一点。

来自http://msdn.microsoft.com/en-us/library/windows/desktop/ms683241(v=vs.85).aspx

参考SERVICE_CONTROL_PRESHUTDOWN

处理此通知的服务会阻止系统关闭,直到服务停止或通过 SERVICE_PRESHUTDOWN_INFO 指定的关闭前超时间隔到期。

在同一页面中,关于SERVICE_CONTROL_SHUTDOWN添加的部分:

请注意,注册 SERVICE_CONTROL_PRESHUTDOWN 通知的服务无法接收此通知,因为它们已经停止

因此,正确的方法是根据您的需要将 设置dwControlsAccepted为包含SERVICE_ACCEPT_SHUTDOWNSERVICE_ACCEPT_PRESHUTDOWN,但不要同时包含两者。

但请注意,您可能希望接受更多控制。您应该始终至少允许SERVICE_CONTROL_INTERROGATE,并且几乎肯定允许SERVICE_CONTROL_STOP,因为没有后者,服务将无法停止(例如,为了卸载软件)并且必须强制终止进程(即终止

于 2012-11-11T09:38:06.583 回答
2

正如上述评论者所指出的,您需要从 SERVICE_ACCEPT_SHUTDOWN 或 SERVICE_ACCEPT_PRESHUTDOWN(Vista 或更高版本)中进行选择。如果您使用的是 SERVICE_ACCEPT_PRESHUTDOWN,您将需要使用RegisterServiceCtrlHandlerEx而不是 RegisterServiceCtrlHandler 向 SCM 注册您的服务,否则您将不会收到预关闭通知。处理程序原型也从 Handler 更改为HandlerEx

另一点需要注意的是,在 Windows Server 2012(可能是 Windows 8)中处理纯关闭事件的时间限制为 5 秒,在 Windows 7 和 Windows Server 2008 中为 12 秒,在 Windows XP 中为 20 秒,然后您的服务在停止时被终止。这就是您可能需要关机前通知的原因。您可能需要在 \\HKLM\SYSTEM\CurrentControlSet\Control\WaitToKillServiceTimeout 中更改此设置。

于 2013-06-17T16:04:05.980 回答
1

在 alexpi 的评论中有一条关键信息。我发现处理 PRESHUTDOWN 的服务需要在 WaitToKillServiceTimeout 过去之前使用新的检查点编号(重复)更新服务状态。我的服务器配置为 5000 毫秒,我的服务仅每 12000 毫秒更新一次,服务器进入 SHUTDOWN 阶段,这导致我尝试停止另一个服务返回正在关闭的错误。

于 2021-10-08T13:33:56.610 回答
0

当我从文档中得到它时,这两个通知似乎有所不同。如果您确实需要让您的服务接收关闭前通知,您应该选择:dwServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_PRESHUTDOWN;但是如果您还想让您的服务接收关闭通知,您应该选择第二个选项。

于 2012-11-11T08:14:06.813 回答