[ros-diffs] [ekohl] 35767: - Add a reference counter to the service record. - Implement a common service record delete function. - RCloseServiceHandle: Remove a service if it has been marked for deletion and the reference counter reaches 0. - RControlService: Stop a service only if there are no dependent services running. Patch based on bug report #3669 by Michael Martin (aka bugboy) <martinmnet at hotmail.com> just like the patches r35748, r35750, r35752 and r35753.

ekohl at svn.reactos.org ekohl at svn.reactos.org
Fri Aug 29 22:43:12 CEST 2008


Author: ekohl
Date: Fri Aug 29 15:43:12 2008
New Revision: 35767

URL: http://svn.reactos.org/svn/reactos?rev=35767&view=rev
Log:
- Add a reference counter to the service record.
- Implement a common service record delete function.
- RCloseServiceHandle: Remove a service if it has been marked for deletion and the reference counter reaches 0.
- RControlService: Stop a service only if there are no dependent services running.
 
 
Patch based on bug report #3669 by Michael Martin (aka bugboy) <martinmnet at hotmail.com> just like the patches r35748, r35750, r35752 and r35753.


Modified:
    trunk/reactos/base/system/services/rpcserver.c
    trunk/reactos/base/system/services/services.h

Modified: trunk/reactos/base/system/services/rpcserver.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/services/rpcserver.c?rev=35767&r1=35766&r2=35767&view=diff
==============================================================================
--- trunk/reactos/base/system/services/rpcserver.c [iso-8859-1] (original)
+++ trunk/reactos/base/system/services/rpcserver.c [iso-8859-1] Fri Aug 29 15:43:12 2008
@@ -404,6 +404,12 @@
     LPSC_RPC_HANDLE hSCObject)
 {
     PMANAGER_HANDLE hManager;
+    PSERVICE_HANDLE hService;
+    PSERVICE lpService;
+    HKEY hServicesKey;
+    DWORD dwError;
+    DWORD pcbBytesNeeded = 0;
+    DWORD dwServicesReturned = 0;
 
     DPRINT("RCloseServiceHandle() called\n");
 
@@ -413,6 +419,7 @@
         return ERROR_INVALID_HANDLE;
 
     hManager = (PMANAGER_HANDLE)*hSCObject;
+    hService = (PSERVICE_HANDLE)*hSCObject;
     if (hManager->Handle.Tag == MANAGER_TAG)
     {
         DPRINT("Found manager handle\n");
@@ -420,24 +427,92 @@
         hManager->Handle.RefCount--;
         if (hManager->Handle.RefCount == 0)
         {
-            /* FIXME: add cleanup code */
+            /* FIXME: add handle cleanup code */
 
             HeapFree(GetProcessHeap(), 0, hManager);
+            hManager = NULL;
         }
 
         DPRINT("RCloseServiceHandle() done\n");
         return ERROR_SUCCESS;
     }
-    else if (hManager->Handle.Tag == SERVICE_TAG)
+    else if (hService->Handle.Tag == SERVICE_TAG)
     {
         DPRINT("Found service handle\n");
 
-        hManager->Handle.RefCount--;
-        if (hManager->Handle.RefCount == 0)
-        {
-            /* FIXME: add cleanup code */
-
-            HeapFree(GetProcessHeap(), 0, hManager);
+        /* Get the pointer to the service record */
+        lpService = hService->ServiceEntry;
+
+        ASSERT(hService->Handle.RefCount > 0);
+
+        hService->Handle.RefCount--;
+        if (hService->Handle.RefCount == 0)
+        {
+            /* FIXME: add handle cleanup code */
+
+            /* Free the handle */
+            HeapFree(GetProcessHeap(), 0, hService);
+            hService = NULL;
+        }
+
+        ASSERT(lpService->dwRefCount > 0);
+
+        lpService->dwRefCount--;
+        DPRINT1("CloseServiceHandle - lpService->dwRefCount %u\n",
+                lpService->dwRefCount);
+
+        if (lpService->dwRefCount == 0)
+        {
+            /* If this service has been marked for deletion */
+            if (lpService->bDeleted)
+            {
+                /* Open the Services Reg key */
+                dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                                        L"System\\CurrentControlSet\\Services",
+                                        0,
+                                        KEY_SET_VALUE | KEY_READ,
+                                        &hServicesKey);
+                if (dwError != ERROR_SUCCESS)
+                {
+                    DPRINT1("Failed to open services key\n");
+                    return dwError;
+                }
+
+                /* Call the internal function with NULL, just to get bytes we need */
+                Int_EnumDependentServicesW(hServicesKey,
+                                           lpService,
+                                           SERVICE_ACTIVE,
+                                           NULL,
+                                           &pcbBytesNeeded,
+                                           &dwServicesReturned);
+
+                /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service*/
+                if (pcbBytesNeeded)
+                {
+                    DPRINT1("Deletion failed due to running dependencies.\n",
+                            lpService->lpServiceName);
+                    RegCloseKey(hServicesKey);
+                    return ERROR_SUCCESS;
+                }
+
+                /* There are no references and no runnning dependencies,
+                   it is now safe to delete the service */
+
+                /* Delete the Service Key */
+                dwError = RegDeleteKey(hServicesKey,
+                                       lpService->lpServiceName);
+
+                RegCloseKey(hServicesKey);
+
+                if (dwError != ERROR_SUCCESS)
+                {
+                    DPRINT1("Failed to Delete the Service Registry key\n");
+                    return dwError;
+                }
+
+                /* Delete the Service */
+                ScmDeleteServiceRecord(lpService);
+            }
         }
 
         DPRINT("RCloseServiceHandle() done\n");
@@ -461,6 +536,9 @@
     PSERVICE lpService;
     ACCESS_MASK DesiredAccess;
     DWORD dwError = ERROR_SUCCESS;
+    DWORD pcbBytesNeeded = 0;
+    DWORD dwServicesReturned = 0;
+    HKEY hServicesKey = NULL;
 
     DPRINT("RControlService() called\n");
 
@@ -472,6 +550,14 @@
     if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
     {
         DPRINT1("Invalid handle tag!\n");
+        return ERROR_INVALID_HANDLE;
+    }
+
+    /* Check the service entry point */
+    lpService = hSvc->ServiceEntry;
+    if (lpService == NULL)
+    {
+        DPRINT1("lpService == NULL!\n"); 
         return ERROR_INVALID_HANDLE;
     }
 
@@ -507,12 +593,40 @@
                                   DesiredAccess))
         return ERROR_ACCESS_DENIED;
 
-    /* Check the service entry point */
-    lpService = hSvc->ServiceEntry;
-    if (lpService == NULL)
-    {
-        DPRINT1("lpService == NULL!\n");
-        return ERROR_INVALID_HANDLE;
+    if (dwControl == SERVICE_CONTROL_STOP)
+    {
+        /* Check if the service has dependencies running as windows
+           doesn't stop a service that does */
+
+        /* Open the Services Reg key */
+        dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                                L"System\\CurrentControlSet\\Services",
+                                0,
+                                KEY_READ,
+                                &hServicesKey);
+        if (dwError != ERROR_SUCCESS)
+        {
+            DPRINT1("Failed to open services key\n");
+            return dwError;
+        }
+
+        /* Call the internal function with NULL, just to get bytes we need */
+        Int_EnumDependentServicesW(hServicesKey,
+                                   lpService,
+                                   SERVICE_ACTIVE,
+                                   NULL,
+                                   &pcbBytesNeeded,
+                                   &dwServicesReturned);
+
+        RegCloseKey(hServicesKey);
+
+        /* If pcbBytesNeeded is not zero then there are services running that
+           are dependent on this service */
+        if (pcbBytesNeeded != 0)
+        {
+            DPRINT("Service has running dependencies. Failed to stop service.\n");
+            return ERROR_DEPENDENT_SERVICES_RUNNING;
+        }
     }
 
     if (lpService->Status.dwServiceType & SERVICE_DRIVER)
@@ -529,6 +643,9 @@
                                     dwControl,
                                     lpServiceStatus);
     }
+
+    if ((dwError == ERROR_SUCCESS) && (pcbBytesNeeded))
+        dwError = ERROR_DEPENDENT_SERVICES_RUNNING;
 
     /* Return service status information */
     RtlCopyMemory(lpServiceStatus,
@@ -1120,7 +1237,7 @@
                                  (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
         if (dwError != ERROR_SUCCESS)
             goto done;
-        /* FIXME: update lpService->lpServiceGroup */
+        /* FIXME: Update lpService->lpServiceGroup */
     }
 
     if (lpdwTagId != NULL)
@@ -1836,6 +1953,9 @@
     if (dwError != ERROR_SUCCESS)
         goto done;
 
+    lpService->dwRefCount = 1;
+    DPRINT1("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
+
 done:;
     if (hServiceKey != NULL)
         RegCloseKey(hServiceKey);
@@ -2308,6 +2428,9 @@
         HeapFree(GetProcessHeap(), 0, hHandle);
         return dwError;
     }
+
+    lpService->dwRefCount++;
+    DPRINT1("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
 
     *lpServiceHandle = (unsigned long)hHandle; /* FIXME: 64 bit portability */
     DPRINT("*hService = %p\n", *lpServiceHandle);

Modified: trunk/reactos/base/system/services/services.h
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/base/system/services/services.h?rev=35767&r1=35766&r2=35767&view=diff
==============================================================================
--- trunk/reactos/base/system/services/services.h [iso-8859-1] (original)
+++ trunk/reactos/base/system/services/services.h [iso-8859-1] Fri Aug 29 15:43:12 2008
@@ -40,6 +40,7 @@
     PSERVICE_IMAGE lpImage;
     BOOL bDeleted;
     DWORD dwResumeCount;
+    DWORD dwRefCount;
 
     CLIENT_HANDLE hClient;
     SERVICE_STATUS Status;
@@ -109,6 +110,7 @@
 PSERVICE ScmGetServiceEntryByClientHandle(ULONG ThreadId);
 DWORD ScmCreateNewServiceRecord(LPWSTR lpServiceName,
                                 PSERVICE *lpServiceRecord);
+VOID ScmDeleteServiceRecord(PSERVICE lpService);
 DWORD ScmMarkServiceForDelete(PSERVICE pService);
 
 DWORD ScmControlService(PSERVICE Service,



More information about the Ros-diffs mailing list