Forward StartServiceA/W to services.exe
[reactos.git] / reactos / subsys / system / services / rpcserver.c
index 1e5d9b7..d88703f 100644 (file)
@@ -444,6 +444,8 @@ ScmrLockServiceDatabase(handle_t BindingHandle,
                                   SC_MANAGER_LOCK))
         return ERROR_ACCESS_DENIED;
 
+//    return ScmLockDatabase(0, hMgr->0xC, hLock);
+
     /* FIXME: Lock the database */
     *hLock = 0x12345678; /* Dummy! */
 
@@ -453,18 +455,204 @@ ScmrLockServiceDatabase(handle_t BindingHandle,
 
 /* Function 4 */
 unsigned long
-ScmrQueryServiceObjectSecurity(handle_t BindingHandle)
+ScmrQueryServiceObjectSecurity(handle_t BindingHandle,
+                               unsigned int hService,
+                               unsigned long dwSecurityInformation,
+                               unsigned char *lpSecurityDescriptor,
+                               unsigned long dwSecuityDescriptorSize,
+                               unsigned long *pcbBytesNeeded)
 {
-    DPRINT1("ScmrQueryServiceSecurity() is unimplemented\n");
+#if 0
+    PSERVICE_HANDLE hSvc;
+    PSERVICE lpService;
+    ULONG DesiredAccess = 0;
+    NTSTATUS Status;
+    DWORD dwBytesNeeded;
+    DWORD dwError;
+
+    DPRINT("ScmrQueryServiceObjectSecurity() called\n");
+
+    hSvc = (PSERVICE_HANDLE)hService;
+    if (hSvc->Handle.Tag != SERVICE_TAG)
+    {
+        DPRINT1("Invalid handle tag!\n");
+        return ERROR_INVALID_HANDLE;
+    }
+
+    if (dwSecurityInformation & (DACL_SECURITY_INFORMATION ||
+                                 GROUP_SECURITY_INFORMATION ||
+                                 OWNER_SECURITY_INFORMATION))
+        DesiredAccess |= READ_CONTROL;
+
+    if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
+        DesiredAccess |= ACCESS_SYSTEM_SECURITY;
+
+    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+                                  DesiredAccess))
+    {
+        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 list */
+
+    Status = RtlQuerySecurityObject(lpService->lpSecurityDescriptor,
+                                    dwSecurityInformation,
+                                    (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
+                                    dwSecuityDescriptorSize,
+                                    &dwBytesNeeded);
+
+    /* FIXME: Unlock the service list */
+
+    if (NT_SUCCESS(Status))
+    {
+        *pcbBytesNeeded = dwBytesNeeded;
+        dwError = STATUS_SUCCESS;
+    }
+    else if (Status == STATUS_BUFFER_TOO_SMALL)
+    {
+        *pcbBytesNeeded = dwBytesNeeded;
+        dwError = ERROR_INSUFFICIENT_BUFFER;
+    }
+    else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
+    {
+        dwError = ERROR_GEN_FAILURE;
+    }
+    else
+    {
+        dwError = RtlNtStatusToDosError(Status);
+    }
+
+    return dwError;
+#endif
+    DPRINT1("ScmrQueryServiceObjectSecurity() is unimplemented\n");
     return ERROR_CALL_NOT_IMPLEMENTED;
 }
 
 
 /* Function 5 */
 unsigned long
-ScmrSetServiceObjectSecurity(handle_t BindingHandle)
+ScmrSetServiceObjectSecurity(handle_t BindingHandle,
+                             unsigned int hService,
+                             unsigned long dwSecurityInformation,
+                             unsigned char *lpSecurityDescriptor,
+                             unsigned long dwSecuityDescriptorSize)
 {
-    DPRINT1("ScmrSetServiceSecurity() is unimplemented\n");
+#if 0
+    PSERVICE_HANDLE hSvc;
+    PSERVICE lpService;
+    ULONG DesiredAccess = 0;
+    HANDLE hToken = NULL;
+    HKEY hServiceKey;
+    NTSTATUS Status;
+    DWORD dwError;
+
+    DPRINT1("ScmrSetServiceObjectSecurity() called\n");
+
+    hSvc = (PSERVICE_HANDLE)hService;
+    if (hSvc->Handle.Tag != SERVICE_TAG)
+    {
+        DPRINT1("Invalid handle tag!\n");
+        return ERROR_INVALID_HANDLE;
+    }
+
+    if (dwSecurityInformation == 0 ||
+        dwSecurityInformation & ~0xF)
+        return 0x57;
+
+    if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
+        return 0x57;
+
+    if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
+        DesiredAccess |= ACCESS_SYSTEM_SECURITY;
+
+    if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
+        DesiredAccess |= 0x40000;
+
+    if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
+        DesiredAccess |= 0x80000;
+
+    if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
+        (((PSECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
+        return 0x57;
+
+    if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
+        (((PSECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
+        return 0x57;
+
+    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+                                  DesiredAccess))
+    {
+        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;
+    }
+
+    if (lpService->bDeleted)
+        return 0x430;
+
+//    RpcImpersonateClient(NULL);
+
+    Status = NtOpenThreadToken(NtCurrentThread(),
+                               8,
+                               1,
+                               &hToken);
+    if (!NT_SUCCESS(Status))
+        return RtlNtStatusToDosError(Status);
+
+//    RpcRevertToSelf();
+
+    /* FIXME: Lock service database */
+
+    Status = RtlSetSecurityObject(dwSecurityInformation,
+                                  (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
+                                  &lpService->lpSecurityDescriptor,
+                                  &ScmServiceMapping,
+                                  hToken);
+    if (!NT_SUCCESS(Status))
+    {
+        dwError = RtlNtStatusToDosError(Status);
+        goto Done;
+    }
+
+    dwError = ScmOpenServiceKey(lpService->lpServiceName,
+                                0x20006,
+                                &hServiceKey);
+    if (dwError != ERROR_SUCCESS)
+        goto Done;
+
+//    dwError = ScmWriteSecurityDescriptor(hServiceKey,
+//                                         lpService->lpSecurityDescriptor);
+
+    RegFlushKey(hServiceKey);
+    RegCloseKey(hServiceKey);
+
+Done:;
+
+    if (hToken != NULL)
+        NtClose(hToken);
+
+    /* FIXME: Unlock service database */
+
+    DPRINT1("ScmrSetServiceObjectSecurity() done (Error %lu)\n", dwError);
+
+    return dwError;
+#endif
+
+    DPRINT1("ScmrSetServiceObjectSecurity() is unimplemented\n");
     return ERROR_CALL_NOT_IMPLEMENTED;
 }
 
@@ -515,7 +703,8 @@ ScmrQueryServiceStatus(handle_t BindingHandle,
 
 /* Function 7 */
 unsigned long
-ScmrSetServiceStatus(handle_t BindingHandle)
+ScmrSetServiceStatus(handle_t BindingHandle,
+                     unsigned long hServiceStatus) /* FIXME */
 {
     DPRINT1("ScmrSetServiceStatus() is unimplemented\n");
     /* FIXME */
@@ -541,7 +730,22 @@ ScmrNotifyBootConfigStatus(handle_t BindingHandle,
 {
     DPRINT1("ScmrNotifyBootConfigStatus() called\n");
     /* FIXME */
-    return ERROR_SUCCESS;
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 10 */
+unsigned long
+ScmrSetServiceBitsW(handle_t BindingHandle,
+                    unsigned long hServiceStatus,
+                    unsigned long dwServiceBits,
+                    unsigned long bSetBitsOn,
+                    unsigned long bUpdateImmediately,
+                    wchar_t *lpString)
+{
+    DPRINT1("ScmrSetServiceBitsW() called\n");
+    /* FIXME */
+    return ERROR_CALL_NOT_IMPLEMENTED;
 }
 
 
@@ -639,7 +843,8 @@ ScmrChangeServiceConfigW(handle_t BiningHandle,
                                  sizeof(DWORD));
         if (dwError != ERROR_SUCCESS)
             goto done;
-        /* FIXME: lpService->dwType = dwServiceType; */
+
+        lpService->Status.dwServiceType = dwServiceType;
     }
 
     if (dwStartType != SERVICE_NO_CHANGE)
@@ -653,6 +858,7 @@ ScmrChangeServiceConfigW(handle_t BiningHandle,
                                  sizeof(DWORD));
         if (dwError != ERROR_SUCCESS)
             goto done;
+
         lpService->dwStartType = dwStartType;
     }
 
@@ -667,6 +873,7 @@ ScmrChangeServiceConfigW(handle_t BiningHandle,
                                  sizeof(DWORD));
         if (dwError != ERROR_SUCCESS)
             goto done;
+
         lpService->dwErrorControl = dwErrorControl;
     }
 
@@ -1032,6 +1239,225 @@ done:;
 }
 
 
+/* Function 13 */
+unsigned long
+ScmrEnumDependentServicesW(handle_t BindingHandle,
+                           unsigned int hService,
+                           unsigned long dwServiceState,
+                           unsigned char *lpServices,
+                           unsigned long cbBufSize,
+                           unsigned long *pcbBytesNeeded,
+                           unsigned long *lpServicesReturned)
+{
+    DWORD dwError = ERROR_SUCCESS;
+
+    DPRINT1("ScmrEnumDependentServicesW() called\n");
+
+    DPRINT1("ScmrEnumDependentServicesW() done (Error %lu)\n", dwError);
+
+    return dwError;
+}
+
+
+/* Function 14 */
+unsigned long
+ScmrEnumServicesStatusW(handle_t BindingHandle,
+                        unsigned int hSCManager,
+                        unsigned long dwServiceType,
+                        unsigned long dwServiceState,
+                        unsigned char *lpServices,
+                        unsigned long dwBufSize,
+                        unsigned long *pcbBytesNeeded,
+                        unsigned long *lpServicesReturned,
+                        unsigned long *lpResumeHandle)
+{
+    PMANAGER_HANDLE hManager;
+    PSERVICE lpService;
+    DWORD dwError = ERROR_SUCCESS;
+    PLIST_ENTRY ServiceEntry;
+    PSERVICE CurrentService;
+    DWORD dwState;
+    DWORD dwRequiredSize;
+    DWORD dwServiceCount;
+    DWORD dwSize;
+    DWORD dwLastResumeCount;
+    LPENUM_SERVICE_STATUSW lpStatusPtr;
+    LPWSTR lpStringPtr;
+
+    DPRINT("ScmrEnumServicesStatusW() called\n");
+
+    if (ScmShutdown)
+        return ERROR_SHUTDOWN_IN_PROGRESS;
+
+    hManager = (PMANAGER_HANDLE)hSCManager;
+    if (hManager->Handle.Tag != MANAGER_TAG)
+    {
+        DPRINT1("Invalid manager handle!\n");
+        return ERROR_INVALID_HANDLE;
+    }
+
+    /* Check access rights */
+    if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
+                                  SC_MANAGER_ENUMERATE_SERVICE))
+    {
+        DPRINT1("Insufficient access rights! 0x%lx\n",
+                hManager->Handle.DesiredAccess);
+        return ERROR_ACCESS_DENIED;
+    }
+
+    *pcbBytesNeeded = 0;
+    *lpServicesReturned = 0;
+
+    dwLastResumeCount = *lpResumeHandle;
+
+    /* Lock the service list shared */
+
+    lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
+    if (lpService == NULL)
+    {
+        dwError = ERROR_SUCCESS;
+        goto Done;
+    }
+
+    dwRequiredSize = 0;
+    dwServiceCount = 0;
+
+    for (ServiceEntry = &lpService->ServiceListEntry;
+         ServiceEntry != &ServiceListHead;
+         ServiceEntry = ServiceEntry->Flink)
+    {
+        CurrentService = CONTAINING_RECORD(ServiceEntry,
+                                           SERVICE,
+                                           ServiceListEntry);
+
+        if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
+            continue;
+
+        dwState = SERVICE_ACTIVE;
+        if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
+            dwState = SERVICE_INACTIVE;
+
+        if ((dwState & dwServiceState) == 0)
+            continue;
+
+        dwSize = sizeof(ENUM_SERVICE_STATUSW) +
+                 ((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
+        {
+            DPRINT("Service name: %S  no fit\n", CurrentService->lpServiceName);
+            break;
+        }
+
+    }
+
+    DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
+    DPRINT("dwServiceCount: %lu\n", dwServiceCount);
+
+    for (;
+         ServiceEntry != &ServiceListHead;
+         ServiceEntry = ServiceEntry->Flink)
+    {
+        CurrentService = CONTAINING_RECORD(ServiceEntry,
+                                           SERVICE,
+                                           ServiceListEntry);
+
+        if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
+            continue;
+
+        dwState = SERVICE_ACTIVE;
+        if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
+            dwState = SERVICE_INACTIVE;
+
+        if ((dwState & dwServiceState) == 0)
+            continue;
+
+        dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
+                           ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
+                           ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
+
+        dwError = ERROR_MORE_DATA;
+    }
+
+    DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
+
+    *lpResumeHandle = dwLastResumeCount;
+    *lpServicesReturned = dwServiceCount;
+    *pcbBytesNeeded = dwRequiredSize;
+
+    lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpServices;
+    lpStringPtr = (LPWSTR)((ULONG_PTR)lpServices +
+                           dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
+
+    dwRequiredSize = 0;
+    for (ServiceEntry = &lpService->ServiceListEntry;
+         ServiceEntry != &ServiceListHead;
+         ServiceEntry = ServiceEntry->Flink)
+    {
+        CurrentService = CONTAINING_RECORD(ServiceEntry,
+                                           SERVICE,
+                                           ServiceListEntry);
+
+        if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
+            continue;
+
+        dwState = SERVICE_ACTIVE;
+        if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
+            dwState = SERVICE_INACTIVE;
+
+        if ((dwState & dwServiceState) == 0)
+            continue;
+
+        dwSize = sizeof(ENUM_SERVICE_STATUSW) +
+                 ((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)lpServices);
+            lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
+
+            /* Copy the display name */
+            wcscpy(lpStringPtr,
+                   CurrentService->lpDisplayName);
+            lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpServices);
+            lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
+
+            /* Copy the status information */
+            memcpy(&lpStatusPtr->ServiceStatus,
+                   &CurrentService->Status,
+                   sizeof(SERVICE_STATUS));
+
+            lpStatusPtr++;
+            dwRequiredSize += dwSize;
+        }
+        else
+        {
+            break;
+        }
+
+    }
+
+Done:;
+    /* Unlock the service list */
+
+    DPRINT("ScmrEnumServicesStatusW() done (Error %lu)\n", dwError);
+
+    return dwError;
+}
+
+
 /* Function 15 */
 unsigned long
 ScmrOpenSCManagerW(handle_t BindingHandle,
@@ -1147,58 +1573,264 @@ ScmrOpenServiceW(handle_t BindingHandle,
 }
 
 
-/* Function 20 */
+/* Function 17 */
 unsigned long
-ScmrGetServiceDisplayNameW(handle_t BindingHandle,
-                           unsigned int hSCManager,
-                           wchar_t *lpServiceName,
-                           wchar_t *lpDisplayName, /* [out, unique] */
-                           unsigned long *lpcchBuffer)
+ScmrQueryServiceConfigW(handle_t BindingHandle,
+                        unsigned int hService,
+                        unsigned char *lpServiceConfig,
+                        unsigned long cbBufSize,
+                        unsigned long *pcbBytesNeeded)
 {
-//    PMANAGER_HANDLE hManager;
-    PSERVICE lpService;
-    DWORD dwLength;
-    DWORD dwError;
+    DWORD dwError = ERROR_SUCCESS;
+    PSERVICE_HANDLE hSvc;
+    PSERVICE lpService = NULL;
+    HKEY hServiceKey = NULL;
+    LPWSTR lpImagePath = NULL;
+    DWORD dwRequiredSize;
+    LPQUERY_SERVICE_CONFIGW lpConfig;
+    LPWSTR lpStr;
 
-    DPRINT1("ScmrGetServiceDisplayNameW() called\n");
-    DPRINT1("hSCManager = %x\n", hSCManager);
-    DPRINT1("lpServiceName: %S\n", lpServiceName);
-    DPRINT1("lpDisplayName: %p\n", lpDisplayName);
-    DPRINT1("*lpcchBuffer: %lu\n", *lpcchBuffer);
+    DPRINT1("ScmrQueryServiceConfigW() called\n");
 
-//    hManager = (PMANAGER_HANDLE)hSCManager;
-//    if (hManager->Handle.Tag != MANAGER_TAG)
-//    {
-//        DPRINT1("Invalid manager handle!\n");
-//        return ERROR_INVALID_HANDLE;
-//    }
+    if (ScmShutdown)
+        return ERROR_SHUTDOWN_IN_PROGRESS;
 
-    /* Get service database entry */
-    lpService = ScmGetServiceEntryByName(lpServiceName);
-    if (lpService == NULL)
+    hSvc = (PSERVICE_HANDLE)hService;
+    if (hSvc->Handle.Tag != SERVICE_TAG)
     {
-        DPRINT1("Could not find a service!\n");
-        return ERROR_SERVICE_DOES_NOT_EXIST;
+        DPRINT1("Invalid handle tag!\n");
+        return ERROR_INVALID_HANDLE;
     }
 
-    dwLength = wcslen(lpService->lpDisplayName) + 1;
+    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+                                  SERVICE_QUERY_CONFIG))
+    {
+        DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
+        return ERROR_ACCESS_DENIED;
+    }
 
-    if (lpDisplayName != NULL &&
-        *lpcchBuffer >= dwLength)
+    lpService = hSvc->ServiceEntry;
+    if (lpService == NULL)
     {
-        wcscpy(lpDisplayName, lpService->lpDisplayName);
+        DPRINT1("lpService == NULL!\n");
+        return ERROR_INVALID_HANDLE;
     }
 
-    dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
+    /* FIXME: Lock the service database shared */
 
-    *lpcchBuffer = dwLength;
+    dwError = ScmOpenServiceKey(lpService->lpServiceName,
+                                KEY_READ,
+                                &hServiceKey);
+    if (dwError != ERROR_SUCCESS)
+        goto Done;
 
-    return dwError;
-}
+    dwError = ScmReadString(hServiceKey,
+                            L"ImagePath",
+                            &lpImagePath);
+    if (dwError != ERROR_SUCCESS)
+        goto Done;
 
+    dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
 
-/* Function 21 */
-unsigned long
+    if (lpImagePath != NULL)
+        dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
+
+    if (lpService->lpServiceGroup  != NULL)
+        dwRequiredSize += ((wcslen(lpService->lpServiceGroup) + 1) * sizeof(WCHAR));
+
+    /* FIXME: Add Dependencies length*/
+
+    /* FIXME: Add ServiceStartName length*/
+
+    if (lpService->lpDisplayName != NULL)
+        dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
+
+    if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
+    {
+        dwError = ERROR_INSUFFICIENT_BUFFER;
+    }
+    else
+    {
+        lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
+        lpConfig->dwServiceType = lpService->Status.dwServiceType;
+        lpConfig->dwStartType = lpService->dwStartType;
+        lpConfig->dwErrorControl = lpService->dwErrorControl;
+        lpConfig->dwTagId = lpService->dwTag;
+
+        lpStr = (LPWSTR)(lpConfig + 1);
+
+        if (lpImagePath != NULL)
+        {
+            wcscpy(lpStr, lpImagePath);
+            lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+            lpStr += (wcslen(lpImagePath) + 1);
+        }
+        else
+        {
+            lpConfig->lpBinaryPathName = NULL;
+        }
+
+        if (lpService->lpServiceGroup != NULL)
+        {
+            wcscpy(lpStr, lpService->lpServiceGroup);
+            lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+            lpStr += (wcslen(lpService->lpServiceGroup) + 1);
+        }
+        else
+        {
+            lpConfig->lpLoadOrderGroup = NULL;
+        }
+
+        /* FIXME: Append Dependencies */
+        lpConfig->lpDependencies = NULL;
+
+        /* FIXME: Append ServiceStartName */
+        lpConfig->lpServiceStartName = NULL;
+
+        if (lpService->lpDisplayName != NULL)
+        {
+            wcscpy(lpStr, lpService->lpDisplayName);
+            lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
+        }
+        else
+        {
+            lpConfig->lpDisplayName = NULL;
+        }
+    }
+
+    if (pcbBytesNeeded != NULL)
+        *pcbBytesNeeded = dwRequiredSize;
+
+Done:;
+    if (lpImagePath != NULL)
+        HeapFree(GetProcessHeap(), 0, lpImagePath);
+
+    if (hServiceKey != NULL)
+        RegCloseKey(hServiceKey);
+
+    /* FIXME: Unlock the service database */
+
+    DPRINT1("ScmrQueryServiceConfigW() done\n");
+
+    return dwError;
+}
+
+
+/* Function 18 */
+unsigned long
+ScmrQueryServiceLockStatusW(handle_t BindingHandle,
+                            unsigned int hSCManager,
+                            unsigned char *lpLockStatus,   /* [out, unique, size_is(cbBufSize)] */
+                            unsigned long cbBufSize,       /* [in] */
+                            unsigned long *pcbBytesNeeded) /* [out] */
+{
+    DPRINT1("ScmrQueryServiceLockStatusW() called\n");
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 19 */
+unsigned long
+ScmrStartServiceW(handle_t BindingHandle,
+                  unsigned int hService,
+                  unsigned long dwNumServiceArgs,
+                  unsigned char *lpServiceArgBuffer,
+                  unsigned long cbBufSize)
+{
+    DWORD dwError = ERROR_SUCCESS;
+    PSERVICE_HANDLE hSvc;
+    PSERVICE lpService = NULL;
+
+    DPRINT1("ScmrStartServiceW() called\n");
+
+    if (ScmShutdown)
+        return ERROR_SHUTDOWN_IN_PROGRESS;
+
+    hSvc = (PSERVICE_HANDLE)hService;
+    if (hSvc->Handle.Tag != SERVICE_TAG)
+    {
+        DPRINT1("Invalid handle tag!\n");
+        return ERROR_INVALID_HANDLE;
+    }
+
+    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+                                  SERVICE_START))
+    {
+        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;
+    }
+
+    if (lpService->dwStartType == SERVICE_DISABLED)
+        return ERROR_SERVICE_DISABLED;
+
+    if (lpService->bDeleted)
+        return ERROR_SERVICE_MARKED_FOR_DELETE;
+
+    /* FIXME: Start the service */
+
+    return dwError;
+}
+
+
+/* Function 20 */
+unsigned long
+ScmrGetServiceDisplayNameW(handle_t BindingHandle,
+                           unsigned int hSCManager,
+                           wchar_t *lpServiceName,
+                           wchar_t *lpDisplayName, /* [out, unique] */
+                           unsigned long *lpcchBuffer)
+{
+//    PMANAGER_HANDLE hManager;
+    PSERVICE lpService;
+    DWORD dwLength;
+    DWORD dwError;
+
+    DPRINT("ScmrGetServiceDisplayNameW() called\n");
+    DPRINT("hSCManager = %x\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;
+//    }
+
+    /* Get service database entry */
+    lpService = ScmGetServiceEntryByName(lpServiceName);
+    if (lpService == NULL)
+    {
+        DPRINT1("Could not find a service!\n");
+        return ERROR_SERVICE_DOES_NOT_EXIST;
+    }
+
+    dwLength = wcslen(lpService->lpDisplayName) + 1;
+
+    if (lpDisplayName != NULL &&
+        *lpcchBuffer >= dwLength)
+    {
+        wcscpy(lpDisplayName, lpService->lpDisplayName);
+    }
+
+    dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
+
+    *lpcchBuffer = dwLength;
+
+    return dwError;
+}
+
+
+/* Function 21 */
+unsigned long
 ScmrGetServiceKeyNameW(handle_t BindingHandle,
                        unsigned int hSCManager,
                        wchar_t *lpDisplayName,
@@ -1210,11 +1842,11 @@ ScmrGetServiceKeyNameW(handle_t BindingHandle,
     DWORD dwLength;
     DWORD dwError;
 
-    DPRINT1("ScmrGetServiceKeyNameW() called\n");
-    DPRINT1("hSCManager = %x\n", hSCManager);
-    DPRINT1("lpDisplayName: %S\n", lpDisplayName);
-    DPRINT1("lpServiceName: %p\n", lpServiceName);
-    DPRINT1("*lpcchBuffer: %lu\n", *lpcchBuffer);
+    DPRINT("ScmrGetServiceKeyNameW() called\n");
+    DPRINT("hSCManager = %x\n", hSCManager);
+    DPRINT("lpDisplayName: %S\n", lpDisplayName);
+    DPRINT("lpServiceName: %p\n", lpServiceName);
+    DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
 
 //    hManager = (PMANAGER_HANDLE)hSCManager;
 //    if (hManager->Handle.Tag != MANAGER_TAG)
@@ -1247,6 +1879,99 @@ ScmrGetServiceKeyNameW(handle_t BindingHandle,
 }
 
 
+/* Function 22 */
+unsigned long
+ScmrSetServiceBitsA(handle_t BindingHandle,
+                    unsigned long hServiceStatus,
+                    unsigned long dwServiceBits,
+                    unsigned long bSetBitsOn,
+                    unsigned long bUpdateImmediately,
+                    char *lpString)
+{
+    DPRINT1("ScmrSetServiceBitsA() is unimplemented\n");
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 23 */
+unsigned long
+ScmrChangeServiceConfigA(handle_t BiningHandle,
+                         unsigned int hService,
+                         unsigned long dwServiceType,
+                         unsigned long dwStartType,
+                         unsigned long dwErrorControl,
+                         char *lpBinaryPathName,
+                         char *lpLoadOrderGroup,
+                         unsigned long *lpdwTagId,
+                         char *lpDependencies,
+                         unsigned long dwDependenciesLength,
+                         char *lpServiceStartName,
+                         char *lpPassword,
+                         unsigned long dwPasswordLength,
+                         char *lpDisplayName)
+{
+    DPRINT1("ScmrChangeServiceConfigA() is unimplemented\n");
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 24 */
+unsigned long
+ScmrCreateServiceA(handle_t BindingHandle,
+                   unsigned int hSCManager,
+                   char *lpServiceName,
+                   char *lpDisplayName,
+                   unsigned long dwDesiredAccess,
+                   unsigned long dwServiceType,
+                   unsigned long dwStartType,
+                   unsigned long dwErrorControl,
+                   char *lpBinaryPathName,
+                   char *lpLoadOrderGroup,
+                   unsigned long *lpdwTagId, /* in, out */
+                   char *lpDependencies,
+                   unsigned long dwDependenciesLength,
+                   char *lpServiceStartName,
+                   char *lpPassword,
+                   unsigned long dwPasswordLength,
+                   unsigned int *hService) /* out */
+{
+    DPRINT1("ScmrCreateServiceA() is unimplemented\n");
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 25 */
+unsigned long
+ScmrEnumDependentServicesA(handle_t BindingHandle,
+                           unsigned int hService,
+                           unsigned long dwServiceState,
+                           unsigned char *lpServices,
+                           unsigned long cbBufSize,
+                           unsigned long *pcbBytesNeeded,
+                           unsigned long *lpServicesReturned)
+{
+    DPRINT1("ScmrEnumDependentServicesA() is unimplemented\n");
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 26 */
+unsigned long
+ScmrEnumServicesStatusA(handle_t BindingHandle,
+                        unsigned int hSCManager,
+                        unsigned long dwServiceType,
+                        unsigned long dwServiceState,
+                        unsigned char *lpServices,
+                        unsigned long dwBufSize,
+                        unsigned long *pcbBytesNeeded,
+                        unsigned long *lpServicesReturned,
+                        unsigned long *lpResumeHandle)
+{
+    DPRINT1("ScmrEnumServicesAtatusA() is unimplemented\n");
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
 /* Function 27 */
 unsigned long
 ScmrOpenSCManagerA(handle_t BindingHandle,
@@ -1313,6 +2038,397 @@ ScmrOpenServiceA(handle_t BindingHandle,
 }
 
 
+/* Function 29 */
+unsigned long
+ScmrQueryServiceConfigA(handle_t BindingHandle,
+                        unsigned int hService,
+                        unsigned char *lpServiceConfig,
+                        unsigned long cbBufSize,
+                        unsigned long *pcbBytesNeeded)
+{
+    DPRINT1("ScmrQueryServiceConfigA() is unimplemented\n");
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 30 */
+unsigned long
+ScmrQueryServiceLockStatusA(handle_t BindingHandle,
+                            unsigned int hSCManager,
+                            unsigned char *lpLockStatus,   /* [out, unique, size_is(cbBufSize)] */
+                            unsigned long cbBufSize,       /* [in] */
+                            unsigned long *pcbBytesNeeded) /* [out] */
+{
+    DPRINT1("ScmrQueryServiceLockStatusA() called\n");
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 31 */
+unsigned long
+ScmrStartServiceA(handle_t BindingHandle,
+                  unsigned int hService,
+                  unsigned long dwNumServiceArgs,
+                  unsigned char *lpServiceArgBuffer,
+                  unsigned long cbBufSize)
+{
+    DPRINT1("ScmrStartServiceA() called\n");
+    return ERROR_SUCCESS;
+//    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 32 */
+unsigned long
+ScmrGetServiceDisplayNameA(handle_t BindingHandle,
+                           unsigned int hSCManager,
+                           char *lpServiceName,
+                           char *lpDisplayName, /* [out, unique] */
+                           unsigned long *lpcchBuffer)
+{
+    DPRINT1("ScmrGetServiceDisplayNameA() is unimplemented\n");
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 33 */
+unsigned long
+ScmrGetServiceKeyNameA(handle_t BindingHandle,
+                       unsigned int hSCManager,
+                       char *lpDisplayName,
+                       char *lpServiceName, /* [out, unique] */
+                       unsigned long *lpcchBuffer)
+{
+    DPRINT1("ScmrGetServiceKeyNameA() is unimplemented\n");
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 34 */
+/* ScmrGetCurrentGroupStateW */
+
+
+/* Function 35 */
+/* ScmrEnumServiceGroupW */
+
+
+/* Function 36 */
+/* ScmrChangeServiceConfig2A */
+
+
+/* Function 37 */
+unsigned long
+ScmrChangeServiceConfig2W(handle_t BindingHandle,
+                          unsigned int hService,
+                          unsigned long dwInfoLevel,
+                          unsigned char *lpInfo,
+                          unsigned long dwInfoSize)
+{
+    DPRINT1("ScmrChangeServiceConfig2W() is unimplemented\n");
+    return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 38 */
+/* ScmrQueryServiceConfig2A */
+
+
+/* Function 39 */
+/* ScmrQueryServiceConfig2W */
+
+
+/* Function 40 */
+unsigned long
+ScmrQueryServiceStatusEx(handle_t BindingHandle,
+                         unsigned int hService,
+                         unsigned long InfoLevel,
+                         unsigned char *lpBuffer, /* out */
+                         unsigned long cbBufSize,
+                         unsigned long *pcbBytesNeeded) /* out */
+{
+    LPSERVICE_STATUS_PROCESS lpStatus;
+    PSERVICE_HANDLE hSvc;
+    PSERVICE lpService;
+
+    DPRINT("ScmrQueryServiceStatusEx() called\n");
+
+    if (ScmShutdown)
+        return ERROR_SHUTDOWN_IN_PROGRESS;
+
+    if (InfoLevel != SC_STATUS_PROCESS_INFO)
+        return ERROR_INVALID_LEVEL;
+
+    *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
+
+    if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
+        return ERROR_INSUFFICIENT_BUFFER;
+
+    hSvc = (PSERVICE_HANDLE)hService;
+    if (hSvc->Handle.Tag != SERVICE_TAG)
+    {
+        DPRINT1("Invalid handle tag!\n");
+        return ERROR_INVALID_HANDLE;
+    }
+
+    if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
+                                  SERVICE_QUERY_STATUS))
+    {
+        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;
+    }
+
+    lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer;
+
+    /* Return service status information */
+    RtlCopyMemory(lpStatus,
+                  &lpService->Status,
+                  sizeof(SERVICE_STATUS));
+
+    lpStatus->dwProcessId = lpService->ProcessId;      /* FIXME */
+    lpStatus->dwServiceFlags = 0;                      /* FIXME */
+
+    return ERROR_SUCCESS;
+}
+
+
+/* Function 41 */
+/* ScmrEnumServicesStatusExA */
+
+
+/* Function 42 */
+unsigned long
+ScmrEnumServicesStatusExW(handle_t BindingHandle,
+                          unsigned int hSCManager,
+                          unsigned long InfoLevel,
+                          unsigned long dwServiceType,
+                          unsigned long dwServiceState,
+                          unsigned char *lpServices,
+                          unsigned long dwBufSize,
+                          unsigned long *pcbBytesNeeded,
+                          unsigned long *lpServicesReturned,
+                          unsigned long *lpResumeHandle,
+                          wchar_t *pszGroupName)
+{
+    PMANAGER_HANDLE hManager;
+    PSERVICE lpService;
+    DWORD dwError = ERROR_SUCCESS;
+    PLIST_ENTRY ServiceEntry;
+    PSERVICE CurrentService;
+    DWORD dwState;
+    DWORD dwRequiredSize;
+    DWORD dwServiceCount;
+    DWORD dwSize;
+    DWORD dwLastResumeCount;
+    LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
+    LPWSTR lpStringPtr;
+
+    DPRINT("ScmrEnumServicesStatusExW() called\n");
+
+    if (ScmShutdown)
+        return ERROR_SHUTDOWN_IN_PROGRESS;
+
+    if (InfoLevel != SC_ENUM_PROCESS_INFO)
+        return ERROR_INVALID_LEVEL;
+
+    hManager = (PMANAGER_HANDLE)hSCManager;
+    if (hManager->Handle.Tag != MANAGER_TAG)
+    {
+        DPRINT1("Invalid manager handle!\n");
+        return ERROR_INVALID_HANDLE;
+    }
+
+    /* Check access rights */
+    if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
+                                  SC_MANAGER_ENUMERATE_SERVICE))
+    {
+        DPRINT1("Insufficient access rights! 0x%lx\n",
+                hManager->Handle.DesiredAccess);
+        return ERROR_ACCESS_DENIED;
+    }
+
+    *pcbBytesNeeded = 0;
+    *lpServicesReturned = 0;
+
+    dwLastResumeCount = *lpResumeHandle;
+
+    /* Lock the service list shared */
+
+    lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
+    if (lpService == NULL)
+    {
+        dwError = ERROR_SUCCESS;
+        goto Done;
+    }
+
+    dwRequiredSize = 0;
+    dwServiceCount = 0;
+
+    for (ServiceEntry = &lpService->ServiceListEntry;
+         ServiceEntry != &ServiceListHead;
+         ServiceEntry = ServiceEntry->Flink)
+    {
+        CurrentService = CONTAINING_RECORD(ServiceEntry,
+                                           SERVICE,
+                                           ServiceListEntry);
+
+        if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
+            continue;
+
+        dwState = SERVICE_ACTIVE;
+        if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
+            dwState = SERVICE_INACTIVE;
+
+        if ((dwState & dwServiceState) == 0)
+            continue;
+
+        if (pszGroupName)
+        {
+            if (_wcsicmp(pszGroupName, CurrentService->lpServiceGroup))
+                continue;
+        }
+
+        dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
+                 ((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
+        {
+            DPRINT("Service name: %S  no fit\n", CurrentService->lpServiceName);
+            break;
+        }
+
+    }
+
+    DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
+    DPRINT("dwServiceCount: %lu\n", dwServiceCount);
+
+    for (;
+         ServiceEntry != &ServiceListHead;
+         ServiceEntry = ServiceEntry->Flink)
+    {
+        CurrentService = CONTAINING_RECORD(ServiceEntry,
+                                           SERVICE,
+                                           ServiceListEntry);
+
+        if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
+            continue;
+
+        dwState = SERVICE_ACTIVE;
+        if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
+            dwState = SERVICE_INACTIVE;
+
+        if ((dwState & dwServiceState) == 0)
+            continue;
+
+        if (pszGroupName)
+        {
+            if (_wcsicmp(pszGroupName, CurrentService->lpServiceGroup))
+                continue;
+        }
+
+        dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
+                           ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
+                           ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
+
+        dwError = ERROR_MORE_DATA;
+    }
+
+    DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
+
+    *lpResumeHandle = dwLastResumeCount;
+    *lpServicesReturned = dwServiceCount;
+    *pcbBytesNeeded = dwRequiredSize;
+
+    lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpServices;
+    lpStringPtr = (LPWSTR)((ULONG_PTR)lpServices +
+                           dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
+
+    dwRequiredSize = 0;
+    for (ServiceEntry = &lpService->ServiceListEntry;
+         ServiceEntry != &ServiceListHead;
+         ServiceEntry = ServiceEntry->Flink)
+    {
+        CurrentService = CONTAINING_RECORD(ServiceEntry,
+                                           SERVICE,
+                                           ServiceListEntry);
+
+        if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
+            continue;
+
+        dwState = SERVICE_ACTIVE;
+        if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
+            dwState = SERVICE_INACTIVE;
+
+        if ((dwState & dwServiceState) == 0)
+            continue;
+
+        if (pszGroupName)
+        {
+            if (_wcsicmp(pszGroupName, CurrentService->lpServiceGroup))
+                continue;
+        }
+
+        dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
+                 ((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)lpServices);
+            lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
+
+            /* Copy the display name */
+            wcscpy(lpStringPtr,
+                   CurrentService->lpDisplayName);
+            lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpServices);
+            lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
+
+            /* Copy the status information */
+            memcpy(&lpStatusPtr->ServiceStatusProcess,
+                   &CurrentService->Status,
+                   sizeof(SERVICE_STATUS));
+            lpStatusPtr->ServiceStatusProcess.dwProcessId = CurrentService->ProcessId; /* FIXME */
+            lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
+
+            lpStatusPtr++;
+            dwRequiredSize += dwSize;
+        }
+        else
+        {
+            break;
+        }
+
+    }
+
+Done:;
+    /* Unlock the service list */
+
+    DPRINT("ScmrEnumServicesStatusExW() done (Error %lu)\n", dwError);
+
+    return dwError;
+}
+
+
+/* Function 43 */
+/* ScmrSendTSMessage */
+
 
 void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)
 {