- Send the SCM reply packet with the final status after completing the requested...
[reactos.git] / reactos / dll / win32 / advapi32 / service / sctrl.c
index 6435f05..60516cd 100644 (file)
@@ -1,40 +1,39 @@
-/* $Id$
+/*
+ * PROJECT:     ReactOS advapi32
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        dll/win32/advapi32/service/sctrl.c
+ * PURPOSE:     Service control manager functions
+ * COPYRIGHT:   Copyright 1999 Emanuele Aliberti
+ *              Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
+ *                             Gregor Brunmar <gregor.brunmar@home.se>
  *
- * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS system libraries
- * FILE:            lib/advapi32/service/sctrl.c
- * PURPOSE:         Service control manager functions
- * PROGRAMMER:      Emanuele Aliberti
- * UPDATE HISTORY:
- *     19990413 EA     created
- *     19990515 EA
  */
 
+
 /* INCLUDES ******************************************************************/
 
 #include <advapi32.h>
+#include "wine/debug.h"
 
-#define NDEBUG
-#include <debug.h>
+WINE_DEFAULT_DEBUG_CHANNEL(advapi);
 
 
 /* TYPES *********************************************************************/
 
 typedef struct _ACTIVE_SERVICE
 {
-  DWORD ThreadId;
-  UNICODE_STRING ServiceName;
-  union
-  {
-    LPSERVICE_MAIN_FUNCTIONA lpFuncA;
-    LPSERVICE_MAIN_FUNCTIONW lpFuncW;
-  } Main;
-  LPHANDLER_FUNCTION HandlerFunction;
-  LPHANDLER_FUNCTION_EX HandlerFunctionEx;
-  LPVOID HandlerContext;
-  SERVICE_STATUS ServiceStatus;
-  BOOL bUnicode;
-  LPWSTR Arguments;
+    SERVICE_STATUS_HANDLE hServiceStatus;
+    UNICODE_STRING ServiceName;
+    union
+    {
+        LPSERVICE_MAIN_FUNCTIONA lpFuncA;
+        LPSERVICE_MAIN_FUNCTIONW lpFuncW;
+    } Main;
+    LPHANDLER_FUNCTION HandlerFunction;
+    LPHANDLER_FUNCTION_EX HandlerFunctionEx;
+    LPVOID HandlerContext;
+    BOOL bUnicode;
+    LPWSTR Arguments;
 } ACTIVE_SERVICE, *PACTIVE_SERVICE;
 
 
@@ -47,283 +46,389 @@ static PACTIVE_SERVICE lpActiveServices = NULL;
 /* FUNCTIONS *****************************************************************/
 
 static PACTIVE_SERVICE
-ScLookupServiceByServiceName(LPWSTR lpServiceName)
+ScLookupServiceByServiceName(LPCWSTR lpServiceName)
 {
-  DWORD i;
+    DWORD i;
 
-  for (i = 0; i < dwActiveServiceCount; i++)
+    for (i = 0; i < dwActiveServiceCount; i++)
     {
-      if (_wcsicmp(lpActiveServices[i].ServiceName.Buffer, lpServiceName) == 0)
-       {
-         return &lpActiveServices[i];
-       }
+        if (_wcsicmp(lpActiveServices[i].ServiceName.Buffer, lpServiceName) == 0)
+        {
+            return &lpActiveServices[i];
+        }
     }
 
-  SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
+    SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
 
-  return NULL;
+    return NULL;
 }
 
 
-static PACTIVE_SERVICE
-ScLookupServiceByThreadId(DWORD ThreadId)
+static DWORD WINAPI
+ScServiceMainStub(LPVOID Context)
 {
-  DWORD i;
+    PACTIVE_SERVICE lpService;
+    DWORD dwArgCount = 0;
+    DWORD dwLength = 0;
+    DWORD dwLen;
+    LPWSTR lpPtr;
+
+    lpService = (PACTIVE_SERVICE)Context;
 
-  for (i = 0; i < dwActiveServiceCount; i++)
+    TRACE("ScServiceMainStub() called\n");
+
+    /* Count arguments */
+    lpPtr = lpService->Arguments;
+    while (*lpPtr)
     {
-      if (lpActiveServices[i].ThreadId == ThreadId)
-       {
-         return &lpActiveServices[i];
-       }
+        TRACE("arg: %S\n", lpPtr);
+        dwLen = wcslen(lpPtr) + 1;
+        dwArgCount++;
+        dwLength += dwLen;
+        lpPtr += dwLen;
     }
+    TRACE("dwArgCount: %ld\ndwLength: %ld\n", dwArgCount, dwLength);
 
-  SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
+    /* Build the argument vector and call the main service routine */
+    if (lpService->bUnicode)
+    {
+        LPWSTR *lpArgVector;
+        LPWSTR Ptr;
+
+        lpArgVector = HeapAlloc(GetProcessHeap(),
+                                HEAP_ZERO_MEMORY,
+                                (dwArgCount + 1) * sizeof(LPWSTR));
+        if (lpArgVector == NULL)
+            return ERROR_OUTOFMEMORY;
+
+        dwArgCount = 0;
+        Ptr = lpService->Arguments;
+        while (*Ptr)
+        {
+            lpArgVector[dwArgCount] = Ptr;
 
-  return NULL;
-}
+            dwArgCount++;
+            Ptr += (wcslen(Ptr) + 1);
+        }
+        lpArgVector[dwArgCount] = NULL;
 
+        (lpService->Main.lpFuncW)(dwArgCount, lpArgVector);
 
-static DWORD WINAPI
-ScServiceMainStub(LPVOID Context)
-{
-  PACTIVE_SERVICE lpService;
-  DWORD dwArgCount = 0;
-  DWORD dwLength = 0;
-
-  lpService = (PACTIVE_SERVICE)Context;
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpArgVector);
+    }
+    else
+    {
+        LPSTR *lpArgVector;
+        LPSTR Ptr;
+        LPSTR AnsiString;
+        DWORD AnsiLength;
+
+        AnsiLength = WideCharToMultiByte(CP_ACP,
+                                         0,
+                                         lpService->Arguments,
+                                         dwLength,
+                                         NULL,
+                                         0,
+                                         NULL,
+                                         NULL);
+        if (AnsiLength == 0)
+            return ERROR_INVALID_PARAMETER; /* ? */
+
+        AnsiString = HeapAlloc(GetProcessHeap(),
+                               0,
+                               AnsiLength + 1);
+        if (AnsiString == NULL)
+            return ERROR_OUTOFMEMORY;
+
+        WideCharToMultiByte(CP_ACP,
+                            0,
+                            lpService->Arguments,
+                            dwLength,
+                            AnsiString,
+                            AnsiLength,
+                            NULL,
+                            NULL);
+
+        AnsiString[AnsiLength] = ANSI_NULL;
+
+        lpArgVector = HeapAlloc(GetProcessHeap(),
+                                0,
+                                (dwArgCount + 1) * sizeof(LPSTR));
+        if (lpArgVector == NULL)
+        {
+            HeapFree(GetProcessHeap(),
+                        0,
+                        AnsiString);
+            return ERROR_OUTOFMEMORY;
+        }
 
-  DPRINT("ScServiceMainStub() called\n");
+        dwArgCount = 0;
+        Ptr = AnsiString;
+        while (*Ptr)
+        {
+            lpArgVector[dwArgCount] = Ptr;
 
-  /* Count arguments */
-  while (lpService->Arguments[dwLength])
-    {
-      dwLength += wcslen(&lpService->Arguments[dwLength]) + 1;
-      dwArgCount++;
-    }
+            dwArgCount++;
+            Ptr += (strlen(Ptr) + 1);
+        }
+        lpArgVector[dwArgCount] = NULL;
 
-  /* Build the argument vector and call the main service routine */
-  if (lpService->bUnicode)
-    {
-      LPWSTR *lpArgVector;
-      LPWSTR Ptr;
+        (lpService->Main.lpFuncA)(dwArgCount, lpArgVector);
 
-      lpArgVector = HeapAlloc(GetProcessHeap(),
-                             HEAP_ZERO_MEMORY,
-                             (dwArgCount + 1) * sizeof(LPWSTR));
-      if (lpArgVector == NULL)
-        return ERROR_OUTOFMEMORY;
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpArgVector);
+        HeapFree(GetProcessHeap(),
+                 0,
+                 AnsiString);
+    }
 
-      dwArgCount = 0;
-      Ptr = lpService->Arguments;
-      while (*Ptr)
-       {
-         lpArgVector[dwArgCount] = Ptr;
-
-         dwArgCount++;
-         Ptr += (wcslen(Ptr) + 1);
-       }
-      lpArgVector[dwArgCount] = NULL;
-
-      (lpService->Main.lpFuncW)(dwArgCount, lpArgVector);
-
-      HeapFree(GetProcessHeap(),
-              0,
-              lpArgVector);
-    }
-  else
-    {
-      LPSTR *lpArgVector;
-      LPSTR Ptr;
-      LPSTR AnsiString;
-      DWORD AnsiLength;
-
-      AnsiLength = WideCharToMultiByte(CP_ACP,
-                                      0,
-                                      lpService->Arguments,
-                                      dwLength,
-                                      NULL,
-                                      0,
-                                      NULL,
-                                      NULL);
-      AnsiString = HeapAlloc(GetProcessHeap(),
-                            0,
-                            AnsiLength);
-      WideCharToMultiByte(CP_ACP,
-                         0,
-                         lpService->Arguments,
-                         dwLength,
-                         AnsiString,
-                         AnsiLength,
-                         NULL,
-                         NULL);
-
-      lpArgVector = HeapAlloc(GetProcessHeap(),
-                             0,
-                             (dwArgCount + 1) * sizeof(LPSTR));
-
-      dwArgCount = 0;
-      Ptr = AnsiString;
-      while (*Ptr)
-       {
-         lpArgVector[dwArgCount] = Ptr;
-
-         dwArgCount++;
-         Ptr += (strlen(Ptr) + 1);
-       }
-      lpArgVector[dwArgCount] = NULL;
-
-      (lpService->Main.lpFuncA)(dwArgCount, lpArgVector);
-
-      HeapFree(GetProcessHeap(),
-              0,
-              lpArgVector);
-      HeapFree(GetProcessHeap(),
-              0,
-              AnsiString);
-    }
-
-  return ERROR_SUCCESS;
+    return ERROR_SUCCESS;
 }
 
 
 static DWORD
 ScConnectControlPipe(HANDLE *hPipe)
 {
-  DWORD dwBytesWritten;
-  DWORD dwProcessId;
-  DWORD dwState;
+    DWORD dwBytesWritten;
+    DWORD dwState;
+    DWORD dwServiceCurrent = 0;
+    NTSTATUS Status;
+    WCHAR NtControlPipeName[MAX_PATH + 1];
+    RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+    DWORD dwProcessId;
+
+    /* Get the service number and create the named pipe */
+    RtlZeroMemory(&QueryTable,
+                  sizeof(QueryTable));
+
+    QueryTable[0].Name = L"";
+    QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+    QueryTable[0].EntryContext = &dwServiceCurrent;
+
+    Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
+                                    L"ServiceCurrent",
+                                    QueryTable,
+                                    NULL,
+                                    NULL);
+
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
+        return RtlNtStatusToDosError(Status);
+    }
+
+    swprintf(NtControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", dwServiceCurrent);
 
-  if (!WaitNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe", 15000))
+    if (!WaitNamedPipeW(NtControlPipeName, 15000))
     {
-      DPRINT1("WaitNamedPipe() failed (Error %lu)\n", GetLastError());
-      return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
+        ERR("WaitNamedPipe(%S) failed (Error %lu)\n", NtControlPipeName, GetLastError());
+        return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
     }
 
-  *hPipe = CreateFileW(L"\\\\.\\pipe\\net\\NtControlPipe",
-                      GENERIC_READ | GENERIC_WRITE,
-                      0,
-                      NULL,
-                      OPEN_EXISTING,
-                      FILE_ATTRIBUTE_NORMAL,
-                      NULL);
-  if (*hPipe == INVALID_HANDLE_VALUE)
+    *hPipe = CreateFileW(NtControlPipeName,
+                         GENERIC_READ | GENERIC_WRITE,
+                         0,
+                         NULL,
+                         OPEN_EXISTING,
+                         FILE_ATTRIBUTE_NORMAL,
+                         NULL);
+    if (*hPipe == INVALID_HANDLE_VALUE)
     {
-      DPRINT1("CreateFileW() failed (Error %lu)\n", GetLastError());
-      return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
+        ERR("CreateFileW() failed for pipe %S (Error %lu)\n", NtControlPipeName, GetLastError());
+        return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
     }
 
-  dwState = PIPE_READMODE_MESSAGE;
-  if (!SetNamedPipeHandleState(*hPipe, &dwState, NULL, NULL))
+    dwState = PIPE_READMODE_MESSAGE;
+    if (!SetNamedPipeHandleState(*hPipe, &dwState, NULL, NULL))
     {
-      CloseHandle(hPipe);
-      *hPipe = INVALID_HANDLE_VALUE;
-      return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
+        CloseHandle(*hPipe);
+        *hPipe = INVALID_HANDLE_VALUE;
+        return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
     }
 
-  dwProcessId = GetCurrentProcessId();
-  WriteFile(*hPipe,
-           &dwProcessId,
-           sizeof(DWORD),
-           &dwBytesWritten,
-           NULL);
+    /* Pass the ProcessId to the SCM */
+    dwProcessId = GetCurrentProcessId();
+    WriteFile(*hPipe,
+              &dwProcessId,
+              sizeof(DWORD),
+              &dwBytesWritten,
+              NULL);
 
-  DPRINT("Sent process id %lu\n", dwProcessId);
+    TRACE("Sent Process ID %lu\n", dwProcessId);
 
-  return ERROR_SUCCESS;
+
+    return ERROR_SUCCESS;
 }
 
 
+static DWORD
+ScStartService(PACTIVE_SERVICE lpService,
+               PSCM_CONTROL_PACKET ControlPacket)
+{
+    HANDLE ThreadHandle;
+    DWORD ThreadId;
+
+    TRACE("ScStartService() called\n");
+    TRACE("Size: %lu\n", ControlPacket->dwSize);
+    TRACE("Service: %S\n", &ControlPacket->szArguments[0]);
+
+    /* Set the service status handle */
+    lpService->hServiceStatus = ControlPacket->hServiceStatus;
+
+    lpService->Arguments = HeapAlloc(GetProcessHeap(),
+                                     HEAP_ZERO_MEMORY,
+                                     (ControlPacket->dwSize + 1) * sizeof(WCHAR));
+    if (lpService->Arguments == NULL)
+        return ERROR_OUTOFMEMORY;
+
+    memcpy(lpService->Arguments,
+           ControlPacket->szArguments,
+           ControlPacket->dwSize * sizeof(WCHAR));
+
+    /* invoke the services entry point and implement the command loop */
+    ThreadHandle = CreateThread(NULL,
+                                0,
+                                ScServiceMainStub,
+                                lpService,
+                                CREATE_SUSPENDED,
+                                &ThreadId);
+    if (ThreadHandle == NULL)
+        return ERROR_SERVICE_NO_THREAD;
+
+    ResumeThread(ThreadHandle);
+    CloseHandle(ThreadHandle);
+
+    return ERROR_SUCCESS;
+}
+
 
 static DWORD
-ScStartService(PSCM_START_PACKET StartPacket)
+ScControlService(PACTIVE_SERVICE lpService,
+                 PSCM_CONTROL_PACKET ControlPacket)
 {
-  PACTIVE_SERVICE lpService;
-  HANDLE ThreadHandle;
-
-  DPRINT("Size: %lu\n", StartPacket->Size);
-  DPRINT("Service: %S\n", &StartPacket->Arguments[0]);
-
-  lpService = ScLookupServiceByServiceName(&StartPacket->Arguments[0]);
-  if (lpService == NULL)
-    return ERROR_SERVICE_DOES_NOT_EXIST;
-
-  lpService->Arguments = HeapAlloc(GetProcessHeap(),
-                                  HEAP_ZERO_MEMORY,
-               StartPacket->Size * sizeof(WCHAR));
-  if (lpService->Arguments == NULL)
-    return ERROR_OUTOFMEMORY;
-
-  memcpy(lpService->Arguments,
-        StartPacket->Arguments,
-        StartPacket->Size * sizeof(WCHAR));
-
-  ThreadHandle = CreateThread(NULL,
-                             0,
-                             ScServiceMainStub,
-                             lpService,
-                             CREATE_SUSPENDED,
-                             &lpService->ThreadId);
-  if (ThreadHandle == NULL)
-    return ERROR_SERVICE_NO_THREAD;
-
-  ResumeThread(ThreadHandle);
-  CloseHandle(ThreadHandle);
-
-  return ERROR_SUCCESS;
+    TRACE("ScControlService() called\n");
+    TRACE("Size: %lu\n", ControlPacket->dwSize);
+    TRACE("Service: %S\n", &ControlPacket->szArguments[0]);
+
+    if (lpService->HandlerFunction)
+    {
+        (lpService->HandlerFunction)(ControlPacket->dwControl);
+    }
+    else if (lpService->HandlerFunctionEx)
+    {
+        /* FIXME: send correct params */
+        (lpService->HandlerFunctionEx)(ControlPacket->dwControl, 0, NULL, NULL);
+    }
+
+    if (ControlPacket->dwControl == SERVICE_CONTROL_STOP)
+    {
+        HeapFree(GetProcessHeap(),
+                 0,
+                 lpService->Arguments);
+    }
+
+    TRACE("ScControlService() done\n");
+
+    return ERROR_SUCCESS;
 }
 
 
 static BOOL
 ScServiceDispatcher(HANDLE hPipe,
-                   PUCHAR lpBuffer,
-                   DWORD dwBufferSize)
+                    PUCHAR lpBuffer,
+                    DWORD dwBufferSize)
 {
-  LPDWORD Buffer;
-  DWORD Count;
-  BOOL bResult;
-
-  DPRINT("ScDispatcherLoop() called\n");
-
-  Buffer = HeapAlloc(GetProcessHeap(),
-                     HEAP_ZERO_MEMORY,
-                     1024);
-  if (Buffer == NULL)
-    return FALSE;
-
-  while (TRUE)
-    {
-      /* Read command from the control pipe */
-      bResult = ReadFile(hPipe,
-                        Buffer,
-                        1024,
-                        &Count,
-                        NULL);
-      if (bResult == FALSE)
+    PSCM_CONTROL_PACKET ControlPacket;
+    DWORD Count;
+    BOOL bResult;
+    DWORD dwRunningServices = 0;
+    LPWSTR lpServiceName;
+    PACTIVE_SERVICE lpService;
+    SCM_REPLY_PACKET ReplyPacket;
+    DWORD dwError;
+
+    TRACE("ScDispatcherLoop() called\n");
+
+    ControlPacket = HeapAlloc(GetProcessHeap(),
+                              HEAP_ZERO_MEMORY,
+                              1024);
+    if (ControlPacket == NULL)
+        return FALSE;
+
+    while (TRUE)
+    {
+        /* Read command from the control pipe */
+        bResult = ReadFile(hPipe,
+                           ControlPacket,
+                           1024,
+                           &Count,
+                           NULL);
+        if (bResult == FALSE)
         {
-          DPRINT1("Pipe read failed (Error: %lu)\n", GetLastError());
-          return FALSE;
+            ERR("Pipe read failed (Error: %lu)\n", GetLastError());
+            return FALSE;
         }
 
-      /* Execute command */
-      switch (Buffer[0])
+        lpServiceName = &ControlPacket->szArguments[0];
+        TRACE("Service: %S\n", lpServiceName);
+
+        lpService = ScLookupServiceByServiceName(lpServiceName);
+        if (lpService != NULL)
         {
-          case SCM_START_COMMAND:
-            DPRINT("Start command\n");
-            ScStartService((PSCM_START_PACKET)Buffer);
-            break;
+            /* Execute command */
+            switch (ControlPacket->dwControl)
+            {
+                case SERVICE_CONTROL_START:
+                    TRACE("Start command - recieved SERVICE_CONTROL_START\n");
+                    dwError = ScStartService(lpService, ControlPacket);
+                    if (dwError == ERROR_SUCCESS)
+                        dwRunningServices++;
+                    break;
+
+                case SERVICE_CONTROL_STOP:
+                    TRACE("Stop command - recieved SERVICE_CONTROL_STOP\n");
+                    dwError = ScControlService(lpService, ControlPacket);
+                    if (dwError == ERROR_SUCCESS)
+                        dwRunningServices--;
+                    break;
+
+                default:
+                    TRACE("Command %lu received", ControlPacket->dwControl);
+                    dwError = ScControlService(lpService, ControlPacket);
+                    break;
+            }
+        }
+        else
+        {
+            dwError = ERROR_NOT_FOUND;
+        }
 
-          default:
-            DPRINT1("Unknown command %lu", Buffer[0]);
-            break;
+        ReplyPacket.dwError = dwError;
+
+        /* Send the reply packet */
+        bResult = WriteFile(hPipe,
+                            &ReplyPacket,
+                            sizeof(ReplyPacket),
+                            &Count,
+                            NULL);
+        if (bResult == FALSE)
+        {
+            ERR("Pipe write failed (Error: %lu)\n", GetLastError());
+            return FALSE;
         }
+
+        if (dwRunningServices == 0)
+            break;
     }
 
-  HeapFree(GetProcessHeap(),
-           0,
-           Buffer);
+    HeapFree(GetProcessHeap(),
+             0,
+             ControlPacket);
 
-  return TRUE;
+    return TRUE;
 }
 
 
@@ -332,27 +437,27 @@ ScServiceDispatcher(HANDLE hPipe,
  *
  * @implemented
  */
-SERVICE_STATUS_HANDLE STDCALL
+SERVICE_STATUS_HANDLE WINAPI
 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
-                           LPHANDLER_FUNCTION lpHandlerProc)
+                            LPHANDLER_FUNCTION lpHandlerProc)
 {
-  ANSI_STRING ServiceNameA;
-  UNICODE_STRING ServiceNameU;
-  SERVICE_STATUS_HANDLE SHandle;
+    ANSI_STRING ServiceNameA;
+    UNICODE_STRING ServiceNameU;
+    SERVICE_STATUS_HANDLE SHandle;
 
-  RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
-  if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
+    RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
+    if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
     {
-      SetLastError(ERROR_OUTOFMEMORY);
-      return (SERVICE_STATUS_HANDLE)0;
+        SetLastError(ERROR_OUTOFMEMORY);
+        return (SERVICE_STATUS_HANDLE)0;
     }
 
-  SHandle = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer,
-                                       lpHandlerProc);
+    SHandle = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer,
+                                          lpHandlerProc);
 
-  RtlFreeUnicodeString(&ServiceNameU);
+    RtlFreeUnicodeString(&ServiceNameU);
 
-  return SHandle;
+    return SHandle;
 }
 
 
@@ -361,22 +466,24 @@ RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
  *
  * @implemented
  */
-SERVICE_STATUS_HANDLE STDCALL
+SERVICE_STATUS_HANDLE WINAPI
 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
-                           LPHANDLER_FUNCTION lpHandlerProc)
+                            LPHANDLER_FUNCTION lpHandlerProc)
 {
-  PACTIVE_SERVICE Service;
+    PACTIVE_SERVICE Service;
 
-  Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName);
-  if (Service == NULL)
+    Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName);
+    if (Service == NULL)
     {
-      return (SERVICE_STATUS_HANDLE)NULL;
+        return (SERVICE_STATUS_HANDLE)NULL;
     }
 
-  Service->HandlerFunction = lpHandlerProc;
-  Service->HandlerFunctionEx = NULL;
+    Service->HandlerFunction = lpHandlerProc;
+    Service->HandlerFunctionEx = NULL;
+
+    TRACE("RegisterServiceCtrlHandler returning %lu\n", Service->hServiceStatus);
 
-  return (SERVICE_STATUS_HANDLE)Service->ThreadId;
+    return Service->hServiceStatus;
 }
 
 
@@ -385,29 +492,29 @@ RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
  *
  * @implemented
  */
-SERVICE_STATUS_HANDLE STDCALL
+SERVICE_STATUS_HANDLE WINAPI
 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName,
-                             LPHANDLER_FUNCTION_EX lpHandlerProc,
-                             LPVOID lpContext)
+                              LPHANDLER_FUNCTION_EX lpHandlerProc,
+                              LPVOID lpContext)
 {
-  ANSI_STRING ServiceNameA;
-  UNICODE_STRING ServiceNameU;
-  SERVICE_STATUS_HANDLE SHandle;
+    ANSI_STRING ServiceNameA;
+    UNICODE_STRING ServiceNameU;
+    SERVICE_STATUS_HANDLE SHandle;
 
-  RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
-  if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
+    RtlInitAnsiString(&ServiceNameA, (LPSTR)lpServiceName);
+    if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE)))
     {
-      SetLastError(ERROR_OUTOFMEMORY);
-      return (SERVICE_STATUS_HANDLE)0;
+        SetLastError(ERROR_OUTOFMEMORY);
+        return (SERVICE_STATUS_HANDLE)0;
     }
 
-  SHandle = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer,
-                                         lpHandlerProc,
-                                         lpContext);
+    SHandle = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer,
+                                            lpHandlerProc,
+                                            lpContext);
 
-  RtlFreeUnicodeString(&ServiceNameU);
+    RtlFreeUnicodeString(&ServiceNameU);
 
-  return SHandle;
+    return SHandle;
 }
 
 
@@ -416,40 +523,117 @@ RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName,
  *
  * @implemented
  */
-SERVICE_STATUS_HANDLE STDCALL
+SERVICE_STATUS_HANDLE WINAPI
 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName,
-                             LPHANDLER_FUNCTION_EX lpHandlerProc,
-                             LPVOID lpContext)
+                              LPHANDLER_FUNCTION_EX lpHandlerProc,
+                              LPVOID lpContext)
+{
+    PACTIVE_SERVICE Service;
+
+    Service = ScLookupServiceByServiceName(lpServiceName);
+    if (Service == NULL)
+    {
+        return (SERVICE_STATUS_HANDLE)NULL;
+    }
+
+    Service->HandlerFunction = NULL;
+    Service->HandlerFunctionEx = lpHandlerProc;
+    Service->HandlerContext = lpContext;
+
+    TRACE("RegisterServiceCtrlHandlerEx returning %lu\n", Service->hServiceStatus);
+
+    return Service->hServiceStatus;
+}
+
+
+/**********************************************************************
+ *     I_ScSetServiceBitsA
+ *
+ * Undocumented
+ *
+ * @implemented
+ */
+BOOL WINAPI
+I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus,
+                    DWORD dwServiceBits,
+                    BOOL bSetBitsOn,
+                    BOOL bUpdateImmediately,
+                    LPSTR lpString)
 {
-  PACTIVE_SERVICE Service;
+    BOOL bResult;
 
-  Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName);
-  if (Service == NULL)
+    RpcTryExcept
     {
-      return (SERVICE_STATUS_HANDLE)NULL;
+        /* Call to services.exe using RPC */
+        bResult = RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
+                                       dwServiceBits,
+                                       bSetBitsOn,
+                                       bUpdateImmediately,
+                                       lpString);
     }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
+        bResult = FALSE;
+    }
+    RpcEndExcept;
+
+    return bResult;
+}
 
-  Service->HandlerFunction = NULL;
-  Service->HandlerFunctionEx = lpHandlerProc;
-  Service->HandlerContext = lpContext;
 
-  return (SERVICE_STATUS_HANDLE)Service->ThreadId;
+/**********************************************************************
+ *     I_ScSetServiceBitsW
+ *
+ * Undocumented
+ *
+ * @implemented
+ */
+BOOL WINAPI
+I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus,
+                    DWORD dwServiceBits,
+                    BOOL bSetBitsOn,
+                    BOOL bUpdateImmediately,
+                    LPWSTR lpString)
+{
+    BOOL bResult;
+
+    RpcTryExcept
+    {
+        /* Call to services.exe using RPC */
+        bResult = RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
+                                       dwServiceBits,
+                                       bSetBitsOn,
+                                       bUpdateImmediately,
+                                       lpString);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        SetLastError(ScmRpcStatusToWinError(RpcExceptionCode()));
+        bResult = FALSE;
+    }
+    RpcEndExcept;
+
+    return bResult;
 }
 
 
 /**********************************************************************
  *     SetServiceBits
  *
- * @unimplemented
+ * @implemented
  */
-BOOL STDCALL
+BOOL WINAPI
 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
-              DWORD dwServiceBits,
-              BOOL bSetBitsOn,
-              BOOL bUpdateImmediately)
+               DWORD dwServiceBits,
+               BOOL bSetBitsOn,
+               BOOL bUpdateImmediately)
 {
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return FALSE;
+    return I_ScSetServiceBitsW(hServiceStatus,
+                               dwServiceBits,
+                               bSetBitsOn,
+                               bUpdateImmediately,
+                               NULL);
 }
 
 
@@ -458,178 +642,208 @@ SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
  *
  * @implemented
  */
-BOOL STDCALL
+BOOL WINAPI
 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
-                LPSERVICE_STATUS lpServiceStatus)
+                 LPSERVICE_STATUS lpServiceStatus)
 {
-  PACTIVE_SERVICE Service;
+    DWORD dwError;
+
+    TRACE("SetServiceStatus() called\n");
+    TRACE("hServiceStatus %lu\n", hServiceStatus);
 
-  Service = ScLookupServiceByThreadId((DWORD)hServiceStatus);
-  if (!Service)
+    /* Call to services.exe using RPC */
+    dwError = RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE)hServiceStatus,
+                                lpServiceStatus);
+    if (dwError != ERROR_SUCCESS)
     {
-      SetLastError(ERROR_INVALID_HANDLE);
-      return FALSE;
+        ERR("ScmrSetServiceStatus() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
     }
 
-  RtlCopyMemory(&Service->ServiceStatus,
-               lpServiceStatus,
-               sizeof(SERVICE_STATUS));
+    TRACE("SetServiceStatus() done (ret %lu)\n", dwError);
 
-  return TRUE;
+    return TRUE;
 }
 
 
 /**********************************************************************
  *     StartServiceCtrlDispatcherA
  *
- * @unimplemented
+ * @implemented
  */
-BOOL STDCALL
-StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable)
+BOOL WINAPI
+StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA * lpServiceStartTable)
 {
-  ULONG i;
-  HANDLE hPipe;
-  DWORD dwError;
-  PUCHAR lpMessageBuffer;
+    ULONG i;
+    HANDLE hPipe;
+    DWORD dwError;
+    PUCHAR lpMessageBuffer;
 
-  DPRINT("StartServiceCtrlDispatcherA() called\n");
+    TRACE("StartServiceCtrlDispatcherA() called\n");
 
-  i = 0;
-  while (lpServiceStartTable[i].lpServiceProc != NULL)
+    i = 0;
+    while (lpServiceStartTable[i].lpServiceProc != NULL)
     {
-      i++;
+        i++;
     }
 
-  dwActiveServiceCount = i;
-  lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
-                                    HEAP_ZERO_MEMORY,
-                                    dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
-  if (lpActiveServices == NULL)
+    dwActiveServiceCount = i;
+    lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
+                                       HEAP_ZERO_MEMORY,
+                                       dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
+    if (lpActiveServices == NULL)
     {
-      return FALSE;
+        return FALSE;
     }
 
-  /* Copy service names and start procedure */
-  for (i = 0; i < dwActiveServiceCount; i++)
+    /* Copy service names and start procedure */
+    for (i = 0; i < dwActiveServiceCount; i++)
     {
-      RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
-                                      lpServiceStartTable[i].lpServiceName);
-      lpActiveServices[i].Main.lpFuncA = lpServiceStartTable[i].lpServiceProc;
-      lpActiveServices[i].bUnicode = FALSE;
+        RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
+                                         lpServiceStartTable[i].lpServiceName);
+        lpActiveServices[i].Main.lpFuncA = lpServiceStartTable[i].lpServiceProc;
+        lpActiveServices[i].hServiceStatus = 0;
+        lpActiveServices[i].bUnicode = FALSE;
     }
 
-  dwError = ScConnectControlPipe(&hPipe);
-  if (dwError != ERROR_SUCCESS)
+    dwError = ScConnectControlPipe(&hPipe);
+    if (dwError != ERROR_SUCCESS)
     {
-      /* Free the service table */
-      RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
-      lpActiveServices = NULL;
-      dwActiveServiceCount = 0;
-      return FALSE;
+        /* Free the service table */
+        for (i = 0; i < dwActiveServiceCount; i++)
+        {
+            RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
+        }
+        RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
+        lpActiveServices = NULL;
+        dwActiveServiceCount = 0;
+        return FALSE;
     }
 
-  lpMessageBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
-                                   HEAP_ZERO_MEMORY,
-                                   256);
-  if (lpMessageBuffer == NULL)
+    lpMessageBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
+                                      HEAP_ZERO_MEMORY,
+                                      256);
+    if (lpMessageBuffer == NULL)
     {
-      /* Free the service table */
-      RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
-      lpActiveServices = NULL;
-      dwActiveServiceCount = 0;
-      CloseHandle(hPipe);
-      return FALSE;
+        /* Free the service table */
+        for (i = 0; i < dwActiveServiceCount; i++)
+        {
+            RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
+        }
+        RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
+        lpActiveServices = NULL;
+        dwActiveServiceCount = 0;
+        CloseHandle(hPipe);
+        return FALSE;
     }
 
-  ScServiceDispatcher(hPipe, lpMessageBuffer, 256);
-  CloseHandle(hPipe);
+    ScServiceDispatcher(hPipe, lpMessageBuffer, 256);
+    CloseHandle(hPipe);
 
-  /* Free the message buffer */
-  RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer);
+    /* Free the message buffer */
+    RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer);
 
-  /* Free the service table */
-  RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
-  lpActiveServices = NULL;
-  dwActiveServiceCount = 0;
+    /* Free the service table */
+    for (i = 0; i < dwActiveServiceCount; i++)
+    {
+        RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
+    }
+    RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
+    lpActiveServices = NULL;
+    dwActiveServiceCount = 0;
 
-  return TRUE;
+    return TRUE;
 }
 
 
 /**********************************************************************
  *     StartServiceCtrlDispatcherW
  *
- * @unimplemented
+ * @implemented
  */
-BOOL STDCALL
-StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable)
+BOOL WINAPI
+StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW * lpServiceStartTable)
 {
-  ULONG i;
-  HANDLE hPipe;
-  DWORD dwError;
-  PUCHAR lpMessageBuffer;
+    ULONG i;
+    HANDLE hPipe;
+    DWORD dwError;
+    PUCHAR lpMessageBuffer;
 
-  DPRINT("StartServiceCtrlDispatcherW() called\n");
+    TRACE("StartServiceCtrlDispatcherW() called\n");
 
-  i = 0;
-  while (lpServiceStartTable[i].lpServiceProc != NULL)
+    i = 0;
+    while (lpServiceStartTable[i].lpServiceProc != NULL)
     {
-      i++;
+        i++;
     }
 
-  dwActiveServiceCount = i;
-  lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
-                                    HEAP_ZERO_MEMORY,
-                                    dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
-  if (lpActiveServices == NULL)
+    dwActiveServiceCount = i;
+    lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(),
+                                       HEAP_ZERO_MEMORY,
+                                       dwActiveServiceCount * sizeof(ACTIVE_SERVICE));
+    if (lpActiveServices == NULL)
     {
-      return FALSE;
+        return FALSE;
     }
 
-  /* Copy service names and start procedure */
-  for (i = 0; i < dwActiveServiceCount; i++)
+    /* Copy service names and start procedure */
+    for (i = 0; i < dwActiveServiceCount; i++)
     {
-      RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
-                            lpServiceStartTable[i].lpServiceName);
-      lpActiveServices[i].Main.lpFuncW = lpServiceStartTable[i].lpServiceProc;
-      lpActiveServices[i].bUnicode = TRUE;
+        RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
+                               lpServiceStartTable[i].lpServiceName);
+        lpActiveServices[i].Main.lpFuncW = lpServiceStartTable[i].lpServiceProc;
+        lpActiveServices[i].hServiceStatus = 0;
+        lpActiveServices[i].bUnicode = TRUE;
     }
 
-  dwError = ScConnectControlPipe(&hPipe);
-  if (dwError != ERROR_SUCCESS)
+    dwError = ScConnectControlPipe(&hPipe);
+    if (dwError != ERROR_SUCCESS)
     {
-      /* Free the service table */
-      RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
-      lpActiveServices = NULL;
-      dwActiveServiceCount = 0;
-      return FALSE;
+        /* Free the service table */
+        for (i = 0; i < dwActiveServiceCount; i++)
+        {
+            RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
+        }
+        RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
+        lpActiveServices = NULL;
+        dwActiveServiceCount = 0;
+        return FALSE;
     }
 
-  lpMessageBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
-                                   HEAP_ZERO_MEMORY,
-                                   256);
-  if (lpMessageBuffer == NULL)
+    lpMessageBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
+                                      HEAP_ZERO_MEMORY,
+                                      256);
+    if (lpMessageBuffer == NULL)
     {
-      /* Free the service table */
-      RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
-      lpActiveServices = NULL;
-      dwActiveServiceCount = 0;
-      CloseHandle(hPipe);
-      return FALSE;
+        /* Free the service table */
+        for (i = 0; i < dwActiveServiceCount; i++)
+        {
+            RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
+        }
+        RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
+        lpActiveServices = NULL;
+        dwActiveServiceCount = 0;
+        CloseHandle(hPipe);
+        return FALSE;
     }
 
-  ScServiceDispatcher(hPipe, lpMessageBuffer, 256);
-  CloseHandle(hPipe);
+    ScServiceDispatcher(hPipe, lpMessageBuffer, 256);
+    CloseHandle(hPipe);
 
-  /* Free the message buffer */
-  RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer);
+    /* Free the message buffer */
+    RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer);
 
-  /* Free the service table */
-  RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
-  lpActiveServices = NULL;
-  dwActiveServiceCount = 0;
+    /* Free the service table */
+    for (i = 0; i < dwActiveServiceCount; i++)
+    {
+        RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
+    }
+    RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
+    lpActiveServices = NULL;
+    dwActiveServiceCount = 0;
 
-  return TRUE;
+    return TRUE;
 }
 
 /* EOF */