Создание сервисов для Windows NT
Страница 2.


 

Функция SetSomeServiceStatus()

Эта функция изменяет содержимое структуры ss, которое использует SCM для получения информации о статусе сервиса.

void SetSomeServiceStatus(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);
}

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

Поле dwControlsAccepted определяет управляющий код, который может принимать и обрабатывать данный сервис. По умолчанию все сервисы могут принимать команду SERVICE_CONTROL_INTERROGATE. Если это поле имеет значение SERVICE_ACCEPT_STOP, то сервис может быть остановлен с помощью команды SERVICE_CONTROL_STOP.

Функции InitSomeServiceData() и StopSomeService()

BOOL InitSomeServiceData() {
//...
return TRUE;
}


BOOL StopSomeService() {
//...
return TRUE;
}

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

Приложение, управляющее сервисом

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

Здесь не будут описываться функции WinMain() и InitApp(), поскольку они не обладают никакими особенностями, заслуживающими внимания. Функция WinMain() создает главное окно с шестью кнопками: "Install Service", "Start Service", "Get Service Configuration", "Stop Service", "Remove Service" и "Exit".

Функция WndProc()

В функции WndProc() используются макросы для обработки сообщений WM_COMMAND и WM_DESTROY:

LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg) {
HANDLE_MSG(hWnd, WM_COMMAND, WndProcOnCommand);
HANDLE_MSG(hWnd, WM_DESTROY, WndProcOnDestroy);
default:
return DefWindowProc(hWnd, msg, wParam, lParam);
}
}

Функция WndProcOnCommand()

Функция WndProcOnCommand() вызывается функцией WndProc(), если окно получает сообщение WM_COMMAND. Функция WndProcOnCommand() содержит код, выполняющийся при нажатии на кнопки главного окна приложения.

Приведем полностью код этой функции:

void
WndProcOnCommand(HWND hWnd, int id, HWND hwndCtl, UINT codeNotify) {
SC_HANDLE hService; //дескриптор сервиса
SC_HANDLE hSCManager; //дескриптор Service Control Manager
LPQUERY_SERVICE_CONFIG lpBufConfig;
DWORD dwBytesNeeded;
char szBufConfig[4096];

switch(id) {
//установка сервиса в систему
case IDB_INSTALL: {
//открываем SCM
hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
if(!hSCManager) {
MessageBox(NULL, "Can't open Service Control Manager", "Error",
MB_OK | MB_ICONERROR);
break;
}
//создаем сервис SomeService
hService = CreateService(hSCManager, SomeServiceName,
SomeServiceName, SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
"c:\\Services\\SomeSrvc.exe",
NULL, NULL, NULL, NULL, NULL);
if(!hService) {
MessageBox(NULL, "Can't create service", "Error",
MB_OK | MB_ICONERROR);
CloseServiceHandle(hSCManager);
break;
}
//закрываем дескриптор сервиса
CloseServiceHandle(hService);
//закрываем дескриптор SCM
CloseServiceHandle(hSCManager);
break;
}

Здесь мы отрываем базу данных Service Control Manager (SCM) с помощью функции OpenSCManager() с уровнем доступа SC_MANAGER_CREATE_SERVICE, который позволяет создавать сервисы.

Для создания сервиса используется функция CreateService(), которая возвращает дескриптор созданного сервиса или NULL в случае неудачного выполнения. Одним из параметров функции является путь к сервису, который должен соответствовать расположению сервиса в Вашем компьютере. Проследите, чтобы путь был указан правильно, иначе создать сервис не получится.

В качестве типа сервиса мы указали SERVICE_WIN32_OWN_PROCESS. Это означает, что сервис будет выполняться как отдельный процесс. При успешном завершении функция CreateService() добавляет сервис в базу данных SCM. Вы можете в этом убедиться, открыв системную панель управления сервисами (Панель управления -> Администрирование -> Службы).

 //запуск сервиса
case IDB_START: {
hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if(!hSCManager) {
MessageBox(NULL, "Can't open Service Control Manager",
"Error", MB_OK | MB_ICONERROR);
break;
}
hService = OpenService(hSCManager, SomeServiceName,
SERVICE_START);
if(!hService) {
GetSomeSvcError();
break;
}
if(!StartService(hService, 0, NULL))
MessageBox(NULL, "Can't start service", "Error",
MB_OK | MB_ICONERROR);
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
break;
}
 
« Предыдущая статья   Следующая статья »