简体   繁体   English

如何将PreShutdown事件添加到ATL服务?

[英]How to add PreShutdown event to ATL service?

I've inherited the C++ code for an old ATL based service which contains the basic structures from the old ATL wizards (_tWinMain(), Run(), RunMessageLoop() etc). 我已经为旧的基于ATL的服务继承了C ++代码,其中包含旧的ATL向导(_tWinMain(),Run(),RunMessageLoop()等)的基本结构。

In particular, this code already handles "Shutdown" and "Stop" events - and I've been asked to add an additional closedown item into the "PreShutdown" event. 特别是,这段代码已经处理了“ Shutdown”和“ Stop”事件-并且我被要求在“ PreShutdown”事件中添加一个额外的closedown项目。

I've added the SERVICE_ACCEPT_PRESHUTDOWN option.. 我添加了SERVICE_ACCEPT_PRESHUTDOWN选项。

m_status.dwControlsAccepted |= SERVICE_ACCEPT_PRESHUTDOWN

..but I can't see how to catch the resulting event - SERVICE_CONTROL_PRESHUTDOWN - as ATL appears to provide for "OnShutdown" and "OnClose" methods but doesn't contain an entry for "OnPreShutdown" that I can see. ..但我看不到如何捕获结果事件-SERVICE_CONTROL_PRESHUTDOWN-ATL似乎提供了“ OnShutdown”和“ OnClose”方法,但没有包含我看到的“ OnPreShutdown”条目。

Can anyone point me at something which will allow me to add an OnPreShutdown to my existing code? 谁能指出我可以使我在现有代码中添加OnPreShutdown的东西?

Implementing services using ATL is covered at ATL Services . ATL服务介绍了使用ATL实施服务 To handle control requests that a default ATL-generated service wouldn't, you need to extend the default-generated Handler implementation. 要处理默认ATL生成的服务不会处理的控制请求,您需要扩展默认生成的Handler实现。

This is a rough sketch for what you need to do (in addition to registering for the control request, which you already are): 这是您需要做的粗略草图(除了注册控制请求之外,您已经是):

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);
    }
}

As an alternative, you could override the OnUnknownRequest member in your custom implementation. 或者,您可以在自定义实现中覆盖OnUnknownRequest成员。 This member is called for all codes that aren't handled by the default implementation: 对于默认实现未处理的所有代码,将调用此成员:

void CMyServiceModule::OnUnknownRequest(DWORD dwOpcode) {
    if (SERVICE_CONTROL_PRESHUTDOWN == dwOpcode) {
        // Perform custom handling
    }
    else {
        // Possibly handle other control codes
    }
}

The main problem is that ATL uses RegisterServiceCtrlHandler instead of RegisterServiceCtrlHandlerEx ; 主要问题是ATL使用RegisterServiceCtrlHandler而不是RegisterServiceCtrlHandlerEx ; only the second of these actually registers for the SERVICE_CONTROL_PRESHUTDOWN message. 这些中只有第二个实际注册了SERVICE_CONTROL_PRESHUTDOWN消息。 Further, ATL does not contain an inheritable template for OnPreShutdown(). 此外,ATL不包含OnPreShutdown()的可继承模板。

The solution is therefore in four parts: 因此,解决方案分为四个部分:

(1) Update the list of accepted control messages to include the SERVICE_ACCEPTED_PRESHUTDOWN message. (1)更新接受的控制消息列表,以包括SERVICE_ACCEPTED_PRESHUTDOWN消息。 You can remove the SERVICE_ACCEPTED_SHUTDOWN as Windows deems the service to be shut down once you have handled the Pre-Shutdown so you will never receive this message. 您可以删除SERVICE_ACCEPTED_SHUTDOWN因为一旦Windows处理您认为“关闭前”服务即被关闭,那么您将永远不会收到此消息。 In my case the change was to the list of controls set in the overridden PreMessageLoop() method: 就我而言,更改是在覆盖的PreMessageLoop()方法中设置的控件列表:

I changed: m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; 我更改了: m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;

To: m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PRESHUTDOWN; 到: m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PRESHUTDOWN; m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PRESHUTDOWN;

However you may not have overridden this method - so you should simply change that list at whatever point you are setting this value. 但是,您可能没有重写此方法-因此您应该在设置此值的任何时候简单地更改该列表。 (IInspectable (see other answer) recommends considering the constructor.) (IInspectable(请参阅其他答案)建议考虑构造函数。)

(2) Override ServiceMain() , replacing it entirely by cloning the code and updating it to use RegisterServiceCtrlHandlerEx . (2)覆盖ServiceMain() ,通过克隆代码并将其更新为使用RegisterServiceCtrlHandlerEx来完全替换它。 The key change is: 关键更改是:

Change: m_hServiceStatus = RegisterServiceCtrlHandler(m_szServiceName, _Handler); 更改: m_hServiceStatus = RegisterServiceCtrlHandler(m_szServiceName, _Handler);

To: m_hServiceStatus = RegisterServiceCtrlHandlerEx(m_szServiceName, (LPHANDLER_FUNCTION_EX)_Handler, NULL); 若要: m_hServiceStatus = RegisterServiceCtrlHandlerEx(m_szServiceName, (LPHANDLER_FUNCTION_EX)_Handler, NULL);

but you will also need to change references to pT and T to be this in order to remove the templating code (you can also remove the line defining pT ); 但是您还需要将对pTT引用更改this ,以删除模板代码(也可以删除定义pT的行); for example: 例如:

Change: hr = T::InitializeCom(); 更改: hr = T::InitializeCom();

To: hr = this->InitializeCom(); 收件人: hr = this->InitializeCom();

Do not include a call to the base class (as this would include a call to RegisterServiceCtrlHandler ). 包括基类的调用(因为这将包括一个呼叫RegisterServiceCtrlHandler )。

(3) Override and extend Handler() . (3)重写并扩展Handler() This requires the addition of new code such as: 这需要添加新的代码,例如:

void CServiceModule::Handler(_In_ DWORD dwOpcpde) throw()
{
    switch (dwOpcode)
    {
        case SERVICE_CONTROL_PRESHUTDOWN:
            this->OnPreShutdown();
            break;

        default:
            __super::Handler(dwOpcode);
            break;
    }
}

(Thanks to IInspectable (see other answer) for helping point me in the right direction on this bit.) (感谢IInspectable(请参见其他答案),在此方面帮助我指出了正确的方向。)

(4) You can now implement an OnPreShutdown() method: (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);
}

Note that Windows expects the service to be stopped during the pre-shutdown if you use it, and once the above is implemented your service will not receive any SERVICE_CONTROL_SHUTDOWN messages (as it should already be shut down). 请注意,如果您使用Windows,则希望该服务在预关闭期间停止,并且一旦实现了上述功能,您的服务将不会收到任何SERVICE_CONTROL_SHUTDOWN消息(因为它应该已经关闭)。 To allow Windows to carry on shutting other services down you therefore need to add a final SetServiceStatus(SERVICE_STOPPED) call at the end of your OnPreShutdown() method. 为了使Windows能够继续关闭其他服务,因此您需要在OnPreShutdown()方法的末尾添加一个最终的SetServiceStatus(SERVICE_STOPPED)调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM