Джонсон Харт - Системное программирование в среде Windows
Обработчик службы должен устанавливать состояние службы при каждом вызове, даже если ее состояние не менялось.
Далее, любой из потоков службы может в любой момент вызвать функцию SetServiceStatus, чтобы сообщить данные, характеризующие степень выполнения задачи, а также предоставить информацию об ошибках или иную информацию, причем для периодического обновления состояния многие службы часто выделяют отдельный поток. Длительность временного промежутка между вызовами обновления состояния указывается в одном из полей структуры данных, выступающей в качестве параметра. Если в пределах указанного промежутка времени состояние не обновлялось, то SCM может предположить, что произошла ошибка.
BOOL SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus, LPSERVICE STATUS lpServiceStatus)
ПараметрыhServiceStatus — дескриптор типа SERVICE_STATUS_HANDLE, возвращенный функцией RegisterCtrlHandlerEx. Поэтому вызову функции SetServiceStatus должен предшествовать вызов функции RegisterCtrlHandlerEx.
lpServiceStatus — указатель на структуру SERVICE_STATUS, содержащую описание свойств, состояния и возможностей службы.
Структура SERVICE_STATUS
Ниже приведено определение структуры SERVICE_STATUS.
typedef struct _SERVICE_STATUS {
DWORD dwServiceType;
DWORD dwCurrentState;
DWORD dwControlsAccepted;
DWORD dwWin32ExitCode;
DWORD dwServiceSpecificExitCode;
DWORD dwCheckPoint;
DWORD dwWaitHint;
} SERVICE_STATUS, *LPSERVICE_STATUS;
ПараметрыdwWin32ExitCode — обычный код завершения потока, используемый логической службой. Служба должна установить этот код равным NO_ERROR в процессе выполнения и при нормальном завершении.
dwServiceSpecificExitCode — может использоваться в качестве кода завершения, когда ошибка возникает при запуске или остановке службы, но это значение игнорируется, если значение параметра dwWin32ExitCode не было установлено равным ERROR_SERVICE_SPECIFIC_ERROR.
dwCheckPoint — служба должна периодически увеличивать значение этого параметра для индикации выполнения на всех стадиях, включая стадии инициализации и остановки. Этот параметр не действует и должен устанавливаться равным 0, если служба не находится в состоянии запуска, остановки, паузы и не выполняет никаких длительных операций.
dwWaitHint — ожидаемая длительность интервалов времени (в миллисекундах) между последовательными вызовами функции SetServiceStatus, осуществляемыми с увеличенным значением параметра dwCheckPoint или измененным значением параметра dwCurrentState. Как уже отмечалось ранее, если на протяжении этого промежутка времени вызова функции SetServiceStatus не происходит, то SCM предполагает, что это вызвано возникновением ошибки.
Остальные элементы структуры SERVICE_STATUS обсуждаются ниже по отдельности.
Тип службыПараметр dwServiceType должен иметь одно из значений, описанных в таблице 13.1.
В наших примерах в качестве типа службы почти всегда будет предполагаться тип SERVICE_WIN32_OWN_PROCESS, но из приведенных в таблице значений видно, что службы могут играть множество различных ролей.
Таблица 13.1. Типы служб
Значение Описание SERVICE WIN32 OWN PROCESS Указывает на службу Windows, выполняющуюся в собственном процессе с собственными ресурсами. Используется в программе 13.2. SERVICE_WIN32_SHARE_PROCESS Указывает на службу Windows, разделяющую процесс с другими службами, в результате чего несколько служб могут совместно использовать одни и те же ресурсы, переменные окружения и так далее. SERVICE_KERNEL_DRIVER Указывает на драйвер устройства Windows. SERVICE_FILE_SYSTEM_DRIVER Определяет драйвер файловой системы Windows. SERVICE_INTERACTIVE_PROCESS Указывает на процесс службы Windows, который может взаимодействовать с пользователем через рабочий стол. Состояние службыЗначение параметра dwCurrentState указывает на текущее состояние службы. Возможные значения этого параметра перечислены в табл. 13.2.
Таблица 13.2. Значения параметра состояния службы
Значение Описание SERVICE_STOPPED Служба не выполняется. SERVICE_START_PENDING Служба находится на стадии запуска, но пока не готова отвечать на запросы. Например, могут еще не быть запущены рабочие потоки. SERVICE_STOP_PENDING Служба находится на стадии остановки, но еще не завершила своего выполнения. Например, мог быть установлен глобальный флаг завершения, но рабочие потоки еще не успели на это отреагировать. SERVICE_RUNNING Служба выполняется. SERVICE CONTINUE_PENDING Служба переходит в состояние выполнения после нахождения в состоянии паузы. SERVICE_PAUSE_PENDING Служба переходит в состояние паузы, но ее безопасное нахождение в этом состоянии пока не обеспечено. SERVICE PAUSED Служба находится в состоянии паузы. Воспринимаемые управляющие кодыПараметр dwControlsAccepted определяет управляющие коды, которые служба будет воспринимать и обрабатывать с помощью своего обработчика (см. следующий раздел). В табл. 13.3 указаны четыре возможных значения, которые могут объединяться посредством операции поразрядного "или" (|). Версия программы serverSK, которую мы впоследствии разработаем, будет воспринимать лишь три первых значения. Дополнительные значения приведены в разделе MSDN, содержащем описание структуры SERVICE_STATUS.
Таблица 13.3. Коды, воспринимаемые службой (неполный перечень)
Значение Описание SERVICE_ACCEPT_STOP Разрешает посылку команды SERVICE_CONTROL_STOP. SERVICE_ACCEPT_PAUSE_CONTINUE Разрешает посылку команд SERVICE_CONTROL_PAUSE и SERVICE_CONTROL_CONTINUE. SERVICE_ACCEPT_SHUTDOWN Уведомляет службу о прекращении работы системы. Это дает системе возможность послать службе команду SERVICE_CONTROL_SHUTDOWN. SERVICE_ACCEPT_PARAMCHANGE Требуется NT5. Обеспечивает изменение параметров запуска без выполнения самого перезапуска. Соответствующей командой является SERVICE_CONTROL_PARAMCHANGEСпецифический для службы код
После того как обработчик зарегистрирован и для службы установлено состояние SERVICE_START_PENDING, служба может инициализировать себя и вновь установить свое состояние. Если говорить о преобразованной версии serverSK, то сразу же после того, как сокеты будут инициализированы, а сервер готов к работе с клиентами, должно быть установлено состояние SERVICE_RUNNING.
Обработчик управляющих команд службы
Обработчик управляющих команд службы, то есть функция косвенного вызова, определяемая с помощью функции RegisterServiceCtrlHandlerEx, имеет следующий прототип:
DWORD WINAPI HandlerEx(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
dwControl — обозначает фактическую управляющую команду, поступившую в обработчик от SCM. До появления NT5 и введения функции RegisterServiceCtrlHandlerEx этот параметр был единственным параметром обработчика.
Всего существует 14 возможных значений параметра dwControl, включая те, которые перечислены в табл. 13.3, хотя некоторые команды поддерживаются только в NT5 или XP. Нас будут интересовать следующие значения, которые используются в примере:
SERVICE_CONTROL_STOP
SERVICE_CONTROL_PAUSE
SERVICE_CONTROL_CONTINUE
SERVICE_CONTROL_INTERROGATE
SERVICE_CONTROL_SHUTDOWN
Разрешены также пользовательские значения, определяемые в интервале 128-255, однако нам они не понадобятся.
dwEventType — обычно принимает значение 0, в то время как ненулевые значения используются для управления устройствами, но рассмотрение этого вопроса выходит за рамки данной книги. Параметр dwEventType определяет дополнительную информацию, которая требуется соответствующим событиям.
Наконец, lpContext — пользовательские данные, передаваемые в функцию RegisterServiceCtrlHandlerEx во время регистрации обработчика.