Программирование на Delphi - обмен опытом / Работа с сервисами Windows NT

© Зайцев Олег 1998-2004
Лучшая портативная техника. Плееры Камеры Телефоны Компьютеры
Покупателям, пришедшим на www.porta.ru по этой ссылке - дополнительная скидка 1%
Железо | Система | WEB | Компоненты | Графика | Ссылки | Мультимедиа | Сети | Прочее | Реестр | Литература

Статистика

Работа с сервисами Windows NT

Рекомендую:
Главная страница \ Системное программирование \ Работа с сервисами Windows NT

  • Работа с сервисами 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 задает тип доступа. Это битовая маска: При доступе можно использовать типовые наборы флагов, для которых имеются именованные константы: При успешном вызове функция возвращает 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 следующего вхождения (для маленького буфера)
       );
    
    Рассмотрм пример, демонстрирующий построение списка сервисов с динамическим определение размера буфера. Следует обратить внимание на два момента:
    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