Перевірка стану служби

Отримати поточний стан служби в структурі SERVICE_STATUS дозволяє наступна служба:

 

BOOL QueryServiceStatus (

SC_HANDLE hService,

LPSERVICE_STATUS lpServiceStatus)

 

Резюме: робота служб і керування ними

На мал.1 показаний диспетчер керування службами (SCM) і його взаємодія з службами й програмою керування. Служба реєструється в SCM і через SCM передаються всі команди для неї.

 


Мал.1. Керування службами NT через SCM

 


Ідея розв’язку задачі

 

Створити процес, котрим можна керувати: встановити, запустити (після чого з’являється попередження про завершення сеансу), призупинити, відновити його роботу, зупинити, видалити.

 



Опис функцій, які використовувалися для програмної реалізації служби

 

Main

 

Функція main – тіло програми, де виконуються, описані вище, функції.

main(int argc, char* argv[]);

Параметри:

argc – [число] кількість параметрів командного рядка.

argv - [текст] самі параметри командного рядка.

 

MySystemReboot

 

Для завершення роботи Windows можна скористатися функцією ExitWindowsEx. При цьому файлові буфери будуть скинуті на диск, а система наведена в стан, коли комп'ютер можна безпечно виключити.

В Windows NT/2000/XP: для завершення роботи системи необхідно одержати привілеї SE_SHUTDOWN_NAME, як і реалізовано у самій функції.

S_Headler

 

Функція керування службою.

void WINAPI S_Handler (DWORD Code1);

 Параметри:

Code1 - значення команди (старт, стоп, пауза)


3.4 ServiceMain

 

Функція, в якій реєструється процес, встановлюється таймер на завершення сеансу (5 сек) і відповідні попередження користувача про ПЕРЕЗАГРУЗКУ (REBOOT).

 


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 | FORMAT_MESSAGE_FROM_SYSTEM |

FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),

MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),

(LPTSTR) &MsgBuf, 0, NULL);

 

printf("%s: %s", Source, MsgBuf);

exit(1);

}

 

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() // ф-ція перезагрузки

{

//HANDLE hToken;

//TOKEN_PRIVILEGES tkp;

// отримуємо маркер поточного процесу

if (!OpenProcessToken(GetCurrentProcess(),

TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))

return(FALSE);

// отримуємо LUID для привілеїв завершення роботи

LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME,

&tkp.Privileges[0].Luid);

 

tkp.PrivilegeCount = 1; // встановлений один привілей

tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

// отримуємо привілеї завершення роботи для даного процесу

AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,

(PTOKEN_PRIVILEGES)NULL, 0);

if (GetLastError()!= ERROR_SUCCESS)

return FALSE;

// перегружаємо систему і змушуємо всі інші програми закритися

if (!ExitWindowsEx(EWX_REBOOT | 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 | SERVICE_ACCEPT_PAUSE_CONTINUE;

s_status.dwWin32ExitCode = NOERROR;

s_status.dwCheckPoint = 0;

s_status.dwWaitHint = 0;

 

SetServiceStatus(s_s_handle, &s_status);

 

MessageBox(0, "System will be restarted in 5 seconds!",

"Shutdown", MB_ICONINFORMATION);

 

h_Timer = CreateWaitableTimer(NULL, FALSE, NULL); // встановлюємо таймер

if(!h_Timer)

ErrorP("CreateWaitableTimer");

 

GetSystemTime(&st_Time);

st_Time.wSecond += 5;

SystemTimeToFileTime(&st_Time, &f_Time);

if(!SetWaitableTimer(h_Timer, (LARGE_INTEGER*)&f_Time, 1000, NULL,

NULL, FALSE)

)

ErrorP("SetWaitableTimer");

 

WaitForSingleObject(h_Timer, INFINITE);

 

MySystemReboot(); // перегружаємося =)

 

 

}

 

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 |

SERVICE_INTERACTIVE_PROCESS, SERVICE_AUTO_START,

SERVICE_ERROR_IGNORE, lpPath, NULL, NULL, NULL,

NULL, NULL);

 

if(!h_SC)

ErrorP("CreateService");

}

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");

}

else

printf("Invalid command\n");

}

else

{

SERVICE_TABLE_ENTRY s_Table[] = { // Запускаємо на виконання

{ MyServiceName, ServiceMain },

{ NULL, NULL }

};

 

StartServiceCtrlDispatcher(s_Table);

 }

 

}


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: