[SERVICES]
[reactos.git] / reactos / base / system / services / database.c
index 130ef54..e4202a7 100644 (file)
 
 #include "services.h"
 
+#include <winuser.h>
+
 #define NDEBUG
 #include <debug.h>
 
 /*
  * Uncomment the line below to start services
- *  using the SERVICE_START_PENDING state
+ * using the SERVICE_START_PENDING state.
  */
-// #define USE_SERVICE_START_PENDING
+#define USE_SERVICE_START_PENDING
 
 /*
  * Uncomment the line below to use asynchronous IO operations
  * on the service control pipes.
  */
-// #define USE_ASYNCHRONOUS_IO
+#define USE_ASYNCHRONOUS_IO
 
 
 /* GLOBALS *******************************************************************/
@@ -36,10 +38,11 @@ LIST_ENTRY ImageListHead;
 LIST_ENTRY ServiceListHead;
 
 static RTL_RESOURCE DatabaseLock;
-static DWORD dwResumeCount = 1;
+static DWORD ResumeCount = 1;
 
+/* The critical section synchronizes service control requests */
 static CRITICAL_SECTION ControlServiceCriticalSection;
-static DWORD dwPipeTimeout = 30000; /* 30 Seconds */
+static DWORD PipeTimeout = 30000; /* 30 Seconds */
 
 
 /* FUNCTIONS *****************************************************************/
@@ -96,7 +99,7 @@ ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage)
     }
 
     /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
-    swprintf(szControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent);
+    swprintf(szControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%lu", ServiceCurrent);
 
     DPRINT("PipeName: %S\n", szControlPipeName);
 
@@ -110,7 +113,7 @@ ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage)
                                                    100,
                                                    8000,
                                                    4,
-                                                   dwPipeTimeout,
+                                                   PipeTimeout,
                                                    NULL);
     DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName);
     if (pServiceImage->hControlPipe == INVALID_HANDLE_VALUE)
@@ -146,7 +149,7 @@ ScmGetServiceImageByImagePath(LPWSTR lpImagePath)
         ImageEntry = ImageEntry->Flink;
     }
 
-    DPRINT1("Couldn't find a matching image\n");
+    DPRINT("Couldn't find a matching image\n");
 
     return NULL;
 
@@ -191,9 +194,9 @@ ScmCreateOrReferenceServiceImage(PSERVICE pService)
     if (pServiceImage == NULL)
     {
         /* Create a new service image */
-        pServiceImage = (PSERVICE_IMAGE)HeapAlloc(GetProcessHeap(),
-                                                  HEAP_ZERO_MEMORY,
-                                                  sizeof(SERVICE_IMAGE) + ((wcslen(ImagePath.Buffer) + 1) * sizeof(WCHAR)));
+        pServiceImage = HeapAlloc(GetProcessHeap(),
+                                  HEAP_ZERO_MEMORY,
+                                  FIELD_OFFSET(SERVICE_IMAGE, szImagePath[ImagePath.Length / sizeof(WCHAR) + 1]));
         if (pServiceImage == NULL)
         {
             dwError = ERROR_NOT_ENOUGH_MEMORY;
@@ -202,7 +205,6 @@ ScmCreateOrReferenceServiceImage(PSERVICE pService)
 
         pServiceImage->dwImageRunCount = 1;
         pServiceImage->hControlPipe = INVALID_HANDLE_VALUE;
-        pServiceImage->hProcess = INVALID_HANDLE_VALUE;
 
         /* Set the image path */
         wcscpy(pServiceImage->szImagePath,
@@ -265,10 +267,6 @@ ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage)
         if (pServiceImage->hControlPipe != INVALID_HANDLE_VALUE)
             CloseHandle(pServiceImage->hControlPipe);
 
-        /* Close the process handle */
-        if (pServiceImage->hProcess != INVALID_HANDLE_VALUE)
-            CloseHandle(pServiceImage->hProcess);
-
         /* Release the service image */
         HeapFree(GetProcessHeap(), 0, pServiceImage);
     }
@@ -364,16 +362,16 @@ ScmGetServiceEntryByResumeCount(DWORD dwResumeCount)
 
 DWORD
 ScmCreateNewServiceRecord(LPCWSTR lpServiceName,
-                          PSERVICE *lpServiceRecord)
+                          PSERVICElpServiceRecord)
 {
     PSERVICE lpService = NULL;
 
     DPRINT("Service: '%S'\n", lpServiceName);
 
     /* Allocate service entry */
-    lpService = (SERVICE*)HeapAlloc(GetProcessHeap(),
+    lpService = HeapAlloc(GetProcessHeap(),
                           HEAP_ZERO_MEMORY,
-                          sizeof(SERVICE) + ((wcslen(lpServiceName) + 1) * sizeof(WCHAR)));
+                          FIELD_OFFSET(SERVICE, szServiceName[wcslen(lpServiceName) + 1]));
     if (lpService == NULL)
         return ERROR_NOT_ENOUGH_MEMORY;
 
@@ -385,7 +383,7 @@ ScmCreateNewServiceRecord(LPCWSTR lpServiceName,
     lpService->lpDisplayName = lpService->lpServiceName;
 
     /* Set the resume count */
-    lpService->dwResumeCount = dwResumeCount++;
+    lpService->dwResumeCount = ResumeCount++;
 
     /* Append service record */
     InsertTailList(&ServiceListHead,
@@ -589,15 +587,17 @@ ScmDeleteRegKey(HKEY hKey, LPCWSTR lpszSubKey)
     {
         /* Find the maximum subkey length so that we can allocate a buffer */
         dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
-                                                         &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
+                                 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
         if (!dwRet)
         {
             dwMaxSubkeyLen++;
-            if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
+            if (dwMaxSubkeyLen > sizeof(szNameBuf) / sizeof(WCHAR))
+            {
                 /* Name too big: alloc a buffer for it */
-                lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
+                lpszName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwMaxSubkeyLen * sizeof(WCHAR));
+            }
 
-            if(!lpszName)
+            if (!lpszName)
                 dwRet = ERROR_NOT_ENOUGH_MEMORY;
             else
             {
@@ -656,7 +656,7 @@ ScmDeleteMarkedServices(VOID)
                     HeapFree(GetProcessHeap(), 0, CurrentService);
                 }
             }
-            
+
             if (dwError != ERROR_SUCCESS)
                 DPRINT1("Delete service failed: %S\n", CurrentService->lpServiceName);
         }
@@ -664,46 +664,6 @@ ScmDeleteMarkedServices(VOID)
 }
 
 
-VOID
-WaitForLSA(VOID)
-{
-    HANDLE hEvent;
-    DWORD dwError;
-
-    DPRINT("WaitForLSA() called\n");
-
-    hEvent = CreateEventW(NULL,
-                          TRUE,
-                          FALSE,
-                          L"LSA_RPC_SERVER_ACTIVE");
-    if (hEvent == NULL)
-    {
-        dwError = GetLastError();
-        DPRINT1("Failed to create the notication event (Error %lu)\n", dwError);
-
-        if (dwError == ERROR_ALREADY_EXISTS)
-        {
-            hEvent = OpenEventW(SYNCHRONIZE,
-                                FALSE,
-                                L"LSA_RPC_SERVER_ACTIVE");
-            if (hEvent != NULL)
-            {
-               DPRINT1("Could not open the notification event!\n");
-               return;
-            }
-        }
-    }
-
-    DPRINT("Wait for LSA!\n");
-    WaitForSingleObject(hEvent, INFINITE);
-    DPRINT("LSA is available!\n");
-
-    CloseHandle(hEvent);
-
-    DPRINT("WaitForLSA() done\n");
-}
-
-
 DWORD
 ScmCreateServiceDatabase(VOID)
 {
@@ -775,8 +735,8 @@ ScmCreateServiceDatabase(VOID)
 
     RegCloseKey(hServicesKey);
 
-    /* Wait for LSA */
-    WaitForLSA();
+    /* Wait for the LSA server */
+    ScmWaitForLsa();
 
     /* Delete services that are marked for delete */
     ScmDeleteMarkedServices();
@@ -815,13 +775,12 @@ ScmCheckDriver(PSERVICE Service)
 
     if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
     {
-        RtlInitUnicodeString(&DirName,
-                             L"\\Driver");
+        RtlInitUnicodeString(&DirName, L"\\Driver");
     }
-    else
+    else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
     {
-        RtlInitUnicodeString(&DirName,
-                             L"\\FileSystem");
+        ASSERT(Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER);
+        RtlInitUnicodeString(&DirName, L"\\FileSystem");
     }
 
     InitializeObjectAttributes(&ObjectAttributes,
@@ -839,8 +798,8 @@ ScmCheckDriver(PSERVICE Service)
     }
 
     BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
-                   2 * MAX_PATH * sizeof(WCHAR);
-    DirInfo = (OBJECT_DIRECTORY_INFORMATION*) HeapAlloc(GetProcessHeap(),
+                       2 * MAX_PATH * sizeof(WCHAR);
+    DirInfo = HeapAlloc(GetProcessHeap(),
                         HEAP_ZERO_MEMORY,
                         BufferLength);
 
@@ -936,20 +895,21 @@ ScmControlService(PSERVICE Service,
     DWORD dwError = ERROR_SUCCESS;
     BOOL bResult;
 #ifdef USE_ASYNCHRONOUS_IO
-    OVERLAPPED Overlapped = {0, 0, 0, 0, 0};
+    OVERLAPPED Overlapped = {0};
 #endif
 
     DPRINT("ScmControlService() called\n");
 
+    /* Acquire the service control critical section, to synchronize requests */
     EnterCriticalSection(&ControlServiceCriticalSection);
 
     /* Calculate the total length of the start command line */
     PacketSize = sizeof(SCM_CONTROL_PACKET);
-    PacketSize += (wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR);
+    PacketSize += (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR));
 
-    ControlPacket = (SCM_CONTROL_PACKET*)HeapAlloc(GetProcessHeap(),
-                                                   HEAP_ZERO_MEMORY,
-                                                   PacketSize);
+    ControlPacket = HeapAlloc(GetProcessHeap(),
+                              HEAP_ZERO_MEMORY,
+                              PacketSize);
     if (ControlPacket == NULL)
     {
         LeaveCriticalSection(&ControlServiceCriticalSection);
@@ -976,16 +936,16 @@ ScmControlService(PSERVICE Service,
                         &Overlapped);
     if (bResult == FALSE)
     {
-        DPRINT1("WriteFile() returned FALSE\n");
+        DPRINT("WriteFile() returned FALSE\n");
 
         dwError = GetLastError();
         if (dwError == ERROR_IO_PENDING)
         {
-            DPRINT1("dwError: ERROR_IO_PENDING\n");
+            DPRINT("dwError: ERROR_IO_PENDING\n");
 
             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
-                                          dwPipeTimeout);
-            DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
+                                          PipeTimeout);
+            DPRINT("WaitForSingleObject() returned %lu\n", dwError);
 
             if (dwError == WAIT_TIMEOUT)
             {
@@ -998,7 +958,7 @@ ScmControlService(PSERVICE Service,
                 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
                 goto Done;
             }
-            else if (dwError == ERROR_SUCCESS)
+            else if (dwError == WAIT_OBJECT_0)
             {
                 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
                                               &Overlapped,
@@ -1030,16 +990,16 @@ ScmControlService(PSERVICE Service,
                        &Overlapped);
     if (bResult == FALSE)
     {
-        DPRINT1("ReadFile() returned FALSE\n");
+        DPRINT("ReadFile() returned FALSE\n");
 
         dwError = GetLastError();
         if (dwError == ERROR_IO_PENDING)
         {
-            DPRINT1("dwError: ERROR_IO_PENDING\n");
+            DPRINT("dwError: ERROR_IO_PENDING\n");
 
             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
-                                          dwPipeTimeout);
-            DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
+                                          PipeTimeout);
+            DPRINT("WaitForSingleObject() returned %lu\n", dwError);
 
             if (dwError == WAIT_TIMEOUT)
             {
@@ -1052,7 +1012,7 @@ ScmControlService(PSERVICE Service,
                 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
                 goto Done;
             }
-            else if (dwError == ERROR_SUCCESS)
+            else if (dwError == WAIT_OBJECT_0)
             {
                 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
                                               &Overlapped,
@@ -1085,6 +1045,16 @@ ScmControlService(PSERVICE Service,
     {
         dwError = GetLastError();
         DPRINT("WriteFile() failed (Error %lu)\n", dwError);
+
+        if ((dwError == ERROR_GEN_FAILURE) &&
+            (dwControl == SERVICE_CONTROL_STOP))
+        {
+            /* Service is already terminated */
+            Service->Status.dwCurrentState = SERVICE_STOPPED;
+            Service->Status.dwControlsAccepted = 0;
+            Service->Status.dwWin32ExitCode = ERROR_SERVICE_NOT_ACTIVE;
+            dwError = ERROR_SUCCESS;
+        }
         goto Done;
     }
 
@@ -1129,7 +1099,7 @@ Done:
 static DWORD
 ScmSendStartCommand(PSERVICE Service,
                     DWORD argc,
-                    LPWSTR *argv)
+                    LPWSTRargv)
 {
     PSCM_CONTROL_PACKET ControlPacket;
     SCM_REPLY_PACKET ReplyPacket;
@@ -1143,14 +1113,14 @@ ScmSendStartCommand(PSERVICE Service,
     PWSTR pArgPtr;
     BOOL bResult;
 #ifdef USE_ASYNCHRONOUS_IO
-    OVERLAPPED Overlapped = {0, 0, 0, 0, 0};
+    OVERLAPPED Overlapped = {0};
 #endif
 
     DPRINT("ScmSendStartCommand() called\n");
 
     /* Calculate the total length of the start command line */
-    PacketSize = sizeof(SCM_CONTROL_PACKET);
-    PacketSize += (wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR);
+    PacketSize = sizeof(SCM_CONTROL_PACKET) +
+                 (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR));
 
     /* Calculate the required packet size for the start arguments */
     if (argc > 0 && argv != NULL)
@@ -1161,19 +1131,21 @@ ScmSendStartCommand(PSERVICE Service,
         for (i = 0; i < argc; i++)
         {
             DPRINT("Argv[%lu]: %S\n", i, argv[i]);
-            PacketSize += (wcslen(argv[i]) + 1) * sizeof(WCHAR) + sizeof(PWSTR);
+            PacketSize += (DWORD)((wcslen(argv[i]) + 1) * sizeof(WCHAR) + sizeof(PWSTR));
         }
     }
 
     /* Allocate a control packet */
-    ControlPacket = (SCM_CONTROL_PACKET*)HeapAlloc(GetProcessHeap(),
-                                                   HEAP_ZERO_MEMORY,
-                                                   PacketSize);
+    ControlPacket = HeapAlloc(GetProcessHeap(),
+                              HEAP_ZERO_MEMORY,
+                              PacketSize);
     if (ControlPacket == NULL)
         return ERROR_NOT_ENOUGH_MEMORY;
 
     ControlPacket->dwSize = PacketSize;
-    ControlPacket->dwControl = SERVICE_CONTROL_START;
+    ControlPacket->dwControl = (Service->Status.dwServiceType & SERVICE_WIN32_OWN_PROCESS)
+                               ? SERVICE_CONTROL_START_OWN
+                               : SERVICE_CONTROL_START_SHARE;
     ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
     ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
 
@@ -1215,16 +1187,16 @@ ScmSendStartCommand(PSERVICE Service,
                         &Overlapped);
     if (bResult == FALSE)
     {
-        DPRINT1("WriteFile() returned FALSE\n");
+        DPRINT("WriteFile() returned FALSE\n");
 
         dwError = GetLastError();
         if (dwError == ERROR_IO_PENDING)
         {
-            DPRINT1("dwError: ERROR_IO_PENDING\n");
+            DPRINT("dwError: ERROR_IO_PENDING\n");
 
             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
-                                          dwPipeTimeout);
-            DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
+                                          PipeTimeout);
+            DPRINT("WaitForSingleObject() returned %lu\n", dwError);
 
             if (dwError == WAIT_TIMEOUT)
             {
@@ -1237,7 +1209,7 @@ ScmSendStartCommand(PSERVICE Service,
                 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
                 goto Done;
             }
-            else if (dwError == ERROR_SUCCESS)
+            else if (dwError == WAIT_OBJECT_0)
             {
                 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
                                               &Overlapped,
@@ -1269,16 +1241,16 @@ ScmSendStartCommand(PSERVICE Service,
                        &Overlapped);
     if (bResult == FALSE)
     {
-        DPRINT1("ReadFile() returned FALSE\n");
+        DPRINT("ReadFile() returned FALSE\n");
 
         dwError = GetLastError();
         if (dwError == ERROR_IO_PENDING)
         {
-            DPRINT1("dwError: ERROR_IO_PENDING\n");
+            DPRINT("dwError: ERROR_IO_PENDING\n");
 
             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
-                                          dwPipeTimeout);
-            DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
+                                          PipeTimeout);
+            DPRINT("WaitForSingleObject() returned %lu\n", dwError);
 
             if (dwError == WAIT_TIMEOUT)
             {
@@ -1291,7 +1263,7 @@ ScmSendStartCommand(PSERVICE Service,
                 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
                 goto Done;
             }
-            else if (dwError == ERROR_SUCCESS)
+            else if (dwError == WAIT_OBJECT_0)
             {
                 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
                                               &Overlapped,
@@ -1365,10 +1337,10 @@ ScmWaitForServiceConnect(PSERVICE Service)
     DWORD dwError = ERROR_SUCCESS;
     BOOL bResult;
 #ifdef USE_ASYNCHRONOUS_IO
-    OVERLAPPED Overlapped = {0, 0, 0, 0, 0};
+    OVERLAPPED Overlapped = {0};
 #endif
 
-    DPRINT1("ScmWaitForServiceConnect()\n");
+    DPRINT("ScmWaitForServiceConnect()\n");
 
 #ifdef USE_ASYNCHRONOUS_IO
     Overlapped.hEvent = (HANDLE)NULL;
@@ -1377,19 +1349,21 @@ ScmWaitForServiceConnect(PSERVICE Service)
                                &Overlapped);
     if (bResult == FALSE)
     {
-        DPRINT1("ConnectNamedPipe() returned FALSE\n");
+        DPRINT("ConnectNamedPipe() returned FALSE\n");
 
         dwError = GetLastError();
         if (dwError == ERROR_IO_PENDING)
         {
-            DPRINT1("dwError: ERROR_IO_PENDING\n");
+            DPRINT("dwError: ERROR_IO_PENDING\n");
 
             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
-                                          dwPipeTimeout);
-            DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
+                                          PipeTimeout);
+            DPRINT("WaitForSingleObject() returned %lu\n", dwError);
 
             if (dwError == WAIT_TIMEOUT)
             {
+                DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
+
                 bResult = CancelIo(Service->lpImage->hControlPipe);
                 if (bResult == FALSE)
                 {
@@ -1398,7 +1372,7 @@ ScmWaitForServiceConnect(PSERVICE Service)
 
                 return ERROR_SERVICE_REQUEST_TIMEOUT;
             }
-            else if (dwError == ERROR_SUCCESS)
+            else if (dwError == WAIT_OBJECT_0)
             {
                 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
                                               &Overlapped,
@@ -1420,7 +1394,7 @@ ScmWaitForServiceConnect(PSERVICE Service)
         }
     }
 
-    DPRINT1("Control pipe connected!\n");
+    DPRINT("Control pipe connected!\n");
 
     Overlapped.hEvent = (HANDLE) NULL;
 
@@ -1432,18 +1406,18 @@ ScmWaitForServiceConnect(PSERVICE Service)
                        &Overlapped);
     if (bResult == FALSE)
     {
-        DPRINT1("ReadFile() returned FALSE\n");
+        DPRINT("ReadFile() returned FALSE\n");
 
         dwError = GetLastError();
         if (dwError == ERROR_IO_PENDING)
         {
-            DPRINT1("dwError: ERROR_IO_PENDING\n");
+            DPRINT("dwError: ERROR_IO_PENDING\n");
 
             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
-                                          dwPipeTimeout);
+                                          PipeTimeout);
             if (dwError == WAIT_TIMEOUT)
             {
-                DPRINT1("WaitForSingleObject() returned WAIT_TIMEOUT\n");
+                DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
 
                 bResult = CancelIo(Service->lpImage->hControlPipe);
                 if (bResult == FALSE)
@@ -1453,11 +1427,11 @@ ScmWaitForServiceConnect(PSERVICE Service)
 
                 return ERROR_SERVICE_REQUEST_TIMEOUT;
             }
-            else if (dwError == ERROR_SUCCESS)
+            else if (dwError == WAIT_OBJECT_0)
             {
-                DPRINT1("WaitForSingleObject() returned ERROR_SUCCESS\n");
+                DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
 
-                DPRINT1("Process Id: %lu\n", dwProcessId);
+                DPRINT("Process Id: %lu\n", dwProcessId);
 
                 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
                                               &Overlapped,
@@ -1483,7 +1457,7 @@ ScmWaitForServiceConnect(PSERVICE Service)
         }
     }
 
-    DPRINT1("ScmWaitForServiceConnect() done\n");
+    DPRINT("ScmWaitForServiceConnect() done\n");
 
     return ERROR_SUCCESS;
 #else
@@ -1506,6 +1480,11 @@ ScmWaitForServiceConnect(PSERVICE Service)
             DPRINT1("Reading the service control pipe failed (Error %lu)\n",
                     dwError);
         }
+        else
+        {
+            dwError = ERROR_SUCCESS;
+            DPRINT("Read control pipe successfully\n");
+        }
     }
     else
     {
@@ -1520,7 +1499,7 @@ ScmWaitForServiceConnect(PSERVICE Service)
 static DWORD
 ScmStartUserModeService(PSERVICE Service,
                         DWORD argc,
-                        LPWSTR *argv)
+                        LPWSTRargv)
 {
     PROCESS_INFORMATION ProcessInformation;
     STARTUPINFOW StartupInfo;
@@ -1536,13 +1515,10 @@ ScmStartUserModeService(PSERVICE Service,
         return ScmSendStartCommand(Service, argc, argv);
     }
 
+    /* Otherwise start its process */
+    ZeroMemory(&StartupInfo, sizeof(StartupInfo));
     StartupInfo.cb = sizeof(StartupInfo);
-    StartupInfo.lpReserved = NULL;
-    StartupInfo.lpDesktop = NULL;
-    StartupInfo.lpTitle = NULL;
-    StartupInfo.dwFlags = 0;
-    StartupInfo.cbReserved2 = 0;
-    StartupInfo.lpReserved2 = 0;
+    ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
 
     Result = CreateProcessW(NULL,
                             Service->lpImage->szImagePath,
@@ -1561,16 +1537,15 @@ ScmStartUserModeService(PSERVICE Service,
         return dwError;
     }
 
-    DPRINT("Process Id: %lu  Handle %lx\n",
+    DPRINT("Process Id: %lu  Handle %p\n",
            ProcessInformation.dwProcessId,
            ProcessInformation.hProcess);
-    DPRINT("Thread Id: %lu  Handle %lx\n",
+    DPRINT("Thread Id: %lu  Handle %p\n",
            ProcessInformation.dwThreadId,
            ProcessInformation.hThread);
 
     /* Get process handle and id */
     Service->lpImage->dwProcessId = ProcessInformation.dwProcessId;
-    Service->lpImage->hProcess = ProcessInformation.hProcess;
 
     /* Resume Thread */
     ResumeThread(ProcessInformation.hThread);
@@ -1580,42 +1555,38 @@ ScmStartUserModeService(PSERVICE Service,
     if (dwError == ERROR_SUCCESS)
     {
         /* Send start command */
-        dwError = ScmSendStartCommand(Service,
-                                      argc,
-                                      argv);
+        dwError = ScmSendStartCommand(Service, argc, argv);
     }
     else
     {
         DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
         Service->lpImage->dwProcessId = 0;
-        Service->lpImage->hProcess = NULL;
-        CloseHandle(ProcessInformation.hProcess);
     }
 
-    /* Close thread handle */
+    /* Close thread and process handle */
     CloseHandle(ProcessInformation.hThread);
+    CloseHandle(ProcessInformation.hProcess);
 
     return dwError;
 }
 
 
-DWORD
-ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
+static DWORD
+ScmLoadService(PSERVICE Service,
+               DWORD argc,
+               LPWSTR* argv)
 {
     PSERVICE_GROUP Group = Service->lpGroup;
     DWORD dwError = ERROR_SUCCESS;
     LPCWSTR ErrorLogStrings[2];
+    WCHAR szErrorBuffer[32];
 
-    DPRINT("ScmStartService() called\n");
-
+    DPRINT("ScmLoadService() called\n");
     DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
 
-    EnterCriticalSection(&ControlServiceCriticalSection);
-
     if (Service->Status.dwCurrentState != SERVICE_STOPPED)
     {
         DPRINT("Service %S is already running!\n", Service->lpServiceName);
-        LeaveCriticalSection(&ControlServiceCriticalSection);
         return ERROR_SERVICE_ALREADY_RUNNING;
     }
 
@@ -1631,7 +1602,7 @@ ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
             Service->Status.dwCurrentState = SERVICE_RUNNING;
         }
     }
-    else
+    else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
     {
         /* Start user-mode service */
         dwError = ScmCreateOrReferenceServiceImage(Service);
@@ -1654,9 +1625,7 @@ ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
         }
     }
 
-    LeaveCriticalSection(&ControlServiceCriticalSection);
-
-    DPRINT("ScmStartService() done (Error %lu)\n", dwError);
+    DPRINT("ScmLoadService() done (Error %lu)\n", dwError);
 
     if (dwError == ERROR_SUCCESS)
     {
@@ -1669,8 +1638,10 @@ ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
     {
         if (Service->dwErrorControl != SERVICE_ERROR_IGNORE)
         {
+            /* Log a failed service start */
+            swprintf(szErrorBuffer, L"%lu", dwError);
             ErrorLogStrings[0] = Service->lpServiceName;
-            ErrorLogStrings[1] = L"Test";
+            ErrorLogStrings[1] = szErrorBuffer;
             ScmLogError(EVENT_SERVICE_START_FAILED,
                         2,
                         ErrorLogStrings);
@@ -1704,18 +1675,67 @@ ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
 }
 
 
+DWORD
+ScmStartService(PSERVICE Service,
+                DWORD argc,
+                LPWSTR* argv)
+{
+    DWORD dwError = ERROR_SUCCESS;
+    SC_RPC_LOCK Lock = NULL;
+
+    DPRINT("ScmStartService() called\n");
+    DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
+
+    /* Acquire the service control critical section, to synchronize starts */
+    EnterCriticalSection(&ControlServiceCriticalSection);
+
+    /*
+     * Acquire the user service start lock while the service is starting, if
+     * needed (i.e. if we are not starting it during the initialization phase).
+     * If we don't success, bail out.
+     */
+    if (!ScmInitialize)
+    {
+        dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
+        if (dwError != ERROR_SUCCESS) goto done;
+    }
+
+    /* Really start the service */
+    dwError = ScmLoadService(Service, argc, argv);
+
+    /* Release the service start lock, if needed, and the critical section */
+    if (Lock) ScmReleaseServiceStartLock(&Lock);
+
+done:
+    LeaveCriticalSection(&ControlServiceCriticalSection);
+
+    DPRINT("ScmStartService() done (Error %lu)\n", dwError);
+
+    return dwError;
+}
+
+
 VOID
 ScmAutoStartServices(VOID)
 {
+    DWORD dwError = ERROR_SUCCESS;
     PLIST_ENTRY GroupEntry;
     PLIST_ENTRY ServiceEntry;
     PSERVICE_GROUP CurrentGroup;
     PSERVICE CurrentService;
     WCHAR szSafeBootServicePath[MAX_PATH];
-    DWORD dwError;
     HKEY hKey;
     ULONG i;
 
+    /*
+     * This function MUST be called ONLY at initialization time.
+     * Therefore, no need to acquire the user service start lock.
+     */
+    ASSERT(ScmInitialize);
+
+    /* Acquire the service control critical section, to synchronize starts */
+    EnterCriticalSection(&ControlServiceCriticalSection);
+
     /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
     ServiceEntry = ServiceListHead.Flink;
     while (ServiceEntry != &ServiceListHead)
@@ -1806,7 +1826,7 @@ ScmAutoStartServices(VOID)
                     (CurrentService->dwTag == CurrentGroup->TagArray[i]))
                 {
                     CurrentService->ServiceVisited = TRUE;
-                    ScmStartService(CurrentService, 0, NULL);
+                    ScmLoadService(CurrentService, 0, NULL);
                 }
 
                 ServiceEntry = ServiceEntry->Flink;
@@ -1824,7 +1844,7 @@ ScmAutoStartServices(VOID)
                 (CurrentService->ServiceVisited == FALSE))
             {
                 CurrentService->ServiceVisited = TRUE;
-                ScmStartService(CurrentService, 0, NULL);
+                ScmLoadService(CurrentService, 0, NULL);
             }
 
             ServiceEntry = ServiceEntry->Flink;
@@ -1844,7 +1864,7 @@ ScmAutoStartServices(VOID)
             (CurrentService->ServiceVisited == FALSE))
         {
             CurrentService->ServiceVisited = TRUE;
-            ScmStartService(CurrentService, 0, NULL);
+            ScmLoadService(CurrentService, 0, NULL);
         }
 
         ServiceEntry = ServiceEntry->Flink;
@@ -1861,7 +1881,7 @@ ScmAutoStartServices(VOID)
             (CurrentService->ServiceVisited == FALSE))
         {
             CurrentService->ServiceVisited = TRUE;
-            ScmStartService(CurrentService, 0, NULL);
+            ScmLoadService(CurrentService, 0, NULL);
         }
 
         ServiceEntry = ServiceEntry->Flink;
@@ -1875,6 +1895,9 @@ ScmAutoStartServices(VOID)
         CurrentService->ServiceVisited = FALSE;
         ServiceEntry = ServiceEntry->Flink;
     }
+
+    /* Release the critical section */
+    LeaveCriticalSection(&ControlServiceCriticalSection);
 }
 
 
@@ -1954,7 +1977,7 @@ ScmInitNamedPipeCriticalSection(VOID)
                          L"ServicesPipeTimeout",
                          0,
                          NULL,
-                         (LPBYTE)&dwPipeTimeout,
+                         (LPBYTE)&PipeTimeout,
                          &dwKeySize);
 
        RegCloseKey(hKey);