/* Определить все элементы структуры состояния сервера. */
hServStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
hServStatus.dwCurrentState = SERVICE_START_PENDING;
hServStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;
hServStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIF0C_ERROR;
hServStatus.dwServiceSpecificExitCode = 0;
hServStatus.dwCheckPoint = 0;
hServStatus.dwWaitHint = 2 * CS_TIMEOUT;
hSStat = RegisterServiceCtrlHandlerEx(ServiceName, ServerCtrlHandler, &Context);
SetServiceStatus(hSStat, &hServStatus);
/* Запустить специфическую для службы обработку; выполнение типового участка кода завершено. */
if (ServiceSpecific(argc, argv) != 0) {
hServStatus.dwCurrentState = SERVICE_STOPPED;
hServStatus.dwServiceSpecificExitCode = 1;
/* Ошибка при инициализации сервера. */
SetServiceStatus(hSStat, &hServStatus);
return;
}
/* Возврат сюда будет осуществлен лишь после завершения функции ServiceSpecific, указывающего на прекращение работы системы. */
UpdateStatus(SERVICE_STOPPED, 0);
return;
}
void UpdateStatus(int NewStatus, int Check)
/* Определить новое состояние и контрольную точку — задается либо истинное значение, либо приращение. */
{
if (Check < 0) hServStatus.dwCheckPoint++;
else hServStatus.dwCheckPoint = Check;
if (NewStatus >= 0) hServStatus.dwCurrentState = NewStatus;
SetServiceStatus(hSStat, &hServStatus);
return;
}
/* Функция обработчика, активизируемая SCM для выполнения в том же */
/* потоке, что и основная программа. */
/* Последние три параметра не используются, так что обработчики, написанные*/
/* для версий Windows младше NT5, в этом примере также будут работать. */
VOID WINAPI ServerCtrlHandlerEx(DWORD Control, DWORD EventType, LPVOID lpEventData, LPVOID lpContext) {
switch (Control) {
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
ShutDown = TRUE; /* Установить глобальный флаг завершения. */
UpdateStatus(SERVICE_STOP_PENDING, –1);
break;
case SERVICE_CONTROL_PAUSE:
PauseFlag = TRUE; /* Периодический опрос. */
break;
case SERVICE_CONTROL_CONTINUE:
PauseFlag = FALSE;
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
if (Control > 127 && Control < 256) /*Пользовательские сигналы.*/
break;
}
UpdateStatus(-1, –1); /* Инкрементировать контрольную точку. */
return;
}
/* Эта специфическая для службы функция играет роль функции "main" и вызывается из более общей функции ServiceMain. Вообще говоря, вы можете взять любой сервер, например ServerNP.c, и поместить его код прямо сюда, переименовав функцию "main" в "ServiceSpecific". Однако для кода обновления состояния потребуются некоторые изменения. */
int ServiceSpecific(int argc, LPTSTR argv[]) {
UpdateStatus(-1, –1); /* Инкрементировать контрольную точку. */
/* … Инициализация системы … */
/* Обеспечьте периодическое обновление контрольной точки. */
return 0;
}
Управление службами Windows
Следующее, что потребуется сделать после написания кода службы — поместить ее под управление SCM, что позволит запускать и останавливать службу, а также осуществлять любые иные формы управления, какие только могут понадобиться.
Для этого необходимо выполнить несколько шагов, включая открытие SCM, создание службы под управлением SCM и последующий ее запуск. При этом вы воздействуете не непосредственно на службу, а на SCM, который, в свою очередь, и осуществляет управление заданной службой.
Для создания службы требуется отдельный процесс, выступающий в качестве "администратора" и играющий во многом ту же роль, что и программа JobShell, которая использовалась в главе 6 для запуска задач. Первый шаг состоит в открытии SCM и получении дескриптора, который впоследствии будет использован для создания службы.
SC_HANDLE OpenSCManager(LPCTSTR lpMachineName, LPCTSTR lpDatabaseName, DWORD dwDesiredAccess)
Параметры
lpMachineName — указатель на строку с именем сетевого компьютера, на котором установлен SCM, или NULL, если SCM установлен на локальном компьютере.
lpDatabaseName — обычно принимает значение NULL.
dwDesiredAccess — обычно указывается значение SC_MANAGER_ALL_ACCESS, соответствующее полным правам доступа, но можно задать и ограничить эти права, о чем более подробно говорится в оперативной справочной системе.
Создание и удаление службы
Для регистрации службы следует вызвать функцию CreateService:
SC_HANDLE CreateService(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);
Читать дальше