[SERVICES] Set default status to SERVICE_START_PENDING when starting a service.
authorEric Kohl <eric.kohl@reactos.org>
Fri, 19 Feb 2010 20:03:11 +0000 (20:03 +0000)
committerEric Kohl <eric.kohl@reactos.org>
Fri, 19 Feb 2010 20:03:11 +0000 (20:03 +0000)
[SYSSETUP] Wait until PlugPlay service is up. Bug #4142.
[UMPNPMGR] Update the service control manager's status information.

Patches by Dmitry Gorbachev.

svn path=/trunk/; revision=45626

reactos/base/services/umpnpmgr/umpnpmgr.c
reactos/base/system/services/database.c
reactos/dll/win32/syssetup/install.c

index 8dc8a16..75080d5 100644 (file)
 
 /* GLOBALS ******************************************************************/
 
-static VOID CALLBACK
-ServiceMain(DWORD argc, LPTSTR *argv);
-
-static SERVICE_TABLE_ENTRY ServiceTable[2] =
+static VOID CALLBACK ServiceMain(DWORD, LPWSTR *);
+static WCHAR ServiceName[] = L"PlugPlay";
+static SERVICE_TABLE_ENTRYW ServiceTable[] =
 {
-    {TEXT("PlugPlay"), ServiceMain},
+    {ServiceName, ServiceMain},
     {NULL, NULL}
 };
 
@@ -2446,63 +2445,36 @@ PnpEventThread(LPVOID lpParameter)
 }
 
 
-static VOID CALLBACK
-ServiceMain(DWORD argc, LPTSTR *argv)
+static DWORD WINAPI
+ServiceControlHandler(DWORD dwControl,
+                      DWORD dwEventType,
+                      LPVOID lpEventData,
+                      LPVOID lpContext)
 {
-    HANDLE hThread;
-    DWORD dwThreadId;
-
-    UNREFERENCED_PARAMETER(argc);
-    UNREFERENCED_PARAMETER(argv);
-
-    DPRINT("ServiceMain() called\n");
-
-    hThread = CreateThread(NULL,
-                           0,
-                           PnpEventThread,
-                           NULL,
-                           0,
-                           &dwThreadId);
-    if (hThread != NULL)
-        CloseHandle(hThread);
-
-    hThread = CreateThread(NULL,
-                           0,
-                           RpcServerThread,
-                           NULL,
-                           0,
-                           &dwThreadId);
-    if (hThread != NULL)
-        CloseHandle(hThread);
-
-    hThread = CreateThread(NULL,
-                           0,
-                           DeviceInstallThread,
-                           NULL,
-                           0,
-                           &dwThreadId);
-    if (hThread != NULL)
-        CloseHandle(hThread);
-
-    DPRINT("ServiceMain() done\n");
+    /* FIXME */
+    DPRINT1("ServiceControlHandler() called (control code %lu)\n", dwControl);
+    return ERROR_SUCCESS;
 }
 
 
-int
-wmain(int argc, WCHAR *argv[])
+static DWORD
+ServiceInit(VOID)
 {
-    BOOLEAN OldValue;
+    HANDLE hThread;
+    DWORD dwThreadId;
     DWORD dwError;
-
-    UNREFERENCED_PARAMETER(argc);
-    UNREFERENCED_PARAMETER(argv);
-
-    DPRINT("Umpnpmgr: main() started\n");
+    BOOLEAN OldValue;
 
     /* We need this privilege for using CreateProcessAsUserW */
-    RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, TRUE, FALSE, &OldValue);
-
-    hInstallEvent = CreateEvent(NULL, TRUE, SetupIsActive()/*FALSE*/, NULL);
+    RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE,
+                       TRUE,
+                       FALSE,
+                       &OldValue);
+
+    hInstallEvent = CreateEvent(NULL,
+                                TRUE,
+                                SetupIsActive()/*FALSE*/,
+                                NULL);
     if (hInstallEvent == NULL)
     {
         dwError = GetLastError();
@@ -2510,7 +2482,10 @@ wmain(int argc, WCHAR *argv[])
         return dwError;
     }
 
-    hDeviceInstallListNotEmpty = CreateEvent(NULL, FALSE, FALSE, NULL);
+    hDeviceInstallListNotEmpty = CreateEvent(NULL,
+                                             FALSE,
+                                             FALSE,
+                                             NULL);
     if (hDeviceInstallListNotEmpty == NULL)
     {
         dwError = GetLastError();
@@ -2557,11 +2532,110 @@ wmain(int argc, WCHAR *argv[])
         return dwError;
     }
 
-    StartServiceCtrlDispatcher(ServiceTable);
+    hThread = CreateThread(NULL,
+                           0,
+                           PnpEventThread,
+                           NULL,
+                           0,
+                           &dwThreadId);
+    if (hThread == NULL)
+    {
+        return GetLastError();
+    }
+    CloseHandle(hThread);
+
+    hThread = CreateThread(NULL,
+                           0,
+                           RpcServerThread,
+                           NULL,
+                           0,
+                           &dwThreadId);
+    if (hThread == NULL)
+    {
+        return GetLastError();
+    }
+    CloseHandle(hThread);
+
+    hThread = CreateThread(NULL,
+                           0,
+                           DeviceInstallThread,
+                           NULL,
+                           0,
+                           &dwThreadId);
+    if (hThread == NULL)
+    {
+        return GetLastError();
+    }
+    CloseHandle(hThread);
+
+    return ERROR_SUCCESS;
+}
+
+
+static VOID CALLBACK
+ServiceMain(DWORD argc,
+            LPWSTR *argv)
+{
+    SERVICE_STATUS ServiceStatus;
+    SERVICE_STATUS_HANDLE ServiceStatusHandle;
+    DWORD dwError;
+
+    UNREFERENCED_PARAMETER(argc);
+    UNREFERENCED_PARAMETER(argv);
+
+    DPRINT("ServiceMain() called\n");
+
+    ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
+                                                        ServiceControlHandler,
+                                                        NULL);
+    if (!ServiceStatusHandle)
+    {
+        dwError = GetLastError();
+        DPRINT1("RegisterServiceCtrlHandlerW() failed! (Error %lu)\n", dwError);
+        return;
+    }
+
+    ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+    ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
+    ServiceStatus.dwControlsAccepted = 0;
+    ServiceStatus.dwWin32ExitCode = NO_ERROR;
+    ServiceStatus.dwServiceSpecificExitCode = 0;
+    ServiceStatus.dwCheckPoint = 0;
+    ServiceStatus.dwWaitHint = 2000;
+
+    SetServiceStatus(ServiceStatusHandle,
+                     &ServiceStatus);
+
+    dwError = ServiceInit();
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("Service stopped\n");
+        ServiceStatus.dwCurrentState = SERVICE_STOPPED;
+    }
+    else
+    {
+        ServiceStatus.dwCurrentState = SERVICE_RUNNING;
+    }
+
+    SetServiceStatus(ServiceStatusHandle,
+                     &ServiceStatus);
+
+    DPRINT("ServiceMain() done\n");
+}
+
+
+int
+wmain(int argc,
+      WCHAR *argv[])
+{
+    UNREFERENCED_PARAMETER(argc);
+    UNREFERENCED_PARAMETER(argv);
+
+    DPRINT1("Umpnpmgr: main() started\n");
 
-    DPRINT("Umpnpmgr: main() done\n");
+    StartServiceCtrlDispatcherW(ServiceTable);
 
-    ExitThread(0);
+    DPRINT1("Umpnpmgr: main() done\n");
 
     return 0;
 }
index d33b234..93a99e5 100644 (file)
@@ -1054,7 +1054,7 @@ ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
         {
             Group->ServicesRunning = TRUE;
         }
-        Service->Status.dwCurrentState = SERVICE_RUNNING;
+        Service->Status.dwCurrentState = SERVICE_START_PENDING;
     }
 #if 0
     else
index a853e8d..b3bd427 100644 (file)
@@ -20,7 +20,7 @@
  * COPYRIGHT:         See COPYING in the top level directory
  * PROJECT:           ReactOS system libraries
  * PURPOSE:           System setup
- * FILE:              lib/syssetup/install.c
+ * FILE:              dll/win32/syssetup/install.c
  * PROGRAMER:         Eric Kohl
  */
 
@@ -473,30 +473,100 @@ InstallSysSetupInfComponents(VOID)
 static BOOL
 EnableUserModePnpManager(VOID)
 {
+    SERVICE_STATUS_PROCESS ServiceStatus;
     SC_HANDLE hSCManager = NULL;
     SC_HANDLE hService = NULL;
+    DWORD dwStartTickCount;
+    DWORD dwOldCheckPoint;
+    DWORD BytesNeeded = 0;
+    DWORD dwWaitTime;
+    DWORD dwMaxWait;
     BOOL ret = FALSE;
 
     hSCManager = OpenSCManager(NULL, NULL, 0);
     if (hSCManager == NULL)
         goto cleanup;
 
-    hService = OpenServiceW(hSCManager, L"PlugPlay", SERVICE_CHANGE_CONFIG | SERVICE_START);
+    hService = OpenServiceW(hSCManager,
+                            L"PlugPlay",
+                            SERVICE_CHANGE_CONFIG | SERVICE_START | SERVICE_QUERY_STATUS);
     if (hService == NULL)
         goto cleanup;
 
-    ret = ChangeServiceConfigW(
-        hService,
-        SERVICE_NO_CHANGE, SERVICE_AUTO_START, SERVICE_NO_CHANGE,
-        NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+    ret = ChangeServiceConfigW(hService,
+                               SERVICE_NO_CHANGE,
+                               SERVICE_AUTO_START,
+                               SERVICE_NO_CHANGE,
+                               NULL, NULL, NULL,
+                               NULL, NULL, NULL, NULL);
     if (!ret)
         goto cleanup;
 
     ret = StartServiceW(hService, 0, NULL);
+    if (!ret)
+    {
+        /* If the service is already running, just return TRUE */
+        ret = GetLastError() == ERROR_SERVICE_ALREADY_RUNNING;
+        goto cleanup;
+    }
+
+    ret = QueryServiceStatusEx(hService,
+                               SC_STATUS_PROCESS_INFO,
+                               (LPBYTE)&ServiceStatus,
+                               sizeof(SERVICE_STATUS_PROCESS),
+                               &BytesNeeded);
     if (!ret)
         goto cleanup;
 
-    ret = TRUE;
+    /* We don't want to wait for more than 30 seconds */
+    dwMaxWait = 30000;
+    dwStartTickCount = GetTickCount();
+
+    /* Loop until it's running */
+    while (ServiceStatus.dwCurrentState != SERVICE_RUNNING)
+    {
+        dwOldCheckPoint = ServiceStatus.dwCheckPoint;
+        dwWaitTime = ServiceStatus.dwWaitHint / 10;
+
+        /* Get the latest status info */
+        if (!QueryServiceStatusEx(hService,
+                                  SC_STATUS_PROCESS_INFO,
+                                  (LPBYTE)&ServiceStatus,
+                                  sizeof(SERVICE_STATUS_PROCESS),
+                                  &BytesNeeded))
+        {
+            /* Something went wrong... */
+            break;
+        }
+
+        /* Is the service making progress? */
+        if (ServiceStatus.dwCheckPoint > dwOldCheckPoint)
+        {
+            /* It is, get the latest tickcount to reset the max wait time */
+            dwStartTickCount = GetTickCount();
+            dwOldCheckPoint = ServiceStatus.dwCheckPoint;
+        }
+        else
+        {
+            /* It's not, make sure we haven't exceeded our wait time */
+            if (GetTickCount() >= dwStartTickCount + dwMaxWait)
+            {
+                /* We have, give up */
+                break;
+            }
+        }
+
+        /* Adjust the wait hint times */
+        if (dwWaitTime < 200)
+            dwWaitTime = 200;
+        else if (dwWaitTime > 10000)
+            dwWaitTime = 10000;
+
+        /* Wait before trying again */
+        Sleep(dwWaitTime);
+    }
+
+    ret = ServiceStatus.dwCurrentState == SERVICE_RUNNING;
 
 cleanup:
     if (hSCManager != NULL)