Как я могу отклонить запрос Windows «Service Stop» в ATL 7? - PullRequest
2 голосов
/ 08 апреля 2010

У меня есть служба Windows, построенная на классе CAtlServiceModuleT ATL 7. Эта служба обслуживает COM-объекты, которые используются различными приложениями в системе, и эти другие приложения, естественно, начинают получать ошибки, если служба остановлена, пока они еще работают.

Я знаю, что библиотеки ATL решают эту проблему, возвращая S_OK в DllCanUnloadNow(), если GetLockCount() в CComModule возвращает 0. То есть он проверяет, что никто не использует COM-объекты, обслуживаемые DLL. Я хочу эквивалентную функциональность в сервисе.

Вот что я сделал в моем переопределении CAtlServiceModuleT::OnStop():

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

    BaseClass::OnStop();
}

Теперь, когда пользователь пытается остановить службу с панели «Службы», ему выдается сообщение об ошибке:

Windows не удалось остановить службу XYZ на локальном компьютере. Служба не вернула ошибку. Это может быть внутренняя ошибка Windows или внутренняя ошибка службы. Если проблема не устранена, обратитесь к системному администратору.

Запрос на остановку действительно отклонен, но, по-видимому, сервис находится в плохом состоянии. Второй запрос на остановку приводит к этому сообщению об ошибке:

Windows не удалось остановить службу XYZ на локальном компьютере.

Ошибка 1061: в данный момент служба не может принимать управляющие сообщения.

Интересно, что служба на самом деле останавливается в этот раз (хотя я бы предпочел этого не делать, поскольку все еще имеются выдающиеся ссылки на COM).

У меня два вопроса:

  1. Считается ли плохой практикой отказ от остановки при запросе?
  2. Есть ли вежливый способ показать, что в запросе Stop отказано; тот, который не переводит Сервис в плохое состояние?

Ответы [ 3 ]

1 голос
/ 24 сентября 2011

Когда счетчик блокировок 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 голос
/ 08 апреля 2010

Вы не можете сделать это. После того, как SCM отправит SERVICE_CONTROL_STOP в ваш сервис, вы должны остановиться.

Если другие ваши приложения также являются сервисами, вы можете сделать их зависимостями в SCM. Конечно, если приложения, использующие этот сервис, являются обычными приложениями, которые нельзя использовать.

0 голосов
/ 02 июля 2016

В вашем конструкторе обновите m_status.dwControlsAccepted, удалив SERVICE_ACCEPT_STOP.Например:

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