Наконец, lpContext — пользовательские данные, передаваемые в функцию RegisterServiceCtrlHandlerEx во время регистрации обработчика.
Обработчик активизируется SCM в том же потоке, что и основная программа, и обычно содержит ряд операторов switch, как будет показано в приведенных ниже примерах.
Пример: "интерфейсная оболочка" службы
Программа 13.2 реализует преобразованный вариант программы serverSK, который мы перед этим обсуждали. Преобразование сервера в службу сопряжено с решением всех ранее описанных задач. После внесения незначительных изменений существующий код сервера помещается в функцию ServiceSpecific. Поэтому представленный ниже код, по сути, является оболочкой (wrapper) существующей программы сервера, точка входа которой main заменена на ServiceSpecifiс.
Другим дополнением, которое здесь не представлено, но включено в вариант программы, находящийся на Web-сайте книги, является использование журнала службы, поскольку службы часто запускаются без интерактивной консоли, никак себя видимо не проявляя.
/* Глава 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);