
Сервисы Windows (120
..pdf
2.2. Протокол взаимодействия SCM и сервиса
На рис. 7 показано взаимодействие пользовательского приложения, SCM и собственно сервиса. Действия в ОС выполняются в такой последовательности.
Ðèñ. 7. Взаимодействие приложения и сервиса
1.Приложение регистрирует точки входа функции ServiceMain всех содержащихся в ней сервисов путем вызова функции StartServiceCtrlDispatcher.
2.SCM в отдельном потоке вызывает точку входа функции ServiceMain сервиса.
3.Сервис регистрирует точку входа по обработке команд (функция Handler) путем вызова функции RegisterServiceCtrlHandler.
4.Сервис сообщает SCM об удачной инициализации путем вызова функции SetServiceStatus с параметром SERVICE_RUNNING (при неудачной инициализации – с параметром SERVICE_ STOPPED). При этом сервис может продолжать выполнение функции ServiceMain или выйти из нее.
5.Команды (остановка, перезапуск и т. п.) со стороны других приложений транслируются в вызовы точки входа функции Handler
âотдельном потоке.
6.При остановке сервис вызывает функцию SetServiceStatus с параметром SERVICE_STOPPED.
2.3. Пример функций сервиса
Приведем пример исходного кода сервиса Win32, выпоняемого как консольное приложение. Бîльшая часть кода взята из [3], где программа называется 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;
}
42
}
// Точка входа в сервис
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)
{
43
// что-то делаем 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;
}
Программа, осуществляющая установку сервиса
Для установки сервиса в ОС можно использовать вспомогательную программу:
44
#include <windows.h> using namespace std;
int wmain(int argc, WCHAR **argv)
{
SC_HANDLE sSCM = OpenSCManager ( NULL, //локальный компьютер
NULL,//активная база данных сервиса SC_MANAGER_ALL_ACCESS//права доступа);
SC_HANDLE MyService = CreateService( sSCM, //база данных SCM
L«Mserv», //имя сервиса
L«My Service», //отображаемое имя сервиса SERVICE_ALL_ACCESS, //доступ SERVICE_WIN32_OWN_PROCESS, //тип сервиса SERVICE_DEMAND_START, //тип запуска SERVICE_ERROR_NORMAL, //тип контроля ошибок argv[1], //путь к сервису
NULL, //нет группы
NULL, //нет тэга идентификатора NULL, //нет зависимости
NULL, //учетная запись LocalSystem NULL); //нет password
If (MyService == NULL)
{
printf(“CreateService failed (%d)\n”, GetLastError()); CloseServiceHandel(sSCM);
Return;
}
CloseServiceHandle(MyService);
CloseServiceHandle(cSCM);
}
2.4. Отладка сервиса
Для отладки сервиса необходимо подключить отладчик к отлаживаемому процессу до того, как возникнет ошибка. Для реализации этой задачи можно использовать следующие способы отладки.
• Подключение отладчика к исследуемому процессу вручную. Подключить отладчик к уже запущенному процессу можно двумя
45
способами: из функции TaskManadger или с помощью команды Build Start Debug Attach to Process. Недостатки этого способа связаны с тем, что от запуска процесса до присоединения отладчика проходит некоторое время, за которое может возникнуть ошибка.
• Использование точки ввода DebugBreak. Функцию DebugBreak можно использовать для прерывания выполнения программы в любом месте. Для этого в исходный код вписывается вызов функции DebugBreak(). Вызов этой функции аналогичен точке останова. Если режим Jast-in-Time debugging включен, то система приостановит программу и будет запущен режим Visual Studio Jast-in-Time Debugger. Для установки режима Jast-in-Time debugging нужно выполнить следующие действия: 1) в меню Tools выбрать пункт Options; 2) в диалоговом окне Options выбрать папку Debugging; 3) в папке Debugging выбрать страницу Just-In-Time; 4) для того чтобы допустить режим Just-In-Time debugging, необходимо выбрать или очистить отвечающие программы: Managed, Native, или Script. Для изменения ключа Just-In-Time debugging необходимо иметь права Администратора;
5)нажать OK.
•Автоматическое подключение отладчика к процессу. Для подключения отладчика к некоторому процессу нужно открыть редактор реестра, выполнив функцию regedit; открыть ключ HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\ Current\Image File Execution Option и добавить подключ, имя которого совпадает с именем exe-файла. В этом подключе надо создать строковый параметр Debugger и записать в него полный путь к отладчику Visual C++. После присоединения отладчика последовательность действий будет такой:
1) если сервис продолжает выполняться, необходимо остановить его;
2) следует убедиться в том, что отладочные символы для приложения загружены. Для этого нужно открыть окно Debug и посмотреть сообщения отладчика. Если присутствует строка “Loaded symbol for …, no matching symbolic information found”, отладчик не нашел отладочные символы;
3)открыть файлы с исходными кодами (File Open) и поставить в нужных местах точки останова;
4)возобновить работу приложения.
46
Список источников
1.Руссинович М., Соломон Д. Внутреннее устройство Microsoft. Windows Server 2003, Windows XP и Windows 2000. Мастер класс: Пер. с англ. 4-е изд. М.: Русская редакция; СПб.: Питер, 2006. 992 с.
2.Jeffrey Richter. Design a Windows NT Service to Exploit Special Operating System Facilities // Microsoft System J., 1997. Vol. 12. No 10. 19 р. – Режим доступа http://www.microsoft.com/msj/1097/ WINNT.aspx
3.MSDN Library, Microsoft. – Режим доступа http:// MSDN.microsoft.com/ru-ru/ library/d56de412.aspx
Îглавление |
|
Введение . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
3 |
1. Службы Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
4 |
1.1. Программа – служба . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
4 |
1.2. Три компонента сервиса . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
5 |
1.3. Особенности SCM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
6 |
1.4. Программы управления сервисами . . . . . . . . . . . . . . . . . . . . . . . |
10 |
1.5. Учетные записи сервиса . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
15 |
Учетная запись локальной системы (Local System) . . . . . . . . . . . . |
15 |
Учетная запись сетевого сервиса (Network Service) . . . . . . . . . . . . |
16 |
Учетная запись локальной службы (Local Service) . . . . . . . . . . . . |
17 |
Выполнение сервисов под другими учетными записями . . . . . . . |
17 |
1.6. Начало работы сервиса . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
17 |
1.7. Выполнение сервиса . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
21 |
2. Разработка сервиса Win32 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
23 |
2.1. Структура программы сервиса . . . . . . . . . . . . . . . . . . . . . . . . . . . |
23 |
Точка входа main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
25 |
Точка входа в сервис (ServiceMain) . . . . . . . . . . . . . . . . . . . . . . . . . |
27 |
Точка входа по обработке команд (Handler) . . . . . . . . . . . . . . . . . . |
34 |
2.2. Протокол взаимодействия SCM и сервиса . . . . . . . . . . . . . . . . . |
41 |
2.3. Пример функций сервиса . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
42 |
Программа, осуществляющая установку сервиса . . . . . . . . . . . . . |
44 |
2.4. Отладка сервиса . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
45 |
Список источников . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . |
47 |
|
47 |
Учебное издание
Крищенко Всеволод Александрович Рязанова Наталья Юрьевна
Сервисы Windows
Редактор Е.К. Кошелева Корректор Л.С. Горбенко
Компьютерная верстка И.А. Марковой
Подписано в печать 15.12.2010. Формат 60
Усл. печ. л. 2,79. Тираж 100 экз. Изд ¹ 69. Заказ
Издательство МГТУ им. Н.Э. Баумана. Типография МГТУ им. Н.Э. Баумана.
105005, Москва, 2-я Бауманская ул., д. 5.