- Implement RCreateServiceA.
[reactos.git] / reactos / dll / win32 / advapi32 / service / sctrl.c
index 5c4fc5d..3094951 100644 (file)
@@ -1,28 +1,28 @@
-/* $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;
+    CLIENT_HANDLE hService;
     UNICODE_STRING ServiceName;
     union
     {
@@ -47,7 +47,7 @@ static PACTIVE_SERVICE lpActiveServices = NULL;
 /* FUNCTIONS *****************************************************************/
 
 static PACTIVE_SERVICE
-ScLookupServiceByServiceName(LPWSTR lpServiceName)
+ScLookupServiceByServiceName(LPCWSTR lpServiceName)
 {
     DWORD i;
 
@@ -65,25 +65,6 @@ ScLookupServiceByServiceName(LPWSTR lpServiceName)
 }
 
 
-static PACTIVE_SERVICE
-ScLookupServiceByThreadId(DWORD ThreadId)
-{
-    DWORD i;
-
-    for (i = 0; i < dwActiveServiceCount; i++)
-    {
-        if (lpActiveServices[i].ThreadId == ThreadId)
-        {
-            return &lpActiveServices[i];
-        }
-    }
-
-    SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
-
-    return NULL;
-}
-
-
 static DWORD WINAPI
 ScServiceMainStub(LPVOID Context)
 {
@@ -95,19 +76,19 @@ ScServiceMainStub(LPVOID Context)
 
     lpService = (PACTIVE_SERVICE)Context;
 
-    DPRINT("ScServiceMainStub() called\n");
+    TRACE("ScServiceMainStub() called\n");
 
     /* Count arguments */
     lpPtr = lpService->Arguments;
     while (*lpPtr)
     {
-        DPRINT("arg: %S\n", *lpPtr);
+        TRACE("arg: %S\n", lpPtr);
         dwLen = wcslen(lpPtr) + 1;
         dwArgCount++;
         dwLength += dwLen;
         lpPtr += dwLen;
     }
-    DPRINT("dwArgCount: %ld\ndwLength: %ld\n", dwArgCount, dwLength);
+    TRACE("dwArgCount: %ld\ndwLength: %ld\n", dwArgCount, dwLength);
 
     /* Build the argument vector and call the main service routine */
     if (lpService->bUnicode)
@@ -153,9 +134,15 @@ ScServiceMainStub(LPVOID Context)
                                          0,
                                          NULL,
                                          NULL);
+        if (AnsiLength == 0)
+            return ERROR_INVALID_PARAMETER; /* ? */
+
         AnsiString = HeapAlloc(GetProcessHeap(),
                                0,
-                               AnsiLength);
+                               AnsiLength + 1);
+        if (AnsiString == NULL)
+            return ERROR_OUTOFMEMORY;
+
         WideCharToMultiByte(CP_ACP,
                             0,
                             lpService->Arguments,
@@ -165,9 +152,18 @@ ScServiceMainStub(LPVOID Context)
                             NULL,
                             NULL);
 
+        AnsiString[AnsiLength] = ANSI_NULL;
+
         lpArgVector = HeapAlloc(GetProcessHeap(),
                                 0,
                                 (dwArgCount + 1) * sizeof(LPSTR));
+        if (lpArgVector == NULL)
+        {
+            HeapFree(GetProcessHeap(),
+                        0,
+                        AnsiString);
+            return ERROR_OUTOFMEMORY;
+        }
 
         dwArgCount = 0;
         Ptr = AnsiString;
@@ -198,16 +194,41 @@ static DWORD
 ScConnectControlPipe(HANDLE *hPipe)
 {
     DWORD dwBytesWritten;
-    DWORD dwProcessId;
     DWORD dwState;
+    DWORD dwServiceCurrent = 0;
+    NTSTATUS Status;
+    WCHAR NtControlPipeName[MAX_PATH + 1];
+    RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+
+    /* 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());
+        ERR("WaitNamedPipe(%S) failed (Error %lu)\n", NtControlPipeName, GetLastError());
         return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
     }
 
-    *hPipe = CreateFileW(L"\\\\.\\pipe\\net\\NtControlPipe",
+    *hPipe = CreateFileW(NtControlPipeName,
                          GENERIC_READ | GENERIC_WRITE,
                          0,
                          NULL,
@@ -216,49 +237,53 @@ ScConnectControlPipe(HANDLE *hPipe)
                          NULL);
     if (*hPipe == INVALID_HANDLE_VALUE)
     {
-        DPRINT1("CreateFileW() failed (Error %lu)\n", GetLastError());
+        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))
     {
-        CloseHandle(hPipe);
+        CloseHandle(*hPipe);
         *hPipe = INVALID_HANDLE_VALUE;
         return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
     }
 
-    dwProcessId = GetCurrentProcessId();
+    /* Share the SERVICE_HANDLE handle with the SCM */
     WriteFile(*hPipe,
-              &dwProcessId,
-              sizeof(DWORD),
+              (DWORD *)&lpActiveServices->hService,
+              sizeof(CLIENT_HANDLE),
               &dwBytesWritten,
               NULL);
 
-    DPRINT("Sent process id %lu\n", dwProcessId);
+    TRACE("Sent SERVICE_HANDLE %lu\n", lpActiveServices->hService);
 
     return ERROR_SUCCESS;
 }
 
 
-
 static DWORD
 ScStartService(PSCM_CONTROL_PACKET ControlPacket)
 {
     PACTIVE_SERVICE lpService;
     HANDLE ThreadHandle;
+    DWORD ThreadId;
 
-    DPRINT("ScStartService() called\n");
-    DPRINT("Size: %lu\n", ControlPacket->dwSize);
-    DPRINT("Service: %S\n", &ControlPacket->szArguments[0]);
+    TRACE("ScStartService() called\n");
+    TRACE("client handle: %lu\n", ControlPacket->hClient);
+    TRACE("Size: %lu\n", ControlPacket->dwSize);
+    TRACE("Service: %S\n", &ControlPacket->szArguments[0]);
 
-    lpService = ScLookupServiceByServiceName(&ControlPacket->szArguments[0]);
+    lpService = (PACTIVE_SERVICE)ControlPacket->hClient;
     if (lpService == NULL)
+    {
+        TRACE("Service not found\n");
         return ERROR_SERVICE_DOES_NOT_EXIST;
+    }
 
     lpService->Arguments = HeapAlloc(GetProcessHeap(),
                                      HEAP_ZERO_MEMORY,
-                                     ControlPacket->dwSize * sizeof(WCHAR));
+                                     (ControlPacket->dwSize + 1) * sizeof(WCHAR));
     if (lpService->Arguments == NULL)
         return ERROR_OUTOFMEMORY;
 
@@ -266,12 +291,13 @@ ScStartService(PSCM_CONTROL_PACKET ControlPacket)
            ControlPacket->szArguments,
            ControlPacket->dwSize * sizeof(WCHAR));
 
+    /* invoke the services entry point and implement the command loop */
     ThreadHandle = CreateThread(NULL,
                                 0,
                                 ScServiceMainStub,
                                 lpService,
                                 CREATE_SUSPENDED,
-                                &lpService->ThreadId);
+                                &ThreadId);
     if (ThreadHandle == NULL)
         return ERROR_SERVICE_NO_THREAD;
 
@@ -282,6 +308,45 @@ ScStartService(PSCM_CONTROL_PACKET ControlPacket)
 }
 
 
+static DWORD
+ScControlService(PSCM_CONTROL_PACKET ControlPacket)
+{
+    PACTIVE_SERVICE lpService;
+
+    TRACE("ScControlService() called\n");
+    TRACE("Size: %lu\n", ControlPacket->dwSize);
+    TRACE("Service: %S\n", &ControlPacket->szArguments[0]);
+
+    lpService = (PACTIVE_SERVICE)ControlPacket->hClient;
+    if (lpService == NULL)
+    {
+        TRACE("Service not found\n");
+        return ERROR_SERVICE_DOES_NOT_EXIST;
+    }
+
+    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,
@@ -292,11 +357,11 @@ ScServiceDispatcher(HANDLE hPipe,
     BOOL bResult;
     DWORD dwRunningServices = 0;
 
-    DPRINT("ScDispatcherLoop() called\n");
+    TRACE("ScDispatcherLoop() called\n");
 
     ControlPacket = HeapAlloc(GetProcessHeap(),
-                       HEAP_ZERO_MEMORY,
-                       1024);
+                              HEAP_ZERO_MEMORY,
+                              1024);
     if (ControlPacket == NULL)
         return FALSE;
 
@@ -310,7 +375,7 @@ ScServiceDispatcher(HANDLE hPipe,
                            NULL);
         if (bResult == FALSE)
         {
-            DPRINT1("Pipe read failed (Error: %lu)\n", GetLastError());
+            ERR("Pipe read failed (Error: %lu)\n", GetLastError());
             return FALSE;
         }
 
@@ -318,19 +383,21 @@ ScServiceDispatcher(HANDLE hPipe,
         switch (ControlPacket->dwControl)
         {
             case SERVICE_CONTROL_START:
-                DPRINT("Start command\n");
+                TRACE("Start command - recieved SERVICE_CONTROL_START\n");
                 if (ScStartService(ControlPacket) == ERROR_SUCCESS)
                     dwRunningServices++;
                 break;
 
             case SERVICE_CONTROL_STOP:
-                DPRINT("Stop command\n");
-                dwRunningServices--;
+                TRACE("Stop command - recieved SERVICE_CONTROL_STOP\n");
+                if (ScControlService(ControlPacket) == ERROR_SUCCESS)
+                    dwRunningServices--;
                 break;
 
             default:
-                DPRINT1("Unknown command %lu", ControlPacket->dwControl);
-                break;
+                TRACE("Command %lu received", ControlPacket->dwControl);
+                ScControlService(ControlPacket);
+                continue;
         }
 
         if (dwRunningServices == 0)
@@ -350,7 +417,7 @@ ScServiceDispatcher(HANDLE hPipe,
  *
  * @implemented
  */
-SERVICE_STATUS_HANDLE STDCALL
+SERVICE_STATUS_HANDLE WINAPI
 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
                             LPHANDLER_FUNCTION lpHandlerProc)
 {
@@ -379,7 +446,7 @@ RegisterServiceCtrlHandlerA(LPCSTR lpServiceName,
  *
  * @implemented
  */
-SERVICE_STATUS_HANDLE STDCALL
+SERVICE_STATUS_HANDLE WINAPI
 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
                             LPHANDLER_FUNCTION lpHandlerProc)
 {
@@ -394,7 +461,9 @@ RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
     Service->HandlerFunction = lpHandlerProc;
     Service->HandlerFunctionEx = NULL;
 
-    return (SERVICE_STATUS_HANDLE)Service->ThreadId;
+    TRACE("RegisterServiceCtrlHandler returning %lu\n", Service->hService);
+
+    return (SERVICE_STATUS_HANDLE)Service->hService;
 }
 
 
@@ -403,7 +472,7 @@ RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName,
  *
  * @implemented
  */
-SERVICE_STATUS_HANDLE STDCALL
+SERVICE_STATUS_HANDLE WINAPI
 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName,
                               LPHANDLER_FUNCTION_EX lpHandlerProc,
                               LPVOID lpContext)
@@ -434,14 +503,14 @@ RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName,
  *
  * @implemented
  */
-SERVICE_STATUS_HANDLE STDCALL
+SERVICE_STATUS_HANDLE WINAPI
 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName,
                               LPHANDLER_FUNCTION_EX lpHandlerProc,
                               LPVOID lpContext)
 {
     PACTIVE_SERVICE Service;
 
-    Service = ScLookupServiceByServiceName((LPWSTR)lpServiceName);
+    Service = ScLookupServiceByServiceName(lpServiceName);
     if (Service == NULL)
     {
         return (SERVICE_STATUS_HANDLE)NULL;
@@ -451,23 +520,100 @@ RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName,
     Service->HandlerFunctionEx = lpHandlerProc;
     Service->HandlerContext = lpContext;
 
-    return (SERVICE_STATUS_HANDLE)Service->ThreadId;
+    TRACE("RegisterServiceCtrlHandlerEx returning %lu\n", Service->hService);
+
+    return (SERVICE_STATUS_HANDLE)Service->hService;
+}
+
+
+/**********************************************************************
+ *     I_ScSetServiceBitsA
+ *
+ * Undocumented
+ *
+ * @implemented
+ */
+BOOL WINAPI
+I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus,
+                    DWORD dwServiceBits,
+                    BOOL bSetBitsOn,
+                    BOOL bUpdateImmediately,
+                    LPSTR lpString)
+{
+    BOOL bResult;
+
+    RpcTryExcept
+    {
+        /* 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;
+}
+
+
+/**********************************************************************
+ *     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)
 {
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    return I_ScSetServiceBitsW(hServiceStatus,
+                               dwServiceBits,
+                               bSetBitsOn,
+                               bUpdateImmediately,
+                               NULL);
 }
 
 
@@ -476,22 +622,26 @@ SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus,
  *
  * @implemented
  */
-BOOL STDCALL
+BOOL WINAPI
 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
                  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);
+        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;
 }
@@ -500,17 +650,17 @@ SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
 /**********************************************************************
  *     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;
 
-    DPRINT("StartServiceCtrlDispatcherA() called\n");
+    TRACE("StartServiceCtrlDispatcherA() called\n");
 
     i = 0;
     while (lpServiceStartTable[i].lpServiceProc != NULL)
@@ -533,6 +683,7 @@ StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable)
         RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
                                          lpServiceStartTable[i].lpServiceName);
         lpActiveServices[i].Main.lpFuncA = lpServiceStartTable[i].lpServiceProc;
+        lpActiveServices[i].hService = (CLIENT_HANDLE)&lpActiveServices[i];
         lpActiveServices[i].bUnicode = FALSE;
     }
 
@@ -540,6 +691,10 @@ StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable)
     if (dwError != ERROR_SUCCESS)
     {
         /* Free the service table */
+        for (i = 0; i < dwActiveServiceCount; i++)
+        {
+            RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
+        }
         RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
         lpActiveServices = NULL;
         dwActiveServiceCount = 0;
@@ -552,6 +707,10 @@ StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable)
     if (lpMessageBuffer == NULL)
     {
         /* Free the service table */
+        for (i = 0; i < dwActiveServiceCount; i++)
+        {
+            RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
+        }
         RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
         lpActiveServices = NULL;
         dwActiveServiceCount = 0;
@@ -566,6 +725,10 @@ StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable)
     RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer);
 
     /* Free the service table */
+    for (i = 0; i < dwActiveServiceCount; i++)
+    {
+        RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
+    }
     RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
     lpActiveServices = NULL;
     dwActiveServiceCount = 0;
@@ -577,17 +740,17 @@ StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable)
 /**********************************************************************
  *     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;
 
-    DPRINT("StartServiceCtrlDispatcherW() called\n");
+    TRACE("StartServiceCtrlDispatcherW() called\n");
 
     i = 0;
     while (lpServiceStartTable[i].lpServiceProc != NULL)
@@ -610,6 +773,7 @@ StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable)
         RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
                                lpServiceStartTable[i].lpServiceName);
         lpActiveServices[i].Main.lpFuncW = lpServiceStartTable[i].lpServiceProc;
+        lpActiveServices[i].hService = (CLIENT_HANDLE)&lpActiveServices[i];
         lpActiveServices[i].bUnicode = TRUE;
     }
 
@@ -617,6 +781,10 @@ StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable)
     if (dwError != ERROR_SUCCESS)
     {
         /* Free the service table */
+        for (i = 0; i < dwActiveServiceCount; i++)
+        {
+            RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
+        }
         RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
         lpActiveServices = NULL;
         dwActiveServiceCount = 0;
@@ -629,6 +797,10 @@ StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable)
     if (lpMessageBuffer == NULL)
     {
         /* Free the service table */
+        for (i = 0; i < dwActiveServiceCount; i++)
+        {
+            RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
+        }
         RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
         lpActiveServices = NULL;
         dwActiveServiceCount = 0;
@@ -643,6 +815,10 @@ StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable)
     RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer);
 
     /* Free the service table */
+    for (i = 0; i < dwActiveServiceCount; i++)
+    {
+        RtlFreeUnicodeString(&lpActiveServices[i].ServiceName);
+    }
     RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices);
     lpActiveServices = NULL;
     dwActiveServiceCount = 0;