如何将 PreShutdown 事件添加到 ATL 服务?
How to add PreShutdown event to ATL service?
我继承了基于旧 ATL 的服务的 C++ 代码,其中包含旧 ATL 向导的基本结构(_tWinMain()、运行()、运行MessageLoop() 等).
特别是,这段代码已经处理了 "Shutdown" 和 "Stop" 事件 - 我被要求在 "PreShutdown" 事件中添加一个额外的关闭项。
我添加了 SERVICE_ACCEPT_PRESHUTDOWN 选项..
m_status.dwControlsAccepted |= SERVICE_ACCEPT_PRESHUTDOWN
..但我看不到如何捕获结果事件 - SERVICE_CONTROL_PRESHUTDOWN - 因为 ATL 似乎提供了 "OnShutdown" 和 "OnClose" 方法但不包含我可以看到 "OnPreShutdown" 的条目。
任何人都可以指出一些允许我向现有代码添加 OnPreShutdown 的东西吗?
ATL Services. To handle control requests that a default ATL-generated service wouldn't, you need to extend the default-generated Handler
实施中介绍了使用 ATL 实施服务。
这是您需要做的事情的粗略描述(除了注册您已经注册的控制请求):
void CMyServiceModule::Handler(DWORD dwOpcode) throw() {
if (SERVICE_CONTROL_PRESHUTDOWN == dwOpcode) {
// Perform custom handling
}
else {
// Pass all other control codes to default implementation
__super::Handler(dwOpcode);
}
}
作为替代方案,您可以在自定义实现中覆盖 OnUnknownRequest
成员。对于默认实现未处理的所有代码调用此成员:
void CMyServiceModule::OnUnknownRequest(DWORD dwOpcode) {
if (SERVICE_CONTROL_PRESHUTDOWN == dwOpcode) {
// Perform custom handling
}
else {
// Possibly handle other control codes
}
}
主要问题是ATL使用RegisterServiceCtrlHandler
而不是RegisterServiceCtrlHandlerEx
;其中只有第二个实际上注册了 SERVICE_CONTROL_PRESHUTDOWN
消息。此外,ATL 不包含 OnPreShutdown() 的可继承模板。
因此解决方案分为四个部分:
(1) 更新接受的控制消息列表以包含 SERVICE_ACCEPTED_PRESHUTDOWN
消息。您可以删除 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();
不要包括对基class的调用(因为这将包括对RegisterServiceCtrlHandler
的调用)。
(3) 覆盖和扩展 Handler()
。这需要添加新代码如:
void CServiceModule::Handler(_In_ DWORD dwOpcpde) throw()
{
switch (dwOpcode)
{
case SERVICE_CONTROL_PRESHUTDOWN:
this->OnPreShutdown();
break;
default:
__super::Handler(dwOpcode);
break;
}
}
(感谢 IInspectable(参见其他答案)帮助我在这一点上指明了正确的方向。)
(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 的服务的 C++ 代码,其中包含旧 ATL 向导的基本结构(_tWinMain()、运行()、运行MessageLoop() 等).
特别是,这段代码已经处理了 "Shutdown" 和 "Stop" 事件 - 我被要求在 "PreShutdown" 事件中添加一个额外的关闭项。
我添加了 SERVICE_ACCEPT_PRESHUTDOWN 选项..
m_status.dwControlsAccepted |= SERVICE_ACCEPT_PRESHUTDOWN
..但我看不到如何捕获结果事件 - SERVICE_CONTROL_PRESHUTDOWN - 因为 ATL 似乎提供了 "OnShutdown" 和 "OnClose" 方法但不包含我可以看到 "OnPreShutdown" 的条目。
任何人都可以指出一些允许我向现有代码添加 OnPreShutdown 的东西吗?
ATL Services. To handle control requests that a default ATL-generated service wouldn't, you need to extend the default-generated Handler
实施中介绍了使用 ATL 实施服务。
这是您需要做的事情的粗略描述(除了注册您已经注册的控制请求):
void CMyServiceModule::Handler(DWORD dwOpcode) throw() {
if (SERVICE_CONTROL_PRESHUTDOWN == dwOpcode) {
// Perform custom handling
}
else {
// Pass all other control codes to default implementation
__super::Handler(dwOpcode);
}
}
作为替代方案,您可以在自定义实现中覆盖 OnUnknownRequest
成员。对于默认实现未处理的所有代码调用此成员:
void CMyServiceModule::OnUnknownRequest(DWORD dwOpcode) {
if (SERVICE_CONTROL_PRESHUTDOWN == dwOpcode) {
// Perform custom handling
}
else {
// Possibly handle other control codes
}
}
主要问题是ATL使用RegisterServiceCtrlHandler
而不是RegisterServiceCtrlHandlerEx
;其中只有第二个实际上注册了 SERVICE_CONTROL_PRESHUTDOWN
消息。此外,ATL 不包含 OnPreShutdown() 的可继承模板。
因此解决方案分为四个部分:
(1) 更新接受的控制消息列表以包含 SERVICE_ACCEPTED_PRESHUTDOWN
消息。您可以删除 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();
不要包括对基class的调用(因为这将包括对RegisterServiceCtrlHandler
的调用)。
(3) 覆盖和扩展 Handler()
。这需要添加新代码如:
void CServiceModule::Handler(_In_ DWORD dwOpcpde) throw()
{
switch (dwOpcode)
{
case SERVICE_CONTROL_PRESHUTDOWN:
this->OnPreShutdown();
break;
default:
__super::Handler(dwOpcode);
break;
}
}
(感谢 IInspectable(参见其他答案)帮助我在这一点上指明了正确的方向。)
(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)
调用。