2016-10-18 86 views
0

我已经继承了旧的基于ATL的服务的C++代码,该服务包含旧的ATL向导(_tWinMain(),Run(),RunMessageLoop()等)的基本结构。如何将PreShutdown事件添加到ATL服务?

特别是,这段代码已经处理了“Shutdown”和“Stop”事件 - 并且我被要求在“PreShutdown”事件中添加一个额外的闭锁项目。

我已经添加了SERVICE_ACCEPT_PRESHUTDOWN选项..

m_status.dwControlsAccepted |= SERVICE_ACCEPT_PRESHUTDOWN 

..但我看不出如何捕捉到结果事件 - SERVICE_CONTROL_PRESHUTDOWN - 作为ATL似乎为“OnShutdown”和“的OnClose”方法,但不包含我可以看到的“OnPreShutdown”条目。

任何人都可以指向我的东西,这将允许我添加一个OnPreShutdown到我现有的代码?

回答

1

的主要问题是,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);

但你也需要改变引用pTTthis以去除模板代码(你也可以删除该行定义为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)呼叫。

+0

然后底线是:ATL尚未更新以包含[功能](https:// msdn。microsoft.com/en-us/library/windows/desktop/ms685058.aspx),至少在Windows XP/Server 2003之后已经出现了。这有点令人难过。虽然,在分析和解决方案方面做得很好。 – IInspectable

1

使用ATL实施服务的范围为ATL Services。要处理默认ATL生成的服务不支持的控制请求,您需要扩展默认生成的Handler实现。

这是你需要做的(除了为控制要求,您已经是注册)什么的草图:

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 
    } 
} 
+0

首先,谢谢你的回答。其次,我已经尝试按照上面描述的方式重写Handler,但从未进入“自定义处理”块。它看起来像使用PRESHUTDOWN可能还需要覆盖ServiceMain,因为它嵌入使用RegisterServiceCtrlHandler而不是RegisterServiceCtrlHandlerEx(这似乎是preshutdown cotrol消息所必需的)。我会仔细看看OnUnknownRequest,看看我能否在那里得到消息。 – n4m16

+0

我刚刚证实,我没有得到OnUnknownRequest中的关机前控制消息。 (可能是因为ATL使用Handler通过RegisterServiceCtrlHandler而不是HandlerEx通过RegisterServiceCtrlHandlerEx,但我不是100%确定的。) – n4m16

+0

@Nick:这不完全清楚从[documentation](https://msdn.microsoft.com /en-us/library/xt3s14t0.aspx),但是你必须在你的构造函数中添加'm_status.dwControlsAccepted | = SERVICE_ACCEPT_PRESHUTDOWN;'。在任何其他时间设置它可能为时已晚。既然你没有在你的问题中提到它,你在哪里更新了'm_status'成员? – IInspectable

相关问题