[ADVAPI32]
[reactos.git] / reactos / dll / win32 / advapi32 / service / sctrl.c
index 90810bc..4a9767f 100644 (file)
 /* INCLUDES ******************************************************************/
 
 #include <advapi32.h>
-#include "wine/debug.h"
-
 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
 
 
 /* TYPES *********************************************************************/
 
+typedef struct _SERVICE_THREAD_PARAMSA
+{
+    LPSERVICE_MAIN_FUNCTIONA lpServiceMain;
+    DWORD dwArgCount;
+    LPSTR *lpArgVector;
+} SERVICE_THREAD_PARAMSA, *PSERVICE_THREAD_PARAMSA;
+
+
+typedef struct _SERVICE_THREAD_PARAMSW
+{
+    LPSERVICE_MAIN_FUNCTIONW lpServiceMain;
+    DWORD dwArgCount;
+    LPWSTR *lpArgVector;
+} SERVICE_THREAD_PARAMSW, *PSERVICE_THREAD_PARAMSW;
+
+
 typedef struct _ACTIVE_SERVICE
 {
     SERVICE_STATUS_HANDLE hServiceStatus;
     UNICODE_STRING ServiceName;
     union
     {
-        LPSERVICE_MAIN_FUNCTIONA lpFuncA;
-        LPSERVICE_MAIN_FUNCTIONW lpFuncW;
-    } Main;
+        SERVICE_THREAD_PARAMSA A;
+        SERVICE_THREAD_PARAMSW W;
+    } ThreadParams;
     LPHANDLER_FUNCTION HandlerFunction;
     LPHANDLER_FUNCTION_EX HandlerFunctionEx;
     LPVOID HandlerContext;
     BOOL bUnicode;
-    LPWSTR Arguments;
+    BOOL bOwnProcess;
 } ACTIVE_SERVICE, *PACTIVE_SERVICE;
 
 
@@ -127,14 +141,23 @@ ScLookupServiceByServiceName(LPCWSTR lpServiceName)
 {
     DWORD i;
 
+    TRACE("ScLookupServiceByServiceName(%S) called\n", lpServiceName);
+
+    if (lpActiveServices[0].bOwnProcess)
+        return &lpActiveServices[0];
+
     for (i = 0; i < dwActiveServiceCount; i++)
     {
+        TRACE("Checking %S\n", lpActiveServices[i].ServiceName.Buffer);
         if (_wcsicmp(lpActiveServices[i].ServiceName.Buffer, lpServiceName) == 0)
         {
+            TRACE("Found!\n");
             return &lpActiveServices[i];
         }
     }
 
+    TRACE("No service found!\n");
+
     SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
 
     return NULL;
@@ -144,122 +167,40 @@ ScLookupServiceByServiceName(LPCWSTR lpServiceName)
 static DWORD WINAPI
 ScServiceMainStub(LPVOID Context)
 {
-    PACTIVE_SERVICE lpService;
-    DWORD dwArgCount = 0;
-    DWORD dwLength = 0;
-    DWORD dwLen;
-    LPWSTR lpPtr;
-
-    lpService = (PACTIVE_SERVICE)Context;
+    PACTIVE_SERVICE lpService = (PACTIVE_SERVICE)Context;
 
     TRACE("ScServiceMainStub() called\n");
 
-    /* Count arguments */
-    lpPtr = lpService->Arguments;
-    while (*lpPtr)
-    {
-        TRACE("arg: %S\n", lpPtr);
-        dwLen = wcslen(lpPtr) + 1;
-        dwArgCount++;
-        dwLength += dwLen;
-        lpPtr += dwLen;
-    }
-    TRACE("dwArgCount: %ld\ndwLength: %ld\n", dwArgCount, dwLength);
-
-    /* Build the argument vector and call the main service routine */
+    /* Call the main service routine and free the arguments vector */
     if (lpService->bUnicode)
     {
-        LPWSTR *lpArgVector;
-        LPWSTR Ptr;
+        (lpService->ThreadParams.W.lpServiceMain)(lpService->ThreadParams.W.dwArgCount,
+                                                  lpService->ThreadParams.W.lpArgVector);
 
-        lpArgVector = HeapAlloc(GetProcessHeap(),
-                                HEAP_ZERO_MEMORY,
-                                (dwArgCount + 1) * sizeof(LPWSTR));
-        if (lpArgVector == NULL)
-            return ERROR_OUTOFMEMORY;
-
-        dwArgCount = 0;
-        Ptr = lpService->Arguments;
-        while (*Ptr)
+        if (lpService->ThreadParams.W.lpArgVector != NULL)
         {
-            lpArgVector[dwArgCount] = Ptr;
+            HeapFree(GetProcessHeap(),
+                     0,
+                     lpService->ThreadParams.W.lpArgVector);
 
-            dwArgCount++;
-            Ptr += (wcslen(Ptr) + 1);
+            lpService->ThreadParams.W.lpArgVector = NULL;
+            lpService->ThreadParams.W.dwArgCount = 0;
         }
-        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);
-        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;
+        (lpService->ThreadParams.A.lpServiceMain)(lpService->ThreadParams.A.dwArgCount,
+                                                  lpService->ThreadParams.A.lpArgVector);
 
-        lpArgVector = HeapAlloc(GetProcessHeap(),
-                                0,
-                                (dwArgCount + 1) * sizeof(LPSTR));
-        if (lpArgVector == NULL)
+        if (lpService->ThreadParams.A.lpArgVector != NULL)
         {
             HeapFree(GetProcessHeap(),
-                        0,
-                        AnsiString);
-            return ERROR_OUTOFMEMORY;
-        }
+                     0,
+                     lpService->ThreadParams.A.lpArgVector);
 
-        dwArgCount = 0;
-        Ptr = AnsiString;
-        while (*Ptr)
-        {
-            lpArgVector[dwArgCount] = Ptr;
-
-            dwArgCount++;
-            Ptr += (strlen(Ptr) + 1);
+            lpService->ThreadParams.A.lpArgVector = NULL;
+            lpService->ThreadParams.A.dwArgCount = 0;
         }
-        lpArgVector[dwArgCount] = NULL;
-
-        (lpService->Main.lpFuncA)(dwArgCount, lpArgVector);
-
-        HeapFree(GetProcessHeap(),
-                 0,
-                 lpArgVector);
-        HeapFree(GetProcessHeap(),
-                 0,
-                 AnsiString);
     }
 
     return ERROR_SUCCESS;
@@ -299,7 +240,7 @@ ScConnectControlPipe(HANDLE *hPipe)
 
     swprintf(NtControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", dwServiceCurrent);
 
-    if (!WaitNamedPipeW(NtControlPipeName, 15000))
+    if (!WaitNamedPipeW(NtControlPipeName, 30000))
     {
         ERR("WaitNamedPipe(%S) failed (Error %lu)\n", NtControlPipeName, GetLastError());
         return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
@@ -307,7 +248,7 @@ ScConnectControlPipe(HANDLE *hPipe)
 
     *hPipe = CreateFileW(NtControlPipeName,
                          GENERIC_READ | GENERIC_WRITE,
-                         0,
+                         FILE_SHARE_READ | FILE_SHARE_WRITE,
                          NULL,
                          OPEN_EXISTING,
                          FILE_ATTRIBUTE_NORMAL,
@@ -340,31 +281,205 @@ ScConnectControlPipe(HANDLE *hPipe)
 }
 
 
+static DWORD
+ScBuildUnicodeArgsVector(PSCM_CONTROL_PACKET ControlPacket,
+                         LPDWORD lpArgCount,
+                         LPWSTR **lpArgVector)
+{
+    LPWSTR *lpVector;
+    LPWSTR *lpArg;
+    LPWSTR pszServiceName;
+    DWORD cbServiceName;
+    DWORD cbTotal;
+    DWORD i;
+
+    if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
+        return ERROR_INVALID_PARAMETER;
+
+    *lpArgCount = 0;
+    *lpArgVector = NULL;
+
+    pszServiceName = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
+    cbServiceName = lstrlenW(pszServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
+
+    cbTotal = cbServiceName + sizeof(LPWSTR);
+    if (ControlPacket->dwArgumentsCount > 0)
+        cbTotal += ControlPacket->dwSize - ControlPacket->dwArgumentsOffset;
+
+    lpVector = HeapAlloc(GetProcessHeap(),
+                         HEAP_ZERO_MEMORY,
+                         cbTotal);
+    if (lpVector == NULL)
+        return ERROR_OUTOFMEMORY;
+
+    lpArg = lpVector;
+    *lpArg = (LPWSTR)(lpArg + 1);
+    lpArg++;
+
+    memcpy(lpArg, pszServiceName, cbServiceName);
+    lpArg = (LPWSTR*)((ULONG_PTR)lpArg + cbServiceName);
+
+    if (ControlPacket->dwArgumentsCount > 0)
+    {
+        memcpy(lpArg,
+               ((PBYTE)ControlPacket + ControlPacket->dwArgumentsOffset),
+               ControlPacket->dwSize - ControlPacket->dwArgumentsOffset);
+
+        for (i = 0; i < ControlPacket->dwArgumentsCount; i++)
+        {
+            *lpArg = (LPWSTR)((ULONG_PTR)lpArg + (ULONG_PTR)*lpArg);
+            lpArg++;
+        }
+    }
+
+    *lpArgCount = ControlPacket->dwArgumentsCount + 1;
+    *lpArgVector = lpVector;
+
+    return ERROR_SUCCESS;
+}
+
+
+static DWORD
+ScBuildAnsiArgsVector(PSCM_CONTROL_PACKET ControlPacket,
+                      LPDWORD lpArgCount,
+                      LPSTR **lpArgVector)
+{
+    LPSTR *lpVector;
+    LPSTR *lpPtr;
+    LPWSTR lpUnicodeString;
+    LPWSTR pszServiceName;
+    LPSTR lpAnsiString;
+    DWORD cbServiceName;
+    DWORD dwVectorSize;
+    DWORD dwUnicodeSize;
+    DWORD dwAnsiSize = 0;
+    DWORD dwAnsiNameSize = 0;
+    DWORD i;
+
+    if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL)
+        return ERROR_INVALID_PARAMETER;
+
+    *lpArgCount = 0;
+    *lpArgVector = NULL;
+
+    pszServiceName = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
+    cbServiceName = lstrlenW(pszServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
+
+    dwAnsiNameSize = WideCharToMultiByte(CP_ACP,
+                                         0,
+                                         pszServiceName,
+                                         cbServiceName,
+                                         NULL,
+                                         0,
+                                         NULL,
+                                         NULL);
+
+    dwVectorSize = ControlPacket->dwArgumentsCount * sizeof(LPWSTR);
+    if (ControlPacket->dwArgumentsCount > 0)
+    {
+        lpUnicodeString = (LPWSTR)((PBYTE)ControlPacket +
+                                   ControlPacket->dwArgumentsOffset +
+                                   dwVectorSize);
+        dwUnicodeSize = (ControlPacket->dwSize -
+                         ControlPacket->dwArgumentsOffset -
+                         dwVectorSize) / sizeof(WCHAR);
+
+        dwAnsiSize = WideCharToMultiByte(CP_ACP,
+                                         0,
+                                         lpUnicodeString,
+                                         dwUnicodeSize,
+                                         NULL,
+                                         0,
+                                         NULL,
+                                         NULL);
+    }
+
+    dwVectorSize += sizeof(LPWSTR);
+
+    lpVector = HeapAlloc(GetProcessHeap(),
+                         HEAP_ZERO_MEMORY,
+                         dwVectorSize + dwAnsiNameSize + dwAnsiSize);
+    if (lpVector == NULL)
+        return ERROR_OUTOFMEMORY;
+
+    lpPtr = (LPSTR*)lpVector;
+    lpAnsiString = (LPSTR)((ULONG_PTR)lpVector + dwVectorSize);
+
+    WideCharToMultiByte(CP_ACP,
+                        0,
+                        pszServiceName,
+                        cbServiceName,
+                        lpAnsiString,
+                        dwAnsiNameSize,
+                        NULL,
+                        NULL);
+
+    if (ControlPacket->dwArgumentsCount > 0)
+    {
+        lpAnsiString = (LPSTR)((ULONG_PTR)lpAnsiString + dwAnsiNameSize);
+
+        WideCharToMultiByte(CP_ACP,
+                            0,
+                            lpUnicodeString,
+                            dwUnicodeSize,
+                            lpAnsiString,
+                            dwAnsiSize,
+                            NULL,
+                            NULL);
+    }
+
+    lpAnsiString = (LPSTR)((ULONG_PTR)lpVector + dwVectorSize);
+    for (i = 0; i < ControlPacket->dwArgumentsCount + 1; i++)
+    {
+        *lpPtr = lpAnsiString;
+
+        lpPtr++;
+        lpAnsiString += (strlen(lpAnsiString) + 1);
+    }
+
+    *lpArgCount = ControlPacket->dwArgumentsCount + 1;
+    *lpArgVector = lpVector;
+
+    return ERROR_SUCCESS;
+}
+
+
 static DWORD
 ScStartService(PACTIVE_SERVICE lpService,
                PSCM_CONTROL_PACKET ControlPacket)
 {
     HANDLE ThreadHandle;
     DWORD ThreadId;
+    DWORD dwError;
+
+    if (lpService == NULL || ControlPacket == NULL)
+        return ERROR_INVALID_PARAMETER;
 
     TRACE("ScStartService() called\n");
     TRACE("Size: %lu\n", ControlPacket->dwSize);
-    TRACE("Service: %S\n", &ControlPacket->szArguments[0]);
+    TRACE("Service: %S\n", (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset));
 
     /* 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;
+    /* Build the arguments vector */
+    if (lpService->bUnicode == TRUE)
+    {
+        dwError = ScBuildUnicodeArgsVector(ControlPacket,
+                                           &lpService->ThreadParams.W.dwArgCount,
+                                           &lpService->ThreadParams.W.lpArgVector);
+    }
+    else
+    {
+        dwError = ScBuildAnsiArgsVector(ControlPacket,
+                                        &lpService->ThreadParams.A.dwArgCount,
+                                        &lpService->ThreadParams.A.lpArgVector);
+    }
 
-    memcpy(lpService->Arguments,
-           ControlPacket->szArguments,
-           ControlPacket->dwSize * sizeof(WCHAR));
+    if (dwError != ERROR_SUCCESS)
+        return dwError;
 
-    /* invoke the services entry point and implement the command loop */
+    /* Invoke the services entry point and implement the command loop */
     ThreadHandle = CreateThread(NULL,
                                 0,
                                 ScServiceMainStub,
@@ -372,7 +487,33 @@ ScStartService(PACTIVE_SERVICE lpService,
                                 CREATE_SUSPENDED,
                                 &ThreadId);
     if (ThreadHandle == NULL)
+    {
+        /* Free the arguments vector */
+        if (lpService->bUnicode)
+        {
+            if (lpService->ThreadParams.W.lpArgVector != NULL)
+            {
+                HeapFree(GetProcessHeap(),
+                         0,
+                         lpService->ThreadParams.W.lpArgVector);
+                lpService->ThreadParams.W.lpArgVector = NULL;
+                lpService->ThreadParams.W.dwArgCount = 0;
+            }
+        }
+        else
+        {
+            if (lpService->ThreadParams.A.lpArgVector != NULL)
+            {
+                HeapFree(GetProcessHeap(),
+                         0,
+                         lpService->ThreadParams.A.lpArgVector);
+                lpService->ThreadParams.A.lpArgVector = NULL;
+                lpService->ThreadParams.A.dwArgCount = 0;
+            }
+        }
+
         return ERROR_SERVICE_NO_THREAD;
+    }
 
     ResumeThread(ThreadHandle);
     CloseHandle(ThreadHandle);
@@ -385,9 +526,12 @@ static DWORD
 ScControlService(PACTIVE_SERVICE lpService,
                  PSCM_CONTROL_PACKET ControlPacket)
 {
+    if (lpService == NULL || ControlPacket == NULL)
+        return ERROR_INVALID_PARAMETER;
+
     TRACE("ScControlService() called\n");
     TRACE("Size: %lu\n", ControlPacket->dwSize);
-    TRACE("Service: %S\n", &ControlPacket->szArguments[0]);
+    TRACE("Service: %S\n", (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset));
 
     if (lpService->HandlerFunction)
     {
@@ -399,13 +543,6 @@ ScControlService(PACTIVE_SERVICE lpService,
         (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;
@@ -414,10 +551,9 @@ ScControlService(PACTIVE_SERVICE lpService,
 
 static BOOL
 ScServiceDispatcher(HANDLE hPipe,
-                    PUCHAR lpBuffer,
+                    PSCM_CONTROL_PACKET ControlPacket,
                     DWORD dwBufferSize)
 {
-    PSCM_CONTROL_PACKET ControlPacket;
     DWORD Count;
     BOOL bResult;
     DWORD dwRunningServices = 0;
@@ -428,10 +564,7 @@ ScServiceDispatcher(HANDLE hPipe,
 
     TRACE("ScDispatcherLoop() called\n");
 
-    ControlPacket = HeapAlloc(GetProcessHeap(),
-                              HEAP_ZERO_MEMORY,
-                              1024);
-    if (ControlPacket == NULL)
+    if (ControlPacket == NULL || dwBufferSize < sizeof(SCM_CONTROL_PACKET))
         return FALSE;
 
     while (TRUE)
@@ -439,7 +572,7 @@ ScServiceDispatcher(HANDLE hPipe,
         /* Read command from the control pipe */
         bResult = ReadFile(hPipe,
                            ControlPacket,
-                           1024,
+                           dwBufferSize,
                            &Count,
                            NULL);
         if (bResult == FALSE)
@@ -448,24 +581,28 @@ ScServiceDispatcher(HANDLE hPipe,
             return FALSE;
         }
 
-        lpServiceName = &ControlPacket->szArguments[0];
+        lpServiceName = (LPWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
         TRACE("Service: %S\n", lpServiceName);
 
+        if (ControlPacket->dwControl == SERVICE_CONTROL_START_OWN)
+            lpActiveServices[0].bOwnProcess = TRUE;
+
         lpService = ScLookupServiceByServiceName(lpServiceName);
         if (lpService != NULL)
         {
             /* Execute command */
             switch (ControlPacket->dwControl)
             {
-                case SERVICE_CONTROL_START:
-                    TRACE("Start command - recieved SERVICE_CONTROL_START\n");
+                case SERVICE_CONTROL_START_SHARE:
+                case SERVICE_CONTROL_START_OWN:
+                    TRACE("Start command - received 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");
+                    TRACE("Stop command - received SERVICE_CONTROL_STOP\n");
                     dwError = ScControlService(lpService, ControlPacket);
                     if (dwError == ERROR_SUCCESS)
                         dwRunningServices--;
@@ -500,10 +637,6 @@ ScServiceDispatcher(HANDLE hPipe,
             break;
     }
 
-    HeapFree(GetProcessHeap(),
-             0,
-             ControlPacket);
-
     return TRUE;
 }
 
@@ -758,12 +891,14 @@ SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus,
  * @implemented
  */
 BOOL WINAPI
-StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA * lpServiceStartTable)
+StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA *lpServiceStartTable)
 {
     ULONG i;
     HANDLE hPipe;
     DWORD dwError;
-    PUCHAR lpMessageBuffer;
+    PSCM_CONTROL_PACKET ControlPacket;
+    DWORD dwBufSize;
+    BOOL bRet = TRUE;
 
     TRACE("StartServiceCtrlDispatcherA() called\n");
 
@@ -787,53 +922,43 @@ StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA * lpServiceStartTable)
     {
         RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
                                          lpServiceStartTable[i].lpServiceName);
-        lpActiveServices[i].Main.lpFuncA = lpServiceStartTable[i].lpServiceProc;
+        lpActiveServices[i].ThreadParams.A.lpServiceMain = lpServiceStartTable[i].lpServiceProc;
         lpActiveServices[i].hServiceStatus = 0;
         lpActiveServices[i].bUnicode = FALSE;
+        lpActiveServices[i].bOwnProcess = FALSE;
     }
 
     dwError = ScConnectControlPipe(&hPipe);
     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;
-        return FALSE;
+        bRet = FALSE;
+        goto done;
     }
 
-    lpMessageBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
-                                      HEAP_ZERO_MEMORY,
-                                      256);
-    if (lpMessageBuffer == NULL)
+    dwBufSize = sizeof(SCM_CONTROL_PACKET) +
+                (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
+
+    ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
+                                    HEAP_ZERO_MEMORY,
+                                    dwBufSize);
+    if (ControlPacket == NULL)
     {
-        /* 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;
+        bRet = FALSE;
+        goto done;
     }
 
     ScCreateStatusBinding();
 
-    ScServiceDispatcher(hPipe, lpMessageBuffer, 256);
+    ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
 
     ScDestroyStatusBinding();
 
     CloseHandle(hPipe);
 
-    /* Free the message buffer */
-    RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer);
+    /* Free the control packet */
+    RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
 
+done:
     /* Free the service table */
     for (i = 0; i < dwActiveServiceCount; i++)
     {
@@ -843,7 +968,7 @@ StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA * lpServiceStartTable)
     lpActiveServices = NULL;
     dwActiveServiceCount = 0;
 
-    return TRUE;
+    return bRet;
 }
 
 
@@ -853,12 +978,14 @@ StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA * lpServiceStartTable)
  * @implemented
  */
 BOOL WINAPI
-StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW * lpServiceStartTable)
+StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable)
 {
     ULONG i;
     HANDLE hPipe;
     DWORD dwError;
-    PUCHAR lpMessageBuffer;
+    PSCM_CONTROL_PACKET ControlPacket;
+    DWORD dwBufSize;
+    BOOL bRet = TRUE;
 
     TRACE("StartServiceCtrlDispatcherW() called\n");
 
@@ -882,53 +1009,43 @@ StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW * lpServiceStartTable)
     {
         RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
                                lpServiceStartTable[i].lpServiceName);
-        lpActiveServices[i].Main.lpFuncW = lpServiceStartTable[i].lpServiceProc;
+        lpActiveServices[i].ThreadParams.W.lpServiceMain = lpServiceStartTable[i].lpServiceProc;
         lpActiveServices[i].hServiceStatus = 0;
         lpActiveServices[i].bUnicode = TRUE;
+        lpActiveServices[i].bOwnProcess = FALSE;
     }
 
     dwError = ScConnectControlPipe(&hPipe);
     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;
-        return FALSE;
+        bRet = FALSE;
+        goto done;
     }
 
-    lpMessageBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
-                                      HEAP_ZERO_MEMORY,
-                                      256);
-    if (lpMessageBuffer == NULL)
+    dwBufSize = sizeof(SCM_CONTROL_PACKET) +
+                (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR);
+
+    ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(),
+                                    HEAP_ZERO_MEMORY,
+                                    dwBufSize);
+    if (ControlPacket == NULL)
     {
-        /* 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;
+        bRet = FALSE;
+        goto done;
     }
 
     ScCreateStatusBinding();
 
-    ScServiceDispatcher(hPipe, lpMessageBuffer, 256);
+    ScServiceDispatcher(hPipe, ControlPacket, dwBufSize);
 
     ScDestroyStatusBinding();
 
     CloseHandle(hPipe);
 
-    /* Free the message buffer */
-    RtlFreeHeap(RtlGetProcessHeap(), 0, lpMessageBuffer);
+    /* Free the control packet */
+    RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket);
 
+done:
     /* Free the service table */
     for (i = 0; i < dwActiveServiceCount; i++)
     {
@@ -938,7 +1055,7 @@ StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW * lpServiceStartTable)
     lpActiveServices = NULL;
     dwActiveServiceCount = 0;
 
-    return TRUE;
+    return bRet;
 }
 
 /* EOF */