Работа с сервисами Windows NT Работа с сервисами Windows NT
Подключение к менеджеру сервисов |
*
| W-NT
|
| |
Работа с сервисами Windows NT (или систем на базе технологии NT)
производится при помощи менеджера сервисов,
открытие которого производится функцией API OpenSCManager (эта
функция и остальные функции API и константы для работы с
сервисами декларированы в модуле winsvc):
SC_HANDLE OpenSCManager(
LPCTSTR lpMachineName, // Имя удаленного ПК или NULL для работы с локальным ПК
LPCTSTR lpDatabaseName, // Имя менеджера (базы менеджера) или NULL для ServicesActive базы (по умолчанию)
DWORD dwDesiredAccess // флаг типа доступа
);
Параметр dwDesiredAccess задает тип доступа. Это битовая маска:
- SC_MANAGER_ALL_ACCESS - полный доступ, включает STANDARD_RIGHTS_REQUIRED
в дополнение ко типам доступа
- SC_MANAGER_CONNECT - разрешает подключение к менеджеру сервисов
- SC_MANAGER_CREATE_SERVICE - разрешает создание сервисов при помощи
CreateService
- SC_MANAGER_ENUMERATE_SERVICE - разрешает перечисление сервисов при
помощи функции EnumServicesStatus
- SC_MANAGER_LOCK - разрешает блокирование базы данных сервисов при
помощи LockServiceDatabase
- SC_MANAGER_QUERY_LOCK_STATUS - разрешает запрос статуса блокировки
базы при помощи QueryServiceLockStatus
- SC_MANAGER_MODIFY_BOOT_CONFIG - модификация параметров загрузки сервиса
При доступе можно использовать типовые наборы флагов, для которых
имеются именованные константы:
- GENERIC_READ - чтение (перечисление сервисов и анализ статуса
блокировки), является комбинацией
STANDARD_RIGHTS_READ,
SC_MANAGER_ENUMERATE_SERVICE,
SC_MANAGER_QUERY_LOCK_STATUS
- GENERIC_WRITE - запись - комбинация STANDARD_RIGHTS_WRITE,
SC_MANAGER_CREATE_SERVICE, C_MANAGER_MODIFY_BOOT_CONFIG
- GENERIC_EXECUTE - комбинация STANDARD_RIGHTS_EXECUTE,
SC_MANAGER_CONNECT и SC_MANAGER_LOCK
При успешном вызове функция возвращает Handle менеджера сервисов.
После завершения работы с менеджером сервисов Handle необходимо
закрыть при помощи CloseServiceHandle.
Получение списка сервисов |
*
| *
|
| |
Список сервисов строится при помощи функции EnumServicesStatus:
BOOL EnumServicesStatus(
SC_HANDLE hSCManager, // handle, полученный при открытии менеджера сервисов
DWORD dwServiceType, // тип перечисляемых сервисов
DWORD dwServiceState, // состояние перечисляемых сервисов
LPENUM_SERVICE_STATUS lpServices, // указатель на буфер, в который сохраняется статус сервисов
DWORD cbBufSize, // размер буфера
LPDWORD pcbBytesNeeded, // Переменная, получающая требуемый объем буфера в байтах
LPDWORD lpServicesReturned, // Переменная, получающая кол-во возвращенных записей
LPDWORD lpResumeHandle // Переменная, получающая Handle следующего вхождения (для маленького буфера)
);
Рассмотрм пример, демонстрирующий построение списка сервисов с
динамическим определение размера буфера. Следует обратить внимание
на два момента:
- EnumServicesStatus объявлена в Delphi не совсем корректно -
параметр lpServices должен быть указателем на массив, а он
объявлен как Record типа TEnumServiceStatus. Выход из положения
прост - нужно создать массив с элементами типа TEnumServiceStatus и
передать при вызове функции его первый элемент.
- lpResumeHandle перед вызовом функции EnumServicesStatus должен
быть обнулен
function TForm1.CreateServiceList: boolean;
var
SCManagerHandle : THandle;
lpServices : array of TEnumServiceStatus;
pcbBytesNeeded, lpServicesReturned, lpResumeHandle: DWORD;
ServiceMode, ServiceStatus : integer;
i : integer;
S : string;
LI : TListItem;
begin
// Очистка списка
ListView1.Items.Clear;
// 1. Подключениемся к менеджеру сервисов
SCManagerHandle := OpenSCManager(nil, nil, GENERIC_READ);
case rgServiceMode.ItemIndex of
0 : ServiceMode := SERVICE_WIN32;
1 : ServiceMode := SERVICE_DRIVER;
2 : ServiceMode := SERVICE_WIN32 or SERVICE_DRIVER;
end;
case rgServiceStatus.ItemIndex of
0 : ServiceStatus := SERVICE_ACTIVE;
1 : ServiceStatus := SERVICE_INACTIVE;
2 : ServiceStatus := SERVICE_ACTIVE or SERVICE_INACTIVE;
end;
// ResumeHandle := 0 !! Это важно, т.к. это задает пречисление
// сервисов с начала
lpResumeHandle := 0;
// 2. Перечисление сервисов (размер буфера = 0 - мы определяем, какой реально
// размер необходим для списка сервисов
EnumServicesStatus(SCManagerHandle,
ServiceMode,
ServiceStatus,
lpServices[0], // !! В описании функции ошибка - эдесь должен быть указатель на массив элементов
0,
pcbBytesNeeded,
lpServicesReturned,
lpResumeHandle);
// 3. Настройка размера массива
SetLength(lpServices, pcbBytesNeeded div SizeOf(TEnumServiceStatus));
// 4. Повторный запрос списка сервисов (размер массива соответствует определенному на шаге 2)
lpResumeHandle := 0;
EnumServicesStatus(SCManagerHandle,
ServiceMode,
ServiceStatus,
lpServices[0],
Length(lpServices) * SizeOf(TEnumServiceStatus),
pcbBytesNeeded,
lpServicesReturned,
lpResumeHandle);
// Вывод полученных данных в ListView1
for i := 0 to lpServicesReturned - 1 do begin
LI := ListView1.Items.Add;
LI.Caption := lpServices[i].lpServiceName;
LI.SubItems.Add(lpServices[i].lpDisplayName);
S := '??';
// Расшифровка кода состояния
case lpServices[i].ServiceStatus.dwCurrentState of
SERVICE_STOPPED : S := 'Сервис не запущен';
SERVICE_START_PENDING : S := 'Сервис в процессе запуска';
SERVICE_STOP_PENDING : S := 'Сервис в процессе завершения';
SERVICE_RUNNING : S := 'Сервис запущен';
SERVICE_CONTINUE_PENDING : S := 'Сервис в процессе запуска после временной оснановки';
SERVICE_PAUSE_PENDING : S := 'Сервис в процессе временной оснановки';
SERVICE_PAUSED : S := 'Сервис временно оснановлен';
end;
LI.SubItems.Add(S);
end;
// 5. Закрытие менеджера
CloseServiceHandle(SCManagerHandle);
end;
Для работы примера необходимы rgServiceMode и rgServiceStatus -
радиогруппы, позволяющие пользователю менять условия выборки
Остановка и приостановка работы сервиса |
*
| *
|
| |
Данная задача решается при помощи вызова ControlService
с соответсвующими параметрами.
Продемонстрируем ото примером:
procedure TForm1.ExecuteControlService(ServiceName: String; ServiceControlCode : DWORD);
var
SCManagerHandle, SCHandle : THandle;
ServiceStatus : TServiceStatus;
begin
// 1. Подключениемся к менеджеру сервисов
SCManagerHandle := OpenSCManager(nil, nil, GENERIC_READ);
// 2. Открытие сервиса
SCHandle := OpenService(SCManagerHandle, PChar(ServiceName), SERVICE_ALL_ACCESS);
// 3. Управление состоянием
ControlService(SCHandle, ServiceControlCode, ServiceStatus);
// 4. Закрытие сервиса
CloseServiceHandle(SCHandle);
// 5. Закрытие менеджера
CloseServiceHandle(SCManagerHandle);
end;
Запуск сервиса |
*
| *
|
| |
procedure TForm1.ExecuteStartService(ServiceName: String);
var
SCManagerHandle, SCHandle : THandle;
p : PChar;
begin
// 1. Подключениемся к менеджеру сервисов
SCManagerHandle := OpenSCManager(nil, nil, GENERIC_READ);
// 2. Открытие сервиса
SCHandle := OpenService(SCManagerHandle, PChar(ServiceName), SERVICE_ALL_ACCESS);
// 3. Запуск сервиса
p := nil;
StartService(SCHandle, 0, p);
// 4. Закрытие сервиса
CloseServiceHandle(SCHandle);
// 5. Закрытие менеджера
CloseServiceHandle(SCManagerHandle);
end;
Пример |
*
| *
|
| |
Описанный выше примеры работы с сервисами
я оформил в виде отдельного приложения,
исходный текст которого можно скачать с
моего сайта - Пример, 9 кб
© Зайцев Олег, "Программирование на Delphi - обмен опытом" 1999-2004. При использовании любых материалов данного сайта
необходимо указывать источник информации. Дата обновления: 22.11.2004. Сайт размещен на хостинге AGAVA - Хостинг от AGAVA.ru