Книга: Системное программирование в среде Windows

Пример: "интерфейсная оболочка" службы

Пример: "интерфейсная оболочка" службы

Программа 13.2 реализует преобразованный вариант программы serverSK, который мы перед этим обсуждали. Преобразование сервера в службу сопряжено с решением всех ранее описанных задач. После внесения незначительных изменений существующий код сервера помещается в функцию ServiceSpecific. Поэтому представленный ниже код, по сути, является оболочкой (wrapper) существующей программы сервера, точка входа которой main заменена на ServiceSpecifiс.

Другим дополнением, которое здесь не представлено, но включено в вариант программы, находящийся на Web-сайте книги, является использование журнала службы, поскольку службы часто запускаются без интерактивной консоли, никак себя видимо не проявляя. 

Программа 13.2. SimpleService: оболочка службы 

/* Глава 13. serviceSK.c
   Преобразование сервера serverSK в службу Windows.
   Несмотря на рассмотрение частного случая, оболочка имеет универсальный характер. */
#include "EvryThng.h"
#include "ClntSrvr.h"
#define UPDATE_TIME 1000 /* Интервал обновления – 1 секунда. */
VOID LogEvent(LPCTSTR, DWORD, BOOL);
void WINAPI ServiceMain(DWORD argc, LPTSTR argv[]);
VOID WINAPI ServerCtrlHandlerEx(DWORD; DWORD, LPVOID, LPVOID);
void UpdateStatus (int, int); /* Вызывает, функцию SetServiceStatus. */
int ServiceSpecific (int, LPTSTR *); /* Ранее программа main. */
volatile static BOOL ShutDown = FALSE, PauseFlag = FALSE;
static SERVICE_STATUS hServStatus;
static SERVICE_STATUS_HANDLE hSStat; /* Дескриптор, используемый при установке состояния. */
static LPTSTR ServiceName = _T("SocketCommandLineService");
static LPTSTR LogFileName = _T("CommandLineServiceLog.txt");
/* Основная процедура, запускающая диспетчер управления службой. */
VOID _tmain(int argc, LPTSTR argv[]) {
 SERVICE_TABLE_ENTRY DispatchTable[] = {
  { ServiceName, ServiceMain }, { NULL, NULL }
 };
 StartServiceCtrlDispatcher(DispatchTable);
 return 0;
}
/* Точка входа ServiceMain, вызываемая при создании службы. */
void WINAPI ServiceMain(DWORD argc, LPTSTR argv[]) {
 DWORD i, Context = 1;
 /* Установить текущий каталог и открыть файл журнала, присоединяемый к существующему файлу. */
 /* Определить все элементы структуры состояния сервера. */
 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;
}
 

Оглавление книги


Генерация: 1.364. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз