|
Розробка служби Win32 |
. створити обробник керування служби, який буде відповідати на команди SCM.Описавши ці три етапи, ми будемо по мірі необхідності давати додаткову інформацію по створенню, запуску служб і керуванню ними. Далі ці дії описанні краще.Функція main().Задача нової функції main(), яку викликає SCM, полягає в реєструванні служби і в запуску диспетчера керування службою. Для цього потрібно визвати функцію StartServiceCtrlDispatcher з ім'ям (іменами) і точкою (точками) входу однієї або декількох логічних служб.BOOL StartServiceCtrlDispatcher (LPSERVICE_TABLE_ENTRY lpServiceStartTable)Єдиний параметр lpServiceStartTable є адресою масиву SERVICE_TABLE_ENTRY, кожен елемент якого містить ім'я і точку входу логічної служби. Кінець масиву позначається парою елементів з значеннями NULL.Виклик StartServiceCtrlDispatcher в головному потоці процесу служби приводить до приєднання потоку до SCM в формі потоку диспетчера керування службою SCM не повертає керування, поки всі служби не будуть закінчені. Але потрібно замітити, що в цей момент логічні служби фактично ще не запускаються.В прикладі 1 показана проста головна програма служби, яка містить одну логічну службу.Приклад 1. Програма main: головна точка входу служби.#include “EvryThng.h”void WINAPI ServiceMain (DWORD argc, LPTSTR argv []);static LPTSTR ServiceName = _T (“SocketCommandLineService”);/* головна процедура, яка запускає диспетчер керуваня службою. */VOID _tmain (int argc, LPTSTR argv []){ SERVICE_TABLE_ENTRY DispatchTable [] ={{ ServiceName, SeviceMain },{ NULL, NULL }};if (!StartServiceCtrlDispatcher (DispatchTable))ReportErrjr (_T(“Не вдалося запустити диспетчер керування службою.”),1, TRUE);/*Servoce<aom () не буде працювати, поки її не запустить SCM.*//*Повернення назад відбувається тільки після завершення всіх служб.*/return;Функції ServiceMain()Ці функції визначені в таблиці служб, як показано в прикладі 1, і представляють логічні служби. Це, по суті, вдосконалені версії основної програми, яка перетворюється в службу, причому кожну логічну службу SCM викликає в окремому потоці. В свою чергу, логічна служба може запускати додаткові потоки, наприклад потоки-робочі сервера, які застосовувалися в програмах serverSK і serverNP. Часто в службі NT знаходиться тільки одна логічна служба. Можливо реалізувати в складі одної служби NT логічні служби як на базі сокетів, так і на базі іменованих каналів, якщо задати дві головні функції служби. Також тут є додатковий код для реєстрації обробника керування служби - функції, яка SCM викликає для керування службами.Реєстрація обробника керування службиОбробник керування служби, який викликається диспетчером SCM, повинен бути здатним керувати відповідною логічною службою. Обробник керування консолі в програмі serverSK, який встановлює глобальний прапор закінчення, в обмеженій формі демонструє, що повинен представляти собою обробник. Але кожна логічна служба повина зареєструвати обробник з використанням функції Register-ServiceCtrlHandler.SERVICE_STATUS_HANDLERegisterServiceCtrlHandler (LPCTSCR lpServiceName,LPHANDLER_FUNCTION lp&HandlerProc)ПараметриlpServiceName - вказане користувачем ім'я служби, яке представлене в елементі таблиці, який відповідає цій логічній службі.lpHandlerProc - адрес функції обробника, яка буде описана нижче.Функція повертає дескриптор об'єкта SERVICE_STATUS_HANDLE, рівний нулю, якщо вийшла помилка; для аналізу помилок можна застосовувати звичайні методи. Встановлення стану службиКоли обробник зареєстрований, то наступна задача полягає в тому, щоб встановити стан служби; в даний момент це SERVICE_STAER_PENDING. Функція, яка для цього застосовується, SetServiceStatus також використовується в деяких інших місцях і повина викликати періодично, щоб інформувати SCM про стан служби (інтервал вказується в полі параметра-структури стану).Структура service_statusСтруктура SERVICE_STATUS визначена слідуючим чином:typedef struct _SERVICE_STATUS {DWORD dwServiceType;DWORD dwCurrentState;WORD dwControlsAccepted;DWORD dwWin32ExitCode;DWORD dwServiceSpecificExitCode;DWORD dwCheckPoint;DWORD dwWaitHint;} SERVICE_STATUS, *LPBERVICE_STATUS;Параметри dwWin32ExitCode - звичайний код закінчення потоку логічної служби, яка повинна присвоїти йому значення NO_ERROR в ході виконання і при нормальному завершені. dwServiceSpecificExitCode можна ви користувати для вказання помилок вводу запуску або закінчення служби, але це значення буде проігнорованим, якщо dwWin32ExitCode не присвоєне значення ERROR_SERVICE_SPECIFIC_ERROR.dwCheckPoint - контрольний показчик проходження службою всіх її значень разом з ініціалізацією і закінченням, які служба повинна періодично зчитувати. Це значення не використовується, якщо служба не має затримки при закінченні, зупинці і відновлені. dwWaitHint - інтервал в мілісекундах між викликами Set ServiceSpecificExitCode і збільшеним значенням dwCheckPoint або зміненим значенням dwCurrentState. SCM може припустити, що виникла помилка, якщо інтервал протікає без такого виклику SetServiceStatus.Тип службиЕлемент dwServiceType повинен мати одне із значень, які приведені в таблиці 3.Для наших цілей тип служби майже завжди буде мати значення SERVICE_WIN32_OWN_PROCESS, хоча різні значення свідчать про те, що служби можуть грати різні ролі.Таблиця 3. Типи служб.|
Значення | Тип служби | | SERVICE_WIN32_OWN_PROCESS | Служба Win32, яка працює в окремому процесі зі своїми власними ресурсами. Використовується в таблиці 2. | | SERVICE_WIN_SHARE_PROCESS | Служба Win32, яка використовує процес спільно з іншими службами, так що декілька служб може спільно користуватися ресурсами, змінними і т.д. | | SERVICE_KERNEL_DRIVER | Драйвер пристрою Windows NT | | SERVICE_FILE_SYSTEM_DRIVER | Драйвер файлової системи Windows NT | | SERVICE_INTERACTIVE_PROCESS | Процес служби Win32, який може взаємодіяти з користувачем через робочий стіл | | | Стан службиПараметр dwCurrentState визначає поточний стан служби. Можливі значення цього параметра приведені в табл.4.Таблиця 4. Значення стану служби.|
Значення | Стан | | SERVICE_STOPPED | Служба зовсім не працює, так як не була запущена | | SERVICE_START_PENDING | Служба знаходиться в процесі запуску, але ще не готова відповідати не запити. Наприклад, потоки-робочі ще не запущені | | SERVICE_STOP_PENDING | Служба зупиняється, але ще не закінчилася до кінця. Наприклад, глобальний прапор закінчення може бути встановленим, але потоки-робочі ще не прореагували | | SERVICE_RUNNING | Служба працює | | SERVICE_CONTINUE_PENDING | Виконується відновлення служби після зупинки | | SERVICE_PAUSE_PENDING | Служба переходить в стан зупинка, але перехід ще не закінчений | | SERVICE_PAYSED | Служба призупинена | | | Коди керування, що сприймаютьсяПараметр dwControlsAccepted визначає коди керування, які служба сприймає і обробляє в своєму обробнику керування. Можливі значення перераховані в таблиці 5; декілька значень можуть об'єднуватися порозрядним „або”. Приведена нижче версія serverSK для служби сприймає всі три значення. Додаткові значення описані в документації MSDN.Таблиця 5. Коди керування, які сприймаються службою|
Значення | Дія | | SERVICE_ACCEPT_STOP | Дозволяється SERVICE_CONTROL_STOP | | SERVICE_ACCEPT_PAUSR_CONTINUE | Дозволяється SERVICE_CONTROL_PAUSE і SERVICE_CONTROL_CONTINUE | | SERVICE_ACCEPT_SHUTDOWN (функція ControlService не може видавати цей код керування) | Служба повідомляє, коли система закінчує роботу. Таким чином, система може послати службі значення SERVICE_CONTROL_ SHUTDOWN | | | Код службиКоли обробник зареєстрований і встановлений стан служби SERVICE_START_PENDING, служба може ініціалізувати себе і встановити стан знову. В прикладі перетворення serverSK після того, як сокети ініціалізовані і сервер буде готовий до прийому клієнтів, слідує встановити стан SERVICE_RUNNING.Обробник керування службиОбробник керування служби, який вказаний в функції RegisterServiceCtrlHandler, має наступну форму:VOID WINAPI ServerCtrlHandler (DWORD fdwControl)Єдиний параметр цієї функції, fdwControl, містить сигнал керування, який передається диспетчером SCM для обробки. Таким чином, обробник керування є узагальненою формою обробника керування консолі.Сигнали керування можуть мати слідуючи значення:SERVICE_CONTROL_STOPSERVICE_CONTROL_PAUSESERVICE_CONTROL_CONTINUESERVICE_CONTROL_INTERROGATESERVICE_CONTROL_SHUTDOWNТакож допускаються значення користувача в діапазоні 128-255, але тут вони не розглядаються.Обробник викликається диспетчером SCM в тому ж потоці, що і головна програма, і звичайно будується на базі оператора switch.Керування службами Windows NTНаступна задача після написання коду - передача служби під керуванням SCM, щоб її можна було запускати, закінчувати і виконувати інші керуючі операції.Для цього потрібно виконати декілька дій з відкриття SCM, створення служби під керуванням SCM і потім з її запуску. Ці дії не керують службою безпосередньо; вони представляють собою команди для SCM, який працює з вказаною службою.Відкриття SCMДля створення служби необхідний окремий процес, який грає роль „адміністратора”. Перша дія - відкриття SCM і отримання дескриптору, який потім дозволяє створити службу.SC_HANDLE OpenSCManager (LPCTSTR lpMachineName,LPCTSTR lpDatabaseName,DWORD dwDesiredAddress)ПараметриlpMachineName рівний NULL, якщо SCM знаходиться в локальній системі, хоча можна звертатися до SCM і на інших машинах в мережі.lpDatabaseName - також звичайно NULL.dwDesiredAddress - звичайно SC_MANAGER_ALL_ACCESS, але можна задати більш обмежені права доступу, як описано в вбудованій документації.Створення і видалення службиНові служби фіксуються в слідую чому розділі системного реєстру:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ServicesДля створення служби слідує визвати функцію Create Service, вказавши дескриптор SC_HANDLE, отриманий при виклику OpenSCManager.SC_HANDLE CreatrService (SC_HANDLE hSCManager,LPCTSTR lpServiceName,LPCTSTR lpDisplayName,DWORD dwDesiredAccess,DWORD dwServiceType,DWORD dwStartType,DWORD dwErrorControl,LPCTSTR lpBinaryPathName,LPCTSTR lpLoadOrderGroup,LPDWORD lpdwTagId,LPCTSTR lpDependencies,LPCTSTR lpServiceStartName,LPCTSTR lpPassword);ПараметриhSCManager - дескриптор SC_HANDLE, який отриманий від OpenSCManager.lpServiceName - ім'я, по якому в подальшому ми будемо посилатися на службу, це одне із імен логічних служб, які вказані в таблиці при виклику StartServiceCtrlDispatcher. Замітимо, що для кожної логічної служби потрібний окремий виклик CreateService.lpDisplayName - ім'я, під яким служба буде відображатися в реєстрі і в аплеті Служби, який відкривається на панелі керування в розділі Средства адміністрування. Це ім'я з'являється зразу після успішного виклику CreateService. dwDesiredAccess може мати значення SERVICE_ALL_ACCESS або бути комбінацією GENERIC_READ, GENERIC_WRITE і GENERIC_EXECUTE. Більш детально це описано в вкладеній документації.dwServiceType має значення, які представленні в таблиці 1.dwStartType визначає порядок запуску служби. В наших прикладах використовується зачення SERVICE_DEMAND_START; інші значення (SERVICE_BOOT_START і SERVICE_SYSTEM_START) дозволяють запускати служби драйверів пристроїв в ході початкового запуску системи, а SERVICI_AUTO_START визначає, що служба повинна автоматично запускатися при запуску системи.lpBinaryPathName вказує на виконуючий файл служби; розширення .exe вказувати не потрібно.Інші параметри визначають ім'я облікового запису і пароль, групи для об'єднувальних служб і залежності в випадку декількох взаємозалежних служб.Для отримання дескриптора іменованої служби використовується функція OpenService, для видалення служби із системного реєстру - DeleteService, а для закриття дескриптора - CloseServiceHandle.Запуск службиЗразу після створення служба ще не працює. Запустіть функцію ServiceMain (), вказавши дескриптор, який отриманий від CreateService, і параметри командного рядка argc, argv, які вимагає „головна” функція служби (тобто функція, яка вказана в таблиці служб).BOOL StartService (SC_HANDLE hService,DWORD argc,LPTSTR argv [] )Керування службиДля керуючої дії над службою диспетчером SCM повинен бути викликаний обробник керування службою з відповідним кодом керування.BOOL ControlService (SC_HANDLE hService,DWORD ControlCode,LPSERVICE_STATUS pServStat)Якщо доступ дозволений, ControlCode має одне із наступних значень:SERVICE_CONTROL_STOPSERVICE_CONTROL_PAUSESERVICE_CONTROL_CONTINUESERVICE_CONTROL_INTERROGATESERVICE_CONTROL_SHUTDOWNабо вказане користувачем значення в діапазоні 128-255. Це ті ж значення, які використовувалися для прапора fdwControl в функції ServerCtrlHandler. pServStat вказує на структуру SERVICE_STATUS, яка отримує поточний стан. Ця ж структура, що використовується в функції SetServiceStatus.Перевірка стану служби Отримати поточний стан служби в структурі SERVICE_STATUS дозволяє наступна служба:BOOL QueryServiceStatus (SC_HANDLE hService,LPSERVICE_STATUS lpServiceStatus)Резюме: робота служб і керування нимиНа мал.1 показаний диспетчер керування службами (SCM) і його взаємодія з службами й програмою керування. Служба реєструється в SCM і через SCM передаються всі команди для неї.32 Мал.1. Керування службами NT через SCM2.2 Ідея розв'язку задачіСтворити процес, котрим можна керувати: встановити, запустити (після чого з'являється попередження про завершення сеансу), призупинити, відновити його роботу, зупинити, видалити. 3. Опис функцій, які використовувалися для програмної реалізації служби3.1 MainФункція main - тіло програми, де виконуються, описані вище, функції. main( int argc, char* argv[] ); Параметри: argc - [число] кількість параметрів командного рядка. argv - [текст] самі параметри командного рядка. 3.2 MySystemRebootДля завершення роботи Windows можна скористатися функцією ExitWindowsEx. При цьому файлові буфери будуть скинуті на диск, а система наведена в стан, коли комп'ютер можна безпечно виключити. В Windows NT/2000/XP: для завершення роботи системи необхідно одержати привілеї SE_SHUTDOWN_NAME, як і реалізовано у самій функції. 3.3 S_HeadlerФункція керування службою. void WINAPI S_Handler ( DWORD Code1 ); Параметри: Code1 - значення команди (старт, стоп, пауза)3.4 ServiceMainФункція, в якій реєструється процес, встановлюється таймер на завершення сеансу (5 сек) і відповідні попередження користувача про ПЕРЕЗАГРУЗКУ (REBOOT). 3.5 ErrorPФункція ErrorP вивід помилки і вихід із програми. void ErrorP ( LPTSTR Source );Параметри: Source - текст попередження про помилку. ВисновкиУ роботі була створена служба Win32, яка перевантажує комп'ютер не відразу, а через деякий час (а саме через 5 секунд), щоб користувач міг завершити почату роботу. Була вивчена структура служб, їх встановлення та керування ними.Література1. Конспект лекцій.2. Майкл Дж. Янг Visual C++ 6 (том 1,2).3. MSDN Library, February 2005.Програмна реалізація#define _WIN32_WINNT 0x0400#include <windows.h>#include <stdio.h>#include <string.h>HANDLE hToken;TOKEN_PRIVILEGES tkp;LPSTR MyServiceName = "DClock";LPSTR MyDisplayName = "Desktop Clock";void ErrorP(LPTSTR Source) // Повідомляємо про помилку і виходимоLPVOID MsgBuf;FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER SERVICE_STATUS_HANDLE s_s_handle;SERVICE_STATUS s_status;void WINAPI S_Handler(DWORD Code1) // функція керування службою{ switch (Code1) { case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: s_status.dwCurrentState = SERVICE_STOPPED; break; case SERVICE_CONTROL_PAUSE: s_status.dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_CONTINUE: s_status.dwCurrentState = SERVICE_RUNNING; break; } SetServiceStatus(s_s_handle, &s_status); //рефреш властивостей функції}BOOL MySystemReboot() // ф-ція перезагрузки EWX_FORCE, 0))return FALSE;return TRUE;void WINAPI ServiceMain(DWORD dwArgc, LPSTR *psArgv)HANDLE h_Timer;SYSTEMTIME st_Time;FILETIME f_Time;s_s_handle = RegisterServiceCtrlHandler(MyServiceName, S_Handler); // Запускаємо службуs_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;s_status.dwCurrentState = SERVICE_RUNNING;s_status.dwControlsAccepted = SERVICE_ACCEPT_STOP void main(int argc, char* argv[]){if(argc > 1){SC_HANDLE h_SC;h_SC = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); //менеджер керування службоюif(!h_SC)ErrorP("OpenSCManager");if(!stricmp(argv[1], "create"))CHAR lpPath[MAX_PATH]; // Створюємо службуGetModuleFileName(NULL, lpPath, MAX_PATH); h_SC = CreateService(h_SC, MyServiceName,MyDisplayName, 0, SERVICE_WIN32_SHARE_PROCESS else if(!stricmp(argv[1], "start")){h_SC = OpenService(h_SC, MyServiceName, SERVICE_START); // Запускаємо службуif(!h_SC)ErrorP("OpenService");if(!StartService(h_SC, 0, NULL))ErrorP("StartService");}else if(!stricmp(argv[1], "pause")){h_SC = OpenService(h_SC, MyServiceName, // призупиняємо службуSERVICE_PAUSE_CONTINUE);if(!h_SC)ErrorP("OpenService");if(!ControlService(h_SC, SERVICE_CONTROL_PAUSE, &s_status))ErrorP("ControlService");}else if(!stricmp(argv[1], "continue")){h_SC = OpenService(h_SC, MyServiceName, // продовжуємо призупинену службуSERVICE_PAUSE_CONTINUE);if(!h_SC)ErrorP("OpenService");if(!ControlService(h_SC, SERVICE_CONTROL_CONTINUE,&s_status))ErrorP("ControlService");}else if(!stricmp(argv[1], "stop")){h_SC = OpenService(h_SC, MyServiceName, SERVICE_STOP); // зупиняємо службуif(!h_SC)ErrorP("OpenService");if(!ControlService(h_SC, SERVICE_CONTROL_STOP, &s_status))ErrorP("ControlService");}else if(!stricmp(argv[1], "delete")){h_SC = OpenService(h_SC, MyServiceName, DELETE); // видаляємо службуif(!h_SC)ErrorP("OpenService");if(!DeleteService(h_SC))ErrorP("DeleteService");}elseprintf("Invalid command\n");}else{ SERVICE_TABLE_ENTRY s_Table[] = { // Запускаємо на виконання{ MyServiceName, ServiceMain },{ NULL, NULL }};StartServiceCtrlDispatcher(s_Table); }}
Страницы: 1, 2
|
|
|
© 2003-2013
Рефераты бесплатно, курсовые, рефераты биология, большая бибилиотека рефератов, дипломы, научные работы, рефераты право, рефераты, рефераты скачать, рефераты литература, курсовые работы, реферат, доклады, рефераты медицина, рефераты на тему, сочинения, реферат бесплатно, рефераты авиация, рефераты психология, рефераты математика, рефераты кулинария, рефераты логистика, рефераты анатомия, рефераты маркетинг, рефераты релиния, рефераты социология, рефераты менеджемент. |
|
|