Читаем Системное программирование в среде Windows полностью

 if (!StartServiceCtrlDispatcher(DispatchTable)) ReportError(_T("Ошибка при запуске диспетчера службы."), 1, TRUE);

 /* ServiceMain начнет выполняться только после того, как ее */

 /* запустит SCM. Возврат сюда осуществляется только после того, */

 /* как завершится выполнение всех служб. */

 return;

} 

<p>Функции ServiceMain</p>

Эти функции, которые указываются в таблице диспетчеризации, фигурирующей в программе 13.1, представляют логические службы. По сути, эти функции являются усовершенствованными версиями основной программы, преобразуемой в службу, и каждая логическая служба будет активизироваться в ее собственном потоке SCM. В свою очередь, логическая служба может запускать дополнительные потоки, например, рабочие потоки сервера, которые использовались в программах serverSK и serverNP. Часто внутри службы существует только одна логическая служба. Логическая служба в программе 13.2 получена путем соответствующей адаптации основного сервера из программы 12.2. В то же время, логические службы на основе сокетов и именованных каналов могут выполняться в рамках одной и той же службы Windows, что потребует предоставления основных функций обеих служб.

Несмотря на то что функция ServiceMain является адаптированным вариантом функции main с ее параметрами, представляющими количество аргументов и содержащую их строку, между ними имеется одно незначительное отличие: функция службы должна быть объявлена с типом void, а не иметь возвращаемое значение типа int, как в случае обычной функции main.

Для регистрации обработчика управляющих команд службы, который представляет собой функцию, вызываемую SCM для осуществления управления службой, требуется дополнительный код.

<p>Регистрация управляющей программы службы</p>

Обработчик управляющих команд службы, вызываемый SCM, должен обеспечивать управление соответствующей логической службой. Возможности обработчиков такого рода в ограниченном виде иллюстрирует обработчик управляющих сигналов консоли в сервере serverSK, устанавливающий глобальный флаг завершения выполнения. Однако, прежде всего, каждая логическая служба должна немедленно зарегистрировать свой обработчик с помощью функции RegisterServiceCtrlHandlerEx. Вызов этой функции должен помещаться в начало функции ServiceMain и впоследствии нигде не повторяться. Обработчик вызывается SCM после получения запроса службы. 

RegisterServiceCtrlHandlerEx(LPCTSTR lpServiceName, LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext) 

Параметры

lpServiceName — определяемое пользователем имя службы, которое предоставляется в соответствующем поле таблицы диспетчеризации, отведенном для данной логической функции.

lpHandlerProc — адрес функции расширенного обработчика, которая описывается в следующем разделе. Расширенный обработчик был добавлен в NT5, причем функция RegisterServiceCtrlHandlerEx заменяет функцию Register-ServiceCtrlHandler. Следующий параметр также был введен в NT5.

lpContext — определяемые пользователем данные, передаваемые обработчику. Благодаря этому обработчик может различать ассоциированные с ним службы, которых может быть несколько.

В случае ошибки возвращаемое функцией значение, которым является объект SEPARARE_STATUS_HANDLE, равно 0, а для анализа ошибок могут быть использованы обычные методы.

<p>Настройка состояния службы</p>

Теперь, когда управляющая программа зарегистрирована, необходимо сразу же перевести службу в состояние SERVICE_START_PENDING, воспользовавшись для этого функцией SetServiceStatus. Функция SetServiceStatus будет применяться еще в других местах для установки различных значений параметра состояния, информируя SCM о текущем состоянии службы. Описания других возможных состояний службы, характеризуемых значениями параметра состояния, отличными от SERVICE_STATUS_PENDING, приведены в табл. 13.3.

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

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

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже