I wrote a quick skeleton service this morning, thought it might be useful to someone.
authorGed Murphy <gedmurphy@reactos.org>
Mon, 31 Mar 2008 14:41:06 +0000 (14:41 +0000)
committerGed Murphy <gedmurphy@reactos.org>
Mon, 31 Mar 2008 14:41:06 +0000 (14:41 +0000)
svn path=/trunk/; revision=32793

rosapps/skel_service/ServiceMain.c [new file with mode: 0644]
rosapps/skel_service/log.c [new file with mode: 0644]
rosapps/skel_service/myservice.h [new file with mode: 0644]

diff --git a/rosapps/skel_service/ServiceMain.c b/rosapps/skel_service/ServiceMain.c
new file mode 100644 (file)
index 0000000..4f040fb
--- /dev/null
@@ -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;
+}
diff --git a/rosapps/skel_service/log.c b/rosapps/skel_service/log.c
new file mode 100644 (file)
index 0000000..ec9a768
--- /dev/null
@@ -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
+}
diff --git a/rosapps/skel_service/myservice.h b/rosapps/skel_service/myservice.h
new file mode 100644 (file)
index 0000000..c353345
--- /dev/null
@@ -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();