- Implement RCreateServiceA.
[reactos.git] / reactos / base / system / services / rpcserver.c
index fb6a446..a5b7f9f 100644 (file)
@@ -6,7 +6,6 @@
  * COPYRIGHT:   Copyright 2005-2006 Eric Kohl
  *              Copyright 2006-2007 HervĂ© Poussineau <hpoussin@reactos.org>
  *              Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
- *
  */
 
 /* INCLUDES ****************************************************************/
@@ -152,9 +151,20 @@ ScmCreateManagerHandle(LPWSTR lpDatabaseName,
     if (lpDatabaseName == NULL)
         lpDatabaseName = SERVICES_ACTIVE_DATABASEW;
 
+    if (_wcsicmp(lpDatabaseName,SERVICES_FAILED_DATABASEW)==0)
+    {
+        DPRINT1("Database %S, does not exist\n",lpDatabaseName);
+        return ERROR_DATABASE_DOES_NOT_EXIST;
+    }
+    else if (_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
+    {
+        DPRINT1("Invalid Database name %S.\n",lpDatabaseName);
+        return ERROR_INVALID_NAME;
+    }
+
     Ptr = (MANAGER_HANDLE*) HeapAlloc(GetProcessHeap(),
                     HEAP_ZERO_MEMORY,
-                    sizeof(MANAGER_HANDLE) + wcslen(lpDatabaseName) * sizeof(WCHAR));
+                    sizeof(MANAGER_HANDLE) + (wcslen(lpDatabaseName) + 1) * sizeof(WCHAR));
     if (Ptr == NULL)
         return ERROR_NOT_ENOUGH_MEMORY;
 
@@ -235,14 +245,172 @@ ScmAssignNewTag(PSERVICE lpService)
 }
 
 
+/* Internal recursive function */
+/* Need to search for every dependency on every service */
+static DWORD
+Int_EnumDependentServicesW(HKEY hServicesKey,
+                           PSERVICE lpService,
+                           DWORD dwServiceState,
+                           PSERVICE *lpServices,
+                           LPDWORD pcbBytesNeeded,
+                           LPDWORD lpServicesReturned)
+{
+    DWORD dwError = ERROR_SUCCESS;
+    WCHAR szNameBuf[MAX_PATH];
+    WCHAR szValueBuf[MAX_PATH];
+    WCHAR *lpszNameBuf = szNameBuf;
+    WCHAR *lpszValueBuf = szValueBuf;
+    DWORD dwSize;
+    DWORD dwNumSubKeys;
+    DWORD dwIteration;
+    PSERVICE lpCurrentService;
+    HKEY hServiceEnumKey;
+    DWORD dwCurrentServiceState = SERVICE_ACTIVE;
+    DWORD dwDependServiceStrPtr = 0;
+    DWORD dwRequiredSize = 0;
+
+    /* Get the number of service keys */
+    dwError = RegQueryInfoKeyW(hServicesKey,
+                               NULL,
+                               NULL,
+                               NULL,
+                               &dwNumSubKeys,
+                               NULL,
+                               NULL,
+                               NULL,
+                               NULL,
+                               NULL,
+                               NULL,
+                               NULL);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ERROR! Unable to get number of services keys.\n");
+        return dwError;
+    }
+
+    /* Iterate the service keys to see if another service depends on the this service */
+    for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
+    {
+        dwSize = MAX_PATH;
+        dwError = RegEnumKeyExW(hServicesKey,
+                                dwIteration,
+                                lpszNameBuf,
+                                &dwSize,
+                                NULL,
+                                NULL,
+                                NULL,
+                                NULL);
+        if (dwError != ERROR_SUCCESS)
+            return dwError;
+
+        /* Open the Service key */
+        dwError = RegOpenKeyExW(hServicesKey,
+                                lpszNameBuf,
+                                0,
+                                KEY_READ,
+                                &hServiceEnumKey);
+        if (dwError != ERROR_SUCCESS)
+            return dwError;
+
+        dwSize = MAX_PATH;
+
+        /* Check for the DependOnService Value */
+        dwError = RegQueryValueExW(hServiceEnumKey,
+                                   L"DependOnService",
+                                   NULL,
+                                   NULL,
+                                   (LPBYTE)lpszValueBuf,
+                                   &dwSize);
+
+        /* FIXME: Handle load order. */
+
+        /* If the service found has a DependOnService value */
+        if (dwError == ERROR_SUCCESS)
+        {
+            dwDependServiceStrPtr = 0;
+
+            /* Can be more than one Dependencies in the DependOnService string */
+            while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
+            {
+                if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
+                {
+                    /* Get the current enumed service pointer */
+                    lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
+
+                    /* Check for valid Service */
+                    if (!lpCurrentService)
+                    {
+                        /* This should never happen! */
+                        DPRINT1("This should not happen at this point, report to Developer\n");
+                        return ERROR_NOT_FOUND;
+                    }
+
+                    /* Determine state the service is in */
+                    if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
+                        dwCurrentServiceState = SERVICE_INACTIVE;
+
+                    /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
+                    if ((dwCurrentServiceState == dwServiceState) ||
+                        (dwServiceState == SERVICE_STATE_ALL))
+                    {
+                        /* Calculate the required size */
+                        dwRequiredSize += sizeof(SERVICE_STATUS);
+                        dwRequiredSize += ((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
+                        dwRequiredSize += ((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
+
+                        /* Add the size for service name and display name pointers */
+                        dwRequiredSize += (2 * sizeof(PVOID));
+
+                        /* increase the BytesNeeded size */
+                        *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
+
+                        /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
+                           comes first */
+
+                        /* Recursive call to check for its dependencies */
+                        Int_EnumDependentServicesW(hServicesKey,
+                                                   lpCurrentService,
+                                                   dwServiceState,
+                                                   lpServices,
+                                                   pcbBytesNeeded,
+                                                   lpServicesReturned);
+
+                        /* If the lpServices is valid set the service pointer */
+                        if (lpServices)
+                            lpServices[*lpServicesReturned] = lpCurrentService;
+
+                        *lpServicesReturned = *lpServicesReturned + 1;
+                    }
+                }
+
+                dwDependServiceStrPtr += (wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
+            }
+        }
+        else if (*pcbBytesNeeded)
+        {
+            dwError = ERROR_SUCCESS;
+        }
+
+        RegCloseKey(hServiceEnumKey);
+    }
+
+    return dwError;
+}
+
+
 /* Function 0 */
-DWORD ScmrCloseServiceHandle(
-    handle_t BindingHandle,
+DWORD RCloseServiceHandle(
     LPSC_RPC_HANDLE hSCObject)
 {
     PMANAGER_HANDLE hManager;
+    PSERVICE_HANDLE hService;
+    PSERVICE lpService;
+    HKEY hServicesKey;
+    DWORD dwError;
+    DWORD pcbBytesNeeded = 0;
+    DWORD dwServicesReturned = 0;
 
-    DPRINT("ScmrCloseServiceHandle() called\n");
+    DPRINT("RCloseServiceHandle() called\n");
 
     DPRINT("hSCObject = %p\n", *hSCObject);
 
@@ -250,6 +418,7 @@ DWORD ScmrCloseServiceHandle(
         return ERROR_INVALID_HANDLE;
 
     hManager = (PMANAGER_HANDLE)*hSCObject;
+    hService = (PSERVICE_HANDLE)*hSCObject;
     if (hManager->Handle.Tag == MANAGER_TAG)
     {
         DPRINT("Found manager handle\n");
@@ -257,27 +426,94 @@ DWORD ScmrCloseServiceHandle(
         hManager->Handle.RefCount--;
         if (hManager->Handle.RefCount == 0)
         {
-            /* FIXME: add cleanup code */
+            /* FIXME: add handle cleanup code */
 
             HeapFree(GetProcessHeap(), 0, hManager);
+            hManager = NULL;
         }
 
-        DPRINT("ScmrCloseServiceHandle() done\n");
+        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)
+        /* 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 cleanup code */
+            /* FIXME: add handle cleanup code */
 
-            HeapFree(GetProcessHeap(), 0, hManager);
+            /* Free the handle */
+            HeapFree(GetProcessHeap(), 0, hService);
+            hService = NULL;
+        }
+
+        ASSERT(lpService->dwRefCount > 0);
+
+        lpService->dwRefCount--;
+        DPRINT("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");
+                    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 = RegDeleteKeyW(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("ScmrCloseServiceHandle() done\n");
+        DPRINT("RCloseServiceHandle() done\n");
         return ERROR_SUCCESS;
     }
 
@@ -288,8 +524,7 @@ DWORD ScmrCloseServiceHandle(
 
 
 /* Function 1 */
-DWORD ScmrControlService(
-    handle_t BindingHandle,
+DWORD RControlService(
     SC_RPC_HANDLE hService,
     DWORD dwControl,
     LPSERVICE_STATUS lpServiceStatus)
@@ -298,8 +533,11 @@ DWORD ScmrControlService(
     PSERVICE lpService;
     ACCESS_MASK DesiredAccess;
     DWORD dwError = ERROR_SUCCESS;
+    DWORD pcbBytesNeeded = 0;
+    DWORD dwServicesReturned = 0;
+    HKEY hServicesKey = NULL;
 
-    DPRINT("ScmrControlService() called\n");
+    DPRINT("RControlService() called\n");
 
     if (ScmShutdown)
         return ERROR_SHUTDOWN_IN_PROGRESS;
@@ -312,6 +550,14 @@ DWORD ScmrControlService(
         return ERROR_INVALID_HANDLE;
     }
 
+    /* Check the service entry point */
+    lpService = hSvc->ServiceEntry;
+    if (lpService == NULL)
+    {
+        DPRINT1("lpService == NULL!\n"); 
+        return ERROR_INVALID_HANDLE;
+    }
+
     /* Check access rights */
     switch (dwControl)
     {
@@ -344,12 +590,40 @@ DWORD ScmrControlService(
                                   DesiredAccess))
         return ERROR_ACCESS_DENIED;
 
-    /* Check the service entry point */
-    lpService = hSvc->ServiceEntry;
-    if (lpService == NULL)
+    if (dwControl == SERVICE_CONTROL_STOP)
     {
-        DPRINT1("lpService == NULL!\n");
-        return ERROR_INVALID_HANDLE;
+        /* 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)
@@ -367,6 +641,9 @@ DWORD ScmrControlService(
                                     lpServiceStatus);
     }
 
+    if ((dwError == ERROR_SUCCESS) && (pcbBytesNeeded))
+        dwError = ERROR_DEPENDENT_SERVICES_RUNNING;
+
     /* Return service status information */
     RtlCopyMemory(lpServiceStatus,
                   &lpService->Status,
@@ -377,15 +654,14 @@ DWORD ScmrControlService(
 
 
 /* Function 2 */
-DWORD ScmrDeleteService(
-    handle_t BindingHandle,
+DWORD RDeleteService(
     SC_RPC_HANDLE hService)
 {
     PSERVICE_HANDLE hSvc;
     PSERVICE lpService;
     DWORD dwError;
 
-    DPRINT("ScmrDeleteService() called\n");
+    DPRINT("RDeleteService() called\n");
 
     if (ScmShutdown)
         return ERROR_SHUTDOWN_IN_PROGRESS;
@@ -395,7 +671,7 @@ DWORD ScmrDeleteService(
         return ERROR_INVALID_HANDLE;
 
     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
-                                  STANDARD_RIGHTS_REQUIRED))
+                                  DELETE))
         return ERROR_ACCESS_DENIED;
 
     lpService = hSvc->ServiceEntry;
@@ -420,21 +696,20 @@ DWORD ScmrDeleteService(
 
     /* FIXME: Release service database lock */
 
-    DPRINT("ScmrDeleteService() done\n");
+    DPRINT("RDeleteService() done\n");
 
     return dwError;
 }
 
 
 /* Function 3 */
-DWORD ScmrLockServiceDatabase(
-    handle_t BindingHandle,
+DWORD RLockServiceDatabase(
     SC_RPC_HANDLE hSCManager,
     LPSC_RPC_LOCK lpLock)
 {
     PMANAGER_HANDLE hMgr;
 
-    DPRINT("ScmrLockServiceDatabase() called\n");
+    DPRINT("RLockServiceDatabase() called\n");
 
     *lpLock = 0;
 
@@ -449,22 +724,20 @@ DWORD ScmrLockServiceDatabase(
 //    return ScmLockDatabase(0, hMgr->0xC, hLock);
 
     /* FIXME: Lock the database */
-    *lpLock = (void *)0x12345678; /* Dummy! */
+    *lpLock = (SC_RPC_LOCK)0x12345678; /* Dummy! */
 
     return ERROR_SUCCESS;
 }
 
 
 /* Function 4 */
-DWORD ScmrQueryServiceObjectSecurity(
-    handle_t BindingHandle,
+DWORD RQueryServiceObjectSecurity(
     SC_RPC_HANDLE hService,
     SECURITY_INFORMATION dwSecurityInformation,
     LPBYTE lpSecurityDescriptor,
     DWORD cbBufSize,
     LPBOUNDED_DWORD_256K pcbBytesNeeded)
 {
-#if 0
     PSERVICE_HANDLE hSvc;
     PSERVICE lpService;
     ULONG DesiredAccess = 0;
@@ -472,7 +745,10 @@ DWORD ScmrQueryServiceObjectSecurity(
     DWORD dwBytesNeeded;
     DWORD dwError;
 
-    DPRINT("ScmrQueryServiceObjectSecurity() called\n");
+
+    SECURITY_DESCRIPTOR ObjectDescriptor;
+
+    DPRINT("RQueryServiceObjectSecurity() called\n");
 
     hSvc = (PSERVICE_HANDLE)hService;
     if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
@@ -505,10 +781,13 @@ DWORD ScmrQueryServiceObjectSecurity(
 
     /* FIXME: Lock the service list */
 
-    Status = RtlQuerySecurityObject(lpService->lpSecurityDescriptor,
+    /* hack */
+    Status = RtlCreateSecurityDescriptor(&ObjectDescriptor, SECURITY_DESCRIPTOR_REVISION);
+
+    Status = RtlQuerySecurityObject(&ObjectDescriptor  /* lpService->lpSecurityDescriptor */,
                                     dwSecurityInformation,
                                     (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
-                                    dwSecuityDescriptorSize,
+                                    cbBufSize,
                                     &dwBytesNeeded);
 
     /* FIXME: Unlock the service list */
@@ -533,15 +812,11 @@ DWORD ScmrQueryServiceObjectSecurity(
     }
 
     return dwError;
-#endif
-    UNIMPLEMENTED;
-    return ERROR_CALL_NOT_IMPLEMENTED;
 }
 
 
 /* Function 5 */
-DWORD ScmrSetServiceObjectSecurity(
-    handle_t BindingHandle,
+DWORD RSetServiceObjectSecurity(
     SC_RPC_HANDLE hService,
     DWORD dwSecurityInformation,
     LPBYTE lpSecurityDescriptor,
@@ -550,12 +825,12 @@ DWORD ScmrSetServiceObjectSecurity(
     PSERVICE_HANDLE hSvc;
     PSERVICE lpService;
     ULONG DesiredAccess = 0;
-    HANDLE hToken = NULL;
+    /* HANDLE hToken = NULL; */
     HKEY hServiceKey;
-    NTSTATUS Status;
+    /* NTSTATUS Status; */
     DWORD dwError;
 
-    DPRINT1("ScmrSetServiceObjectSecurity() called\n");
+    DPRINT1("RSetServiceObjectSecurity() called\n");
 
     hSvc = (PSERVICE_HANDLE)hService;
     if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
@@ -582,11 +857,11 @@ DWORD ScmrSetServiceObjectSecurity(
         DesiredAccess |= WRITE_OWNER;
 
     if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
-        (((PSECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
+        (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
         return ERROR_INVALID_PARAMETER;
 
     if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
-        (((PSECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
+        (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
         return ERROR_INVALID_PARAMETER;
 
     if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
@@ -606,6 +881,7 @@ DWORD ScmrSetServiceObjectSecurity(
     if (lpService->bDeleted)
         return ERROR_SERVICE_MARKED_FOR_DELETE;
 
+#if 0
     RpcImpersonateClient(NULL);
 
     Status = NtOpenThreadToken(NtCurrentThread(),
@@ -613,13 +889,12 @@ DWORD ScmrSetServiceObjectSecurity(
                                TRUE,
                                &hToken);
     if (!NT_SUCCESS(Status))
-        return RtlNtStatusToDosError(Status);
+        return RtlNtStatusToDosError(Status); 
 
     RpcRevertToSelf();
 
     /* FIXME: Lock service database */
 
-#if 0
     Status = RtlSetSecurityObject(dwSecurityInformation,
                                   (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
                                   &lpService->lpSecurityDescriptor,
@@ -648,27 +923,28 @@ DWORD ScmrSetServiceObjectSecurity(
 
 Done:
 
+#if 0
     if (hToken != NULL)
         NtClose(hToken);
+#endif
 
     /* FIXME: Unlock service database */
 
-    DPRINT("ScmrSetServiceObjectSecurity() done (Error %lu)\n", dwError);
+    DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
 
     return dwError;
 }
 
 
 /* Function 6 */
-DWORD ScmrQueryServiceStatus(
-    handle_t BindingHandle,
+DWORD RQueryServiceStatus(
     SC_RPC_HANDLE hService,
     LPSERVICE_STATUS lpServiceStatus)
 {
     PSERVICE_HANDLE hSvc;
     PSERVICE lpService;
 
-    DPRINT("ScmrQueryServiceStatus() called\n");
+    DPRINT("RQueryServiceStatus() called\n");
 
     if (ScmShutdown)
         return ERROR_SHUTDOWN_IN_PROGRESS;
@@ -703,40 +979,92 @@ DWORD ScmrQueryServiceStatus(
 }
 
 
+static BOOL
+ScmIsValidServiceState(DWORD dwCurrentState)
+{
+    switch (dwCurrentState)
+    {
+        case SERVICE_STOPPED:
+        case SERVICE_START_PENDING:
+        case SERVICE_STOP_PENDING:
+        case SERVICE_RUNNING:
+        case SERVICE_CONTINUE_PENDING:
+        case SERVICE_PAUSE_PENDING:
+        case SERVICE_PAUSED:
+            return TRUE;
+
+        default:
+            return FALSE;
+    }
+}
+
+
 /* Function 7 */
-DWORD ScmrSetServiceStatus(
-    handle_t BindingHandle,
-    SC_RPC_HANDLE hServiceStatus,
+DWORD RSetServiceStatus(
+    RPC_SERVICE_STATUS_HANDLE hServiceStatus,
     LPSERVICE_STATUS lpServiceStatus)
 {
     PSERVICE lpService;
 
-    DPRINT("ScmrSetServiceStatus() called\n");
-
-    if (ScmShutdown)
-        return ERROR_SHUTDOWN_IN_PROGRESS;
+    DPRINT("RSetServiceStatus() called\n");
+    DPRINT("hServiceStatus = %p\n", hServiceStatus);
+    DPRINT("dwServiceType = %lu\n", lpServiceStatus->dwServiceType);
+    DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
+    DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
+    DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
+    DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
+    DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
+    DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
+
+    if (hServiceStatus == 0)
+    {
+        DPRINT1("hServiceStatus == NULL!\n");
+        return ERROR_INVALID_HANDLE;
+    }
 
-    lpService = ScmGetServiceEntryByClientHandle((ULONG)hServiceStatus);
+    lpService = ScmGetServiceEntryByClientHandle((HANDLE)hServiceStatus);
     if (lpService == NULL)
     {
         DPRINT1("lpService == NULL!\n");
         return ERROR_INVALID_HANDLE;
     }
 
+    /* Check current state */
+    if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
+    {
+        DPRINT1("Invalid service state!\n");
+        return ERROR_INVALID_DATA;
+    }
+
+    /* Check service type */
+    if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
+         (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
+    {
+        DPRINT1("Invalid service type!\n");
+        return ERROR_INVALID_DATA;
+    }
+
+    /* Check accepted controls */
+    if (lpServiceStatus->dwControlsAccepted & ~0xFF)
+    {
+        DPRINT1("Invalid controls accepted!\n");
+        return ERROR_INVALID_DATA;
+    }
+
+
     RtlCopyMemory(&lpService->Status,
                   lpServiceStatus,
                   sizeof(SERVICE_STATUS));
 
     DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
-    DPRINT("ScmrSetServiceStatus() done\n");
+    DPRINT("RSetServiceStatus() done\n");
 
     return ERROR_SUCCESS;
 }
 
 
 /* Function 8 */
-DWORD ScmrUnlockServiceDatabase(
-    handle_t BindingHandle,
+DWORD RUnlockServiceDatabase(
     LPSC_RPC_LOCK Lock)
 {
     UNIMPLEMENTED;
@@ -745,8 +1073,7 @@ DWORD ScmrUnlockServiceDatabase(
 
 
 /* Function 9 */
-DWORD ScmrNotifyBootConfigStatus(
-    handle_t BindingHandle,
+DWORD RNotifyBootConfigStatus(
     SVCCTL_HANDLEW lpMachineName,
     DWORD BootAcceptable)
 {
@@ -756,9 +1083,8 @@ DWORD ScmrNotifyBootConfigStatus(
 
 
 /* Function 10 */
-DWORD ScmrSetServiceBitsW(
-    handle_t BindingHandle,
-    SC_RPC_HANDLE hServiceStatus,
+DWORD RI_ScSetServiceBitsW(
+    RPC_SERVICE_STATUS_HANDLE hServiceStatus,
     DWORD dwServiceBits,
     int bSetBitsOn,
     int bUpdateImmediately,
@@ -770,8 +1096,7 @@ DWORD ScmrSetServiceBitsW(
 
 
 /* Function 11 */
-DWORD ScmrChangeServiceConfigW(
-    handle_t BindingHandle,
+DWORD RChangeServiceConfigW(
     SC_RPC_HANDLE hService,
     DWORD dwServiceType,
     DWORD dwStartType,
@@ -790,8 +1115,9 @@ DWORD ScmrChangeServiceConfigW(
     PSERVICE_HANDLE hSvc;
     PSERVICE lpService = NULL;
     HKEY hServiceKey = NULL;
+    LPWSTR lpDisplayNameW = NULL;
 
-    DPRINT("ScmrChangeServiceConfigW() called\n");
+    DPRINT("RChangeServiceConfigW() called\n");
     DPRINT("dwServiceType = %lu\n", dwServiceType);
     DPRINT("dwStartType = %lu\n", dwStartType);
     DPRINT("dwErrorControl = %lu\n", dwErrorControl);
@@ -849,7 +1175,21 @@ DWORD ScmrChangeServiceConfigW(
                        REG_SZ,
                        (LPBYTE)lpDisplayName,
                        (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
-        /* FIXME: update lpService->lpDisplayName */
+
+        /* Update the display name */
+        lpDisplayNameW = (LPWSTR)HeapAlloc(GetProcessHeap(),
+                                           0,
+                                           (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
+        if (lpDisplayNameW == NULL)
+        {
+            dwError = ERROR_NOT_ENOUGH_MEMORY;
+            goto done;
+        }
+
+        if (lpService->lpDisplayName != lpService->lpServiceName)
+            HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
+
+        lpService->lpDisplayName = lpDisplayNameW;
     }
 
     if (dwServiceType != SERVICE_NO_CHANGE)
@@ -942,7 +1282,11 @@ DWORD ScmrChangeServiceConfigW(
                                  (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
         if (dwError != ERROR_SUCCESS)
             goto done;
-        /* FIXME: update lpService->lpServiceGroup */
+
+        dwError = ScmSetServiceGroup(lpService,
+                                     lpLoadOrderGroup);
+        if (dwError != ERROR_SUCCESS)
+            goto done;
     }
 
     if (lpdwTagId != NULL)
@@ -984,11 +1328,12 @@ done:
     if (hServiceKey != NULL)
         RegCloseKey(hServiceKey);
 
-    DPRINT("ScmrChangeServiceConfigW() done (Error %lu)\n", dwError);
+    DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
 
     return dwError;
 }
 
+
 /* Create a path suitable for the bootloader out of the full path */
 DWORD
 ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
@@ -1004,12 +1349,12 @@ ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
     DPRINT("ScmConvertToBootPathName %S\n", CanonName);
 
     ServiceNameLen = wcslen(CanonName);
+
     /* First check, if it's already good */
     if (ServiceNameLen > 12 &&
-        !wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
+        !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
     {
         *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
-
         if (*RelativeName == NULL)
         {
             DPRINT1("Error allocating memory for boot driver name!\n");
@@ -1025,7 +1370,7 @@ ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
 
     /* If it has %SystemRoot% prefix, substitute it to \System*/
     if (ServiceNameLen > 13 &&
-        !wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
+        !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
     {
         /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
         *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR));
@@ -1057,8 +1402,8 @@ ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
     Expanded = LocalAlloc(LMEM_ZEROINIT, BufferSize * sizeof(WCHAR) + sizeof(WCHAR));
     if (!Expanded)
     {
-            DPRINT1("Error allocating memory for boot driver name!\n");
-            return ERROR_NOT_ENOUGH_MEMORY;
+        DPRINT1("Error allocating memory for boot driver name!\n");
+        return ERROR_NOT_ENOUGH_MEMORY;
     }
 
     /* Expand it */
@@ -1095,12 +1440,11 @@ ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
     Expanded[ExpandedLen] = 0;
 
     if (ServiceNameLen > ExpandedLen &&
-        !wcsnicmp(Expanded, CanonName, ExpandedLen))
+        !_wcsnicmp(Expanded, CanonName, ExpandedLen))
     {
         /* Only \SystemRoot\ is missing */
         *RelativeName = LocalAlloc(LMEM_ZEROINIT,
             (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
-
         if (*RelativeName == NULL)
         {
             DPRINT1("Error allocating memory for boot driver name!\n");
@@ -1168,7 +1512,7 @@ ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
 
                 ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
                 if ((ServiceNameLen > ExpandedLen) &&
-                    !wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
+                    !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
                 {
                     *RelativeName = LocalAlloc(LMEM_ZEROINIT,
                        (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
@@ -1235,20 +1579,20 @@ ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
 
 DWORD
 ScmCanonDriverImagePath(DWORD dwStartType,
-                        wchar_t *lpServiceName,
+                        const wchar_t *lpServiceName,
                         wchar_t **lpCanonName)
 {
     DWORD ServiceNameLen, Result;
     UNICODE_STRING NtServiceName;
     WCHAR *RelativeName;
-    WCHAR *SourceName = lpServiceName;
+    const WCHAR *SourceName = lpServiceName;
 
     /* Calculate the length of the service's name */
     ServiceNameLen = wcslen(lpServiceName);
 
     /* 12 is wcslen(L"\\SystemRoot\\") */
     if (ServiceNameLen > 12 &&
-        !wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
+        !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
     {
         /* SystemRoot prefix is already included */
 
@@ -1273,7 +1617,7 @@ ScmCanonDriverImagePath(DWORD dwStartType,
 
     /* Check if it has %SystemRoot% (len=13) */
     if (ServiceNameLen > 13 &&
-        !wcsnicmp(L"%%SystemRoot%%\\", lpServiceName, 13))
+        !_wcsnicmp(L"%%SystemRoot%%\\", lpServiceName, 13))
     {
         /* Substitute %SystemRoot% with \\SystemRoot\\ */
         *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
@@ -1365,21 +1709,20 @@ ScmCanonDriverImagePath(DWORD dwStartType,
 
 
 /* Function 12 */
-DWORD ScmrCreateServiceW(
-    handle_t BindingHandle,
+DWORD RCreateServiceW(
     SC_RPC_HANDLE hSCManager,
-    LPWSTR lpServiceName,
-    LPWSTR lpDisplayName,
+    LPCWSTR lpServiceName,
+    LPCWSTR lpDisplayName,
     DWORD dwDesiredAccess,
     DWORD dwServiceType,
     DWORD dwStartType,
     DWORD dwErrorControl,
-    LPWSTR lpBinaryPathName,
-    LPWSTR lpLoadOrderGroup,
+    LPCWSTR lpBinaryPathName,
+    LPCWSTR lpLoadOrderGroup,
     LPDWORD lpdwTagId,
     LPBYTE lpDependencies,
     DWORD dwDependSize,
-    LPWSTR lpServiceStartName,
+    LPCWSTR lpServiceStartName,
     LPBYTE lpPassword,
     DWORD dwPwSize,
     LPSC_RPC_HANDLE lpServiceHandle)
@@ -1390,8 +1733,9 @@ DWORD ScmrCreateServiceW(
     SC_HANDLE hServiceHandle = NULL;
     LPWSTR lpImagePath = NULL;
     HKEY hServiceKey = NULL;
+    LPWSTR lpObjectName;
 
-    DPRINT("ScmrCreateServiceW() called\n");
+    DPRINT("RCreateServiceW() called\n");
     DPRINT("lpServiceName = %S\n", lpServiceName);
     DPRINT("lpDisplayName = %S\n", lpDisplayName);
     DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
@@ -1420,19 +1764,64 @@ DWORD ScmrCreateServiceW(
         return ERROR_ACCESS_DENIED;
     }
 
-    /* Fail if the service already exists! */
-    if (ScmGetServiceEntryByName(lpServiceName) != NULL)
+    if (wcslen(lpServiceName) == 0)
+    {
+        return ERROR_INVALID_NAME;
+    }
+
+    if (wcslen(lpBinaryPathName) == 0)
+    {
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
+        (lpServiceStartName))
+    {
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    if ((dwServiceType > SERVICE_WIN32_SHARE_PROCESS) &&
+        (dwServiceType != (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
+        (dwServiceType != (SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS)))
+    {
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    if (dwStartType > SERVICE_DISABLED)
+    {
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    lpService = ScmGetServiceEntryByName(lpServiceName);
+    if (lpService)
+    {
+        /* check if it is marked for deletion */
+        if (lpService->bDeleted)
+            return ERROR_SERVICE_MARKED_FOR_DELETE;
+        /* Return Error exist */
         return ERROR_SERVICE_EXISTS;
+    }
+
+    if (lpDisplayName != NULL &&
+        ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
+        return ERROR_DUPLICATE_SERVICE_NAME;
 
     if (dwServiceType & SERVICE_DRIVER)
     {
         dwError = ScmCanonDriverImagePath(dwStartType,
-            lpBinaryPathName,
-            &lpImagePath);
-
+                                          lpBinaryPathName,
+                                          &lpImagePath);
         if (dwError != ERROR_SUCCESS)
             goto done;
     }
+    else
+    {
+        if (dwStartType == SERVICE_BOOT_START ||
+            dwStartType == SERVICE_SYSTEM_START)
+        {
+            return ERROR_INVALID_PARAMETER;
+        }
+    }
 
     /* Allocate a new service entry */
     dwError = ScmCreateNewServiceRecord(lpServiceName,
@@ -1448,7 +1837,7 @@ DWORD ScmrCreateServiceW(
     /* Fill the display name */
     if (lpDisplayName != NULL &&
         *lpDisplayName != 0 &&
-        wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
+        _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
     {
         lpService->lpDisplayName = (WCHAR*) HeapAlloc(GetProcessHeap(), 0,
                                              (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
@@ -1585,6 +1974,20 @@ DWORD ScmrCreateServiceW(
             goto done;
     }
 
+    /* Write service start name */
+    if (dwServiceType & SERVICE_WIN32)
+    {
+        lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
+        dwError = RegSetValueExW(hServiceKey,
+                                 L"ObjectName",
+                                 0,
+                                 REG_SZ,
+                                 (LPBYTE)lpObjectName,
+                                 (wcslen(lpObjectName) + 1) * sizeof(WCHAR));
+        if (dwError != ERROR_SUCCESS)
+            goto done;
+    }
+
     if (lpPassword != NULL)
     {
         /* FIXME: Write password */
@@ -1600,6 +2003,9 @@ DWORD ScmrCreateServiceW(
     if (dwError != ERROR_SUCCESS)
         goto done;
 
+    lpService->dwRefCount = 1;
+    DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
+
 done:;
     if (hServiceKey != NULL)
         RegCloseKey(hServiceKey);
@@ -1607,7 +2013,7 @@ done:;
     if (dwError == ERROR_SUCCESS)
     {
         DPRINT("hService %p\n", hServiceHandle);
-        *lpServiceHandle = (unsigned long)hServiceHandle; /* FIXME: 64 bit portability */
+        *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
 
         if (lpdwTagId != NULL)
             *lpdwTagId = lpService->dwTag;
@@ -1633,15 +2039,14 @@ done:;
     if (lpImagePath != NULL)
         HeapFree(GetProcessHeap(), 0, lpImagePath);
 
-    DPRINT("ScmrCreateServiceW() done (Error %lu)\n", dwError);
+    DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
 
     return dwError;
 }
 
 
 /* Function 13 */
-DWORD ScmrEnumDependentServicesW(
-    handle_t BindingHandle,
+DWORD REnumDependentServicesW(
     SC_RPC_HANDLE hService,
     DWORD dwServiceState,
     LPBYTE lpServices,
@@ -1650,29 +2055,136 @@ DWORD ScmrEnumDependentServicesW(
     LPBOUNDED_DWORD_256K lpServicesReturned)
 {
     DWORD dwError = ERROR_SUCCESS;
+    DWORD dwServicesReturned = 0;
+    DWORD dwServiceCount;
+    HKEY hServicesKey = NULL;
+    LPSC_RPC_HANDLE hSCObject;
+    PSERVICE_HANDLE hSvc;
+    PSERVICE lpService = NULL;
+    PSERVICE *lpServicesArray = NULL;
+    LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
+    LPWSTR lpStr;
 
-    UNIMPLEMENTED;
     *pcbBytesNeeded = 0;
     *lpServicesReturned = 0;
 
-    DPRINT1("ScmrEnumDependentServicesW() done (Error %lu)\n", dwError);
+    DPRINT("REnumDependentServicesW() called\n");
 
-    return dwError;
-}
+    hSCObject = &hService;
+    hSvc = (PSERVICE_HANDLE) *hSCObject;
+    lpService = hSvc->ServiceEntry;
 
+    /* Check access rights */
+    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+                                  SC_MANAGER_ENUMERATE_SERVICE))
+    {
+        DPRINT1("Insufficient access rights! 0x%lx\n",
+                hSvc->Handle.DesiredAccess);
+        return ERROR_ACCESS_DENIED;
+    }
 
-/* Function 14 */
-DWORD ScmrEnumServicesStatusW(
-    handle_t BindingHandle,
-    SC_RPC_HANDLE hSCManager,
-    DWORD dwServiceType,
-    DWORD dwServiceState,
-    LPBYTE lpBuffer,
-    DWORD dwBufSize,
-    LPBOUNDED_DWORD_256K pcbBytesNeeded,
-    LPBOUNDED_DWORD_256K lpServicesReturned,
-    LPBOUNDED_DWORD_256K lpResumeHandle)
-{
+    /* Open the Services Reg key */
+    dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                            L"System\\CurrentControlSet\\Services",
+                            0,
+                            KEY_READ,
+                            &hServicesKey);
+    if (dwError != ERROR_SUCCESS)
+        return dwError;
+
+    /* First determine the bytes needed and get the number of dependent services */
+    dwError = Int_EnumDependentServicesW(hServicesKey,
+                                         lpService,
+                                         dwServiceState,
+                                         NULL,
+                                         pcbBytesNeeded,
+                                         &dwServicesReturned);
+    if (dwError != ERROR_SUCCESS)
+        goto Done;
+
+    /* If buffer size is less than the bytes needed or pointer is null */
+    if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
+    {
+        dwError = ERROR_MORE_DATA;
+        goto Done;
+    }
+
+    /* Allocate memory for array of service pointers */
+    lpServicesArray = HeapAlloc(GetProcessHeap(),
+                                0,
+                                (dwServicesReturned + 1) * sizeof(PSERVICE));
+    if (!lpServicesArray)
+    {
+        DPRINT1("Could not allocate a buffer!!\n");
+        dwError = ERROR_NOT_ENOUGH_MEMORY;
+        goto Done;
+    }
+
+    dwServicesReturned = 0;
+    *pcbBytesNeeded = 0;
+
+    dwError = Int_EnumDependentServicesW(hServicesKey,
+                                         lpService,
+                                         dwServiceState,
+                                         lpServicesArray,
+                                         pcbBytesNeeded,
+                                         &dwServicesReturned);
+    if (dwError != ERROR_SUCCESS)
+    {
+        goto Done;
+    }
+
+    lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices;
+    lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
+
+    /* Copy EnumDepenedentService to Buffer */
+    for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
+    {
+        lpService = lpServicesArray[dwServiceCount];
+
+        /* Copy status info */
+        memcpy(&lpServicesPtr->ServiceStatus,
+               &lpService->Status,
+               sizeof(SERVICE_STATUS));
+
+        /* Copy display name */
+        wcscpy(lpStr, lpService->lpDisplayName);
+        lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
+        lpStr += (wcslen(lpService->lpDisplayName) + 1);
+
+        /* Copy service name */
+        wcscpy(lpStr, lpService->lpServiceName);
+        lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
+        lpStr += (wcslen(lpService->lpServiceName) + 1);
+
+        lpServicesPtr ++;
+    }
+
+    *lpServicesReturned = dwServicesReturned;
+
+Done:
+    if (lpServicesArray != NULL)
+        HeapFree(GetProcessHeap(), 0, lpServicesArray);
+
+    RegCloseKey(hServicesKey);
+
+    DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
+
+    return dwError;
+}
+
+
+/* Function 14 */
+DWORD REnumServicesStatusW(
+    SC_RPC_HANDLE hSCManager,
+    DWORD dwServiceType,
+    DWORD dwServiceState,
+    LPBYTE lpBuffer,
+    DWORD dwBufSize,
+    LPBOUNDED_DWORD_256K pcbBytesNeeded,
+    LPBOUNDED_DWORD_256K lpServicesReturned,
+    LPBOUNDED_DWORD_256K lpResumeHandle)
+{
     PMANAGER_HANDLE hManager;
     PSERVICE lpService;
     DWORD dwError = ERROR_SUCCESS;
@@ -1682,11 +2194,11 @@ DWORD ScmrEnumServicesStatusW(
     DWORD dwRequiredSize;
     DWORD dwServiceCount;
     DWORD dwSize;
-    DWORD dwLastResumeCount;
+    DWORD dwLastResumeCount = 0;
     LPENUM_SERVICE_STATUSW lpStatusPtr;
     LPWSTR lpStringPtr;
 
-    DPRINT("ScmrEnumServicesStatusW() called\n");
+    DPRINT("REnumServicesStatusW() called\n");
 
     if (ScmShutdown)
         return ERROR_SHUTDOWN_IN_PROGRESS;
@@ -1698,6 +2210,21 @@ DWORD ScmrEnumServicesStatusW(
         return ERROR_INVALID_HANDLE;
     }
 
+    *pcbBytesNeeded = 0;
+    *lpServicesReturned = 0;
+
+    if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
+    {
+        DPRINT("Not a valid Service Type!\n");
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
+    {
+        DPRINT("Not a valid Service State!\n");
+        return ERROR_INVALID_PARAMETER;
+    }
+
     /* Check access rights */
     if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
                                   SC_MANAGER_ENUMERATE_SERVICE))
@@ -1707,10 +2234,8 @@ DWORD ScmrEnumServicesStatusW(
         return ERROR_ACCESS_DENIED;
     }
 
-    *pcbBytesNeeded = 0;
-    *lpServicesReturned = 0;
-
-    dwLastResumeCount = *lpResumeHandle;
+    if (lpResumeHandle)
+        dwLastResumeCount = *lpResumeHandle;
 
     /* FIXME: Lock the service list shared */
 
@@ -1746,19 +2271,16 @@ DWORD ScmrEnumServicesStatusW(
                  ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
                  ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
 
-        if (dwRequiredSize + dwSize <= dwBufSize)
-        {
-            DPRINT("Service name: %S  fit\n", CurrentService->lpServiceName);
-            dwRequiredSize += dwSize;
-            dwServiceCount++;
-            dwLastResumeCount = CurrentService->dwResumeCount;
-        }
-        else
+        if (dwRequiredSize + dwSize > dwBufSize)
         {
             DPRINT("Service name: %S  no fit\n", CurrentService->lpServiceName);
             break;
         }
 
+        DPRINT("Service name: %S  fit\n", CurrentService->lpServiceName);
+        dwRequiredSize += dwSize;
+        dwServiceCount++;
+        dwLastResumeCount = CurrentService->dwResumeCount;
     }
 
     DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
@@ -1791,7 +2313,9 @@ DWORD ScmrEnumServicesStatusW(
 
     DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
 
-    *lpResumeHandle = dwLastResumeCount;
+    if (lpResumeHandle)
+        *lpResumeHandle = dwLastResumeCount;
+
     *lpServicesReturned = dwServiceCount;
     *pcbBytesNeeded = dwRequiredSize;
 
@@ -1822,47 +2346,45 @@ DWORD ScmrEnumServicesStatusW(
                  ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
                  ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
 
-        if (dwRequiredSize + dwSize <= dwBufSize)
-        {
-            /* Copy the service name */
-            wcscpy(lpStringPtr,
-                   CurrentService->lpServiceName);
-            lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
-            lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
+        if (dwRequiredSize + dwSize > dwBufSize)
+            break;
 
-            /* Copy the display name */
-            wcscpy(lpStringPtr,
-                   CurrentService->lpDisplayName);
-            lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
-            lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
+        /* Copy the service name */
+        wcscpy(lpStringPtr, CurrentService->lpServiceName);
+        lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
+        lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
 
-            /* Copy the status information */
-            memcpy(&lpStatusPtr->ServiceStatus,
-                   &CurrentService->Status,
-                   sizeof(SERVICE_STATUS));
+        /* Copy the display name */
+        wcscpy(lpStringPtr, CurrentService->lpDisplayName);
+        lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
+        lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
 
-            lpStatusPtr++;
-            dwRequiredSize += dwSize;
-        }
-        else
-        {
-            break;
-        }
+        /* Copy the status information */
+        memcpy(&lpStatusPtr->ServiceStatus,
+               &CurrentService->Status,
+               sizeof(SERVICE_STATUS));
+
+        lpStatusPtr++;
+        dwRequiredSize += dwSize;
+    }
 
+    if (dwError == 0) 
+    {
+        *pcbBytesNeeded = 0;
+        if (lpResumeHandle) *lpResumeHandle = 0;
     }
 
 Done:;
     /* FIXME: Unlock the service list */
 
-    DPRINT("ScmrEnumServicesStatusW() done (Error %lu)\n", dwError);
+    DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
 
     return dwError;
 }
 
 
 /* Function 15 */
-DWORD ScmrOpenSCManagerW(
-    handle_t BindingHandle,
+DWORD ROpenSCManagerW(
     LPWSTR lpMachineName,
     LPWSTR lpDatabaseName,
     DWORD dwDesiredAccess,
@@ -1871,7 +2393,7 @@ DWORD ScmrOpenSCManagerW(
     DWORD dwError;
     SC_HANDLE hHandle;
 
-    DPRINT("ScmrOpenSCManagerW() called\n");
+    DPRINT("ROpenSCManagerW() called\n");
     DPRINT("lpMachineName = %p\n", lpMachineName);
     DPRINT("lpMachineName: %S\n", lpMachineName);
     DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
@@ -1902,18 +2424,17 @@ DWORD ScmrOpenSCManagerW(
         return dwError;
     }
 
-    *lpScHandle = (unsigned long)hHandle; /* FIXME: 64 bit portability */
+    *lpScHandle = (SC_RPC_HANDLE)hHandle;
     DPRINT("*hScm = %p\n", *lpScHandle);
 
-    DPRINT("ScmrOpenSCManagerW() done\n");
+    DPRINT("ROpenSCManagerW() done\n");
 
     return ERROR_SUCCESS;
 }
 
 
 /* Function 16 */
-DWORD ScmrOpenServiceW(
-    handle_t BindingHandle,
+DWORD ROpenServiceW(
     SC_RPC_HANDLE hSCManager,
     LPWSTR lpServiceName,
     DWORD dwDesiredAccess,
@@ -1924,7 +2445,7 @@ DWORD ScmrOpenServiceW(
     SC_HANDLE hHandle;
     DWORD dwError;
 
-    DPRINT("ScmrOpenServiceW() called\n");
+    DPRINT("ROpenServiceW() called\n");
     DPRINT("hSCManager = %p\n", hSCManager);
     DPRINT("lpServiceName = %p\n", lpServiceName);
     DPRINT("lpServiceName: %S\n", lpServiceName);
@@ -1933,9 +2454,6 @@ DWORD ScmrOpenServiceW(
     if (ScmShutdown)
         return ERROR_SHUTDOWN_IN_PROGRESS;
 
-    if (!lpServiceHandle)
-        return ERROR_INVALID_PARAMETER;
-
     hManager = (PMANAGER_HANDLE)hSCManager;
     if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
     {
@@ -1943,6 +2461,12 @@ DWORD ScmrOpenServiceW(
         return ERROR_INVALID_HANDLE;
     }
 
+    if (!lpServiceHandle)
+        return ERROR_INVALID_PARAMETER;
+
+    if (!lpServiceName)
+        return ERROR_INVALID_ADDRESS;
+
     /* FIXME: Lock the service list */
 
     /* Get service database entry */
@@ -1972,18 +2496,20 @@ DWORD ScmrOpenServiceW(
         return dwError;
     }
 
-    *lpServiceHandle = (unsigned long)hHandle; /* FIXME: 64 bit portability */
+    lpService->dwRefCount++;
+    DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
+
+    *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
     DPRINT("*hService = %p\n", *lpServiceHandle);
 
-    DPRINT("ScmrOpenServiceW() done\n");
+    DPRINT("ROpenServiceW() done\n");
 
     return ERROR_SUCCESS;
 }
 
 
 /* Function 17 */
-DWORD ScmrQueryServiceConfigW(
-    handle_t BindingHandle,
+DWORD RQueryServiceConfigW(
     SC_RPC_HANDLE hService,
     LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
     DWORD cbBufSize,
@@ -1996,11 +2522,14 @@ DWORD ScmrQueryServiceConfigW(
     HKEY hServiceKey = NULL;
     LPWSTR lpImagePath = NULL;
     LPWSTR lpServiceStartName = NULL;
+    LPWSTR lpDependencies = NULL;
+    DWORD dwDependenciesLength = 0;
     DWORD dwRequiredSize;
-    LPQUERY_SERVICE_CONFIGW lpConfig;
+    LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
+    WCHAR lpEmptyString[] = {0,0};
     LPWSTR lpStr;
 
-    DPRINT("ScmrQueryServiceConfigW() called\n");
+    DPRINT("RQueryServiceConfigW() called\n");
 
     if (ScmShutdown)
         return ERROR_SHUTDOWN_IN_PROGRESS;
@@ -2034,31 +2563,49 @@ DWORD ScmrQueryServiceConfigW(
     if (dwError != ERROR_SUCCESS)
         goto Done;
 
+    /* Read the image path */
     dwError = ScmReadString(hServiceKey,
                             L"ImagePath",
                             &lpImagePath);
     if (dwError != ERROR_SUCCESS)
         goto Done;
 
+    /* Read the service start name */
     ScmReadString(hServiceKey,
                   L"ObjectName",
                   &lpServiceStartName);
 
+    /* Read the dependencies */
+    ScmReadDependencies(hServiceKey,
+                        &lpDependencies,
+                        &dwDependenciesLength);
+
     dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
 
     if (lpImagePath != NULL)
         dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
+    else
+        dwRequiredSize += 2 * sizeof(WCHAR);
 
     if (lpService->lpGroup != NULL)
         dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
+    else
+        dwRequiredSize += 2 * sizeof(WCHAR);
 
-    /* FIXME: Add Dependencies length*/
+    if (lpDependencies != NULL)
+        dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
+    else
+        dwRequiredSize += 2 * sizeof(WCHAR);
 
     if (lpServiceStartName != NULL)
         dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
+    else
+        dwRequiredSize += 2 * sizeof(WCHAR);
 
     if (lpService->lpDisplayName != NULL)
         dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
+    else
+        dwRequiredSize += 2 * sizeof(WCHAR);
 
     if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
     {
@@ -2074,51 +2621,74 @@ DWORD ScmrQueryServiceConfigW(
 
         lpStr = (LPWSTR)(lpConfig + 1);
 
+        /* Append the image path */
         if (lpImagePath != NULL)
         {
             wcscpy(lpStr, lpImagePath);
-            lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
-            lpStr += (wcslen(lpImagePath) + 1);
         }
         else
         {
-            lpConfig->lpBinaryPathName = NULL;
+            wcscpy(lpStr, lpEmptyString);
         }
 
+        lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+        lpStr += (wcslen(lpStr) + 1);
+
+        /* Append the group name */
         if (lpService->lpGroup != NULL)
         {
             wcscpy(lpStr, lpService->lpGroup->lpGroupName);
-            lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
-            lpStr += (wcslen(lpService->lpGroup->lpGroupName) + 1);
         }
         else
         {
-            lpConfig->lpLoadOrderGroup = NULL;
+            wcscpy(lpStr, lpEmptyString);
+        }
+
+        lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+        lpStr += (wcslen(lpStr) + 1);
+
+        /* Append Dependencies */
+        if (lpDependencies != NULL)
+        {
+            memcpy(lpStr,
+                   lpDependencies,
+                   dwDependenciesLength * sizeof(WCHAR));
+        }
+        else
+        {
+            wcscpy(lpStr, lpEmptyString);
         }
 
-        /* FIXME: Append Dependencies */
-        lpConfig->lpDependencies = NULL;
+        lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+        if (lpDependencies != NULL)
+            lpStr += dwDependenciesLength * sizeof(WCHAR);
+        else
+            lpStr += (wcslen(lpStr) + 1);
 
+        /* Append the service start name */
         if (lpServiceStartName != NULL)
         {
             wcscpy(lpStr, lpServiceStartName);
-            lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
-            lpStr += (wcslen(lpServiceStartName) + 1);
         }
         else
         {
-            lpConfig->lpServiceStartName = NULL;
+            wcscpy(lpStr, lpEmptyString);
         }
 
+        lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+        lpStr += (wcslen(lpStr) + 1);
+
+        /* Append the display name */
         if (lpService->lpDisplayName != NULL)
         {
             wcscpy(lpStr, lpService->lpDisplayName);
-            lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
         }
         else
         {
-            lpConfig->lpDisplayName = NULL;
+            wcscpy(lpStr, lpEmptyString);
         }
+
+        lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
     }
 
     if (pcbBytesNeeded != NULL)
@@ -2131,20 +2701,22 @@ Done:;
     if (lpServiceStartName != NULL)
         HeapFree(GetProcessHeap(), 0, lpServiceStartName);
 
+    if (lpDependencies != NULL)
+        HeapFree(GetProcessHeap(), 0, lpDependencies);
+
     if (hServiceKey != NULL)
         RegCloseKey(hServiceKey);
 
     /* FIXME: Unlock the service database */
 
-    DPRINT("ScmrQueryServiceConfigW() done\n");
+    DPRINT("RQueryServiceConfigW() done\n");
 
     return dwError;
 }
 
 
 /* Function 18 */
-DWORD ScmrQueryServiceLockStatusW(
-    handle_t BindingHandle,
+DWORD RQueryServiceLockStatusW(
     SC_RPC_HANDLE hSCManager,
     LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
     DWORD cbBufSize,
@@ -2156,8 +2728,7 @@ DWORD ScmrQueryServiceLockStatusW(
 
 
 /* Function 19 */
-DWORD ScmrStartServiceW(
-    handle_t BindingHandle,
+DWORD RStartServiceW(
     SC_RPC_HANDLE hService,
     DWORD argc,
     LPSTRING_PTRSW argv)
@@ -2166,7 +2737,7 @@ DWORD ScmrStartServiceW(
     PSERVICE_HANDLE hSvc;
     PSERVICE lpService = NULL;
 
-    DPRINT("ScmrStartServiceW() called\n");
+    DPRINT("RStartServiceW() called\n");
 
     if (ScmShutdown)
         return ERROR_SHUTDOWN_IN_PROGRESS;
@@ -2211,10 +2782,9 @@ DWORD ScmrStartServiceW(
 
 
 /* Function 20 */
-DWORD ScmrGetServiceDisplayNameW(
-    handle_t BindingHandle,
+DWORD RGetServiceDisplayNameW(
     SC_RPC_HANDLE hSCManager,
-    LPWSTR lpServiceName,
+    LPCWSTR lpServiceName,
     LPWSTR lpDisplayName,
     DWORD *lpcchBuffer)
 {
@@ -2223,7 +2793,7 @@ DWORD ScmrGetServiceDisplayNameW(
     DWORD dwLength;
     DWORD dwError;
 
-    DPRINT("ScmrGetServiceDisplayNameW() called\n");
+    DPRINT("RGetServiceDisplayNameW() called\n");
     DPRINT("hSCManager = %p\n", hSCManager);
     DPRINT("lpServiceName: %S\n", lpServiceName);
     DPRINT("lpDisplayName: %p\n", lpDisplayName);
@@ -2241,15 +2811,40 @@ DWORD ScmrGetServiceDisplayNameW(
     if (lpService == NULL)
     {
         DPRINT1("Could not find a service!\n");
+
+        /* If the service could not be found and lpcchBuffer is less than 2, windows
+           puts null in lpDisplayName and puts 2 in lpcchBuffer */
+        if (*lpcchBuffer < 2)
+        {
+            *lpcchBuffer = 2;
+            if (lpDisplayName != NULL)
+            {
+                *lpDisplayName = '\0';
+            }
+        }
+
         return ERROR_SERVICE_DOES_NOT_EXIST;
     }
 
-    dwLength = wcslen(lpService->lpDisplayName) + 1;
+    if (!lpService->lpDisplayName)
+    {
+        dwLength = wcslen(lpService->lpServiceName);
 
-    if (lpDisplayName != NULL &&
-        *lpcchBuffer >= dwLength)
+        if (lpDisplayName != NULL &&
+            *lpcchBuffer > dwLength)
+        {
+            wcscpy(lpDisplayName, lpService->lpServiceName);
+        }
+    }
+    else
     {
-        wcscpy(lpDisplayName, lpService->lpDisplayName);
+        dwLength = wcslen(lpService->lpDisplayName);
+
+        if (lpDisplayName != NULL &&
+            *lpcchBuffer > dwLength)
+        {
+            wcscpy(lpDisplayName, lpService->lpDisplayName);
+        }
     }
 
     dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
@@ -2261,10 +2856,9 @@ DWORD ScmrGetServiceDisplayNameW(
 
 
 /* Function 21 */
-DWORD ScmrGetServiceKeyNameW(
-    handle_t BindingHandle,
+DWORD RGetServiceKeyNameW(
     SC_RPC_HANDLE hSCManager,
-    LPWSTR lpDisplayName,
+    LPCWSTR lpDisplayName,
     LPWSTR lpServiceName,
     DWORD *lpcchBuffer)
 {
@@ -2273,7 +2867,7 @@ DWORD ScmrGetServiceKeyNameW(
     DWORD dwLength;
     DWORD dwError;
 
-    DPRINT("ScmrGetServiceKeyNameW() called\n");
+    DPRINT("RGetServiceKeyNameW() called\n");
     DPRINT("hSCManager = %p\n", hSCManager);
     DPRINT("lpDisplayName: %S\n", lpDisplayName);
     DPRINT("lpServiceName: %p\n", lpServiceName);
@@ -2291,15 +2885,29 @@ DWORD ScmrGetServiceKeyNameW(
     if (lpService == NULL)
     {
         DPRINT1("Could not find a service!\n");
+
+        /* If the service could not be found and lpcchBuffer is less than 2, windows
+           puts null in lpDisplayName and puts 2 in lpcchBuffer */
+        if (*lpcchBuffer < 2)
+        {
+            *lpcchBuffer = 2;
+            if (lpServiceName != NULL)
+            {
+                *lpServiceName = '\0';
+            }
+        }
+
         return ERROR_SERVICE_DOES_NOT_EXIST;
     }
 
-    dwLength = wcslen(lpService->lpServiceName) + 1;
+    dwLength = wcslen(lpService->lpServiceName);
 
     if (lpServiceName != NULL &&
-        *lpcchBuffer >= dwLength)
+        *lpcchBuffer > dwLength)
     {
         wcscpy(lpServiceName, lpService->lpServiceName);
+        *lpcchBuffer = dwLength;
+        return ERROR_SUCCESS;
     }
 
     dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
@@ -2311,9 +2919,8 @@ DWORD ScmrGetServiceKeyNameW(
 
 
 /* Function 22 */
-DWORD ScmrSetServiceBitsA(
-    handle_t BindingHandle,
-    SC_RPC_HANDLE hServiceStatus,
+DWORD RI_ScSetServiceBitsA(
+    RPC_SERVICE_STATUS_HANDLE hServiceStatus,
     DWORD dwServiceBits,
     int bSetBitsOn,
     int bUpdateImmediately,
@@ -2325,8 +2932,7 @@ DWORD ScmrSetServiceBitsA(
 
 
 /* Function 23 */
-DWORD ScmrChangeServiceConfigA(
-    handle_t BindingHandle,
+DWORD RChangeServiceConfigA(
     SC_RPC_HANDLE hService,
     DWORD dwServiceType,
     DWORD dwStartType,
@@ -2341,97 +2947,702 @@ DWORD ScmrChangeServiceConfigA(
     DWORD dwPwSize,
     LPSTR lpDisplayName)
 {
-    UNIMPLEMENTED;
-    return ERROR_CALL_NOT_IMPLEMENTED;
-}
-
-
-/* Function 24 */
-DWORD ScmrCreateServiceA(
-    handle_t BindingHandle,
-    SC_RPC_HANDLE hSCManager,
-    LPSTR lpServiceName,
-    LPSTR lpDisplayName,
-    DWORD dwDesiredAccess,
-    DWORD dwServiceType,
-    DWORD dwStartType,
-    DWORD dwErrorControl,
-    LPSTR lpBinaryPathName,
-    LPSTR lpLoadOrderGroup,
-    LPDWORD lpdwTagId,
-    LPBYTE lpDependencies,
-    DWORD dwDependSize,
-    LPSTR lpServiceStartName,
-    LPBYTE lpPassword,
-    DWORD dwPwSize,
-    LPSC_RPC_HANDLE lpServiceHandle)
-{
-    UNIMPLEMENTED;
-    return ERROR_CALL_NOT_IMPLEMENTED;
-}
+    DWORD dwError = ERROR_SUCCESS;
+    PSERVICE_HANDLE hSvc;
+    PSERVICE lpService = NULL;
+    HKEY hServiceKey = NULL;
+    LPWSTR lpDisplayNameW = NULL;
+    // LPWSTR lpBinaryPathNameW = NULL;
+    LPWSTR lpLoadOrderGroupW = NULL;
+    LPWSTR lpDependenciesW = NULL;
+    // LPWSTR lpPasswordW = NULL;
 
+    DPRINT("RChangeServiceConfigA() called\n");
+    DPRINT("dwServiceType = %lu\n", dwServiceType);
+    DPRINT("dwStartType = %lu\n", dwStartType);
+    DPRINT("dwErrorControl = %lu\n", dwErrorControl);
+    DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
+    DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
+    DPRINT("lpDisplayName = %s\n", lpDisplayName);
 
-/* Function 25 */
-DWORD ScmrEnumDependentServicesA(
-    handle_t BindingHandle,
-    SC_RPC_HANDLE hService,
-    DWORD dwServiceState,
-    LPBYTE lpServices,
-    DWORD cbBufSize,
-    LPBOUNDED_DWORD_256K pcbBytesNeeded,
-    LPBOUNDED_DWORD_256K lpServicesReturned)
-{
-    UNIMPLEMENTED;
-    *pcbBytesNeeded = 0;
-    *lpServicesReturned = 0;
-    return ERROR_CALL_NOT_IMPLEMENTED;
-}
+    if (ScmShutdown)
+        return ERROR_SHUTDOWN_IN_PROGRESS;
 
+    hSvc = (PSERVICE_HANDLE)hService;
+    if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
+    {
+        DPRINT1("Invalid handle tag!\n");
+        return ERROR_INVALID_HANDLE;
+    }
 
-/* Function 26 */
-DWORD ScmrEnumServicesStatusA(
-    handle_t BindingHandle,
-    SC_RPC_HANDLE hSCManager,
-    DWORD dwServiceType,
-    DWORD dwServiceState,
-    LPBYTE lpBuffer,
-    DWORD dwBufSize,
-    LPBOUNDED_DWORD_256K pcbBytesNeeded,
-    LPBOUNDED_DWORD_256K lpServicesReturned,
-    LPBOUNDED_DWORD_256K lpResumeHandle)
-{
-    UNIMPLEMENTED;
-    return ERROR_CALL_NOT_IMPLEMENTED;
-}
+    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+                                  SERVICE_CHANGE_CONFIG))
+    {
+        DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
+        return ERROR_ACCESS_DENIED;
+    }
 
+    lpService = hSvc->ServiceEntry;
+    if (lpService == NULL)
+    {
+        DPRINT1("lpService == NULL!\n");
+        return ERROR_INVALID_HANDLE;
+    }
 
-/* Function 27 */
-DWORD ScmrOpenSCManagerA(
-    handle_t BindingHandle,
-    LPSTR lpMachineName,
-    LPSTR lpDatabaseName,
-    DWORD dwDesiredAccess,
-    LPSC_RPC_HANDLE lpScHandle)
-{
-    UNICODE_STRING MachineName;
-    UNICODE_STRING DatabaseName;
-    DWORD dwError;
+    /* FIXME: Lock database exclusively */
 
-    DPRINT("ScmrOpenSCManagerA() called\n");
+    if (lpService->bDeleted)
+    {
+        /* FIXME: Unlock database */
+        DPRINT1("The service has already been marked for delete!\n");
+        return ERROR_SERVICE_MARKED_FOR_DELETE;
+    }
 
-    if (lpMachineName)
-        RtlCreateUnicodeStringFromAsciiz(&MachineName,
+    /* Open the service key */
+    dwError = ScmOpenServiceKey(lpService->szServiceName,
+                                KEY_SET_VALUE,
+                                &hServiceKey);
+    if (dwError != ERROR_SUCCESS)
+        goto done;
+
+    /* Write service data to the registry */
+
+    if (lpDisplayName != NULL && *lpDisplayName != 0)
+    {
+        /* Set the display name */
+        lpDisplayNameW = HeapAlloc(GetProcessHeap(),
+                                   0,
+                                   (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
+        if (lpDisplayNameW == NULL)
+        {
+            dwError = ERROR_NOT_ENOUGH_MEMORY;
+            goto done;
+        }
+
+        MultiByteToWideChar(CP_ACP,
+                            0,
+                            lpDisplayName,
+                            -1,
+                            lpDisplayNameW,
+                            strlen(lpDisplayName) + 1);
+
+        RegSetValueExW(hServiceKey,
+                       L"DisplayName",
+                       0,
+                       REG_SZ,
+                       (LPBYTE)lpDisplayNameW,
+                       (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
+
+        /* Update lpService->lpDisplayName */
+        if (lpService->lpDisplayName)
+            HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
+
+        lpService->lpDisplayName = lpDisplayNameW;
+    }
+
+    if (dwServiceType != SERVICE_NO_CHANGE)
+    {
+        /* Set the service type */
+        dwError = RegSetValueExW(hServiceKey,
+                                 L"Type",
+                                 0,
+                                 REG_DWORD,
+                                 (LPBYTE)&dwServiceType,
+                                 sizeof(DWORD));
+        if (dwError != ERROR_SUCCESS)
+            goto done;
+
+        lpService->Status.dwServiceType = dwServiceType;
+    }
+
+    if (dwStartType != SERVICE_NO_CHANGE)
+    {
+        /* Set the start value */
+        dwError = RegSetValueExW(hServiceKey,
+                                 L"Start",
+                                 0,
+                                 REG_DWORD,
+                                 (LPBYTE)&dwStartType,
+                                 sizeof(DWORD));
+        if (dwError != ERROR_SUCCESS)
+            goto done;
+
+        lpService->dwStartType = dwStartType;
+    }
+
+    if (dwErrorControl != SERVICE_NO_CHANGE)
+    {
+        /* Set the error control value */
+        dwError = RegSetValueExW(hServiceKey,
+                                 L"ErrorControl",
+                                 0,
+                                 REG_DWORD,
+                                 (LPBYTE)&dwErrorControl,
+                                 sizeof(DWORD));
+        if (dwError != ERROR_SUCCESS)
+            goto done;
+
+        lpService->dwErrorControl = dwErrorControl;
+    }
+
+#if 0
+    /* FIXME: set the new ImagePath value */
+
+    /* Set the image path */
+    if (dwServiceType & SERVICE_WIN32)
+    {
+        if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
+        {
+            lpBinaryPathNameW=HeapAlloc(GetProcessHeap(),0, (strlen(lpBinaryPathName)+1) * sizeof(WCHAR));
+            MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, strlen(lpBinaryPathName)+1);
+            dwError = RegSetValueExW(hServiceKey,
+                                     L"ImagePath",
+                                     0,
+                                     REG_EXPAND_SZ,
+                                     (LPBYTE)lpBinaryPathNameW,
+                                     (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
+            if (dwError != ERROR_SUCCESS)
+                goto done;
+        }
+    }
+    else if (dwServiceType & SERVICE_DRIVER)
+    {
+        if (lpImagePath != NULL && *lpImagePath != 0)
+        {
+            dwError = RegSetValueExW(hServiceKey,
+                                     L"ImagePath",
+                                     0,
+                                     REG_EXPAND_SZ,
+                                     (LPBYTE)lpImagePath,
+                                     (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
+            if (dwError != ERROR_SUCCESS)
+                goto done;
+        }
+    }
+#endif
+
+    /* Set the group name */
+    if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
+    {
+        lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
+                                      0,
+                                      (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
+        if (lpLoadOrderGroupW == NULL)
+        {
+            dwError = ERROR_NOT_ENOUGH_MEMORY;
+            goto done;
+        }
+
+        MultiByteToWideChar(CP_ACP,
+                            0,
+                            lpLoadOrderGroup,
+                            -1,
+                            lpLoadOrderGroupW,
+                            strlen(lpLoadOrderGroup) + 1);
+
+        dwError = RegSetValueExW(hServiceKey,
+                                 L"Group",
+                                 0,
+                                 REG_SZ,
+                                 (LPBYTE)lpLoadOrderGroupW,
+                                 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
+        if (dwError != ERROR_SUCCESS)
+        {
+            HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
+            goto done;
+        }
+
+        dwError = ScmSetServiceGroup(lpService,
+                                     lpLoadOrderGroupW);
+
+        HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
+
+        if (dwError != ERROR_SUCCESS)
+            goto done;
+    }
+
+    if (lpdwTagId != NULL)
+    {
+        dwError = ScmAssignNewTag(lpService);
+        if (dwError != ERROR_SUCCESS)
+            goto done;
+
+        dwError = RegSetValueExW(hServiceKey,
+                                 L"Tag",
+                                 0,
+                                 REG_DWORD,
+                                 (LPBYTE)&lpService->dwTag,
+                                 sizeof(DWORD));
+        if (dwError != ERROR_SUCCESS)
+            goto done;
+
+        *lpdwTagId = lpService->dwTag;
+    }
+
+    /* Write dependencies */
+    if (lpDependencies != NULL && *lpDependencies != 0)
+    {
+        lpDependenciesW = HeapAlloc(GetProcessHeap(),
+                                    0,
+                                    (strlen(lpDependencies) + 1) * sizeof(WCHAR));
+        if (lpDependenciesW == NULL)
+        {
+            dwError = ERROR_NOT_ENOUGH_MEMORY;
+            goto done;
+        }
+
+        MultiByteToWideChar(CP_ACP,
+                            0,
+                            lpDependencies,
+                            dwDependSize,
+                            lpDependenciesW,
+                            strlen(lpDependencies) + 1);
+
+        dwError = ScmWriteDependencies(hServiceKey,
+                                       (LPWSTR)lpDependenciesW,
+                                       dwDependSize);
+
+        HeapFree(GetProcessHeap(), 0, lpDependenciesW);
+    }
+
+    if (lpPassword != NULL)
+    {
+        /* FIXME: Write password */
+    }
+
+    /* FIXME: Unlock database */
+
+done:
+    if (hServiceKey != NULL)
+        RegCloseKey(hServiceKey);
+
+    DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
+
+    return dwError;
+}
+
+
+/* Function 24 */
+DWORD RCreateServiceA(
+    SC_RPC_HANDLE hSCManager,
+    LPSTR lpServiceName,
+    LPSTR lpDisplayName,
+    DWORD dwDesiredAccess,
+    DWORD dwServiceType,
+    DWORD dwStartType,
+    DWORD dwErrorControl,
+    LPSTR lpBinaryPathName,
+    LPSTR lpLoadOrderGroup,
+    LPDWORD lpdwTagId,
+    LPBYTE lpDependencies,
+    DWORD dwDependSize,
+    LPSTR lpServiceStartName,
+    LPBYTE lpPassword,
+    DWORD dwPwSize,
+    LPSC_RPC_HANDLE lpServiceHandle)
+{
+    DWORD dwError = ERROR_SUCCESS;
+    LPWSTR lpServiceNameW = NULL;
+    LPWSTR lpDisplayNameW = NULL;
+    LPWSTR lpBinaryPathNameW = NULL;
+    LPWSTR lpLoadOrderGroupW = NULL;
+    LPWSTR lpDependenciesW = NULL;
+    LPWSTR lpServiceStartNameW = NULL;
+    DWORD dwDependenciesLength = 0;
+    DWORD dwLength;
+    int len;
+    LPSTR lpStr;
+
+    if (lpServiceName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
+        lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        if (!lpServiceNameW)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
+        }
+        MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
+    }
+
+    if (lpDisplayName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
+        lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        if (!lpDisplayNameW)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
+        }
+        MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
+    }
+
+    if (lpBinaryPathName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
+        lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        if (!lpBinaryPathNameW)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
+        }
+        MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
+    }
+
+    if (lpLoadOrderGroup)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
+        lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        if (!lpLoadOrderGroupW)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
+        }
+        MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
+    }
+
+    if (lpDependencies)
+    {
+        lpStr = (LPSTR)lpDependencies;
+        while (*lpStr)
+        {
+            dwLength = strlen(lpStr) + 1;
+            dwDependenciesLength += dwLength;
+            lpStr = lpStr + dwLength;
+        }
+        dwDependenciesLength++;
+
+        lpDependenciesW = HeapAlloc(GetProcessHeap(), 0, dwDependenciesLength * sizeof(WCHAR));
+        if (!lpDependenciesW)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
+        }
+        MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
+    }
+
+    if (lpServiceStartName)
+    {
+        len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
+        lpServiceStartNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+        if (!lpServiceStartNameW)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            goto cleanup;
+        }
+        MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
+    }
+
+    dwError = RCreateServiceW(hSCManager,
+                              lpServiceNameW,
+                              lpDisplayNameW,
+                              dwDesiredAccess,
+                              dwServiceType,
+                              dwStartType,
+                              dwErrorControl,
+                              lpBinaryPathNameW,
+                              lpLoadOrderGroupW,
+                              lpdwTagId,
+                              (LPBYTE)lpDependenciesW,
+                              dwDependenciesLength,
+                              lpServiceStartNameW,
+                              lpPassword,
+                              dwPwSize,
+                              lpServiceHandle);
+
+cleanup:
+    if (lpServiceNameW !=NULL)
+        HeapFree(GetProcessHeap(), 0, lpServiceNameW);
+
+    if (lpDisplayNameW != NULL)
+        HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
+
+    if (lpBinaryPathNameW != NULL)
+        HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
+
+    if (lpLoadOrderGroupW != NULL)
+        HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
+
+    if (lpDependenciesW != NULL)
+        HeapFree(GetProcessHeap(), 0, lpDependenciesW);
+
+    if (lpServiceStartNameW != NULL)
+        HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
+
+    return dwError;
+}
+
+
+/* Function 25 */
+DWORD REnumDependentServicesA(
+    SC_RPC_HANDLE hService,
+    DWORD dwServiceState,
+    LPBYTE lpServices,
+    DWORD cbBufSize,
+    LPBOUNDED_DWORD_256K pcbBytesNeeded,
+    LPBOUNDED_DWORD_256K lpServicesReturned)
+{
+    DWORD dwError = ERROR_SUCCESS;
+    DWORD dwServicesReturned = 0;
+    DWORD dwServiceCount;
+    HKEY hServicesKey = NULL;
+    LPSC_RPC_HANDLE hSCObject;
+    PSERVICE_HANDLE hSvc;
+    PSERVICE lpService = NULL;
+    PSERVICE *lpServicesArray = NULL;
+    LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
+    LPSTR lpStr;
+
+    *pcbBytesNeeded = 0;
+    *lpServicesReturned = 0;
+
+    DPRINT("REnumDependentServicesA() called\n");
+
+    hSCObject = &hService;
+    hSvc = (PSERVICE_HANDLE) *hSCObject;
+    lpService = hSvc->ServiceEntry;
+
+    /* Check access rights */
+    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+                                  SC_MANAGER_ENUMERATE_SERVICE))
+    {
+        DPRINT1("Insufficient access rights! 0x%lx\n",
+                hSvc->Handle.DesiredAccess);
+        return ERROR_ACCESS_DENIED;
+    }
+
+    /* Open the Services Reg key */
+    dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                            L"System\\CurrentControlSet\\Services",
+                            0,
+                            KEY_READ,
+                            &hServicesKey);
+
+    if (dwError != ERROR_SUCCESS)
+        return dwError;
+
+    /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
+             both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
+             are the same for both. Verified in WINXP. */
+
+    /* First determine the bytes needed and get the number of dependent services*/
+    dwError = Int_EnumDependentServicesW(hServicesKey,
+                                         lpService,
+                                         dwServiceState,
+                                         NULL,
+                                         pcbBytesNeeded,
+                                         &dwServicesReturned);
+    if (dwError != ERROR_SUCCESS)
+        goto Done;
+
+    /* If buffer size is less than the bytes needed or pointer is null*/
+    if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
+    {
+        dwError = ERROR_MORE_DATA;
+        goto Done;
+    }
+
+    /* Allocate memory for array of service pointers */
+    lpServicesArray = HeapAlloc(GetProcessHeap(),
+                                0,
+                                (dwServicesReturned + 1) * sizeof(PSERVICE));
+    if (!lpServicesArray)
+    {
+        DPRINT1("Could not allocate a buffer!!\n");
+        dwError = ERROR_NOT_ENOUGH_MEMORY;
+        goto Done;
+    }
+
+    dwServicesReturned = 0;
+    *pcbBytesNeeded = 0;
+
+    dwError = Int_EnumDependentServicesW(hServicesKey,
+                                         lpService,
+                                         dwServiceState,
+                                         lpServicesArray,
+                                         pcbBytesNeeded,
+                                         &dwServicesReturned);
+    if (dwError != ERROR_SUCCESS)
+    {
+        goto Done;
+    }
+
+    lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
+    lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
+
+    /* Copy EnumDepenedentService to Buffer */
+    for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
+    {
+        lpService = lpServicesArray[dwServiceCount];
+
+        /* Copy the status info */
+        memcpy(&lpServicesPtr->ServiceStatus,
+               &lpService->Status,
+               sizeof(SERVICE_STATUS));
+
+        /* Copy display name */
+        WideCharToMultiByte(CP_ACP,
+                            0,
+                            lpService->lpDisplayName,
+                            -1,
+                            lpStr,
+                            wcslen(lpService->lpDisplayName),
+                            0,
+                            0);
+        lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
+        lpStr += strlen(lpStr) + 1;
+
+        /* Copy service name */
+        WideCharToMultiByte(CP_ACP,
+                            0,
+                            lpService->lpServiceName,
+                            -1,
+                            lpStr,
+                            wcslen(lpService->lpServiceName),
+                            0,
+                            0);
+        lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
+        lpStr += strlen(lpStr) + 1;
+
+        lpServicesPtr ++;
+    }
+
+    *lpServicesReturned = dwServicesReturned;
+
+Done:
+    if (lpServicesArray)
+        HeapFree(GetProcessHeap(), 0, lpServicesArray);
+
+    RegCloseKey(hServicesKey);
+
+    DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
+
+    return dwError;
+}
+
+
+/* Function 26 */
+DWORD REnumServicesStatusA(
+    SC_RPC_HANDLE hSCManager,
+    DWORD dwServiceType,
+    DWORD dwServiceState,
+    LPBYTE lpBuffer,
+    DWORD dwBufSize,
+    LPBOUNDED_DWORD_256K pcbBytesNeeded,
+    LPBOUNDED_DWORD_256K lpServicesReturned,
+    LPBOUNDED_DWORD_256K lpResumeHandle)
+{
+    LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
+    LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
+    LPWSTR lpStringPtrW;
+    LPSTR lpStringPtrA;
+    DWORD dwError;
+    DWORD dwServiceCount;
+
+    DPRINT("REnumServicesStatusA() called\n");
+
+    if ((dwBufSize > 0) && (lpBuffer))
+    {
+        lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
+        if (!lpStatusPtrW)
+        {
+            DPRINT1("Failed to allocate buffer!\n");
+            return ERROR_NOT_ENOUGH_MEMORY;
+        }
+    }
+
+    dwError = REnumServicesStatusW(hSCManager,
+                                   dwServiceType,
+                                   dwServiceState,
+                                   (LPBYTE)lpStatusPtrW,
+                                   dwBufSize,
+                                   pcbBytesNeeded,
+                                   lpServicesReturned,
+                                   lpResumeHandle);
+
+    /* if no services were returned then we are Done */
+    if (*lpServicesReturned == 0)
+        goto Done;
+
+    lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
+    lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
+                  *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
+    lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW + 
+                  *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
+
+    for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
+    {
+        /* Copy the service name */
+        WideCharToMultiByte(CP_ACP,
+                            0,
+                            lpStringPtrW,
+                            -1,
+                            lpStringPtrA,
+                            wcslen(lpStringPtrW),
+                            0,
+                            0);
+
+        lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
+        lpStringPtrA += wcslen(lpStringPtrW) + 1;
+        lpStringPtrW += wcslen(lpStringPtrW) + 1;
+
+        /* Copy the display name */
+        WideCharToMultiByte(CP_ACP,
+                            0,
+                            lpStringPtrW,
+                            -1,
+                            lpStringPtrA,
+                            wcslen(lpStringPtrW),
+                            0,
+                            0);
+
+        lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
+        lpStringPtrA += wcslen(lpStringPtrW) + 1;
+        lpStringPtrW += wcslen(lpStringPtrW) + 1;
+
+        /* Copy the status information */
+        memcpy(&lpStatusPtrA->ServiceStatus,
+               &lpStatusPtrW->ServiceStatus,
+               sizeof(SERVICE_STATUS));
+
+        lpStatusPtrA++;
+    }
+
+Done:;
+    if (lpStatusPtrW)
+        HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
+
+    DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
+
+    return dwError;
+}
+
+
+/* Function 27 */
+DWORD ROpenSCManagerA(
+    LPSTR lpMachineName,
+    LPSTR lpDatabaseName,
+    DWORD dwDesiredAccess,
+    LPSC_RPC_HANDLE lpScHandle)
+{
+    UNICODE_STRING MachineName;
+    UNICODE_STRING DatabaseName;
+    DWORD dwError;
+
+    DPRINT("ROpenSCManagerA() called\n");
+
+    if (lpMachineName)
+        RtlCreateUnicodeStringFromAsciiz(&MachineName,
                                          lpMachineName);
 
     if (lpDatabaseName)
         RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
                                          lpDatabaseName);
 
-    dwError = ScmrOpenSCManagerW(BindingHandle,
-                                 lpMachineName ? MachineName.Buffer : NULL,
-                                 lpDatabaseName ? DatabaseName.Buffer : NULL,
-                                 dwDesiredAccess,
-                                 lpScHandle);
+    dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
+                              lpDatabaseName ? DatabaseName.Buffer : NULL,
+                              dwDesiredAccess,
+                              lpScHandle);
 
     if (lpMachineName)
         RtlFreeUnicodeString(&MachineName);
@@ -2444,8 +3655,7 @@ DWORD ScmrOpenSCManagerA(
 
 
 /* Function 28 */
-DWORD ScmrOpenServiceA(
-    handle_t BindingHandle,
+DWORD ROpenServiceA(
     SC_RPC_HANDLE hSCManager,
     LPSTR lpServiceName,
     DWORD dwDesiredAccess,
@@ -2454,39 +3664,266 @@ DWORD ScmrOpenServiceA(
     UNICODE_STRING ServiceName;
     DWORD dwError;
 
-    DPRINT("ScmrOpenServiceA() called\n");
+    DPRINT("ROpenServiceA() called\n");
 
-    RtlCreateUnicodeStringFromAsciiz(&ServiceName,
-                                     lpServiceName);
+    if (lpServiceName)
+        RtlCreateUnicodeStringFromAsciiz(&ServiceName,
+                                         lpServiceName);
 
-    dwError = ScmrOpenServiceW(BindingHandle,
-                               hSCManager,
-                               ServiceName.Buffer,
-                               dwDesiredAccess,
-                               lpServiceHandle);
+    dwError = ROpenServiceW(hSCManager,
+                            lpServiceName ? ServiceName.Buffer : NULL,
+                            dwDesiredAccess,
+                            lpServiceHandle);
 
-    RtlFreeUnicodeString(&ServiceName);
+    if (lpServiceName)
+        RtlFreeUnicodeString(&ServiceName);
 
     return dwError;
 }
 
 
 /* Function 29 */
-DWORD ScmrQueryServiceConfigA(
-    handle_t BindingHandle,
+DWORD RQueryServiceConfigA(
     SC_RPC_HANDLE hService,
-    LPQUERY_SERVICE_CONFIGA lpServiceConfig,
+    LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
     DWORD cbBufSize,
     LPBOUNDED_DWORD_8K pcbBytesNeeded)
 {
-    UNIMPLEMENTED;
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
+    DWORD dwError = ERROR_SUCCESS;
+    PSERVICE_HANDLE hSvc;
+    PSERVICE lpService = NULL;
+    HKEY hServiceKey = NULL;
+    LPWSTR lpImagePath = NULL;
+    LPWSTR lpServiceStartName = NULL;
+    LPWSTR lpDependencies = NULL;
+    DWORD dwDependenciesLength = 0;
+    DWORD dwRequiredSize;
+    LPQUERY_SERVICE_CONFIGA lpConfig = NULL;
+    CHAR lpEmptyString[]={0,0};
+    LPSTR lpStr;
+
+    DPRINT("RQueryServiceConfigA() called\n");
+
+    if (ScmShutdown)
+        return ERROR_SHUTDOWN_IN_PROGRESS;
+
+    hSvc = (PSERVICE_HANDLE)hService;
+    if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
+    {
+        DPRINT1("Invalid handle tag!\n");
+        return ERROR_INVALID_HANDLE;
+    }
+
+    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+                                  SERVICE_QUERY_CONFIG))
+    {
+        DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
+        return ERROR_ACCESS_DENIED;
+    }
+
+    lpService = hSvc->ServiceEntry;
+    if (lpService == NULL)
+    {
+        DPRINT1("lpService == NULL!\n");
+        return ERROR_INVALID_HANDLE;
+    }
+
+    /* FIXME: Lock the service database shared */
+
+    dwError = ScmOpenServiceKey(lpService->lpServiceName,
+                                KEY_READ,
+                                &hServiceKey);
+    if (dwError != ERROR_SUCCESS)
+        goto Done;
+
+    /* Read the image path */
+    dwError = ScmReadString(hServiceKey,
+                            L"ImagePath",
+                            &lpImagePath);
+    if (dwError != ERROR_SUCCESS)
+        goto Done;
+
+    /* Read the service start name */
+    ScmReadString(hServiceKey,
+                  L"ObjectName",
+                  &lpServiceStartName);
+
+    /* Read the dependencies */
+    ScmReadDependencies(hServiceKey,
+                        &lpDependencies,
+                        &dwDependenciesLength);
+
+    dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
+
+    if (lpImagePath != NULL)
+        dwRequiredSize += wcslen(lpImagePath) + 1;
+    else
+        dwRequiredSize += 2;
+
+    if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
+        dwRequiredSize += wcslen(lpService->lpGroup->lpGroupName) + 1;
+    else
+        dwRequiredSize += 2;
+
+    /* Add Dependencies length */
+    if (lpDependencies != NULL)
+        dwRequiredSize += dwDependenciesLength;
+    else
+        dwRequiredSize += 2;
+
+    if (lpServiceStartName != NULL)
+        dwRequiredSize += wcslen(lpServiceStartName) + 1;
+    else
+        dwRequiredSize += 2;
+
+    if (lpService->lpDisplayName != NULL)
+        dwRequiredSize += wcslen(lpService->lpDisplayName) + 1;
+    else
+        dwRequiredSize += 2;
+
+    if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
+    {
+        dwError = ERROR_INSUFFICIENT_BUFFER;
+    }
+    else
+    {
+        lpConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig;
+        lpConfig->dwServiceType = lpService->Status.dwServiceType;
+        lpConfig->dwStartType = lpService->dwStartType;
+        lpConfig->dwErrorControl = lpService->dwErrorControl;
+        lpConfig->dwTagId = lpService->dwTag;
+
+        lpStr = (LPSTR)(lpServiceConfig + 1);
+
+        /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
+          Verified in WINXP*/
+
+        if (lpImagePath)
+        {
+            WideCharToMultiByte(CP_ACP,
+                                0,
+                                lpImagePath,
+                                -1,
+                                lpStr,
+                                wcslen(lpImagePath) + 1,
+                                0,
+                                0);
+        }
+        else
+        {
+            strcpy(lpStr, lpEmptyString);
+        }
+
+        lpConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+        lpStr += (strlen((LPSTR)lpStr) + 1);
+
+        if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
+        {
+            WideCharToMultiByte(CP_ACP,
+                                0,
+                                lpService->lpGroup->lpGroupName,
+                                -1,
+                                lpStr,
+                                wcslen(lpService->lpGroup->lpGroupName) + 1,
+                                0,
+                                0);
+        }
+        else
+        {
+            strcpy(lpStr, lpEmptyString);
+        }
+
+        lpConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+        lpStr += (strlen(lpStr) + 1);
+
+        /* Append Dependencies */
+        if (lpDependencies)
+        {
+            WideCharToMultiByte(CP_ACP,
+                                0,
+                                lpDependencies,
+                                dwDependenciesLength,
+                                lpStr,
+                                dwDependenciesLength,
+                                0,
+                                0);
+        }
+        else
+        {
+            strcpy(lpStr, lpEmptyString);
+        }
+
+        lpConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+        if (lpDependencies)
+            lpStr += dwDependenciesLength;
+        else
+            lpStr += (strlen(lpStr) + 1);
+
+        if (lpServiceStartName)
+        {
+            WideCharToMultiByte(CP_ACP,
+                                0,
+                                lpServiceStartName,
+                                -1,
+                                lpStr,
+                                wcslen(lpServiceStartName) + 1,
+                                0,
+                                0);
+        }
+        else
+        {
+            strcpy(lpStr, lpEmptyString);
+        }
+
+        lpConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+        lpStr += (strlen(lpStr) + 1);
+
+        if (lpService->lpDisplayName)
+        {
+            WideCharToMultiByte(CP_ACP,
+                                0,
+                                lpService->lpDisplayName,
+                                -1,
+                                lpStr,
+                                wcslen(lpService->lpDisplayName) + 1,
+                                0,
+                                0);
+        }
+        else
+        {
+            strcpy(lpStr, lpEmptyString);
+        }
+
+        lpConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+    }
+
+    if (pcbBytesNeeded != NULL)
+        *pcbBytesNeeded = dwRequiredSize;
+
+Done:;
+    if (lpImagePath != NULL)
+        HeapFree(GetProcessHeap(), 0, lpImagePath);
+
+    if (lpServiceStartName != NULL)
+        HeapFree(GetProcessHeap(), 0, lpServiceStartName);
+
+    if (lpDependencies != NULL)
+        HeapFree(GetProcessHeap(), 0, lpDependencies);
+
+    if (hServiceKey != NULL)
+        RegCloseKey(hServiceKey);
+
+    /* FIXME: Unlock the service database */
+
+    DPRINT("RQueryServiceConfigA() done\n");
+
+    return dwError;
 }
 
 
 /* Function 30 */
-DWORD ScmrQueryServiceLockStatusA(
-    handle_t BindingHandle,
+DWORD RQueryServiceLockStatusA(
     SC_RPC_HANDLE hSCManager,
     LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
     DWORD cbBufSize,
@@ -2498,8 +3935,7 @@ DWORD ScmrQueryServiceLockStatusA(
 
 
 /* Function 31 */
-DWORD ScmrStartServiceA(
-    handle_t BindingHandle,
+DWORD RStartServiceA(
     SC_RPC_HANDLE hService,
     DWORD argc,
     LPSTRING_PTRSA argv)
@@ -2508,7 +3944,7 @@ DWORD ScmrStartServiceA(
     PSERVICE_HANDLE hSvc;
     PSERVICE lpService = NULL;
 
-    DPRINT1("ScmrStartServiceA() called\n");
+    DPRINT1("RStartServiceA() called\n");
 
     if (ScmShutdown)
         return ERROR_SHUTDOWN_IN_PROGRESS;
@@ -2547,39 +3983,199 @@ DWORD ScmrStartServiceA(
 
     /* FIXME: Free argument vector */
 
-    return dwError;
-}
+    return dwError;
+}
+
+
+/* Function 32 */
+DWORD RGetServiceDisplayNameA(
+    SC_RPC_HANDLE hSCManager,
+    LPCSTR lpServiceName,
+    LPSTR lpDisplayName,
+    LPBOUNDED_DWORD_4K lpcchBuffer)
+{
+//    PMANAGER_HANDLE hManager;
+    PSERVICE lpService = NULL;
+    DWORD dwLength;
+    DWORD dwError;
+    LPWSTR lpServiceNameW;
+
+    DPRINT("RGetServiceDisplayNameA() called\n");
+    DPRINT("hSCManager = %p\n", hSCManager);
+    DPRINT("lpServiceName: %s\n", lpServiceName);
+    DPRINT("lpDisplayName: %p\n", lpDisplayName);
+    DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
+
+//    hManager = (PMANAGER_HANDLE)hSCManager;
+//    if (hManager->Handle.Tag != MANAGER_TAG)
+//    {
+//        DPRINT1("Invalid manager handle!\n");
+//        return ERROR_INVALID_HANDLE;
+//    }
+
+    if (lpServiceName != NULL)
+    {
+        dwLength = strlen(lpServiceName) + 1;
+        lpServiceNameW = HeapAlloc(GetProcessHeap(),
+                                   HEAP_ZERO_MEMORY,
+                                   dwLength * sizeof(WCHAR));
+        if (!lpServiceNameW)
+            return ERROR_NOT_ENOUGH_MEMORY;
+
+        MultiByteToWideChar(CP_ACP,
+                            0,
+                            lpServiceName,
+                            -1,
+                            lpServiceNameW,
+                            dwLength);
+
+        lpService = ScmGetServiceEntryByName(lpServiceNameW);
+
+        HeapFree(GetProcessHeap(), 0, lpServiceNameW);
+    }
+
+    if (lpService == NULL)
+    {
+        DPRINT1("Could not find a service!\n");
+
+        /* If the service could not be found and lpcchBuffer is 0, windows
+           puts null in lpDisplayName and puts 1 in lpcchBuffer */
+        if (*lpcchBuffer == 0)
+        {
+            *lpcchBuffer = 1;
+            if (lpDisplayName != NULL)
+            {
+                *lpDisplayName = '\0';
+            }
+        }
+        return ERROR_SERVICE_DOES_NOT_EXIST;
+    }
+
+    if (!lpService->lpDisplayName)
+    {
+        dwLength = wcslen(lpService->lpServiceName);
+        if (lpDisplayName != NULL &&
+            *lpcchBuffer > dwLength)
+        {
+            WideCharToMultiByte(CP_ACP,
+                                0,
+                                lpService->lpServiceName,
+                                wcslen(lpService->lpServiceName),
+                                lpDisplayName,
+                                dwLength + 1,
+                                NULL,
+                                NULL);
+            return ERROR_SUCCESS;
+        }
+    }
+    else
+    {
+        dwLength = wcslen(lpService->lpDisplayName);
+        if (lpDisplayName != NULL &&
+            *lpcchBuffer > dwLength)
+        {
+            WideCharToMultiByte(CP_ACP,
+                                0,
+                                lpService->lpDisplayName,
+                                wcslen(lpService->lpDisplayName),
+                                lpDisplayName,
+                                dwLength + 1,
+                                NULL,
+                                NULL);
+            return ERROR_SUCCESS;
+        }
+    }
+
+    dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
+
+    *lpcchBuffer = dwLength * 2;
+
+    return dwError;
+}
+
+
+/* Function 33 */
+DWORD RGetServiceKeyNameA(
+    SC_RPC_HANDLE hSCManager,
+    LPCSTR lpDisplayName,
+    LPSTR lpServiceName,
+    LPBOUNDED_DWORD_4K lpcchBuffer)
+{
+    PSERVICE lpService;
+    DWORD dwLength;
+    DWORD dwError;
+    LPWSTR lpDisplayNameW;
+
+    DPRINT("RGetServiceKeyNameA() called\n");
+    DPRINT("hSCManager = %p\n", hSCManager);
+    DPRINT("lpDisplayName: %s\n", lpDisplayName);
+    DPRINT("lpServiceName: %p\n", lpServiceName);
+    DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
+
+    dwLength = strlen(lpDisplayName) + 1;
+    lpDisplayNameW = HeapAlloc(GetProcessHeap(),
+                               HEAP_ZERO_MEMORY,
+                               dwLength * sizeof(WCHAR));
+    if (!lpDisplayNameW)
+        return ERROR_NOT_ENOUGH_MEMORY;
+
+    MultiByteToWideChar(CP_ACP,
+                        0,
+                        lpDisplayName,
+                        -1,
+                        lpDisplayNameW,
+                        dwLength);
+
+    lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
+
+    HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
+
+    if (lpService == NULL)
+    {
+        DPRINT1("Could not find the service!\n");
+
+        /* If the service could not be found and lpcchBuffer is 0,
+           put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
+        if (*lpcchBuffer == 0)
+        {
+            *lpcchBuffer = 1;
+            if (lpServiceName != NULL)
+            {
+                *lpServiceName = '\0';
+            }
+        }
+
+        return ERROR_SERVICE_DOES_NOT_EXIST;
+    }
 
+    dwLength = wcslen(lpService->lpServiceName);
+    if (lpServiceName != NULL &&
+        *lpcchBuffer > dwLength)
+    {
+        WideCharToMultiByte(CP_ACP,
+                            0,
+                            lpService->lpServiceName,
+                            wcslen(lpService->lpServiceName),
+                            lpServiceName,
+                            dwLength + 1,
+                            NULL,
+                            NULL);
+        return ERROR_SUCCESS;
+    }
 
-/* Function 32 */
-DWORD ScmrGetServiceDisplayNameA(
-    handle_t BindingHandle,
-    SC_RPC_HANDLE hSCManager,
-    LPSTR lpServiceName,
-    LPSTR lpDisplayName,
-    LPBOUNDED_DWORD_4K lpcchBuffer)
-{
-    UNIMPLEMENTED;
-    return ERROR_CALL_NOT_IMPLEMENTED;
-}
+    dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
 
+    *lpcchBuffer = dwLength * 2;
 
-/* Function 33 */
-DWORD ScmrGetServiceKeyNameA(
-    handle_t BindingHandle,
-    SC_RPC_HANDLE hSCManager,
-    LPSTR lpDisplayName,
-    LPSTR lpKeyName,
-    LPBOUNDED_DWORD_4K lpcchBuffer)
-{
-    UNIMPLEMENTED;
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    return dwError;
 }
 
 
 /* Function 34 */
-DWORD ScmrGetCurrentGroupStateW(
-    handle_t BindingHandle)
+DWORD RI_ScGetCurrentGroupStateW(
+    SC_RPC_HANDLE hSCManager,
+    LPWSTR lpLoadOrderGroup,
+    LPDWORD lpState)
 {
     UNIMPLEMENTED;
     return ERROR_CALL_NOT_IMPLEMENTED;
@@ -2587,8 +4183,7 @@ DWORD ScmrGetCurrentGroupStateW(
 
 
 /* Function 35 */
-DWORD ScmrEnumServiceGroupW(
-    handle_t BindingHandle,
+DWORD REnumServiceGroupW(
     SC_RPC_HANDLE hSCManager,
     DWORD dwServiceType,
     DWORD dwServiceState,
@@ -2597,27 +4192,130 @@ DWORD ScmrEnumServiceGroupW(
     LPBOUNDED_DWORD_256K pcbBytesNeeded,
     LPBOUNDED_DWORD_256K lpServicesReturned,
     LPBOUNDED_DWORD_256K lpResumeIndex,
-    LPWSTR pszGroupName)
+    LPCWSTR pszGroupName)
 {
     UNIMPLEMENTED;
     return ERROR_CALL_NOT_IMPLEMENTED;
 }
 
 
+//
+// WARNING: This function is untested
+//
 /* Function 36 */
-DWORD ScmrChangeServiceConfig2A(
-    handle_t BindingHandle,
+DWORD RChangeServiceConfig2A(
     SC_RPC_HANDLE hService,
     SC_RPC_CONFIG_INFOA Info)
 {
-    UNIMPLEMENTED;
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    SC_RPC_CONFIG_INFOW InfoW;
+    DWORD dwRet, dwLength;
+    PVOID ptr = NULL;
+
+    DPRINT("RChangeServiceConfig2A() called\n");
+    DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
+
+    InfoW.dwInfoLevel = Info.dwInfoLevel;
+
+    if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
+    {
+        LPSERVICE_DESCRIPTIONW lpServiceDescriptonW;
+        LPSERVICE_DESCRIPTIONA lpServiceDescriptonA;
+
+        lpServiceDescriptonA = Info.psd;
+
+        ///if (lpServiceDescriptonA &&
+        ///lpServiceDescriptonA->lpDescription)
+        ///{
+            dwLength = (strlen(Info.lpDescription) + 1) * sizeof(WCHAR);
+
+            lpServiceDescriptonW = HeapAlloc(GetProcessHeap(),
+                                            0,
+                                            dwLength + sizeof(SERVICE_DESCRIPTIONW));
+            if (!lpServiceDescriptonW)
+            {
+                return ERROR_NOT_ENOUGH_MEMORY;
+            }
+
+            lpServiceDescriptonW->lpDescription = (LPWSTR)(lpServiceDescriptonW + 1);
+
+            MultiByteToWideChar(CP_ACP,
+                                0,
+                                Info.lpDescription,
+                                -1,
+                                lpServiceDescriptonW->lpDescription,
+                                dwLength);
+
+            ptr = lpServiceDescriptonW;
+            InfoW.psd = lpServiceDescriptonW;
+        ///}
+    }
+    else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
+    {
+        LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
+        LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
+        DWORD dwRebootLen = 0;
+        DWORD dwCommandLen = 0;
+
+        lpServiceFailureActionsA = Info.psfa;
+
+        if (lpServiceFailureActionsA)
+        {
+            if (lpServiceFailureActionsA->lpRebootMsg)
+            {
+                dwRebootLen = (strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR);
+            }
+            if (lpServiceFailureActionsA->lpCommand)
+            {
+                dwCommandLen = (strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR);
+            }
+            dwLength = dwRebootLen + dwCommandLen + sizeof(SERVICE_FAILURE_ACTIONSW);
+
+            lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
+                                                 0,
+                                                 dwLength);
+            if (!lpServiceFailureActionsW)
+            {
+                return ERROR_NOT_ENOUGH_MEMORY;
+            }
+
+            lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
+            lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
+            CopyMemory(lpServiceFailureActionsW->lpsaActions, lpServiceFailureActionsA->lpsaActions, sizeof(SC_ACTION));
+
+            if (lpServiceFailureActionsA->lpRebootMsg)
+            {
+                MultiByteToWideChar(CP_ACP,
+                                    0,
+                                    lpServiceFailureActionsA->lpRebootMsg,
+                                    -1,
+                                    lpServiceFailureActionsW->lpRebootMsg,
+                                    dwRebootLen);
+            }
+
+            if (lpServiceFailureActionsA->lpCommand)
+            {
+                MultiByteToWideChar(CP_ACP,
+                                    0,
+                                    lpServiceFailureActionsA->lpCommand,
+                                    -1,
+                                    lpServiceFailureActionsW->lpCommand,
+                                    dwCommandLen);
+            }
+
+            ptr = lpServiceFailureActionsW;
+        }
+    }
+
+    dwRet = RChangeServiceConfig2W(hService, InfoW);
+
+    HeapFree(GetProcessHeap(), 0, ptr);
+
+    return dwRet;
 }
 
 
 /* Function 37 */
-DWORD ScmrChangeServiceConfig2W(
-    handle_t BindingHandle,
+DWORD RChangeServiceConfig2W(
     SC_RPC_HANDLE hService,
     SC_RPC_CONFIG_INFOW Info)
 {
@@ -2626,7 +4324,7 @@ DWORD ScmrChangeServiceConfig2W(
     PSERVICE lpService = NULL;
     HKEY hServiceKey = NULL;
 
-    DPRINT("ScmrChangeServiceConfig2W() called\n");
+    DPRINT("RChangeServiceConfig2W() called\n");
     DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
 
     if (ScmShutdown)
@@ -2669,16 +4367,17 @@ DWORD ScmrChangeServiceConfig2W(
     if (dwError != ERROR_SUCCESS)
         goto done;
 
-    if (Info.dwInfoLevel & SERVICE_CONFIG_DESCRIPTION)
+    if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
     {
         LPSERVICE_DESCRIPTIONW lpServiceDescription;
 
-        lpServiceDescription = (LPSERVICE_DESCRIPTIONW)&Info;
-        lpServiceDescription->lpDescription = (LPWSTR)(&Info + sizeof(LPSERVICE_DESCRIPTIONW));
+        lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd;
+        lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpServiceDescription + sizeof(LPSERVICE_DESCRIPTIONW));
 
         if (lpServiceDescription != NULL &&
             lpServiceDescription->lpDescription != NULL)
         {
+            DPRINT1("Setting value %S\n", lpServiceDescription->lpDescription);
             RegSetValueExW(hServiceKey,
                            L"Description",
                            0,
@@ -2690,7 +4389,7 @@ DWORD ScmrChangeServiceConfig2W(
                 goto done;
         }
     }
-    else if (Info.dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
+    else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
     {
         UNIMPLEMENTED;
         dwError = ERROR_CALL_NOT_IMPLEMENTED;
@@ -2702,29 +4401,133 @@ done:
     if (hServiceKey != NULL)
         RegCloseKey(hServiceKey);
 
-    DPRINT("ScmrChangeServiceConfig2W() done (Error %lu)\n", dwError);
+    DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError);
 
     return dwError;
 }
 
 
 /* Function 38 */
-DWORD ScmrQueryServiceConfig2A(
-    handle_t BindingHandle,
+DWORD RQueryServiceConfig2A(
     SC_RPC_HANDLE hService,
     DWORD dwInfoLevel,
     LPBYTE lpBuffer,
     DWORD cbBufSize,
     LPBOUNDED_DWORD_8K pcbBytesNeeded)
 {
-    UNIMPLEMENTED;
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    DWORD dwError = ERROR_SUCCESS;
+    PSERVICE_HANDLE hSvc;
+    PSERVICE lpService = NULL;
+    HKEY hServiceKey = NULL;
+    LPWSTR lpDescriptionW = NULL;
+    LPSTR lpDescription = NULL;
+
+    DPRINT1("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
+            hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
+
+    if (!lpBuffer)
+        return ERROR_INVALID_ADDRESS;
+
+    if (ScmShutdown)
+        return ERROR_SHUTDOWN_IN_PROGRESS;
+
+    hSvc = (PSERVICE_HANDLE)hService;
+    if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
+    {
+        DPRINT1("Invalid handle tag!\n");
+        return ERROR_INVALID_HANDLE;
+    }
+
+    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+                                  SERVICE_QUERY_CONFIG))
+    {
+        DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
+        return ERROR_ACCESS_DENIED;
+    }
+
+    lpService = hSvc->ServiceEntry;
+    if (lpService == NULL)
+    {
+        DPRINT1("lpService == NULL!\n");
+        return ERROR_INVALID_HANDLE;
+    }
+
+    /* FIXME: Lock the service database shared */
+
+    dwError = ScmOpenServiceKey(lpService->lpServiceName,
+                                KEY_READ,
+                                &hServiceKey);
+    if (dwError != ERROR_SUCCESS)
+        goto done;
+
+    if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
+    {
+        LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
+        LPSTR lpStr;
+
+        *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA);
+
+        dwError = ScmReadString(hServiceKey,
+                                L"Description",
+                                &lpDescriptionW);
+        if (dwError == ERROR_SUCCESS)
+        {
+            *pcbBytesNeeded += ((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR));
+        }
+
+        if (cbBufSize >= *pcbBytesNeeded)
+        {
+
+            if (dwError == ERROR_SUCCESS)
+            {
+                lpStr = (LPSTR)(lpServiceDescription + 1);
+
+                WideCharToMultiByte(CP_ACP,
+                                    0,
+                                    lpDescriptionW,
+                                    -1,
+                                    lpStr,
+                                    wcslen(lpDescriptionW),
+                                    NULL,
+                                    NULL);
+                lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
+            }
+            else
+            {
+                lpServiceDescription->lpDescription = NULL;
+                goto done;
+            }
+        }
+        else
+        {
+            dwError = ERROR_INSUFFICIENT_BUFFER;
+            goto done;
+        }
+    }
+    else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
+    {
+        UNIMPLEMENTED;
+        dwError = ERROR_CALL_NOT_IMPLEMENTED;
+        goto done;
+    }
+
+done:
+    if (lpDescription != NULL)
+        HeapFree(GetProcessHeap(), 0, lpDescription);
+
+    if (hServiceKey != NULL)
+        RegCloseKey(hServiceKey);
+
+    /* FIXME: Unlock database */
+
+    DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
+
+    return dwError;
 }
 
 
 /* Function 39 */
-DWORD ScmrQueryServiceConfig2W(
-    handle_t BindingHandle,
+DWORD RQueryServiceConfig2W(
     SC_RPC_HANDLE hService,
     DWORD dwInfoLevel,
     LPBYTE lpBuffer,
@@ -2737,8 +4540,13 @@ DWORD ScmrQueryServiceConfig2W(
     HKEY hServiceKey = NULL;
     DWORD dwRequiredSize;
     LPWSTR lpDescription = NULL;
+    LPWSTR lpFailureCommand = NULL;
+    LPWSTR lpRebootMessage = NULL;
 
-    DPRINT("ScmrQueryServiceConfig2W() called\n");
+    DPRINT("RQueryServiceConfig2W() called\n");
+
+    if (!lpBuffer)
+        return ERROR_INVALID_ADDRESS;
 
     if (ScmShutdown)
         return ERROR_SHUTDOWN_IN_PROGRESS;
@@ -2772,7 +4580,7 @@ DWORD ScmrQueryServiceConfig2W(
     if (dwError != ERROR_SUCCESS)
         goto done;
 
-    if (dwInfoLevel & SERVICE_CONFIG_DESCRIPTION)
+    if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
     {
         LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer;
         LPWSTR lpStr;
@@ -2791,17 +4599,62 @@ DWORD ScmrQueryServiceConfig2W(
             dwError = ERROR_INSUFFICIENT_BUFFER;
             goto done;
         }
-        else
-        {
-            lpStr = (LPWSTR)(lpServiceDescription + 1);
-            wcscpy(lpStr, lpDescription);
-            lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
-        }
+
+        lpStr = (LPWSTR)(lpServiceDescription + 1);
+        wcscpy(lpStr, lpDescription);
+        lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
     }
-    else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
+    else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
     {
+        LPWSTR lpStr;
+        LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer;
+
         UNIMPLEMENTED;
-        dwError = ERROR_CALL_NOT_IMPLEMENTED;
+
+        dwError = ScmReadString(hServiceKey,
+                                L"FailureCommand",
+                                &lpFailureCommand);
+
+        dwError = ScmReadString(hServiceKey,
+                                L"RebootMessage",
+                                &lpRebootMessage);
+
+        dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
+
+        if (lpFailureCommand)
+            dwRequiredSize += (wcslen(lpFailureCommand) + 1) * sizeof(WCHAR);
+
+        if (lpRebootMessage)
+            dwRequiredSize += (wcslen(lpRebootMessage) + 1) * sizeof(WCHAR);
+
+        if (cbBufSize < dwRequiredSize)
+        {
+            *pcbBytesNeeded = dwRequiredSize;
+            dwError = ERROR_INSUFFICIENT_BUFFER;
+            goto done;
+        }
+
+        lpFailureActions->cActions = 0; 
+        lpFailureActions->dwResetPeriod = 0;
+        lpFailureActions->lpCommand = NULL;
+        lpFailureActions->lpRebootMsg = NULL;
+        lpFailureActions->lpsaActions = NULL;
+
+        lpStr = (LPWSTR)(lpFailureActions + 1);
+        if (lpRebootMessage)
+        {
+            wcscpy(lpStr, lpRebootMessage);
+            lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpRebootMessage);
+            lpStr += wcslen(lpRebootMessage) + 1;
+        }
+
+        if (lpFailureCommand)
+        {
+            wcscpy(lpStr, lpFailureCommand);
+            lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureCommand);
+            lpStr += wcslen(lpRebootMessage) + 1;
+        }
+        dwError = STATUS_SUCCESS;
         goto done;
     }
 
@@ -2809,20 +4662,25 @@ done:
     if (lpDescription != NULL)
         HeapFree(GetProcessHeap(), 0, lpDescription);
 
+    if (lpRebootMessage != NULL)
+        HeapFree(GetProcessHeap(), 0, lpRebootMessage);
+
+    if (lpFailureCommand != NULL)
+        HeapFree(GetProcessHeap(), 0, lpFailureCommand);
+
     if (hServiceKey != NULL)
         RegCloseKey(hServiceKey);
 
     /* FIXME: Unlock database */
 
-    DPRINT("ScmrQueryServiceConfig2W() done (Error %lu)\n", dwError);
+    DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
 
     return dwError;
 }
 
 
 /* Function 40 */
-DWORD ScmrQueryServiceStatusEx(
-    handle_t BindingHandle,
+DWORD RQueryServiceStatusEx(
     SC_RPC_HANDLE hService,
     SC_STATUS_TYPE InfoLevel,
     LPBYTE lpBuffer,
@@ -2833,7 +4691,7 @@ DWORD ScmrQueryServiceStatusEx(
     PSERVICE_HANDLE hSvc;
     PSERVICE lpService;
 
-    DPRINT("ScmrQueryServiceStatusEx() called\n");
+    DPRINT("RQueryServiceStatusEx() called\n");
 
     if (ScmShutdown)
         return ERROR_SHUTDOWN_IN_PROGRESS;
@@ -2882,8 +4740,7 @@ DWORD ScmrQueryServiceStatusEx(
 
 
 /* Function 41 */
-DWORD ScmrEnumServicesStatusExA(
-    handle_t BindingHandle,
+DWORD REnumServicesStatusExA(
     SC_RPC_HANDLE hSCManager,
     SC_ENUM_TYPE InfoLevel,
     DWORD dwServiceType,
@@ -2893,18 +4750,121 @@ DWORD ScmrEnumServicesStatusExA(
     LPBOUNDED_DWORD_256K pcbBytesNeeded,
     LPBOUNDED_DWORD_256K lpServicesReturned,
     LPBOUNDED_DWORD_256K lpResumeIndex,
-    LPSTR pszGroupName)
+    LPCSTR pszGroupName)
 {
-    UNIMPLEMENTED;
-    *pcbBytesNeeded = 0;
-    *lpServicesReturned = 0;
-    return ERROR_CALL_NOT_IMPLEMENTED;
+    LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL;
+    LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL;
+    LPWSTR lpStringPtrW;
+    LPSTR lpStringPtrA;
+    LPWSTR pszGroupNameW = NULL;
+    DWORD dwError;
+    DWORD dwServiceCount;
+
+    DPRINT("REnumServicesStatusExA() called\n");
+
+    if (pszGroupName)
+    {
+        pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR));
+        if (!pszGroupNameW)
+        {
+             DPRINT1("Failed to allocate buffer!\n");
+             return ERROR_NOT_ENOUGH_MEMORY;
+        }
+
+        MultiByteToWideChar(CP_ACP,
+                            0,
+                            pszGroupName,
+                            -1,
+                            pszGroupNameW,
+                            strlen(pszGroupName) + 1);
+    }
+
+    if ((cbBufSize > 0) && (lpBuffer))
+    {
+        lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize);
+        if (!lpStatusPtrW)
+        {
+            DPRINT1("Failed to allocate buffer!\n");
+            return ERROR_NOT_ENOUGH_MEMORY;
+        }
+    }
+
+    dwError = REnumServicesStatusExW(hSCManager,
+                                     InfoLevel,
+                                     dwServiceType,
+                                     dwServiceState,
+                                     (LPBYTE)lpStatusPtrW,
+                                     cbBufSize,
+                                     pcbBytesNeeded,
+                                     lpServicesReturned,
+                                     lpResumeIndex,
+                                     pszGroupNameW);
+
+    /* if no services were returned then we are Done */
+    if (*lpServicesReturned == 0)
+        goto Done;
+
+    lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer;
+    lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
+                  *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA));
+    lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW + 
+                  *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
+
+    for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
+    {
+        /* Copy the service name */
+        WideCharToMultiByte(CP_ACP,
+                            0,
+                            lpStringPtrW,
+                            -1,
+                            lpStringPtrA,
+                            wcslen(lpStringPtrW),
+                            0,
+                            0);
+
+        lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
+        lpStringPtrA += wcslen(lpStringPtrW) + 1;
+        lpStringPtrW += wcslen(lpStringPtrW) + 1;
+
+        /* Copy the display name */
+        WideCharToMultiByte(CP_ACP,
+                            0,
+                            lpStringPtrW,
+                            -1,
+                            lpStringPtrA,
+                            wcslen(lpStringPtrW),
+                            0,
+                            0);
+
+        lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
+        lpStringPtrA += wcslen(lpStringPtrW) + 1;
+        lpStringPtrW += wcslen(lpStringPtrW) + 1;
+
+        /* Copy the status information */
+        memcpy(&lpStatusPtrA->ServiceStatusProcess,
+               &lpStatusPtrW->ServiceStatusProcess,
+               sizeof(SERVICE_STATUS));
+
+        lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrW->ServiceStatusProcess.dwProcessId; /* FIXME */
+        lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
+        lpStatusPtrA++;
+    }
+
+Done:;
+    if (pszGroupNameW)
+        HeapFree(GetProcessHeap(), 0, pszGroupNameW);
+
+    if (lpStatusPtrW)
+        HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
+
+    DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError);
+
+    return dwError;
 }
 
 
 /* Function 42 */
-DWORD ScmrEnumServicesStatusExW(
-    handle_t BindingHandle,
+DWORD REnumServicesStatusExW(
     SC_RPC_HANDLE hSCManager,
     SC_ENUM_TYPE InfoLevel,
     DWORD dwServiceType,
@@ -2914,7 +4874,7 @@ DWORD ScmrEnumServicesStatusExW(
     LPBOUNDED_DWORD_256K pcbBytesNeeded,
     LPBOUNDED_DWORD_256K lpServicesReturned,
     LPBOUNDED_DWORD_256K lpResumeIndex,
-    LPWSTR pszGroupName)
+    LPCWSTR pszGroupName)
 {
     PMANAGER_HANDLE hManager;
     PSERVICE lpService;
@@ -2925,11 +4885,11 @@ DWORD ScmrEnumServicesStatusExW(
     DWORD dwRequiredSize;
     DWORD dwServiceCount;
     DWORD dwSize;
-    DWORD dwLastResumeCount;
+    DWORD dwLastResumeCount = 0;
     LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
     LPWSTR lpStringPtr;
 
-    DPRINT("ScmrEnumServicesStatusExW() called\n");
+    DPRINT("REnumServicesStatusExW() called\n");
 
     if (ScmShutdown)
         return ERROR_SHUTDOWN_IN_PROGRESS;
@@ -2944,6 +4904,21 @@ DWORD ScmrEnumServicesStatusExW(
         return ERROR_INVALID_HANDLE;
     }
 
+    *pcbBytesNeeded = 0;
+    *lpServicesReturned = 0;
+
+    if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
+    {
+        DPRINT1("Not a valid Service Type!\n");
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
+    {
+        DPRINT1("Not a valid Service State!\n");
+        return ERROR_INVALID_PARAMETER;
+    }
+
     /* Check access rights */
     if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
                                   SC_MANAGER_ENUMERATE_SERVICE))
@@ -2953,10 +4928,7 @@ DWORD ScmrEnumServicesStatusExW(
         return ERROR_ACCESS_DENIED;
     }
 
-    *pcbBytesNeeded = 0;
-    *lpServicesReturned = 0;
-
-    dwLastResumeCount = *lpResumeIndex;
+    if (lpResumeIndex) dwLastResumeCount = *lpResumeIndex;
 
     /* Lock the service list shared */
 
@@ -3067,10 +5039,19 @@ DWORD ScmrEnumServicesStatusExW(
 
     DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
 
-    *lpResumeIndex = dwLastResumeCount;
+    if (lpResumeIndex)
+        *lpResumeIndex = dwLastResumeCount;
+
     *lpServicesReturned = dwServiceCount;
     *pcbBytesNeeded = dwRequiredSize;
 
+    /* If there was no services that matched */
+    if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA))
+    {
+        dwError = ERROR_SERVICE_DOES_NOT_EXIST;
+        goto Done;
+    }
+
     lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer;
     lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
                            dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
@@ -3141,21 +5122,27 @@ DWORD ScmrEnumServicesStatusExW(
         {
             break;
         }
+    }
 
+    if (dwError == 0) 
+    {
+        *pcbBytesNeeded = 0;
+        if (lpResumeIndex)
+            *lpResumeIndex = 0;
     }
 
 Done:;
     /* Unlock the service list */
 
-    DPRINT("ScmrEnumServicesStatusExW() done (Error %lu)\n", dwError);
+    DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError);
 
     return dwError;
 }
 
 
 /* Function 43 */
-DWORD ScmrSendTSMessage(
-    handle_t BindingHandle)
+DWORD RSendTSMessage(
+    handle_t BindingHandle)  /* FIXME */
 {
     UNIMPLEMENTED;
     return ERROR_CALL_NOT_IMPLEMENTED;
@@ -3163,7 +5150,7 @@ DWORD ScmrSendTSMessage(
 
 
 /* Function 44 */
-DWORD ScmrCreateServiceWOW64A(
+DWORD RCreateServiceWOW64A(
     handle_t BindingHandle,
     LPSTR lpServiceName,
     LPSTR lpDisplayName,
@@ -3187,7 +5174,7 @@ DWORD ScmrCreateServiceWOW64A(
 
 
 /* Function 45 */
-DWORD ScmrCreateServiceWOW64W(
+DWORD RCreateServiceWOW64W(
     handle_t BindingHandle,
     LPWSTR lpServiceName,
     LPWSTR lpDisplayName,
@@ -3211,8 +5198,8 @@ DWORD ScmrCreateServiceWOW64W(
 
 
 /* Function 46 */
-DWORD ScmrFunction46(
-    handle_t BindingHandle)
+DWORD RQueryServiceTagInfo(
+    handle_t BindingHandle)  /* FIXME */
 {
     UNIMPLEMENTED;
     return ERROR_CALL_NOT_IMPLEMENTED;
@@ -3220,8 +5207,7 @@ DWORD ScmrFunction46(
 
 
 /* Function 47 */
-DWORD ScmrNotifyServiceStatusChange(
-    handle_t BindingHandle,
+DWORD RNotifyServiceStatusChange(
     SC_RPC_HANDLE hService,
     SC_RPC_NOTIFY_PARAMS NotifyParams,
     GUID *pClientProcessGuid,
@@ -3235,8 +5221,7 @@ DWORD ScmrNotifyServiceStatusChange(
 
 
 /* Function 48 */
-DWORD ScmrGetNotifyResults(
-    handle_t BindingHandle,
+DWORD RGetNotifyResults(
     SC_NOTIFY_RPC_HANDLE hNotify,
     PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
 {
@@ -3246,8 +5231,7 @@ DWORD ScmrGetNotifyResults(
 
 
 /* Function 49 */
-DWORD ScmrCloseNotifyHandle(
-    handle_t BindingHandle,
+DWORD RCloseNotifyHandle(
     LPSC_NOTIFY_RPC_HANDLE phNotify,
     PBOOL pfApcFired)
 {
@@ -3257,8 +5241,7 @@ DWORD ScmrCloseNotifyHandle(
 
 
 /* Function 50 */
-DWORD ScmrControlServiceExA(
-    handle_t BindingHandle,
+DWORD RControlServiceExA(
     SC_RPC_HANDLE hService,
     DWORD dwControl,
     DWORD dwInfoLevel)
@@ -3269,8 +5252,7 @@ DWORD ScmrControlServiceExA(
 
 
 /* Function 51 */
-DWORD ScmrControlServiceExW(
-    handle_t BindingHandle,
+DWORD RControlServiceExW(
     SC_RPC_HANDLE hService,
     DWORD dwControl,
     DWORD dwInfoLevel)
@@ -3281,8 +5263,8 @@ DWORD ScmrControlServiceExW(
 
 
 /* Function 52 */
-DWORD ScmrFunction52(
-    handle_t BindingHandle)
+DWORD RSendPnPMessage(
+    handle_t BindingHandle)  /* FIXME */
 {
     UNIMPLEMENTED;
     return ERROR_CALL_NOT_IMPLEMENTED;
@@ -3290,8 +5272,8 @@ DWORD ScmrFunction52(
 
 
 /* Function 53 */
-DWORD ScmrFunction53(
-    handle_t BindingHandle)
+DWORD RValidatePnPService(
+    handle_t BindingHandle)  /* FIXME */
 {
     UNIMPLEMENTED;
     return ERROR_CALL_NOT_IMPLEMENTED;
@@ -3299,8 +5281,8 @@ DWORD ScmrFunction53(
 
 
 /* Function 54 */
-DWORD ScmrFunction54(
-    handle_t BindingHandle)
+DWORD ROpenServiceStatusHandle(
+    handle_t BindingHandle)  /* FIXME */
 {
     UNIMPLEMENTED;
     return ERROR_CALL_NOT_IMPLEMENTED;
@@ -3308,15 +5290,15 @@ DWORD ScmrFunction54(
 
 
 /* Function 55 */
-DWORD ScmrFunction55(
-    handle_t BindingHandle)
+DWORD RFunction55(
+    handle_t BindingHandle)  /* FIXME */
 {
     UNIMPLEMENTED;
     return ERROR_CALL_NOT_IMPLEMENTED;
 }
 
 
-void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)
+void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
 {
     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
 }
@@ -3342,5 +5324,4 @@ void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify)
 {
 }
 
-
 /* EOF */