Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Программирование для Windows NT

© Александр Фролов, Григорий Фролов
Том 27, часть 2, М.: Диалог-МИФИ, 1996, 272 стр.

[Назад] [Содеожание] [Дальше]

Управление сервисами

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

Получение идентификатора системы управления сервисами

Идентификатор системы управления сервисами нужен для выполнения различных операций над сервисами, таких например, как установка сервиса. Вы можете получить этот идентификатор с помощью функции OpenSCManager:


SC_HANDLE OpenSCManager(
  LPCTSTR lpszMachineName,   // адрес имени рабочей станции 
  LPCTSTR lpszDatabaseName,  // адрес имени базы данных 
  DWORD   fdwDesiredAccess); // нужный тип доступа

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

Для наших примеров параметр lpszDatabaseName, определяющий имя базы данных системы управления сервисами, нужно указать как NULL. При этом по умолчанию будет использована база данных активных сервисов ServicesActive.

Через параметр fdwDesiredAccess нужно задать требуемый тип доступа. Здесь можно использовать следующие константы:

 Константа

 Разрешенный тип доступа

 SC_MANAGER_ALL_ACCESS

 Полный доступ

 SC_MANAGER_CONNECT

 Подключение к системе управления сервисами

 SC_MANAGER_CREATE_SERVICE

 Создание новых сервисов и добавление их к регистрационной базе данных

 SC_MANAGER_ENUMERATE_SERVICE

 Просмотр списка всех установленных сервисов при попщи функции EnumServicesStatus (в нашей книге эта функция и следующие две функции не описаны)

 SC_MANAGER_LOCK

 Блокирование базыв данных функцией LockServiceDatabase

 SC_MANAGER_QUERY_LOCK_STATUS

 Определение состояние блокировки базы данных функцией QueryServiceLockStatus

Ниже мы привели пример вызова функции OpenSCManager:


schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

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

CloseServiceHandle(schSCManager);

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

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

Прототип функции CreateService мы привели ниже:


SC_HANDLE CreateService(
  SC_HANDLE hSCManager,    // идентификатор базы данных системы 
                           // управления сервисами 
  LPCTSTR lpServiceName,   // имя сервиса, которое будет использовано 
                           // для запуска 
  LPCTSTR lpDisplayName,   // имя сервиса для отображения 
  DWORD   dwDesiredAccess, // тип доступа к сервису 
  DWORD   dwServiceType,   // тип сервиса 
  DWORD   dwStartType,     // способ запуска сервиса 
  DWORD   dwErrorControl,  // действия при ошибках в момент запуска 
  LPCTSTR lpBinaryPathName,   // путь к загрузочному файлу сервиса 
  LPCTSTR lpLoadOrderGroup,   // имя группы порядка загрузки 
  LPDWORD lpdwTagId,          // адрес переменной для сохранения 
                              // идентификатора тега 
  LPCTSTR lpDependencies,     // адрес массива имен взаимосвязей 
  LPCTSTR lpServiceStartName, // адрес имени пользователя, права 
                    // которого будут применены для работы сервиса 
  LPCTSTR lpPassword );       // адрес пароля пользователя

Через параметр hSCManager вы должны передать функции CreateService идентификатор базы данных системы управления сервисами, полученный от функции OpenSCManager, описанной выше.

Через параметры lpServiceName и lpDisplayName задаются, соответственно, имя сервиса, которое будет использовано для запуска и имя сервиса для отображения в списке установленных сервисов.

С помощью параметра dwDesiredAccess вы должны указать тип доступа, разрешенный при обращении к данному сервису. Здесь вы можете указать следующие значения:

 Значение

 Разрешенный тип доступа

 SERVICE_ALL_ACCESS

 Полный доступ

 SERVICE_CHANGE_CONFIG

 Изменение конфигурации сервиса функцией ChangeServiceConfig

 SERVICE_ENUMERATE_DEPENDENTS

 Просмотр сервиса в списке сервисов, созданных на базе данного сервиса функцией EnumDependentServices

 SERVICE_INTERROGATE

 Выдача сервису команды немедленного определения текущего состояния сервиса при помощи функции ControlService (эта функция будет описана ниже)

 SERVICE_PAUSE_CONTINUE

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

 SERVICE_QUERY_CONFIG

 Определение текущей конфигурации функцией QueryServiceConfig

 SERVICE_QUERY_STATUS

 Определение текущего состояния сервиса функцией QueryServiceStatus

 SERVICE_START

 Запуск сервиса функцией StartService

 SERVICE_STOP

 Остановка сервиса выдачей соответствующей команды функцией ControlService

 SERVICE_USER_DEFINE_CONTROL

 Возможность передачи сервису команды, определенной пользователем, с помощью функции ControlService

Через параметр dwServiceType необходимо передать тип сервиса. Здесь вы можете указывать те же самые флаги, что и в поле dwServiceType структуры SERVICE_STATUS, описанной выше:

 Флаг

 Описание

 SERVICE_WIN32_OWN_PROCESS

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

 SERVICE_WIN32_SHARE_PROCESS

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

 SERVICE_KERNEL_DRIVER

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

 SERVICE_FILE_SYSTEM_DRIVER

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

 SERVICE_INTERACTIVE_PROCESS

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

В параметре dwStartType указывается один из следующих способов запуска сервиса:

 Константа

 Способ запуска

 SERVICE_BOOT_START

 Используется только для сервисов типа SERVICE_KERNEL_DRIVER или SERVICE_FILE_SYSTEM_DRIVER (драйверы). Указывает, что драйвер должен загружаться при загрузке операционной системы

 SERVICE_SYSTEM_START XE

 Аналогично предыдущему, но драйвер запускается при помощи функции IoInitSystem, не описанной в нашей книге

 SERVICE_AUTO_START

 Драйвер или обычный сервис, который запускается при загрузке операционной системы

 SERVICE_DEMAND_START

 Драйвер или обычный сервис, который запускается функцией StartService

 SERVICE_DISABLED

 Отключение возможности запуска драйвера или обычного сервиса

Параметр dwErrorControl задает действия, выполняемые при обнаружении ошибки в момент загрузки сервиса. Здесь можно указывать одно из следующих значений:

 Значение

 Реакция на ошибку

 SERVICE_ERROR_IGNORE

 Протоколирование ошибки в системном журнале и продолжение процедуры запуска сервиса

 SERVICE_ERROR_NORMAL

 Протоколирование ошибки в системном журнале без продолжения процедуры запуска сервиса

 SERVICE_ERROR_SEVERE

 Протоколирование ошибки в системном журнале. Если это возможно, используется конфигурация, с которой сервис успешно был запущен в прошлый раз. В противном случае система перезапускается с использованием работоспособной конфигурации

 SERVICE_ERROR_CRITICAL

 Криичная ошибка. Сообщение при возможности записывается в системный журнал. Операция запуска отменяется, система перезапускается с с использованием работоспособной конфигурации

В параметре lpBinaryPathName вы должны указать полный путь к загрузочному файлу сервиса.

Через параметр lpLoadOrderGroup передается указатель на имя группы порядка загрузки сервиса. Сделав сервис членом одной из групп порядка загрузки, вы можете определить последовательность загрузки вашего сервиса относительно других сервисов. Список групп порядка загрузки находится в регистрационной базе данных:


HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\ServiceGroupOrder

Если относительный порядок загрузки не имеет значения, укажите для параметра lpLoadOrderGroup значение NULL.

Параметр lpdwTagId используется только в том случае, если значение параметра lpLoadOrderGroup не равно NULL.

Параметр lpDependencies должен содержать указатель на массив строк имен сервисов или групп порядка загрузки, которые должны быть запущены перед запуском данного сервиса. Последняя строка такого массива должна быть закрыта двумя двоичными нулями. Если зависимостей от других сервисов нет, для параметра lpDependencies можно указать значение NULL.

Последние два параметра функции lpServiceStartName и lpPassword указывают, соответственно, имя и пароль пользователя, с правами которого данный сервис будет работать в системе (имя указывается в форме “ИмяДомена\имяПользователя”). Если параметр lpServiceStartName указан как NULL, сервис подключится к системе как пользователь LocalSystem. При этом параметр lpPassword должен быть указан как NULL.

Ниже мы привели фрагмент исходного текста приложения, в котором выполняется установка сервиса из каталога c:\ntbk2\src\service\small\debug:


schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
schService = CreateService(
  schSCManager, MYServiceName, MYServiceName,
  SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
  SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
  "c:\\ntbk2\\src\\service\\small\\debug\\small.exe",
  NULL, NULL, "", NULL, NULL);
CloseServiceHandle(schSCManager);

Получение идентификатора сервиса

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


SC_HANDLE OpenService(
  SC_HANDLE schSCManager,      // идентификатор базы данных системы 
                               // управления сервисами 
  LPCTSTR   lpszServiceName,   // имя сервиса 
  DWORD     fdwDesiredAccess); // тип доступа к сервису

Через параметр schSCManager вы должны передать функции OpenService идентификатор базы данных системы управления сервисами, полученный от функции OpenSCManager.

Параметр lpszServiceName определяет имя сервиса, а параметр fdwDesiredAccess - желаемый тип доступа к сервису.

Выдача команд сервису

Приложение или сервис может выдать команду сервису, вызвав функцию ControlService:


BOOL ControlService(
  SC_HANDLE hService,                // идентификатор сервиса 
  DWORD     dwControl,               // код команды 
  LPSERVICE_STATUS lpServiceStatus); // адрес структуры состояния 
                                     // сервиса SERVICE_STATUS

В качестве кода команды вы можете указать один из следующих стандартных кодов:

 Код

 Команда

 SERVICE_CONTROL_STOP

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

 SERVICE_CONTROL_PAUSE

 Временная остановка сервиса

 SERVICE_CONTROL_CONTINUE

 Продолжение работы сервиса после временной установки

 SERVICE_CONTROL_INTERROGATE

 Запрос текущего состояния сервиса

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

Удаление сервиса из системы

Для удаления сервиса из системы используется функция DeleteService. В качетсве единственного параметра этой функции необходимо передать идентификатор сервиса, полученный от функции OpenService.

Ниже мы привели фрагмент приложения, удаляющий сервис с именем MYServiceName из системы:


schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
schService = OpenService(
  schSCManager, MYServiceName, SERVICE_ALL_ACCESS);
ControlService(schService, SERVICE_CONTROL_STOP, &ss);
DeleteService(schService);
CloseServiceHandle(schSCManager);

Заметим, что перед удалением мы останавливаем сервис.

Запуск сервиса

Для запуска сервиса вы должны использовать функцию StartService:


BOOL StartService(
  SC_HANDLE schService,        // идентификатор сервиса 
  DWORD     dwNumServiceArgs,  // количество аргументов 
  LPCTSTR   *lpszServiceArgs); // адрес массива аргументов

Через параметр schService вы должны передать функции StartService идентификатор сервиса, полученный от функции OpenService.

Параметры dwNumServiceArgs и lpszServiceArgs определяют, соответственно, количество аргументов и адрес массива аргументов, которые получит функция точки входа сервиса. Эти параметры могут использоваться в процессе инициализации.

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


schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
schService = OpenService(
  schSCManager, MYServiceName, SERVICE_ALL_ACCESS);
StartService(schService, 0, NULL);
CloseServiceHandle(schSCManager);

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

Остановка сервиса выполняется посылкой сервису команды SERVICE_CONTROL_STOP, для чего эта комнда передается функции ControlService XE "ControlService" :


ControlService(schService, SERVICE_CONTROL_STOP, &ss);

Определение конфигурации сервиса

Приложение или сервис может определить конфигурацию заданного сервиса, вызвав для этого функцию QueryServiceConfig XE "QueryServiceConfig" :


BOOL QueryServiceConfig(
  SC_HANDLE schService,  // идентификатор сервиса 
  LPQUERY_SERVICE_CONFIG lpqscServConfig, // адрес структуры 
                         // QUERY_SERVICE_CONFIG, в которую будет 
                         // записана конфигурация сервиса 
  DWORD   cbBufSize,     // размер буфера для записи конфигурации 
  LPDWORD lpcbBytesNeeded); // адрес переменной, в котоую будет 
                        // записан размер буфера, необходимый для 
                        // сохранения всей информации о конфигурации 

Формат структуры QUERY_SERVICE_CONFIG приведен ниже:


typedef struct _QUERY_SERVICE_CONFIG 
{  
  DWORD  dwServiceType;
  DWORD  dwStartType;
  DWORD  dwErrorControl;
  LPTSTR lpBinaryPathName;
  LPTSTR lpLoadOrderGroup;
  DWORD  dwTagId;
  LPTSTR lpDependencies;
  LPTSTR lpServiceStartName;
  LPTSTR lpDisplayName;
} QUERY_SERVICE_CONFIG, LPQUERY_SERVICE_CONFIG;

Содержимое полей этой структуры соответствует содержимому параметров функции CreateService, описанной ранее.

Ниже расположен фрагмент кода, в котором определяется текущая конфигурация сервиса:


schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
schService = OpenService(
  schSCManager, MYServiceName, SERVICE_ALL_ACCESS);
lpBuf = (LPQUERY_SERVICE_CONFIG)malloc(4096);
if(lpBuf != NULL)
{
  QueryServiceConfig(schService, lpBuf, 4096, &dwBytesNeeded);
  . . .        
  free(lpBuf);
}
[Назад] [Содеожание] [Дальше]