Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
сервисы-пос1.doc
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
688.64 Кб
Скачать

2.2. Протокол взаимодействия scm и сервиса

На рисунке 7 показано взаимодействие пользовательского приложения, программы управления сервисами (SCM) и, собственно, сервиса. Действия в системе выполняются в следующей последовательности:

  1. Приложение регистрирует точки входа ServiceMain всех содержащихся в нем сервисов путем вызова StartServiceCtrlDispatcher.

  2. SCM в отдельном потоке вызывает точку входа ServiceMain сервиса.

  3. Сервис регистрирует точку входа по обработке команд (Handler) путем вызова RegisterServiceCtrlHandler.

  4. Сервис сообщает SCM об удачной инициализации путем вызова SetServiceStatus с параметром SERVICE_RUNNING (при неудачной инициализации – с параметром SERVICE_STOPPED). При этом сервис может продолжать выполнение функции ServiceMain или выйти из нее.

  5. Команды (остановка, перезапуск и т.п.) со стороны других приложений транслируются в вызовы точки входа Handler в отдельном потоке.

  6. При остановке сервис вызывает функцию SetServiceStatus с параметром SERVICE_STOPPED.

Рис.7. Взаимодействие приложения и сервиса

2.3. Пример функций сервиса.

Пример исходного кода сервиса Win32, выпоняемого как консольное приложение. Большая часть кода взята из примера в MSDN [1]. В MSDN программа называется Svc.cpp. Здесь программа называется mys.cpp.

Файл sample.h создается при построении DLL сообщений - Sample.dll. Для построения DLL сообщений выполняются следующие действия: 1. mc –U sample.mc; 2. rc –r sample.rc; 3. link –dll –noentry –out: saple.dll sample.res.

#include <windows.h>

#include <tchar.h>

#include <strsafe.h>

#include "sample.h"

using namespace std;

SERVICE_STATUS Status;

SERVICE_STATUS_HANDLE StatusHandle;

HANDLE ControlWorking = NULL;

VOID WINAPI MyServiceHandler( DWORD );

VOID WINAPI MyServiceMain( DWORD, LPTSTR * );

//главная точка входа процесса

void main(int argc, TCHAR *argv[])

{

if( lstrcmpi( argv[1], TEXT("install")) == 0 )

{

printf("Cannot install service (%d)\n", GetLastError());

return;

}

SERVICE_TABLE_ENTRY DispatchTable[] =

{ { L”SeviceName”, (LPSERVICE_MAIN_FUNCTION) MyServiceMain },

{ NULL, NULL } }; //перечень всех сервисов процесса

//Возврат из вызова – при остановке работы сервиса.

// Процесс должен быть завершент при возврате из вызова.

if (!StartServiceCtrlDispatcher( DispatchTable ))

{

printf(“Start ServiceCtrlDispatcher: Error %ld\n”, GetLastError());

return;

}

}

// Точка входа в сервис

VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )

{

// Регистрация точки входа handler

StatusHandle = RegisterServiceCtrlHandler(

L”ServiceName”,

MyServiceHandler);

if( ! StatusHandle )

{

printf("RegisterServiceCtrlHandler Error\n");

return;

}

// Определение полей структуры SERVICE_STATUS

Status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;

Status.dwCurrentState = SERVICE_START_PENDING;

Status.dwControlAccepted = SERVICE_ACCEPT_STOP;

Status.dwWin32ExitCode = 0;

Status.dwCheckPoint = 0;

Status.dwWaitHint = 0;

// Сообщение об инициализации для SCM

ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 );

//Мьютекс для защиты рабочей секции потока сервиса

ControlWorking = CreateMutex(

NULL, // атрибуты защиты по умолчанию

FALSE, // нет владельца

NULL); // безимянный mutex

if (ControlWorking == NULL)

{

printf("CreateMutex error: %d\n", GetLastError());

return;

}

Status.dwCurrentState = SERVICE_RUNNING;

//Сообщение текущего статуса после завершения инициализации

SetServiceStatus(StatusHandle,&Status);

While(true)

{

// что-то делаем

WaitForSingleObject(ControlWorking,INFINITE);

//критические действия

ReleaseMutex(ControlWorking);

}

return;

}

//Точка входа Handler

VOID WINAPI MyServiceHandler( DWORD dwCtrl )

{

switch(dwCtrl)

{

case SERVICE_CONTROL_STOP:

//ждем выхода из критической секции

WaitForSingleObject(ControlWorking,INFINITE);

Status.dwCurrentState = SERVICE_STOP_PENDING;

CloseHandel(ControlWorking);

SetSeviceStatus(StatusHandel,&Status);

return;

case SERVICE_CONTROL_SHUTDOWN:

//ждем выхода из критической секции

WaitForSingleObject(ControlWorking,INFINITE);

Status.dwCurrentState = SERVICE_STOPPED;

CloseHandel(ControlWorking);

SetSeviceStatus(StatusHandel,&Status);

return;

case SERVICE_CONTROL_INTERROGATE:

// Fall through to send current status.

break;

default:

break;

}

return;

}