Программирование для Windows NT (том 2)

Состояние сервиса


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

BOOL SetServiceStatus(

  SERVICE_STATUS_HANDLE sshServiceStatus, // идентификатор

                                          // состояния сервиса

  LPSERVICE_STATUS lpssServiceStatus);    // адрес структуры,

                               // содержащей состояние сервиса

Через параметр sshServiceStatus функции SetServiceStatus вы должны передать идентификатор состояния сервиса, полученный от функции RegisterServiceCtrlHandler.

В параметре lpssServiceStatus вы должны передать адрес предварительно заполненной структуры типа SERVICE_STATUS:

typedef struct _SERVICE_STATUS 

{

  DWORD dwServiceType;       // тип сервиса

  DWORD dwCurrentState;      // текущее состояние сервиса

  DWORD dwControlsAccepted;  // обрабатываемые команды



  DWORD dwWin32ExitCode;     // код ошибки при запуске

                             // и остановке сервиса

  DWORD dwServiceSpecificExitCode; // специфический код ошибки

  DWORD dwCheckPoint;        // контрольная точка при

                             // выполнении длительных операций

  DWORD dwWaitHint;          // время ожидания

} SERVICE_STATUS, *LPSERVICE_STATUS;

В поле dwServiceType необходимо записать один из перечисленных ниже флагов, определяющих тип сервиса:

Флаг

Описание

SERVICE_WIN32_OWN_PROCESS

Сервис работает как отдельный процесс

SERVICE_WIN32_SHARE_PROCESS

Сервис работает вместе с другими сервисами в рамках одного и того же процесса

SERVICE_KERNEL_DRIVER

Сервис представляет собой драйвер операционной системы Microsoft Windows NT

SERVICE_FILE_SYSTEM_DRIVER

Сервис является драйвером файловой системы

SERVICE_INTERACTIVE_PROCESS 

Сервисный процесс может взаимодействовать с программным интерфейсом рабочего стола Desktop

В поле dwCurrentState вы должны записать текущее состояние сервиса. Здесь можно использовать одну из перечисленных ниже констант:

Константа

Состояние сервиса

SERVICE_STOPPED

Сервис остановлен

SERVICE_START_PENDING

Сервис находится в состоянии запуска, но еще не работает

SERVICE_STOP_PENDING

Сервис находится в состоянии остановки, но еще не остановился

SERVICE_RUNNING

Сервис работает

SERVICE_CONTINUE_PENDING

Сервис начинает запускаться после временной остановки, но еще не работает

SERVICE_PAUSE_PENDING

Сервис начинает переход в состояние временной остановки, но еще не остановился

SERVICE_PAUSED

Сервис находится в состоянии верменной остановки

<
Задавая различные значения в поле dwControlsAccepted, вы можете указать, какие команды обрабатывает сервис. Ниже приведен список возможных значений:

Значение

Команды,, которые может воспринимать сервис

SERVICE_ACCEPT_STOP

Команда остановки сервиса SERVICE_CONTROL_STOP

SERVICE_ACCEPT_PAUSE_CONTINUE

Команды временной остановки SERVICE_CONTROL_PAUSE и продолжения работы после временной остановки SERVICE_CONTROL_CONTINUE

SERVICE_ACCEPT_SHUTDOWN

Команда остановки при завершении работы операционной системы SERVICE_CONTROL_SHUTDOWN

Значение в поле dwWin32ExitCode определяет код ошибки WIN32, который используется для сообщения о возникновении ошибочной ситуации при запуске и остановки сервиса. Если в этом поле указать значение ERROR_SERVICE_SPECIFIC_ERROR, то будет использован специфический для данного сервиса код ошибки, указанной в поле dwServiceSpecificExitCode структуры SERVICE_STATUS. Если ошибки нет, в поле dwWin32ExitCode необходимо записать значение NO_ERROR.

Поле dwServiceSpecificExitCode используется в том случае, когда в поле dwWin32ExitCode указано значение ERROR_SERVICE_SPECIFIC_ERROR.

Теперь о поле dwCheckPoint.

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

Содержимое поля dwWaitHint определяет ожидаемое время выполнения (в миллисекундах) длительной операции запуска, остановки или продолжения работы после временной остановки. Если за указанное время не изменится содержимое полей dwCheckPoint или dwCurrentState, процесс управления сервисами будет считать, что произошла ошибка.

В наших примерах для сообщения текущего состояния сервиса процессу управления сервисами мы используем функцию ReportStatus, исходный текст которой приведен ниже:

void ReportStatus(DWORD dwCurrentState,

       DWORD dwWin32ExitCode, DWORD dwWaitHint)



{

  static DWORD dwCheckPoint = 1;

  if(dwCurrentState == SERVICE_START_PENDING)

    ss.dwControlsAccepted = 0;

  else

    ss.dwControlsAccepted = SERVICE_ACCEPT_STOP;

  ss.dwCurrentState  = dwCurrentState;

  ss.dwWin32ExitCode = dwWin32ExitCode;

  ss.dwWaitHint      = dwWaitHint;

  if((dwCurrentState == SERVICE_RUNNING)

     (dwCurrentState == SERVICE_STOPPED))

    ss.dwCheckPoint = 0;

  else

    ss.dwCheckPoint = dwCheckPoint++;

  SetServiceStatus(ssHandle, &ss);

}

При заполнении структуры SERVICE_STATUS  эта функция проверяет содержимое поля dwCurrentState. Если сервис находится в состоянии ожидания запуска, в поле допустимых команд dwControlsAccepted записывается нулевое значение. В противном случае функция записывает туда значение SERVICE_ACCEPT_STOP, в результате чего сервису может быть передана команда остановки. Далее функция заполняет поля dwCurrentState, dwWin32ExitCode и dwWaitHint значениями, полученными через параметры.

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

После подготовки структуры SERVICE_STATUS ее адрес передается функции установки состояния сервиса SetServiceStatus.

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

BOOL QueryServiceStatus(

  SC_HANDLE        schService,         // идентификатор сервиса

  LPSERVICE_STATUS lpssServiceStatus); // адрес структуры

                                       // SERVICE_STATUS 

Идентификатор сервиса вы можете получить от функций OpenService или CreateService, которые будут описаны ниже.


Содержание раздела