Харт Джонсон М.
Шрифт:
Несмотря на то что функция ServiceMain является адаптированным вариантом функции main с ее параметрами, представляющими количество аргументов и содержащую их строку, между ними имеется одно незначительное отличие: функция службы должна быть объявлена с типом void, а не иметь возвращаемое значение типа int, как в случае обычной функции main.
Для регистрации обработчика управляющих команд службы, который представляет собой функцию, вызываемую SCM для осуществления управления службой, требуется дополнительный код.
Регистрация управляющей программы службы
Обработчик управляющих команд службы, вызываемый SCM, должен обеспечивать управление соответствующей логической службой. Возможности обработчиков такого рода в ограниченном виде иллюстрирует обработчик управляющих сигналов консоли в сервере serverSK, устанавливающий глобальный флаг завершения выполнения. Однако, прежде всего, каждая логическая служба должна немедленно зарегистрировать свой обработчик с помощью функции RegisterServiceCtrlHandlerEx. Вызов этой функции должен помещаться в начало функции ServiceMain и впоследствии нигде не повторяться. Обработчик вызывается SCM после получения запроса службы.
lpServiceName — определяемое пользователем имя службы, которое предоставляется в соответствующем поле таблицы диспетчеризации, отведенном для данной логической функции.
lpHandlerProc — адрес функции расширенного обработчика, которая описывается в следующем разделе. Расширенный обработчик был добавлен в NT5, причем функция RegisterServiceCtrlHandlerEx заменяет функцию Register-ServiceCtrlHandler. Следующий параметр также был введен в NT5.
lpContext — определяемые пользователем данные, передаваемые обработчику. Благодаря этому обработчик может различать ассоциированные с ним службы, которых может быть несколько.
В случае ошибки возвращаемое функцией значение, которым является объект SEPARARE_STATUS_HANDLE, равно 0, а для анализа ошибок могут быть использованы обычные методы.
Настройка состояния службы
Теперь, когда управляющая программа зарегистрирована, необходимо сразу же перевести службу в состояние SERVICE_START_PENDING, воспользовавшись для этого функцией SetServiceStatus. Функция SetServiceStatus будет применяться еще в других местах для установки различных значений параметра состояния, информируя SCM о текущем состоянии службы. Описания других возможных состояний службы, характеризуемых значениями параметра состояния, отличными от SERVICE_STATUS_PENDING, приведены в табл. 13.3.
Обработчик службы должен устанавливать состояние службы при каждом вызове, даже если ее состояние не менялось.
Далее, любой из потоков службы может в любой момент вызвать функцию SetServiceStatus, чтобы сообщить данные, характеризующие степень выполнения задачи, а также предоставить информацию об ошибках или иную информацию, причем для периодического обновления состояния многие службы часто выделяют отдельный поток. Длительность временного промежутка между вызовами обновления состояния указывается в одном из полей структуры данных, выступающей в качестве параметра. Если в пределах указанного промежутка времени состояние не обновлялось, то SCM может предположить, что произошла ошибка.
hServiceStatus — дескриптор типа SERVICE_STATUS_HANDLE, возвращенный функцией RegisterCtrlHandlerEx. Поэтому вызову функции SetServiceStatus должен предшествовать вызов функции RegisterCtrlHandlerEx.
lpServiceStatus — указатель на структуру SERVICE_STATUS, содержащую описание свойств, состояния и возможностей службы.
Структура SERVICE_STATUS
Ниже приведено определение структуры SERVICE_STATUS.
dwWin32ExitCode — обычный код завершения потока, используемый логической службой. Служба должна установить этот код равным NO_ERROR в процессе выполнения и при нормальном завершении.
dwServiceSpecificExitCode — может использоваться в качестве кода завершения, когда ошибка возникает при запуске или остановке службы, но это значение игнорируется, если значение параметра dwWin32ExitCode не было установлено равным ERROR_SERVICE_SPECIFIC_ERROR.