mirror of
https://github.com/reactos/reactos.git
synced 2025-02-22 08:25:03 +00:00
I wrote a quick skeleton service this morning, thought it might be useful to someone.
svn path=/trunk/; revision=32793
This commit is contained in:
parent
bae8253dc7
commit
317b7559ff
3 changed files with 414 additions and 0 deletions
199
rosapps/skel_service/ServiceMain.c
Normal file
199
rosapps/skel_service/ServiceMain.c
Normal file
|
@ -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 <gedmurphy@reactos.org>
|
||||
*
|
||||
*/
|
||||
|
||||
#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;
|
||||
}
|
194
rosapps/skel_service/log.c
Normal file
194
rosapps/skel_service/log.c
Normal file
|
@ -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 <gedmurphy@reactos.org>
|
||||
*
|
||||
*/
|
||||
|
||||
#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
|
||||
}
|
21
rosapps/skel_service/myservice.h
Normal file
21
rosapps/skel_service/myservice.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
|
||||
#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();
|
Loading…
Reference in a new issue