- •Введение
- •1. Службы Windows.
- •1.1. Программа – служба
- •1.2. Три компонента сервиса
- •1.3. Диспетчер управления сервисами (scm)
- •1.4. Программы управления сервисами
- •1.5. Учетные зависи сервиса
- •1.6. Начало работы сервиса
- •1.7. Выполнение сервиса
- •2. Разработка сервиса Win32.
- •2.1. Структура программы сервиса
- •2.2. Протокол взаимодействия scm и сервиса
- •2.3. Пример функций сервиса.
- •Программа, осуществляющая установку сервиса.
- •Отладка сервиса.
- •Литература
- •Оглавление
2.2. Протокол взаимодействия scm и сервиса
На рисунке 7 показано взаимодействие пользовательского приложения, программы управления сервисами (SCM) и, собственно, сервиса. Действия в системе выполняются в следующей последовательности:
Приложение регистрирует точки входа ServiceMain всех содержащихся в нем сервисов путем вызова StartServiceCtrlDispatcher.
SCM в отдельном потоке вызывает точку входа ServiceMain сервиса.
Сервис регистрирует точку входа по обработке команд (Handler) путем вызова RegisterServiceCtrlHandler.
Сервис сообщает SCM об удачной инициализации путем вызова SetServiceStatus с параметром SERVICE_RUNNING (при неудачной инициализации – с параметром SERVICE_STOPPED). При этом сервис может продолжать выполнение функции ServiceMain или выйти из нее.
Команды (остановка, перезапуск и т.п.) со стороны других приложений транслируются в вызовы точки входа Handler в отдельном потоке.
При остановке сервис вызывает функцию 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;
}
