的主要问题是,ATL使用RegisterServiceCtrlHandler
代替RegisterServiceCtrlHandlerEx
;只有第二个实际注册为SERVICE_CONTROL_PRESHUTDOWN
消息。此外,ATL不包含OnPreShutdown()的可继承模板。
因此在四个部分的解决方案是:
(1)更新接受的控制消息的列表以包括SERVICE_ACCEPTED_PRESHUTDOWN
消息。 Windows处理预关闭后,您可以删除SERVICE_ACCEPTED_SHUTDOWN
,因为Windows认为该服务将被关闭,因此您将永远不会收到此消息。在我的情况的变化是在覆盖PreMessageLoop()
方法设置控件列表:
我改变:m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
要:m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PRESHUTDOWN;
但是你可能没有覆盖这个方法 - 所以你应该简单地在您设置此值的任何点更改该列表。 (IInspectable(见其他回答)建议考虑的构造。)
(2)重写ServiceMain()
,完全由克隆的代码,并更新它使用RegisterServiceCtrlHandlerEx
取代它。关键的变化是:
变化:m_hServiceStatus = RegisterServiceCtrlHandler(m_szServiceName, _Handler);
为:m_hServiceStatus = RegisterServiceCtrlHandlerEx(m_szServiceName, (LPHANDLER_FUNCTION_EX)_Handler, NULL);
但你也需要改变引用pT
和T
是this
以去除模板代码(你也可以删除该行定义为pT
);例如:
变化:hr = T::InitializeCom();
要:hr = this->InitializeCom();
做不包括基类的调用(因为这将包括对RegisterServiceCtrlHandler
的调用)。
(3)覆盖并延伸Handler()
。这就需要增加新的代码,如:(感谢IInspectable(见其他答案)帮助指向我在此位正确的方向)
void CServiceModule::Handler(_In_ DWORD dwOpcpde) throw()
{
switch (dwOpcode)
{
case SERVICE_CONTROL_PRESHUTDOWN:
this->OnPreShutdown();
break;
default:
__super::Handler(dwOpcode);
break;
}
}
(4)你可以现在实施OnPreShutdown()
方法:
void CServiceModule::OnPreShutdown() throw()
{
// custom handling code
// ...
// note: service must shutdown in this handler, so finish
// by notifying this to SCM.
SetServiceStatus(SERVICE_STOPPED);
}
注意,Windows预计预关闭期间要停止的服务,如果你使用它,而一旦上述实施您的服务将不会收到任何SERVICE_CONTROL_SHUTDOWN
消息(因为它应该已经关闭)。为了让Windows继续关闭其他服务,您需要在OnPreShutdown()
方法的末尾添加最后的SetServiceStatus(SERVICE_STOPPED)
呼叫。
然后底线是:ATL尚未更新以包含[功能](https:// msdn。microsoft.com/en-us/library/windows/desktop/ms685058.aspx),至少在Windows XP/Server 2003之后已经出现了。这有点令人难过。虽然,在分析和解决方案方面做得很好。 – IInspectable