Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxService-win.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxService-win.cpp	(revision 29816)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxService-win.cpp	(revision 29817)
@@ -5,5 +5,5 @@
 
 /*
- * Copyright (C) 2009 Oracle Corporation
+ * Copyright (C) 2009-2010 Oracle Corporation
  *
  * This file is part of VirtualBox Open Source Edition (OSE), as
@@ -29,15 +29,23 @@
 #include <aclapi.h>
 
-DWORD                 g_rcWinService = 0;
+
+/*******************************************************************************
+*   Internal Functions                                                         *
+*******************************************************************************/
+static void WINAPI vboxServiceWinMain(DWORD argc, LPTSTR *argv);
+
+
+/*******************************************************************************
+*   Global Variables                                                           *
+*******************************************************************************/
+static DWORD          g_dwWinServiceLastStatus = 0;
 SERVICE_STATUS_HANDLE g_hWinServiceStatus = NULL;
 /** The semaphore for the dummy Windows service. */
 static RTSEMEVENT     g_WindowsEvent = NIL_RTSEMEVENT;
 
-void WINAPI VBoxServiceWinMain (DWORD argc, LPTSTR *argv);
-
-static SERVICE_TABLE_ENTRY const g_aServiceTable[]=
-{
-    {VBOXSERVICE_NAME, VBoxServiceWinMain},
-    {NULL,NULL}
+static SERVICE_TABLE_ENTRY const g_aServiceTable[] =
+{
+    { VBOXSERVICE_NAME, vboxServiceWinMain },
+    { NULL,             NULL}
 };
 
@@ -48,11 +56,11 @@
  * @todo Add event log capabilities / check return values.
  */
-DWORD VBoxServiceWinAddAceToObjectsSecurityDescriptor(LPTSTR pszObjName,
-                                                      SE_OBJECT_TYPE ObjectType,
-                                                      LPTSTR pszTrustee,
-                                                      TRUSTEE_FORM TrusteeForm,
-                                                      DWORD dwAccessRights,
-                                                      ACCESS_MODE AccessMode,
-                                                      DWORD dwInheritance)
+static DWORD vboxServiceWinAddAceToObjectsSecurityDescriptor(LPTSTR pszObjName,
+                                                             SE_OBJECT_TYPE ObjectType,
+                                                             LPTSTR pszTrustee,
+                                                             TRUSTEE_FORM TrusteeForm,
+                                                             DWORD dwAccessRights,
+                                                             ACCESS_MODE AccessMode,
+                                                             DWORD dwInheritance)
 {
     DWORD dwRes = 0;
@@ -74,5 +82,5 @@
         else
             VBoxServiceError("AddAceToObjectsSecurityDescriptor: GetNamedSecurityInfo: Error %u\n", dwRes);
-        goto Cleanup;
+        goto l_Cleanup;
     }
 
@@ -90,5 +98,5 @@
     {
         VBoxServiceError("AddAceToObjectsSecurityDescriptor: SetEntriesInAcl: Error %u\n", dwRes);
-        goto Cleanup;
+        goto l_Cleanup;
     }
 
@@ -100,9 +108,9 @@
     {
         VBoxServiceError("AddAceToObjectsSecurityDescriptor: SetNamedSecurityInfo: Error %u\n", dwRes);
-        goto Cleanup;
+        goto l_Cleanup;
     }
 
     /** @todo get rid of that spaghetti jump ... */
-Cleanup:
+l_Cleanup:
 
     if(pSD != NULL)
@@ -116,15 +124,15 @@
 
 /** Reports our current status to the SCM. */
-BOOL VBoxServiceWinSetStatus(DWORD dwStatus, DWORD dwCheckPoint)
-{
-    if (NULL == g_hWinServiceStatus) /* Program could be in testing mode, so no service environment available. */
+static BOOL vboxServiceWinSetStatus(DWORD dwStatus, DWORD dwCheckPoint)
+{
+    if (g_hWinServiceStatus == NULL) /* Program could be in testing mode, so no service environment available. */
         return FALSE;
 
     VBoxServiceVerbose(2, "Setting service status to: %ld\n", dwStatus);
-    g_rcWinService  = dwStatus;
+    g_dwWinServiceLastStatus = dwStatus;
 
     SERVICE_STATUS ss;
     ss.dwServiceType              = SERVICE_WIN32_OWN_PROCESS;
-    ss.dwCurrentState             = g_rcWinService;
+    ss.dwCurrentState             = dwStatus;
     ss.dwControlsAccepted         = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
     ss.dwWin32ExitCode            = NO_ERROR;
@@ -137,103 +145,98 @@
 
 
-int VBoxServiceWinSetDesc(SC_HANDLE hService)
-{
+/**
+ * Reports SERVICE_STOP_PENDING to SCM.
+ *
+ * @param   uCheckPoint         Some number.
+ */
+void VBoxServiceWinSetStopPendingStatus(uint32_t uCheckPoint)
+{
+    vboxServiceWinSetStatus(SERVICE_STOP_PENDING, uCheckPoint);
+}
+
+
+static RTEXITCODE vboxServiceWinSetDesc(SC_HANDLE hService)
+{
+#ifndef TARGET_NT4
     /* On W2K+ there's ChangeServiceConfig2() which lets us set some fields
        like a longer service description. */
-#ifndef TARGET_NT4
+    /** @todo On Vista+ SERVICE_DESCRIPTION also supports localized strings! */
     SERVICE_DESCRIPTION desc;
-    /** @todo On Vista+ SERVICE_DESCRIPTION also supports localized strings! */
-    desc. lpDescription = VBOXSERVICE_DESCRIPTION;
-    if (FALSE == ChangeServiceConfig2(hService,
-                                      SERVICE_CONFIG_DESCRIPTION, /* Service info level */
-                                      &desc))
+    desc.lpDescription = VBOXSERVICE_DESCRIPTION;
+    if (!ChangeServiceConfig2(hService,
+                              SERVICE_CONFIG_DESCRIPTION, /* Service info level */
+                              &desc))
     {
         VBoxServiceError("Cannot set the service description! Error: %ld\n", GetLastError());
-        return 1;
-    }
-#endif
-    return VINF_SUCCESS;
-}
-
-
-/** Installs the service into the registry. */
-int VBoxServiceWinInstall(void)
-{
-    SC_HANDLE hService, hSCManager;
+        return RTEXITCODE_FAILURE;
+    }
+#endif
+    return RTEXITCODE_SUCCESS;
+}
+
+
+/**
+ * Installs the service.
+ */
+RTEXITCODE VBoxServiceWinInstall(void)
+{
+    VBoxServiceVerbose(1, "Installing service ...\n");
+
     TCHAR imagePath[MAX_PATH] = { 0 };
-
-    GetModuleFileName(NULL,imagePath,MAX_PATH);
-    VBoxServiceVerbose(1, "Installing service ...\n");
-
-    hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
-
-    if (NULL == hSCManager)
+    GetModuleFileName(NULL, imagePath, sizeof(imagePath));
+
+    SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+    if (hSCManager == NULL)
     {
         VBoxServiceError("Could not open SCM! Error: %ld\n", GetLastError());
-        return 1;
-    }
-
-    hService = ::CreateService (hSCManager,
-                                VBOXSERVICE_NAME, VBOXSERVICE_FRIENDLY_NAME,
-                                SERVICE_ALL_ACCESS,
-                                SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
-                                SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
-                                imagePath, NULL, NULL, NULL, NULL, NULL);
-    int rc = VINF_SUCCESS;
-    if (NULL == hService)
+        return RTEXITCODE_FAILURE;
+    }
+
+    RTEXITCODE rc       = RTEXITCODE_SUCCESS;
+    SC_HANDLE  hService = CreateService(hSCManager,
+                                        VBOXSERVICE_NAME, VBOXSERVICE_FRIENDLY_NAME,
+                                        SERVICE_ALL_ACCESS,
+                                        SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
+                                        SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
+                                        imagePath, NULL, NULL, NULL, NULL, NULL);
+    if (hService != NULL)
+        VBoxServiceVerbose(0, "Service successfully installed!\n");
+    else
     {
         DWORD dwErr = GetLastError();
         switch (dwErr)
         {
-
-        case ERROR_SERVICE_EXISTS:
-
-            VBoxServiceVerbose(1, "Service already exists, just updating the service config.\n");
-            hService = OpenService (hSCManager,
-                                    VBOXSERVICE_NAME,
-                                    SERVICE_ALL_ACCESS);
-            if (NULL == hService)
-            {
-                VBoxServiceError("Could not open service! Error: %ld\n", GetLastError());
-                rc = 1;
-            }
-            else
-            {
-                if (ChangeServiceConfig (hService,
-                                         SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
-                                         SERVICE_DEMAND_START,
-                                         SERVICE_ERROR_NORMAL,
-                                         imagePath,
-                                         NULL,
-                                         NULL,
-                                         NULL,
-                                         NULL,
-                                         NULL,
-                                         VBOXSERVICE_FRIENDLY_NAME))
+            case ERROR_SERVICE_EXISTS:
+                VBoxServiceVerbose(1, "Service already exists, just updating the service config.\n");
+                hService = OpenService(hSCManager, VBOXSERVICE_NAME, SERVICE_ALL_ACCESS);
+                if (hService)
                 {
-                    VBoxServiceVerbose(1, "The service config has been successfully updated.\n");
+                    if (ChangeServiceConfig (hService,
+                                             SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
+                                             SERVICE_DEMAND_START,
+                                             SERVICE_ERROR_NORMAL,
+                                             imagePath,
+                                             NULL,
+                                             NULL,
+                                             NULL,
+                                             NULL,
+                                             NULL,
+                                             VBOXSERVICE_FRIENDLY_NAME))
+                        VBoxServiceVerbose(1, "The service config has been successfully updated.\n");
+                    else
+                        rc = VBoxServiceError("Could not change service config! Error: %ld\n", GetLastError());
                 }
                 else
-                {
-                    VBoxServiceError("Could not change service config! Error: %ld\n", GetLastError());
-                    rc = 1;
-                }
-            }
-            break;
-
-        default:
-
-            VBoxServiceError("Could not create service! Error: %ld\n", dwErr);
-            rc = 1;
-            break;
-        }
-    }
-    else
-    {
-        VBoxServiceVerbose(0, "Service successfully installed!\n");
-    }
-
-    if (RT_SUCCESS(rc))
-        rc = VBoxServiceWinSetDesc(hService);
+                    rc = VBoxServiceError("Could not open service! Error: %ld\n", GetLastError());
+                break;
+
+            default:
+                rc = VBoxServiceError("Could not create service! Error: %ld\n", dwErr);
+                break;
+        }
+    }
+
+    if (rc == RTEXITCODE_SUCCESS)
+        rc = vboxServiceWinSetDesc(hService);
 
     CloseServiceHandle(hService);
@@ -242,50 +245,55 @@
 }
 
-/** Uninstalls the service from the registry. */
-int VBoxServiceWinUninstall(void)
-{
-    SC_HANDLE hService, hSCManager;
-    hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
-
+/**
+ * Uninstalls the service.
+ */
+RTEXITCODE VBoxServiceWinUninstall(void)
+{
     VBoxServiceVerbose(1, "Uninstalling service ...\n");
 
-    if (NULL == hSCManager) {
+    SC_HANDLE hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
+    if (hSCManager == NULL)
+    {
         VBoxServiceError("Could not open SCM! Error: %d\n", GetLastError());
-        return 1;
-    }
-
-    hService = OpenService (hSCManager, VBOXSERVICE_NAME, SERVICE_ALL_ACCESS );
-    if (NULL == hService) {
-        VBoxServiceError("Could not open service! Error: %d\n", GetLastError());
-        CloseServiceHandle (hSCManager);
-        return 1;
-    }
-
-    if (FALSE == DeleteService (hService))
-    {
-        VBoxServiceError("Could not remove service! Error: %d\n", GetLastError());
-        CloseServiceHandle (hService);
-        CloseServiceHandle (hSCManager);
-        return 1;
+        return RTEXITCODE_FAILURE;
+    }
+
+    RTEXITCODE rcExit;
+    SC_HANDLE  hService = OpenService(hSCManager, VBOXSERVICE_NAME, SERVICE_ALL_ACCESS );
+    if (hService != NULL)
+    {
+        if (DeleteService(hService))
+        {
+            /*
+             * ???
+             */
+            HKEY hKey = NULL;
+            if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+                             "SYSTEM\\CurrentControlSet\\Services\\EventLog\\System",
+                             0,
+                             KEY_ALL_ACCESS,
+                             &hKey)
+                == ERROR_SUCCESS)
+            {
+                RegDeleteKey(hKey, VBOXSERVICE_NAME);
+                RegCloseKey(hKey);
+            }
+
+            VBoxServiceVerbose(0, "Service successfully uninstalled!\n");
+            rcExit = RTEXITCODE_SUCCESS;
+        }
+        else
+            rcExit = VBoxServiceError("Could not remove service! Error: %d\n", GetLastError());
+        CloseServiceHandle(hService);
     }
     else
-    {
-        HKEY hKey = NULL;
-        if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\System", 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) {
-            RegDeleteKey(hKey, VBOXSERVICE_NAME);
-            RegCloseKey(hKey);
-        }
-
-        VBoxServiceVerbose(0, "Service successfully uninstalled!\n");
-    }
-
-    CloseServiceHandle(hService);
+        rcExit = VBoxServiceError("Could not open service! Error: %d\n", GetLastError());
     CloseServiceHandle(hSCManager);
 
-    return 0;
-}
-
-
-int VBoxServiceWinStart(void)
+    return rcExit;
+}
+
+
+static int vboxServiceWinStart(void)
 {
     int rc = VINF_SUCCESS;
@@ -296,20 +304,21 @@
     SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_LOCAL_SID_AUTHORITY;
 
-    if(!AllocateAndInitializeSid(&SIDAuthWorld, 1,
-                                 SECURITY_LOCAL_RID,
-                                 0, 0, 0, 0, 0, 0, 0,
-                                 &pBuiltinUsersSID))
-    {
+    if (!AllocateAndInitializeSid(&SIDAuthWorld, 1,
+                                  SECURITY_LOCAL_RID,
+                                  0, 0, 0, 0, 0, 0, 0,
+                                  &pBuiltinUsersSID))
+    {
+        /**@todo r=bird: rc = RTErrConvertFromWin32(GetLastError()); ?*/
         VBoxServiceError("AllocateAndInitializeSid: Error %u\n", GetLastError());
     }
     else
     {
-        DWORD dwRes = VBoxServiceWinAddAceToObjectsSecurityDescriptor (TEXT("\\\\.\\VBoxMiniRdrDN"),
-                                                                       SE_FILE_OBJECT,
-                                                                       (LPTSTR)pBuiltinUsersSID,
-                                                                       TRUSTEE_IS_SID,
-                                                                       FILE_GENERIC_READ | FILE_GENERIC_WRITE,
-                                                                       SET_ACCESS,
-                                                                       NO_INHERITANCE);
+        DWORD dwRes = vboxServiceWinAddAceToObjectsSecurityDescriptor(TEXT("\\\\.\\VBoxMiniRdrDN"),
+                                                                      SE_FILE_OBJECT,
+                                                                      (LPTSTR)pBuiltinUsersSID,
+                                                                      TRUSTEE_IS_SID,
+                                                                      FILE_GENERIC_READ | FILE_GENERIC_WRITE,
+                                                                      SET_ACCESS,
+                                                                      NO_INHERITANCE);
         if (dwRes != ERROR_SUCCESS)
         {
@@ -318,8 +327,9 @@
                 /* If we don't find our "VBoxMiniRdrDN" (for Shared Folders) object above,
                    don't report an error; it just might be not installed. Otherwise this
-                   would cause the SCM to hang on starting up the service. */
+                  would cause the SCM to hang on starting up the service. */
                 rc = VINF_SUCCESS;
             }
-            else rc = RTErrConvertFromWin32(dwRes);
+            else
+                rc = RTErrConvertFromWin32(dwRes);
         }
     }
@@ -328,13 +338,14 @@
     if (RT_SUCCESS(rc))
     {
-        /* Notify SCM *before* we're starting the services, because the last services
-           always starts in main thread (which causes the SCM to wait because of the non-responding
-           service). */
-        VBoxServiceWinSetStatus (SERVICE_RUNNING, 0);
-
         rc = VBoxServiceStartServices();
-        if (RT_FAILURE(rc))
-            VBoxServiceWinSetStatus (SERVICE_STOPPED, 0);
-    }
+        if (RT_SUCCESS(rc))
+        {
+            vboxServiceWinSetStatus(SERVICE_RUNNING, 0);
+            VBoxServiceMainWait();
+        }
+        else
+            vboxServiceWinSetStatus(SERVICE_STOPPED, 0);
+    }
+    /**@todo r=bird: else vboxServiceWinSetStatus(SERVICE_STOPPED, 0); ? */
 
     if (RT_FAILURE(rc))
@@ -345,102 +356,115 @@
 
 
+/**
+ * Call StartServiceCtrlDispatcher.
+ *
+ * The main() thread invokes this when not started in foreground mode.  It
+ * won't return till the service is being shutdown (unless start up fails).
+ *
+ * @returns RTEXITCODE_SUCCESS on normal return after service shutdown.
+ *          Something else on failure, error will have been reported.
+ */
+RTEXITCODE VBoxServiceWinEnterCtrlDispatcher(void)
+{
+    if (!StartServiceCtrlDispatcher(&g_aServiceTable[0]))
+        return VBoxServiceError("StartServiceCtrlDispatcher: %u. Please start %s with option -f (foreground)!",
+                                GetLastError(), g_pszProgName);
+    return RTEXITCODE_SUCCESS;
+}
+
+
 #ifdef TARGET_NT4
-VOID WINAPI VBoxServiceWinCtrlHandler(DWORD dwControl)
+static VOID WINAPI vboxServiceWinCtrlHandler(DWORD dwControl)
 #else
-DWORD WINAPI VBoxServiceWinCtrlHandler(DWORD dwControl,
-                                       DWORD dwEventType,
-                                       LPVOID lpEventData,
-                                       LPVOID lpContext)
-#endif
-{
-    DWORD rc = NO_ERROR;
-
-    VBoxServiceVerbose(2, "Control handler: Control=%ld\n", dwControl);
+static DWORD WINAPI vboxServiceWinCtrlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
+#endif
+{
+    DWORD rcRet = NO_ERROR;
+
+#ifdef TARGET_NT4
+    VBoxServiceVerbose(2, "Control handler: Control=%#x\n", dwControl);
+#else
+    VBoxServiceVerbose(2, "Control handler: Control=%#x EventType=%#x\n", dwControl, dwEventType);
+#endif
+
+    switch (dwControl)
+    {
+        case SERVICE_CONTROL_INTERROGATE:
+            vboxServiceWinSetStatus(g_dwWinServiceLastStatus, 0);
+            break;
+
+        case SERVICE_CONTROL_STOP:
+        case SERVICE_CONTROL_SHUTDOWN:
+        {
+            vboxServiceWinSetStatus(SERVICE_STOP_PENDING, 0);
+
+            int rc2 = VBoxServiceStopServices();
+            if (RT_FAILURE(rc2))
+                rcRet = ERROR_GEN_FAILURE;
+
+            vboxServiceWinSetStatus(SERVICE_STOPPED, 0);
+            break;
+        }
+
+        case SERVICE_CONTROL_SESSIONCHANGE:     /* Only Win XP and up. */
 #ifndef TARGET_NT4
-    VBoxServiceVerbose(2, "Control handler: EventType=%ld\n", dwEventType);
-#endif
-
-    switch (dwControl)
-    {
-
-    case SERVICE_CONTROL_INTERROGATE:
-        VBoxServiceWinSetStatus(g_rcWinService, 0);
-        break;
-
-    case SERVICE_CONTROL_STOP:
-    case SERVICE_CONTROL_SHUTDOWN:
-        {
-            VBoxServiceWinSetStatus(SERVICE_STOP_PENDING, 0);
-
-            rc = VBoxServiceStopServices();
-
-            VBoxServiceWinSetStatus(SERVICE_STOPPED, 0);
-        }
-        break;
-
-    case SERVICE_CONTROL_SESSIONCHANGE:     /* Only Win XP and up. */
+# if 0
+            switch (dwEventType)
+            {
+                case WTS_SESSION_LOGON:
+                    VBoxServiceVerbose(2, "A user has logged on to the session.\n");
+                    break;
+
+                case WTS_SESSION_LOGOFF:
+                    VBoxServiceVerbose(2, "A user has logged off from the session.\n");
+                    break;
+                default:
+                    break;
+            }
+# endif
+#endif /* !TARGET_NT4 */
+            break;
+
+        default:
+            VBoxServiceVerbose(1, "Service control function not implemented: %#x\n", dwControl);
+            rcRet = ERROR_CALL_NOT_IMPLEMENTED;
+            break;
+    }
 
 #ifndef TARGET_NT4
-        switch (dwEventType)
-        {
-        /*case WTS_SESSION_LOGON:
-            VBoxServiceVerbose(2, "A user has logged on to the session.\n");
-            break;
-
-        case WTS_SESSION_LOGOFF:
-            VBoxServiceVerbose(2, "A user has logged off from the session.\n");
-            break;*/
-        default:
-            break;
-        }
-#endif /* TARGET_NT4 */
-        break;
-
-    default:
-
-        VBoxServiceVerbose(1, "Service control function not implemented: %ld\n", dwControl);
-        rc = ERROR_CALL_NOT_IMPLEMENTED;
-        break;
-    }
-
-#ifndef TARGET_NT4
-    return rc;
-#endif
-}
-
-
-void WINAPI VBoxServiceWinMain(DWORD argc, LPTSTR *argv)
-{
-    int rc = VINF_SUCCESS;
-
+    return rcRet;
+#endif
+}
+
+
+static void WINAPI vboxServiceWinMain(DWORD argc, LPTSTR *argv)
+{
     VBoxServiceVerbose(2, "Registering service control handler ...\n");
 #ifdef TARGET_NT4
-    g_hWinServiceStatus = RegisterServiceCtrlHandler (VBOXSERVICE_NAME, VBoxServiceWinCtrlHandler);
+    g_hWinServiceStatus = RegisterServiceCtrlHandler(VBOXSERVICE_NAME, vboxServiceWinCtrlHandler);
 #else
-    g_hWinServiceStatus = RegisterServiceCtrlHandlerEx (VBOXSERVICE_NAME, VBoxServiceWinCtrlHandler, NULL);
-#endif
-
-    if (NULL == g_hWinServiceStatus)
+    g_hWinServiceStatus = RegisterServiceCtrlHandlerEx(VBOXSERVICE_NAME, vboxServiceWinCtrlHandler, NULL);
+#endif
+    if (g_hWinServiceStatus != NULL)
+    {
+        VBoxServiceVerbose(2, "Service control handler registered.\n");
+        vboxServiceWinStart();
+    }
+    else
     {
         DWORD dwErr = GetLastError();
-
         switch (dwErr)
         {
-        case ERROR_INVALID_NAME:
-            VBoxServiceError("Invalid service name!\n");
-            break;
-        case ERROR_SERVICE_DOES_NOT_EXIST:
-            VBoxServiceError("Service does not exist!\n");
-            break;
-        default:
-            VBoxServiceError("Could not register service control handle! Error: %ld\n", dwErr);
-            break;
-        }
-    }
-    else
-    {
-        VBoxServiceVerbose(2, "Service control handler registered.\n");
-
-        rc = VBoxServiceWinStart();
-    }
-}
+            case ERROR_INVALID_NAME:
+                VBoxServiceError("Invalid service name!\n");
+                break;
+            case ERROR_SERVICE_DOES_NOT_EXIST:
+                VBoxServiceError("Service does not exist!\n");
+                break;
+            default:
+                VBoxServiceError("Could not register service control handle! Error: %ld\n", dwErr);
+                break;
+        }
+    }
+}
+
Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxService.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxService.cpp	(revision 29816)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxService.cpp	(revision 29817)
@@ -57,7 +57,7 @@
 #ifdef RT_OS_WINDOWS
 /** Signal shutdown to the Windows service thread. */
-bool volatile g_WindowsServiceShutdown;
+static bool volatile g_fWindowsServiceShutdown;
 /** Event the Windows service thread waits for shutdown. */
-RTSEMEVENT g_WindowsServiceEvent;
+static RTSEMEVENT g_hEvtWindowsService;
 #endif
 
@@ -155,9 +155,9 @@
  * Displays a syntax error message.
  *
- * @returns 1
+ * @returns RTEXITCODE_SYNTAX.
  * @param   pszFormat   The message text.
  * @param   ...         Format arguments.
  */
-int VBoxServiceSyntax(const char *pszFormat, ...)
+RTEXITCODE VBoxServiceSyntax(const char *pszFormat, ...)
 {
     RTStrmPrintf(g_pStdErr, "%s: syntax error: ", g_pszProgName);
@@ -168,5 +168,5 @@
     va_end(va);
 
-    return 1;
+    return RTEXITCODE_SYNTAX;
 }
 
@@ -175,9 +175,9 @@
  * Displays an error message.
  *
- * @returns 1
+ * @returns RTEXITCODE_FAILURE.
  * @param   pszFormat   The message text.
  * @param   ...         Format arguments.
  */
-int VBoxServiceError(const char *pszFormat, ...)
+RTEXITCODE VBoxServiceError(const char *pszFormat, ...)
 {
     RTStrmPrintf(g_pStdErr, "%s: error: ", g_pszProgName);
@@ -192,5 +192,5 @@
     va_end(va);
 
-    return 1;
+    return RTEXITCODE_FAILURE;
 }
 
@@ -308,5 +308,4 @@
     VBoxServiceVerbose(2, "Initializing services ...\n");
     for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
-    {
         if (g_aServices[j].fEnabled)
         {
@@ -326,5 +325,4 @@
             }
         }
-    }
 
     /*
@@ -357,22 +355,4 @@
     }
 
-#ifdef RT_OS_WINDOWS
-    if (RT_SUCCESS(rc))
-    {
-        /* Block the main thread. */
-        VBoxServiceVerbose(1, "Waiting in main thread\n");
-        int rc = RTSemEventCreate(&g_WindowsServiceEvent);
-        AssertRC(rc);
-        for (;;)
-        {
-            if (g_WindowsServiceShutdown)
-                break;
-            rc = RTSemEventWait(g_WindowsServiceEvent, RT_INDEFINITE_WAIT);
-            AssertRC(rc);
-        }
-        RTSemEventDestroy(g_WindowsServiceEvent);
-        g_WindowsServiceEvent = NIL_RTSEMEVENT;
-    }
-#endif
     return rc;
 }
@@ -389,6 +369,13 @@
     int rc = VINF_SUCCESS;
 
-    for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
-        ASMAtomicXchgBool(&g_aServices[j].fShutdown, true);
+    /*
+     * Signal all the services.
+     */
+    for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
+        ASMAtomicWriteBool(&g_aServices[j].fShutdown, true);
+
+    /*
+     * Do the pfnStop callback on all running services.
+     */
     for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
         if (g_aServices[j].fStarted)
@@ -397,4 +384,8 @@
             g_aServices[j].pDesc->pfnStop();
         }
+
+    /*
+     * Wait for all the service threads to complete.
+     */
     for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
     {
@@ -411,5 +402,5 @@
 #ifdef RT_OS_WINDOWS
                 /* Notify SCM that it takes a bit longer ... */
-                VBoxServiceWinSetStatus(SERVICE_STOP_PENDING, i);
+                VBoxServiceWinSetStopPendingStatus(i + j*32);
 #endif
             }
@@ -423,14 +414,12 @@
 #ifdef RT_OS_WINDOWS
     /*
-     * As we're now done terminating all service threads,
-     * we have to stop the main thread as well (if defined). Note that the termination
-     * function will be called in a later context (when the main thread returns from the worker
-     * function).
-     */
-    if (g_WindowsServiceEvent != NIL_RTSEMEVENT)
+     * Wake up and tell the main() thread that we're shutting down (it's
+     * sleeping in VBoxServiceMainWait).
+     */
+    if (g_hEvtWindowsService != NIL_RTSEMEVENT)
     {
         VBoxServiceVerbose(3, "Stopping the main thread...\n");
-        ASMAtomicXchgBool(&g_WindowsServiceShutdown, true);
-        rc = RTSemEventSignal(g_WindowsServiceEvent);
+        ASMAtomicWriteBool(&g_fWindowsServiceShutdown, true);
+        rc = RTSemEventSignal(g_hEvtWindowsService);
         AssertRC(rc);
     }
@@ -442,13 +431,35 @@
 
 
-#ifndef RT_OS_WINDOWS
-/**
- * Block all important signals, then explicitly wait until one of these
- * signal arrives.
- */
-static void VBoxServiceWaitSignal(void)
-{
+/**
+ * Block the main thread until the service shuts down.
+ */
+void VBoxServiceMainWait(void)
+{
+    int rc;
+
+#ifdef RT_OS_WINDOWS
+    /*
+     * Wait for the semaphore to be signalled.
+     */
+    VBoxServiceVerbose(1, "Waiting in main thread\n");
+    rc = RTSemEventCreate(&g_hEvtWindowsService);
+    AssertRC(rc);
+    while (!ASMAtomicReadBool(&g_fWindowsServiceShutdown))
+    {
+        rc = RTSemEventWait(g_hEvtWindowsService, RT_INDEFINITE_WAIT);
+        AssertRC(rc);
+    }
+    RTSemEventDestroy(g_hEvtWindowsService);
+    g_hEvtWindowsService = NIL_RTSEMEVENT;
+
+#else
+    /*
+     * Wait explicitly for a HUP, INT, QUIT, ABRT or TERM signal, blocking
+     * all important signals.
+     *
+     * The annoying EINTR/ERESTART loop is for the benefit of Solaris where
+     * sigwait returns when we receive a SIGCHLD.  Kind of makes sense since
+     */
     sigset_t signalMask;
-    int iSignal;
     sigemptyset(&signalMask);
     sigaddset(&signalMask, SIGHUP);
@@ -459,6 +470,5 @@
     pthread_sigmask(SIG_BLOCK, &signalMask, NULL);
 
-    /* This loop is required on Solaris at least. FreeBSD doesn't know ERESTART. */
-    int rc;
+    int iSignal;
     do
     {
@@ -472,7 +482,7 @@
           );
 
-    VBoxServiceVerbose(3, "VBoxServiceWaitSignal: Received signal %d (rc=%d)\n", iSignal, rc);
-}
+    VBoxServiceVerbose(3, "VBoxServiceMainWait: Received signal %d (rc=%d)\n", iSignal, rc);
 #endif /* !RT_OS_WINDOWS */
+}
 
 
@@ -653,24 +663,10 @@
      * Daemonize if requested.
      */
+    RTEXITCODE rcExit;
     if (fDaemonize && !fDaemonized)
     {
 #ifdef RT_OS_WINDOWS
-        /** @todo Should do something like VBoxSVC here, OR automatically re-register
-         *        the service and start it. Involving VbglR3Daemonize isn't an option
-         *        here.
-         *
-         *        Also, the idea here, IIRC, was to map the sub service to windows
-         *        services. The todo below is for mimicking windows services on
-         *        non-windows systems. Not sure if this is doable or not, but in anycase
-         *        this code can be moved into -win.
-         *
-         *        You should return when StartServiceCtrlDispatcher, btw., not
-         *        continue.
-         */
         VBoxServiceVerbose(2, "Starting service dispatcher ...\n");
-        if (!StartServiceCtrlDispatcher(&g_aServiceTable[0]))
-            return VBoxServiceError("StartServiceCtrlDispatcher: %u. Please start %s with option -f (foreground)!",
-                                    GetLastError(), g_pszProgName);
-        /* Service now lives in the control dispatcher registered above. */
+        rcExit = VBoxServiceWinEnterCtrlDispatcher();
 #else
         VBoxServiceVerbose(1, "Daemonizing...\n");
@@ -694,8 +690,7 @@
          */
         rc = VBoxServiceStartServices();
-#ifndef RT_OS_WINDOWS
+        rcExit = RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
         if (RT_SUCCESS(rc))
-            VBoxServiceWaitSignal();
-#endif
+            VBoxServiceMainWait();
         VBoxServiceStopServices();
     }
@@ -713,4 +708,5 @@
 
     VBoxServiceVerbose(0, "Ended.\n");
-    return RT_SUCCESS(rc) ? 0 : 1;
-}
+    return rcExit;
+}
+
Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h	(revision 29816)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceInternal.h	(revision 29817)
@@ -102,4 +102,8 @@
 /** The following constant may be defined by including NtStatus.h. */
 # define STATUS_SUCCESS             ((NTSTATUS)0x00000000L)
+
+/** @todo Move these Windows stuff into VBoxServiceVMInfo-win.cpp and hide all
+ *        the windows details using behind function calls!
+ * @{  */
 /** Structure for storing the looked up user information. */
 typedef struct
@@ -123,4 +127,5 @@
 /** Function prototypes for dynamic loading. */
 typedef DWORD (WINAPI *PFNWTSGETACTIVECONSOLESESSIONID)(void);
+/** @} */
 
 #endif /* RT_OS_WINDOWS */
@@ -253,36 +258,37 @@
 RT_C_DECLS_BEGIN
 
-extern char *g_pszProgName;
-extern int g_cVerbosity;
-extern uint32_t g_DefaultInterval;
-
-extern int VBoxServiceSyntax(const char *pszFormat, ...);
-extern int VBoxServiceError(const char *pszFormat, ...);
-extern void VBoxServiceVerbose(int iLevel, const char *pszFormat, ...);
-extern int VBoxServiceArgUInt32(int argc, char **argv, const char *psz, int *pi, uint32_t *pu32, uint32_t u32Min, uint32_t u32Max);
-extern int VBoxServiceStartServices(void);
-extern int VBoxServiceStopServices(void);
-
-extern VBOXSERVICE g_TimeSync;
-extern VBOXSERVICE g_Clipboard;
-extern VBOXSERVICE g_Control;
-extern VBOXSERVICE g_VMInfo;
-extern VBOXSERVICE g_CpuHotPlug;
+extern char        *g_pszProgName;
+extern int          g_cVerbosity;
+extern uint32_t     g_DefaultInterval;
+extern VBOXSERVICE  g_TimeSync;
+extern VBOXSERVICE  g_Clipboard;
+extern VBOXSERVICE  g_Control;
+extern VBOXSERVICE  g_VMInfo;
+extern VBOXSERVICE  g_CpuHotPlug;
 #ifdef VBOXSERVICE_MANAGEMENT
-extern VBOXSERVICE g_MemBalloon;
-extern VBOXSERVICE g_VMStatistics;
+extern VBOXSERVICE  g_MemBalloon;
+extern VBOXSERVICE  g_VMStatistics;
 #endif
 #ifdef VBOX_WITH_PAGE_SHARING
-extern VBOXSERVICE g_PageSharing;
-#endif
-
+extern VBOXSERVICE  g_PageSharing;
+#endif
+
+extern RTEXITCODE   VBoxServiceSyntax(const char *pszFormat, ...);
+extern RTEXITCODE   VBoxServiceError(const char *pszFormat, ...);
+extern void         VBoxServiceVerbose(int iLevel, const char *pszFormat, ...);
+extern int          VBoxServiceArgUInt32(int argc, char **argv, const char *psz, int *pi, uint32_t *pu32,
+                                         uint32_t u32Min, uint32_t u32Max);
+extern int          VBoxServiceStartServices(void);
+extern int          VBoxServiceStopServices(void);
+extern void         VBoxServiceMainWait(void);
 #ifdef RT_OS_WINDOWS
-extern DWORD g_rcWinService;
-extern SERVICE_TABLE_ENTRY const g_aServiceTable[];     /** @todo generate on the fly, see comment in main() from the enabled sub services. */
+extern RTEXITCODE   VBoxServiceWinInstall(void);
+extern RTEXITCODE   VBoxServiceWinUninstall(void);
+extern RTEXITCODE   VBoxServiceWinEnterCtrlDispatcher(void);
+extern void         VBoxServiceWinSetStopPendingStatus(uint32_t uCheckPoint);
+#endif
+
+#ifdef RT_OS_WINDOWS
 extern PFNWTSGETACTIVECONSOLESESSIONID g_pfnWTSGetActiveConsoleSessionId; /* VBoxServiceVMInfo-win.cpp */
-
-extern int  VBoxServiceWinInstall(void);
-extern int  VBoxServiceWinUninstall(void);
-extern BOOL VBoxServiceWinSetStatus(DWORD dwStatus, DWORD dwCheckPoint);
 # ifdef VBOX_WITH_GUEST_PROPS
 extern bool VBoxServiceVMInfoWinSessionHasProcesses(PLUID pSession, VBOXSERVICEVMINFOPROC const *paProcs, DWORD cProcs);
@@ -295,13 +301,13 @@
 
 #ifdef VBOX_WITH_GUEST_CONTROL
-extern int VBoxServiceControlExecProcess(uint32_t uContext, const char *pszCmd, uint32_t uFlags,
-                                         const char *pszArgs, uint32_t uNumArgs,
-                                         const char *pszEnv, uint32_t cbEnv, uint32_t uNumEnvVars,
-                                         const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS);
+extern int  VBoxServiceControlExecProcess(uint32_t uContext, const char *pszCmd, uint32_t uFlags,
+                                          const char *pszArgs, uint32_t uNumArgs,
+                                          const char *pszEnv, uint32_t cbEnv, uint32_t uNumEnvVars,
+                                          const char *pszUser, const char *pszPassword, uint32_t uTimeLimitMS);
 extern void VBoxServiceControlExecDestroyThreadData(PVBOXSERVICECTRLTHREADDATAEXEC pThread);
-extern int VBoxServiceControlExecReadPipeBufferContent(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
-                                                       uint8_t *pbBuffer, uint32_t cbBuffer, uint32_t *pcbToRead);
-extern int VBoxServiceControlExecWritePipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
-                                                 uint8_t *pbData, uint32_t cbData);
+extern int  VBoxServiceControlExecReadPipeBufferContent(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
+                                                        uint8_t *pbBuffer, uint32_t cbBuffer, uint32_t *pcbToRead);
+extern int  VBoxServiceControlExecWritePipeBuffer(PVBOXSERVICECTRLEXECPIPEBUF pBuf,
+                                                  uint8_t *pbData, uint32_t cbData);
 #endif
 
