Сервис И Месседжы

15.10.2010
8
0
#1
Доброго времени суток, уважаемые форумчане!

Занимаюсь созданием сервиса для Windows, который должен отлавливать один единственный месседж от ОС - WM_TIMECHANGE и писать это в лог-файл (в дальнейшем - писать на syslog-сервер).
Заготовка сервиса создана, уже умеет запускатся/останавливатся.
Единственное что - никак не могу сообразить как обрабатывать сообщения, не имея при этом окна.

Быть может, кто-либо подскажет как сие реализовать? Желательно, куском кода или пошаговым описанием процесса. Короче, как для человека, изрядно подзабывшего Cpp... :)

<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Выглядит заготовка так :</div></div><div class="sp-body"><div class="sp-content">
C++:
#include <stdio.h>
#include "stdafx.h"
#include <Windows.h>
#include <time.h>
#include <iomanip>

DWORD WINAPI HandlerEx(DWORD control, DWORD eventType, void *eventData, void *context);
void ReportErrorStatus(DWORD errorCode);
void ReportProgressStatus(DWORD state, DWORD checkPoint, DWORD waitHint);
void ReportStatus(DWORD state);
void WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
void addLogMessage(const TCHAR* t, ...);

int StartService();
int RemoveService();
void InstallService();

LPTSTR svcName; 
LPTSTR svcPath;

time_t curTime;

SERVICE_STATUS_HANDLE g_ServiceStatusHandle; 
HANDLE g_StopEvent;
DWORD g_CurrentState = 0;
bool g_SystemShutdown = false;

int _tmain(int argc, wchar_t* argv[]) 
{
time(&curTime);

svcName = LPTSTR(L"TimeWatcher");
svcPath = LPTSTR(argv[0]);

TCHAR buf[64] = {0};
wsprintf(buf, L"Trying to %s service\n", argv[argc - 1]);
addLogMessage(buf);

if (wcscmp(argv[argc-1], _T("install")) == 0) 
{
InstallService();
} 
else if (wcscmp(argv[argc-1], _T("remove")) == 0) 
{
RemoveService();
} 
else if (wcscmp(argv[argc-1], _T("start")) == 0) 
{
StartService();
} 
else if (wcscmp(argv[argc-1], _T("service")) == 0) 
{

SERVICE_TABLE_ENTRY serviceTable[] = {
{ _T(""), &ServiceMain },
{ NULL, NULL }
};
if (StartServiceCtrlDispatcher(serviceTable))
return 0;
else if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
return -1; // Program not started as a service.
else
return -2; // Other error.
}
return 0;
}

// Main function to be executed as entire service code.
void WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
{
g_ServiceStatusHandle = RegisterServiceCtrlHandlerEx(svcName, &HandlerEx, NULL);

time(&curTime);

ReportStatus(SERVICE_START_PENDING);
g_StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

ReportStatus(SERVICE_RUNNING);

while (WaitForSingleObject(g_StopEvent, 3000) != WAIT_OBJECT_0)
{
// add something here
}

ReportStatus(SERVICE_STOP_PENDING);
addLogMessage(TEXT("Service shutdown! \n"));

CloseHandle(g_StopEvent);
ReportStatus(SERVICE_STOPPED);
}

void ReportStatus(DWORD state)
{
g_CurrentState = state;
SERVICE_STATUS serviceStatus = {
SERVICE_WIN32_OWN_PROCESS,
g_CurrentState,
state == SERVICE_START_PENDING ? 0 : SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN,
NO_ERROR,
0,
0,
0,
};
SetServiceStatus(g_ServiceStatusHandle, &serviceStatus);
}

void ReportProgressStatus(DWORD state, DWORD checkPoint, DWORD waitHint)
{
g_CurrentState = state;
SERVICE_STATUS serviceStatus = {
SERVICE_WIN32_OWN_PROCESS,
g_CurrentState,
state == SERVICE_START_PENDING ? 0 : SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN,
NO_ERROR,
0,
checkPoint,
waitHint,
};
SetServiceStatus(g_ServiceStatusHandle, &serviceStatus);
}

void ReportErrorStatus(DWORD errorCode)
{
g_CurrentState = SERVICE_STOPPED;
SERVICE_STATUS serviceStatus = {
SERVICE_WIN32_OWN_PROCESS,
g_CurrentState,
0,
ERROR_SERVICE_SPECIFIC_ERROR,
errorCode,
0,
0,
};
SetServiceStatus(g_ServiceStatusHandle, &serviceStatus);
}

// Handler for service control events.
DWORD WINAPI HandlerEx(DWORD control, DWORD eventType, void *eventData, void *context)
{
switch (control)
{
// System is shutting down.
case SERVICE_CONTROL_SHUTDOWN:
g_SystemShutdown = true;
// continue...
// Service is being stopped.
case SERVICE_CONTROL_STOP:
ReportStatus(SERVICE_STOP_PENDING);
SetEvent(g_StopEvent);
break;
// Ignoring all other events, but we must always report service status.
default:
ReportStatus(g_CurrentState);
break;
}
return NO_ERROR;
}


void InstallService()
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
TCHAR szPath[MAX_PATH + 9];
TCHAR tCantInst[] = L"Cannot install service (%d)";

if (!GetModuleFileName(NULL, szPath, MAX_PATH))
{
addLogMessage(tCantInst);
return;
}
wcscat_s(szPath,MAX_PATH+9,L" service");

schSCManager = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
if (!schSCManager)
{
addLogMessage(tCantInst);
return;
}

schService=CreateService(schSCManager, svcName, svcName,
SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL, szPath, 0, 0, 0, 0, 0);
if (!schService)
{
addLogMessage(tCantInst);
CloseServiceHandle(schSCManager);
return;
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
time(&curTime);
addLogMessage(L"Service Installed!\n");
}

int RemoveService() 
{
SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (!hSCManager) 
{
addLogMessage(TEXT("Error: Can't open Service Control Manager\n"));
return -1;
}
SC_HANDLE hService = OpenService(hSCManager, svcName, SERVICE_STOP | DELETE);
if (!hService) 
{
addLogMessage(TEXT("Error: Can't remove service\n"));
CloseServiceHandle(hSCManager);
return -1;
}

DeleteService(hService);
CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
addLogMessage(TEXT("Success remove service!\n"));
return 0;
}

int StartService() 
{
SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
SC_HANDLE hService = OpenService(hSCManager, svcName, SERVICE_START);
if (!StartService(hService, 0, NULL)) 
{
CloseServiceHandle(hSCManager);
addLogMessage(TEXT("Error: Can't start service\n"));
return -1;
}

CloseServiceHandle(hService);
CloseServiceHandle(hSCManager);
return 0;
}


void getServicePath(TCHAR *path)
{
HKEY hKey = 0;
TCHAR buf[260] = {0};
DWORD dwBufSize = sizeof(buf);

TCHAR subkey[260];
wsprintf(subkey, L"SYSTEM\\CurrentControlSet\\services\\%s", svcName);

if (RegOpenKey(HKEY_LOCAL_MACHINE, subkey, &hKey) == ERROR_SUCCESS)
{
int i = 0;
if (RegQueryValueEx(hKey, TEXT("ImagePath"), NULL, NULL, (LPBYTE)buf, &dwBufSize) == ERROR_SUCCESS)
{
//wcsncpy(path, buf, dwBufSize);
_wsplitpath(buf, NULL, path, NULL, NULL);
}
RegCloseKey(hKey);
}
}


WCHAR* timeStamp(WCHAR* txt)
{
WCHAR* rc;
WCHAR timestamp[16];
time_t rawtime = time(0);
tm *now = localtime(&rawtime);

if (rawtime != -1) 
{
wcsftime(timestamp, 16, __TEXT("%d_%m_%y.log"), gmtime(&curTime));
rc = wcscat(txt, timestamp);
}
return(rc);
}

void addLogMessage(const TCHAR* t,...)
{
TCHAR format[MAX_PATH] = {0};
TCHAR fname[MAX_PATH] = {0};
getServicePath(format);
timeStamp(fname);
wcsncat(format, L"tw_", MAX_PATH);
wcsncat(format, fname, MAX_PATH);

TCHAR tmstp[MAX_PATH] = {0};
timeStamp(tmstp);

HANDLE h = ::CreateFile(format, GENERIC_WRITE, 0, 0, OPEN_ALWAYS, 0, 0);
if (INVALID_HANDLE_VALUE != h)
{
unsigned long w = 0;
va_list val;
TCHAR f[0x1000];
int l;

va_start(val, t);
wsprintf(f, L"%w - ", tmstp);
l = _vsntprintf_s(f, sizeof(f)/sizeof(f[0]), _TRUNCATE, t, val);
va_end(val);
if (0 == SetFilePointer(h, 0, 0, FILE_END))
{
if (sizeof(short) == sizeof(TCHAR))
{
unsigned short unicode = 0xFeFF;
WriteFile(h, (void*)&unicode, 2, &w, 0);
}
}
WriteFile(h, (void*)f, l*sizeof(TCHAR), &w, 0);
CloseHandle(h);
}
}