如何在ATL 7中拒绝Windows“服务停止”请求?

时间:2010-04-08 16:39:17

标签: com windows-services atl

我有一个基于ATL 7 CAtlServiceModuleT课程的Windows服务。此服务提供系统上各种应用程序使用的COM对象,如果服务在运行时停止,这些其他应用程序自然会开始出错。

我知道ATL DLL通过在DllCanUnloadNow()中返回S_OK来解决这个问题,如果CComModule的GetLockCount()返回0。也就是说,它会检查以确保当前没有人正在使用由DLL。我想在服务中使用相同的功能。

以下是我在覆盖CAtlServiceModuleT::OnStop()时所做的事情:

void CMyServiceModule::OnStop()
{
    if( GetLockCount() != 0 ) {
        return;
    }

    BaseClass::OnStop();
}

现在,当用户尝试从“服务”面板停止服务时,会显示一条错误消息:

  

Windows无法在本地计算机上停止XYZ服务。   该服务未返回错误。这可能是内部Windows错误或内部服务错误。   如果问题仍然存在,请与系统管理员联系。

确实拒绝了Stop请求,但它似乎使服务处于错误状态。第二个Stop请求会产生以下错误消息:

  

Windows无法在本地计算机上停止XYZ服务。

     

错误1061:此时服务无法接受控制消息。

有趣的是,这次服务确实停止了(虽然我不愿意,因为仍有未完成的COM引用)。

我有两个问题:

  1. 服务在被问及拒绝停止时被视为不良做法?
  2. 是否有礼貌的方式表示停止请求被拒绝;一个不会使服务陷入糟糕状态的人?

3 个答案:

答案 0 :(得分:1)

你不能这样做。一旦SCM向您的服务发送SERVICE_CONTROL_STOP,您就必须停止。

如果您的其他应用程序也是服务,您可以在SCM中使它们成为依赖项。当然,如果使用此服务的应用程序只是无法使用的常规应用程序。

答案 1 :(得分:1)

当ATL的锁定计数增加到1时,在SetServiceStatus()字段中省略SERVICE_ACCEPT_STOP标记,调用SERVICE_STATUS::dwControlsAccepted。然后,您根本不会收到任何SERVICE_CONTROL_STOP个请求。任何停止服务的尝试都将立即失败。当ATL的锁定计数回落到0时,再次使用指定的SetServiceStatus()标志调用SERVICE_ACCEPT_STOP

我只需要在2个(较旧的)基于ATL的服务中执行此操作,并且它运行良好。当然,我无法找出直接覆盖Lock()和Unlock()的最佳方法,所以我只是在我的服务中放了一个小循环,频繁地检查GetLockCount()并在调用时SetServiceStatus()调用{{1}}需要的。

答案 2 :(得分:0)

在构造函数中,更新m_status.dwControlsAccepted删除SERVICE_ACCEPT_STOP。例如:

CMyServiceModule::CMyServiceModule()
    : ATL::CAtlServiceModuleT<CMyServiceModule, IDS_SERVICENAME>()
{
    m_status.dw &= ~SERVICE_ACCEPT_STOP
}