From 317b7559ffa5acaf37eb680c07b2edc0b60da489 Mon Sep 17 00:00:00 2001 From: Ged Murphy Date: Mon, 31 Mar 2008 14:41:06 +0000 Subject: [PATCH] I wrote a quick skeleton service this morning, thought it might be useful to someone. svn path=/trunk/; revision=32793 --- rosapps/skel_service/ServiceMain.c | 199 +++++++++++++++++++++++++++++ rosapps/skel_service/log.c | 194 ++++++++++++++++++++++++++++ rosapps/skel_service/myservice.h | 21 +++ 3 files changed, 414 insertions(+) create mode 100644 rosapps/skel_service/ServiceMain.c create mode 100644 rosapps/skel_service/log.c create mode 100644 rosapps/skel_service/myservice.h diff --git a/rosapps/skel_service/ServiceMain.c b/rosapps/skel_service/ServiceMain.c new file mode 100644 index 00000000000..4f040fb0f28 --- /dev/null +++ b/rosapps/skel_service/ServiceMain.c @@ -0,0 +1,199 @@ +/* + * PROJECT: ReactOS services + * LICENSE: GPL - See COPYING in the top level directory + * FILE: + * PURPOSE: skeleton service + * COPYRIGHT: Copyright 2008 Ged Murphy + * + */ + +#include "myservice.h" + +volatile BOOL bShutDown = FALSE; +volatile BOOL bPause = FALSE; + +LPTSTR ServiceName = _T("skel_service"); + +typedef struct _ServiceInfo +{ + SERVICE_STATUS servStatus; + SERVICE_STATUS_HANDLE hStatus; +} SERVICEINFO, *PSERVICEINFO; + +/********* To be moved to new file **********/ +typedef struct _ServiceData +{ + INT val1; + INT val2; +} SERVICEDATA, *PSERVICEDATA; + +DWORD WINAPI ThreadProc(LPVOID lpParam) +{ + while (!bShutDown) + Sleep(1000); + + return 0; +} +/*******************************************/ + + +VOID +UpdateStatus(PSERVICEINFO pServInfo, + DWORD NewStatus, + DWORD Check) +{ + TCHAR szSet[50]; + + if (Check > 0) + pServInfo->servStatus.dwCheckPoint += Check; + else + pServInfo->servStatus.dwCheckPoint = Check; + + if (NewStatus > 0) + pServInfo->servStatus.dwCurrentState = NewStatus; + + _sntprintf(szSet, 49, _T("Setting service to 0x%lu, CheckPoint %lu"), NewStatus, pServInfo->servStatus.dwCheckPoint); + LogEvent(szSet, 0, 0, LOG_FILE); + + if (!SetServiceStatus(pServInfo->hStatus, &pServInfo->servStatus)) + LogEvent(_T("Cannot set service status"), GetLastError(), 0, LOG_ALL); + + return; +} + +INT +CreateServiceThread(PSERVICEINFO pServInfo) +{ + HANDLE hThread; + PSERVICEDATA servData; + + UpdateStatus(pServInfo, 0, 1); + + LogEvent(_T("Creating service thread"), 0, 0, LOG_FILE); + + hThread = CreateThread(NULL, + 0, + ThreadProc, + &servData, + 0, + NULL); + + if (!hThread) + { + LogEvent(_T("Failed to start service thread"), GetLastError(), 101, LOG_ALL); + } + + UpdateStatus(pServInfo, 0, 1); + + LogEvent(_T("setting service status to running"), 0, 0, LOG_FILE); + UpdateStatus(pServInfo, SERVICE_RUNNING, 0); + + WaitForSingleObject(hThread, INFINITE); + + if (hThread) + CloseHandle(hThread); + + return 0; +} + + +VOID WINAPI +ServerCtrlHandler(DWORD dwControl, + DWORD dwEventType, + LPVOID lpEventData, + LPVOID lpContext) + +{ + PSERVICEINFO pServInfo = (PSERVICEINFO)lpContext; + + switch (dwControl) + { + case SERVICE_CONTROL_SHUTDOWN: + case SERVICE_CONTROL_STOP: + LogEvent(_T("\nSetting the service to SERVICE_STOP_PENDING"), 0, 0, LOG_FILE); + InterlockedExchange((LONG *)&bShutDown, TRUE); + pServInfo->servStatus.dwWin32ExitCode = 0; + pServInfo->servStatus.dwWaitHint = 0; + UpdateStatus(pServInfo, SERVICE_STOP_PENDING, 1); + break; + + case SERVICE_CONTROL_PAUSE: + LogEvent(_T("Setting the service to SERVICE_PAUSED"), 0, 0, LOG_FILE); + InterlockedExchange((LONG *)&bPause, TRUE); + UpdateStatus(pServInfo, SERVICE_PAUSED, 0); + break; + + case SERVICE_CONTROL_CONTINUE: + LogEvent(_T("Setting the service to SERVICE_RUNNING"), 0, 0, LOG_FILE); + InterlockedExchange((LONG *)&bPause, FALSE); + UpdateStatus(pServInfo, SERVICE_RUNNING, 0); + break; + + case SERVICE_CONTROL_INTERROGATE: + break; + + default: + if (dwControl > 127 && dwControl < 256) /* user defined */ + LogEvent(_T("User defined control code"), 0, 0, LOG_FILE); + else + LogEvent(_T("ERROR: Bad control code"), 0, 0, LOG_FILE); + break; + } + + return; +} + + +VOID WINAPI +ServiceMain(DWORD argc, LPTSTR argv[]) +{ + SERVICEINFO servInfo; + + LogEvent(_T("Entering ServiceMain"), 0, 0, LOG_FILE); + + servInfo.servStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + servInfo.servStatus.dwCurrentState = SERVICE_STOPPED; + servInfo.servStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE; + servInfo.servStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; + servInfo.servStatus.dwServiceSpecificExitCode = 0; + servInfo.servStatus.dwCheckPoint = 0; + servInfo.servStatus.dwWaitHint = 1000; + + LogEvent(_T("Registering service control handler"), 0, 0, LOG_FILE); + servInfo.hStatus = RegisterServiceCtrlHandlerEx(ServiceName, ServerCtrlHandler, &servInfo); + if (!servInfo.hStatus) + LogEvent(_T("Failed to register service"), GetLastError(), 100, LOG_ALL); + + UpdateStatus(&servInfo, SERVICE_START_PENDING, 1); + + if (CreateServiceThread(&servInfo) != 0) + { + servInfo.servStatus.dwServiceSpecificExitCode = 1; + UpdateStatus(&servInfo, SERVICE_STOPPED, 0); + return; + } + + LogEvent(_T("Service thread shut down. Set SERVICE_STOPPED status"), 0, 0, LOG_FILE); + UpdateStatus(&servInfo, SERVICE_STOPPED, 0); + + LogEvent(_T("Leaving ServiceMain"), 0, 0, LOG_FILE); + + return; +} + + +int _tmain(int argc, LPTSTR argv[]) +{ + SERVICE_TABLE_ENTRY ServiceTable[] = + { + {ServiceName, ServiceMain}, + {NULL, NULL } + }; + + InitLogging(); + + if (!StartServiceCtrlDispatcher(ServiceTable)) + LogEvent(_T("failed to start the service control dispatcher"), GetLastError(), 101, LOG_ALL); + + return 0; +} diff --git a/rosapps/skel_service/log.c b/rosapps/skel_service/log.c new file mode 100644 index 00000000000..ec9a768f4f2 --- /dev/null +++ b/rosapps/skel_service/log.c @@ -0,0 +1,194 @@ +/* + * PROJECT: ReactOS services + * LICENSE: GPL - See COPYING in the top level directory + * FILE: + * PURPOSE: skeleton service + * COPYRIGHT: Copyright 2008 Ged Murphy + * + */ + +#include "myservice.h" + +static LPTSTR lpEventSource = _T("Skeleton service"); +static LPTSTR lpLogFileName = _T("C:\\skel_service.log"); +static HANDLE hLogFile; + +// needs work +static VOID +LogToEventLog(LPCTSTR lpMsg, + DWORD errNum, + DWORD exitCode, + UINT flags) +{ + HANDLE hEventLog; + + hEventLog = RegisterEventSource(NULL, lpEventSource); + if (hEventLog) + { + ReportEvent(hEventLog, + (flags & LOG_ERROR) ? EVENTLOG_ERROR_TYPE : EVENTLOG_SUCCESS, + 0, + 0, + NULL, + 1, + 0, + &lpMsg, + NULL); + + CloseEventLog(hEventLog); + } +} + +static BOOL +OpenLogFile() +{ + hLogFile = CreateFile(lpLogFileName, + GENERIC_WRITE, + 0, + NULL, + OPEN_ALWAYS, + FILE_ATTRIBUTE_NORMAL, + NULL); + if (hLogFile == INVALID_HANDLE_VALUE) + return FALSE; + + return TRUE; +} + +static BOOL +LogToFile(LPCTSTR lpMsg, + DWORD errNum, + DWORD exitCode, + UINT flags) +{ + LPTSTR lpFullMsg = NULL; + DWORD msgLen; + + if (!OpenLogFile()) + return FALSE; + + msgLen = _tcslen(lpMsg) + 1; + + if (flags & LOG_ERROR) + { + LPVOID lpSysMsg; + DWORD eMsgLen; + + eMsgLen = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + errNum, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpSysMsg, + 0, + NULL); + + msgLen = msgLen + eMsgLen + 26; + + lpFullMsg = HeapAlloc(GetProcessHeap(), + 0, + msgLen * sizeof(TCHAR)); + if (lpFullMsg) + { + _sntprintf(lpFullMsg, + msgLen, + _T("%s %s ErrNum = %lu ExitCode = %lu\r\n"), + lpMsg, + lpSysMsg, + errNum, + exitCode); + } + + LocalFree(lpSysMsg); + + } + else + { + msgLen += 2; + + lpFullMsg = HeapAlloc(GetProcessHeap(), + 0, + msgLen * sizeof(TCHAR)); + if (lpFullMsg) + { + _sntprintf(lpFullMsg, + msgLen, + _T("%s\r\n"), + lpMsg); + } + } + + if (lpFullMsg) + { + DWORD bytesWritten; + + SetFilePointer(hLogFile, 0, NULL, FILE_END); + + WriteFile(hLogFile, + lpFullMsg, + msgLen * sizeof(TCHAR), + &bytesWritten, + NULL); + if (bytesWritten == 0) + { + LogToEventLog(_T("Failed to write to log file"), + GetLastError(), + 0, + LOG_EVENTLOG | LOG_ERROR); + } + + HeapFree(GetProcessHeap(), + 0, + lpFullMsg); + } + + CloseHandle(hLogFile); + + if (exitCode > 0) + ExitProcess(exitCode); +} + + +VOID +LogEvent(LPCTSTR lpMsg, + DWORD errNum, + DWORD exitCode, + UINT flags) +{ +#ifdef DEBUG + if (flags & LOG_FILE) + LogToFile(lpMsg, errNum, exitCode, flags); +#endif + if (flags & LOG_EVENTLOG) + LogToEventLog(lpMsg, errNum, exitCode, flags); +} + + +VOID +InitLogging() +{ + WCHAR wcBom = 0xFEFF; + + DeleteFile(lpLogFileName); + +#ifdef _UNICODE + if (OpenLogFile()) + { + DWORD bytesWritten; + + WriteFile(hLogFile, + &wcBom, + sizeof(WCHAR), + &bytesWritten, + NULL); + if (bytesWritten == 0) + { + LogToEventLog(_T("Failed to write to log file"), + GetLastError(), + 0, + LOG_EVENTLOG | LOG_ERROR); + } + + CloseHandle(hLogFile); + } +#endif +} diff --git a/rosapps/skel_service/myservice.h b/rosapps/skel_service/myservice.h new file mode 100644 index 00000000000..c353345c441 --- /dev/null +++ b/rosapps/skel_service/myservice.h @@ -0,0 +1,21 @@ +#include +#include + +#define DEBUG 1 + +#define LOG_FILE 1 +#define LOG_EVENTLOG 2 +#define LOG_ERROR 4 +#define LOG_ALL (LOG_FILE | LOG_EVENTLOG | LOG_ERROR) + +extern volatile BOOL bShutDown; +extern volatile BOOL bPause; + +VOID +LogEvent(LPCTSTR lpMsg, + DWORD errNum, + DWORD exitCode, + UINT flags); + +VOID +InitLogging();