- Merge from trunk up to r45543
[reactos.git] / base / applications / mscutils / servman / stop.c
index 22c018d..da36ac5 100644 (file)
@@ -3,7 +3,7 @@
  * LICENSE:     GPL - See COPYING in the top level directory
  * FILE:        base/applications/mscutils/servman/stop.c
  * PURPOSE:     Stops running a service
- * COPYRIGHT:   Copyright 2006-2009 Ged Murphy <gedmurphy@reactos.org>
+ * COPYRIGHT:   Copyright 2006-2010 Ged Murphy <gedmurphy@reactos.org>
  *
  */
 
 
 
 static BOOL
-StopService(PSTOP_INFO pStopInfo,
-            SC_HANDLE hService)
+StopService(PMAIN_WND_INFO pInfo,
+            LPWSTR lpServiceName,
+            HWND hProgress OPTIONAL)
 {
+    SC_HANDLE hSCManager;
+    SC_HANDLE hService;
     SERVICE_STATUS_PROCESS ServiceStatus;
     DWORD dwBytesNeeded;
     DWORD dwStartTime;
     DWORD dwTimeout;
-    HWND hProgDlg;
     BOOL bRet = FALSE;
 
-    dwStartTime = GetTickCount();
-    dwTimeout = 30000; // 30 secs
-
-    hProgDlg = CreateProgressDialog(pStopInfo->pInfo->hMainWnd,
-                                    pStopInfo->pInfo->pCurrentService->lpServiceName,
-                                    IDS_PROGRESS_INFO_STOP);
-    if (hProgDlg)
+    if (hProgress)
     {
-        IncrementProgressBar(hProgDlg);
+        /* Set the service name and reset the progress bag */
+        InitializeProgressDialog(hProgress, lpServiceName);
+    }
 
-        if (ControlService(hService,
-                           SERVICE_CONTROL_STOP,
-                           (LPSERVICE_STATUS)&ServiceStatus))
+    hSCManager = OpenSCManager(NULL,
+                               NULL,
+                               SC_MANAGER_CONNECT);
+    if (hSCManager)
+    {
+        hService = OpenService(hSCManager,
+                               lpServiceName,
+                               SERVICE_STOP | SERVICE_QUERY_STATUS);
+        if (hService)
         {
-            while (ServiceStatus.dwCurrentState != SERVICE_STOPPED)
+            if (hProgress)
+            {
+                /* Increment the progress bar */
+                IncrementProgressBar(hProgress, DEFAULT_STEP);
+            }
+
+            /* Set the wait time to 30 secs */
+            dwStartTime = GetTickCount();
+            dwTimeout = 30000;
+
+            /* Send the service the stop code */
+            if (ControlService(hService,
+                               SERVICE_CONTROL_STOP,
+                               (LPSERVICE_STATUS)&ServiceStatus))
             {
-                Sleep(ServiceStatus.dwWaitHint);
+                if (hProgress)
+                {
+                    /* Increment the progress bar */
+                    IncrementProgressBar(hProgress, DEFAULT_STEP);
+                }
 
-                if (QueryServiceStatusEx(hService,
-                                         SC_STATUS_PROCESS_INFO,
-                                         (LPBYTE)&ServiceStatus,
-                                         sizeof(SERVICE_STATUS_PROCESS),
-                                         &dwBytesNeeded))
+                while (ServiceStatus.dwCurrentState != SERVICE_STOPPED)
                 {
-                    if (GetTickCount() - dwStartTime > dwTimeout)
+                    /* Don't sleep for more than 3 seconds */
+                    if (ServiceStatus.dwWaitHint > 3000)
+                        ServiceStatus.dwWaitHint = 3000;
+
+                    Sleep(ServiceStatus.dwWaitHint);
+
+                    if (hProgress)
+                    {
+                        /* Increment the progress bar */
+                        IncrementProgressBar(hProgress, DEFAULT_STEP);
+                    }
+
+                    if (QueryServiceStatusEx(hService,
+                                             SC_STATUS_PROCESS_INFO,
+                                             (LPBYTE)&ServiceStatus,
+                                             sizeof(SERVICE_STATUS_PROCESS),
+                                             &dwBytesNeeded))
                     {
-                        /* We exceeded our max wait time, give up */
-                        break;
+                        /* Have we exceeded our wait time? */
+                        if (GetTickCount() - dwStartTime > dwTimeout)
+                        {
+                            /* Yep, give up */
+                            break;
+                        }
                     }
                 }
-            }
 
-            if (ServiceStatus.dwCurrentState == SERVICE_STOPPED)
-            {
-                bRet = TRUE;
+                /* If the service is stopped, return TRUE */
+                if (ServiceStatus.dwCurrentState == SERVICE_STOPPED)
+                {
+                    bRet = TRUE;
+                }
             }
+
+            CloseServiceHandle(hService);
         }
 
-        CompleteProgressBar(hProgDlg);
-        Sleep(500);
-        DestroyWindow(hProgDlg);
+        CloseServiceHandle(hSCManager);
     }
 
     return bRet;
 }
 
 static BOOL
-StopDependentServices(PSTOP_INFO pStopInfo,
-                      SC_HANDLE hService)
+StopDependantServices(PMAIN_WND_INFO pInfo,
+                      LPWSTR lpServiceList,
+                      HWND hProgress OPTIONAL)
 {
-    LPENUM_SERVICE_STATUS lpDependencies;
-    SC_HANDLE hDepService;
-    DWORD dwCount;
+    LPWSTR lpStr;
     BOOL bRet = FALSE;
 
-    lpDependencies = GetServiceDependents(hService, &dwCount);
-    if (lpDependencies)
-    {
-        LPENUM_SERVICE_STATUS lpEnumServiceStatus;
-        DWORD i;
+    lpStr = lpServiceList;
 
-        for (i = 0; i < dwCount; i++)
+    /* Loop through all the services in the list */
+    while (TRUE)
+    {
+        /* Break when we hit the double null */
+        if (*lpStr == L'\0' && *(lpStr + 1) == L'\0')
+            break;
+
+        /* If this isn't our first time in the loop we'll
+           have been left on a null char */
+        if (*lpStr == L'\0')
+            lpStr++;
+
+        /* Stop the requested service */
+        bRet = StopService(pInfo,
+                           lpStr,
+                           hProgress);
+
+        /* Complete the progress bar if we succeeded */
+        if (bRet)
         {
-            lpEnumServiceStatus = &lpDependencies[i];
-
-            hDepService = OpenService(pStopInfo->hSCManager,
-                                      lpEnumServiceStatus->lpServiceName,
-                                      SERVICE_STOP | SERVICE_QUERY_STATUS);
-            if (hDepService)
-            {
-                bRet = StopService(pStopInfo, hDepService);
-
-                CloseServiceHandle(hDepService);
-
-                if (!bRet)
-                {
-                    GetError();
-                    break;
-                }
-            }
+            CompleteProgressBar(hProgress);
         }
 
-        HeapFree(GetProcessHeap(),
-                 0,
-                 lpDependencies);
+        /* Move onto the next string */
+        while (*lpStr != L'\0')
+            lpStr++;
     }
 
     return bRet;
@@ -115,52 +150,76 @@ StopDependentServices(PSTOP_INFO pStopInfo,
 BOOL
 DoStop(PMAIN_WND_INFO pInfo)
 {
-    STOP_INFO stopInfo;
-    SC_HANDLE hSCManager;
-    SC_HANDLE hService;
+    HWND hProgress;
+    LPWSTR lpServiceList;
     BOOL bRet = FALSE;
+    BOOL bStopMainService = TRUE;
 
     if (pInfo)
     {
-        stopInfo.pInfo = pInfo;
-
-        hSCManager = OpenSCManager(NULL,
-                                   NULL,
-                                   SC_MANAGER_ALL_ACCESS);
-        if (hSCManager)
+        /* Does the service have any dependent services which need stopping first */
+        lpServiceList = GetListOfServicesToStop(pInfo->pCurrentService->lpServiceName);
+        if (lpServiceList)
         {
-            hService = OpenService(hSCManager,
-                                   pInfo->pCurrentService->lpServiceName,
-                                   SERVICE_STOP | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS);
-            if (hService)
+            /* Tag the service list to the main wnd info */
+            pInfo->pTag = (PVOID)lpServiceList;
+
+            /* List them and ask the user if they want to stop them */
+            if (DialogBoxParamW(hInstance,
+                                     MAKEINTRESOURCEW(IDD_DLG_DEPEND_STOP),
+                                     pInfo->hMainWnd,
+                                     StopDependsDialogProc,
+                                     (LPARAM)pInfo) == IDOK)
             {
-                stopInfo.hSCManager = hSCManager;
-                stopInfo.hMainService = hService;
+                /* Create a progress window to track the progress of the stopping services */
+                hProgress = CreateProgressDialog(pInfo->hMainWnd,
+                                                 IDS_PROGRESS_INFO_STOP);
 
-                if (HasDependentServices(hService))
-                {
-                    INT ret = DialogBoxParam(hInstance,
-                                             MAKEINTRESOURCE(IDD_DLG_DEPEND_STOP),
-                                             pInfo->hMainWnd,
-                                             StopDependsDialogProc,
-                                             (LPARAM)&stopInfo);
-                    if (ret == IDOK)
-                    {
-                        if (StopDependentServices(&stopInfo, hService))
-                        {
-                            bRet = StopService(&stopInfo, hService);
-                        }
-                    }
-                }
-                else
+                /* Stop all the dependant services */
+                StopDependantServices(pInfo, lpServiceList, hProgress);
+
+                /* Now stop the requested one */
+                bRet = StopService(pInfo,
+                                   pInfo->pCurrentService->lpServiceName,
+                                   hProgress);
+
+                /* We've already stopped the main service, don't try to stop it again */
+                bStopMainService = FALSE;
+
+                if (hProgress)
                 {
-                    bRet = StopService(&stopInfo, hService);
+                    /* Complete and destroy the progress bar */
+                    DestroyProgressDialog(hProgress, TRUE);
                 }
-
-                CloseServiceHandle(hService);
+            }
+            else
+            {
+                /* Don't stop the main service if the user selected not to */
+                bStopMainService = FALSE;
             }
 
-            CloseServiceHandle(hSCManager);
+            HeapFree(GetProcessHeap(),
+                     0,
+                     lpServiceList);
+        }
+
+        /* If the service has no running dependents, then we stop it here */
+        if (bStopMainService)
+        {
+            /* Create a progress window to track the progress of the stopping service */
+            hProgress = CreateProgressDialog(pInfo->hMainWnd,
+                                             IDS_PROGRESS_INFO_STOP);
+
+            /* Stop the requested service */
+            bRet = StopService(pInfo,
+                               pInfo->pCurrentService->lpServiceName,
+                               hProgress);
+
+            if (hProgress)
+            {
+                /* Complete and destroy the progress bar */
+                DestroyProgressDialog(hProgress, TRUE);
+            }
         }
     }