Я пишу локальное приложение-службу, используя C ++, и не могу найти правильный способ регистрации для предварительного уведомления о завершении работы (для ОС более поздней, чем Windows XP). Я считаю, что SERVICE_CONTROL_PRESHUTDOWN уведомление было добавлено с Vista, но когда вы вызываете SetServiceStatus, нам нужно указать:
dwServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_PRESHUTDOWN;
или же
dwServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PRESHUTDOWN;
Вы не можете согласиться с отключением и предварительным отключением, если ваша служба правильно закодирована. Документация прямо заявляет об этом.
От http://msdn.microsoft.com/en-us/library/windows/desktop/ms683241(v=vs.85).aspx:
Ссылаясь на SERVICE_CONTROL_PRESHUTDOWN
: «Служба, которая обрабатывает это уведомление, блокирует выключение системы пока сервис не остановится или истекает интервал ожидания предварительного отключения, указанный в SERVICE_PRESHUTDOWN_INFO. »
На той же странице раздел о SERVICE_CONTROL_SHUTDOWN
добавляет: «Обратите внимание, что службы, которые регистрируются для уведомлений SERVICE_CONTROL_PRESHUTDOWN не может получить это уведомление, потому что они уже остановились.»
Таким образом, правильным способом является установка dwControlsAccepted для включения либо SERVICE_ACCEPT_SHUTDOWN, либо SERVICE_ACCEPT_PRESHUTDOWN, в зависимости от ваших потребностей, но не для обоих одновременно.
Но обратите внимание, что вы, вероятно, хотите принять больше элементов управления. Вам следует всегда разрешить хотя бы SERVICE_CONTROL_INTERROGATE
и почти наверняка позволит SERVICE_CONTROL_STOP
поскольку без последнего служба не может быть остановлена (например, для удаления программного обеспечения), и процесс должен быть принудительно завершен (т.е. убитый).
Как отмечалось в комментариях выше, вам нужно будет выбрать либо SERVICE_ACCEPT_SHUTDOWN, либо SERVICE_ACCEPT_PRESHUTDOWN (Vista или более поздняя версия). Если вы используете SERVICE_ACCEPT_PRESHUTDOWN, вам нужно будет зарегистрировать свой сервис в SCM, используя RegisterServiceCtrlHandlerEx вместо RegisterServiceCtrlHandler, иначе вы не будете получать уведомления перед отключением. Прототип обработчика также изменяется с Handler на HandlerEx.
Следует также отметить, что обработка событий чистого отключения ограничена 5 секундами в Windows Server 2012 (и, вероятно, Windows 8), 12 секундами в Windows 7 и Windows Server 2008, 20 секундами в Windows XP до остановки службы при остановке. Это причина, почему вам может потребоваться уведомление перед отключением. Вы можете изменить это в \\ HKLM \ SYSTEM \ CurrentControlSet \ Control \ WaitToKillServiceTimeout.
Эти два уведомления кажутся разными, как я понял из документации. Если вам действительно нужно, чтобы ваша служба получила уведомление перед отключением, вам необходимо: dwServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_PRESHUTDOWN;
Но если вы также хотите, чтобы ваша служба получала уведомления о завершении работы, вам следует воспользоваться вторым вариантом.