Как я могу гарантировать, что Windows 2008 R2 будет передавать служебное уведомление SERVICE_CONTROL_PRESHUTDOWN службе - PullRequest
1 голос
/ 05 декабря 2011

Я пишу сервис с использованием простого C ++ и Windows API и хочу, чтобы он получал уведомления PRESHUTDOWN, доступные из Windows 2008 R2.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms685996(v=vs.85).aspx

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

Мой ServiceMain зацикливается, выводя сообщение каждые 5 секунд.

Я устанавливаю dwControlsAcceptpted:

SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PRESHUTDOWN

Я получаю уведомление SERVICE_CONTROL_STOP в моем обратном вызове ServiceControl.

Если я запусту свой сервис и позвоню

sc query "MyService"

Там написано:

(STOPPABLE, NOT_PAUSABLE, ACCEPTS_PRESHUTDOWN)

Я записываю запись в файл журнала, как только получаю уведомление о контроле сервиса, прежде чем даже посмотреть, что это такое.

Когда я выключаюсь, Windows говорит о том, что «Остановка MyService» большими белыми буквами на экране, немного ждет, затем завершает работу.

Тем не менее:

Основной цикл продолжает запись в файл журнала. Файл журнала не содержит ссылок на какие-либо попытки управления службами.

Затем Windows перестает закрывать мой сервис и просто убивает его.

Теперь, если я делаю то же самое, но регистрируюсь на SHUTDOWN вместо PRESHUTDOWN, я вижу все уведомления в файле журнала, которые я ожидаю увидеть (хотя не могу продлить период выключения, как мы можем ' сделать это из уведомления об остановке).

Единственное изменение в коде - удаление трех букв «PRE» в вызовах для установки статуса.

Я даже не дошел до того, что могу начать увеличивать dwCheckPoint - подсистема Windows не уведомляет меня.

Windows знает, что я ищу сообщения перед выключением, о чем свидетельствует "запрос sc", есть ли что-то, что может помешать ему получить сообщение перед выключением?

Соответствующие методы:

При сообщении о состоянии (SCM сообщает, что служба запущена, довольно счастливо)

VOID ServiceReportStatus (DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
    // Fill in the SERVICE_STATUS structure.
    g_serviceStatus.dwCurrentState = dwCurrentState;
    g_serviceStatus.dwWin32ExitCode = dwWin32ExitCode;
    g_serviceStatus.dwWaitHint = dwWaitHint;

    switch(dwCurrentState)
    {
    case SERVICE_START_PENDING:
    case SERVICE_STOP_PENDING:
    case SERVICE_CONTINUE_PENDING:
    case SERVICE_PAUSE_PENDING:
        g_serviceStatus.dwControlsAccepted = 0;
        break;
    default:
        g_serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PRESHUTDOWN;
    }

    // Report the status of the service to the SCM.
    SetServiceStatus (g_serviceStatusHandle, &g_serviceStatus);
}

Когда я получаю сообщение:

VOID WINAPI ServiceCtrlHandler (DWORD dwCtrl)
{
    LOG(eDeveloper10, L"ServiceCtrlHandler", L"Decoding SvcControl %d\n", dwCtrl);
   switch(dwCtrl) 
   {
      case SERVICE_CONTROL_PRESHUTDOWN:
          {
             LOG(eDeveloper10, L"ServiceCtrlHandler", L"Received SERVICE_CONTROL_PRESHUTDOWN\n");
             ServiceReportStatus(SERVICE_STOP_PENDING, NO_ERROR, 10000);

             // Signal the service to stop.
             SetEvent(g_serviceStopEvent);
             break;
          }
    }
}

Это больше, но ничего полезного для этого примера, поскольку я даже не вижу журнал (если я не регистрируюсь вместо SHUTDOWN).

ServiceCtrlHandler всегда возвращается быстро, я не блокирую здесь, я не собираюсь заходить сюда для обработчика перед выключением. Регистрация для PRESHUTDOWN и SHUTDOWN тоже не помогает. Я пробовал это на двух машинах Windows 2008R2, одной виртуальной машине, одной физической, с одинаковыми результатами. Сервис скомпилирован как двоичный файл x64.

Есть идеи?

Некоторые примеры журналов, этот журнал, когда я запрашиваю уведомление о выключении:

L0  T2672 2781140 [CDbgEntry::LoadSystemDetails()] System Details Follow:

   Computer Name     : \\****
   Domain/Workgroup  : **** [Domain]
   User Name         : SYSTEM
   Operating System  : Windows NT Version 6.1 Build 7600
   Service Pack      : None.    
   Terminal Services : Terminal Services Present
   System Root       : C:\Windows\system32
   User's Windir     : C:\Windows


This file is recording debug messages with a maximum level of 10
L10 T2672 2781140 [ServiceInitialize] Service initialised, waiting for stop event
L10 T2672 2786140 [ServiceInitialize] Still waiting for stop event.
L10 T2668 2789328 [ServiceCtrlHandler] Decoding SvcControl 5
L10 T2668 2789328 [ServiceCtrlHandler] Received SERVICE_CONTROL_SHUTDOWN
L10 T2672 2789328 [ServiceInitialize] Stop event detected
L10 T2672 2789328 [ServiceInitialize] Blocking service shutdown
L10 T2672 2790328 [ServiceInitialize] Blocking service shutdown
L10 T2672 2791328 [ServiceInitialize] Blocking service shutdown
L10 T2672 2792328 [ServiceInitialize] Blocking service shutdown
L10 T2672 2793328 [ServiceInitialize] Blocking service shutdown
L10 T2672 2794328 [ServiceInitialize] Blocking service shutdown
L10 T2672 2795437 [ServiceInitialize] Blocking service shutdown
L10 T2672 2796437 [ServiceInitialize] Blocking service shutdown

Обратите внимание, что отключение службы блокировки является правильным поведением в данном конкретном случае.

Если я зарегистрируюсь в PRESHUTDOWN, я вообще ничего не получу от ServiceCtrlHandler:

L0  T2244 516625 [CDbgEntry::LoadSystemDetails()] System Details Follow:

   Computer Name     : \\****
   Domain/Workgroup  : **** [Domain]
   User Name         : SYSTEM
   Operating System  : Windows NT Version 6.1 Build 7600
   Service Pack      : None.
   Terminal Services : Terminal Services Present
   System Root       : C:\Windows\system32
   User's Windir     : C:\Windows


This file is recording debug messages with a maximum level of 10
L10 T2244 516453 [ServiceInitialize] Service initialised, waiting for stop event
L10 T2244 521625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 526625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 531625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 536625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 541625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 546625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 551625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 556625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 561625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 566625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 571625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 576625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 581625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 586625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 591625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 596625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 601625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 606625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 611625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 616625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 621625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 626625 [ServiceInitialize] Still waiting for stop event.
L10 T2244 631625 [ServiceInitialize] Still waiting for stop event.

Никаких событий, пока окна не сдаются и не убивают его.

1 Ответ

3 голосов
/ 06 декабря 2011

Согласно документации , SERVICE_CONTROL_PRESHUTDOWN отправляется только на расширенный обратный вызов . Попробуйте использовать RegisterServiceCtrlHandlerEx .

...