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(a)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/rpcse…
==============================================================================
--- 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/servi…
==============================================================================
--- 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,