Implement QueryServiceConfigW.
Modified: trunk/reactos/include/idl/svcctl.idl
Modified: trunk/reactos/lib/advapi32/service/scm.c
Modified: trunk/reactos/subsys/system/services/database.c
Modified: trunk/reactos/subsys/system/services/driver.c
Modified: trunk/reactos/subsys/system/services/rpcserver.c
Modified: trunk/reactos/subsys/system/services/services.h

Modified: trunk/reactos/include/idl/svcctl.idl
--- trunk/reactos/include/idl/svcctl.idl	2005-12-18 18:14:48 UTC (rev 20254)
+++ trunk/reactos/include/idl/svcctl.idl	2005-12-18 19:50:53 UTC (rev 20255)
@@ -5,6 +5,7 @@
 //#include <windef.h>
 //#include <winsvc.h>
 
+#define BYTE unsigned char
 #define DWORD unsigned long
 #define BOOL unsigned long
 #define SC_HANDLE unsigned int
@@ -113,7 +114,26 @@
                            [in] DWORD dwPasswordLength,
                            [out] SC_HANDLE *hService);
 
+  /* Function 13 */
+  DWORD ScmrEnumDependentServicesW([in] handle_t BindingHandle,
+                                   [in] SC_HANDLE hService,
+                                   [in] DWORD dwServiceState,
+                                   [out, size_is(cbBufSize)] BYTE *lpServices,
+                                   [in] DWORD cbBufSize,
+                                   [out] LPDWORD pcbBytesNeeded,
+                                   [out] LPDWORD lpServicesReturned);
 
+  /* Function 14 */
+  DWORD ScmrEnumServicesStatusW([in] handle_t BindingHandle,
+                                [in] SC_HANDLE hSCManager,
+                                [in] DWORD dwServiceType,
+                                [in] DWORD dwServiceState,
+                                [out, size_is(dwBufSize)] BYTE *lpServices,
+                                [in] DWORD dwBufSize,
+                                [out] LPDWORD pcbBytesNeeded,
+                                [out] LPDWORD lpServicesReturned,
+                                [in, out] LPDWORD lpResumeHandle); /* FIXME: unique */
+
   /* Function 15 */
   DWORD ScmrOpenSCManagerW([in] handle_t BindingHandle,
                            [in, string, unique] LPCWSTR lpMachineName,
@@ -128,7 +148,14 @@
                              [in] DWORD dwDesiredAccess,
                              [out] SC_HANDLE *hScm);
 
+  /* Function 17 */
+  DWORD ScmrQueryServiceConfigW([in] handle_t BindingHandle,
+                                [in] SC_HANDLE hService,
+                                [out, unique, size_is(cbBufSize)] BYTE *lpServiceConfig,
+                                [in] DWORD cbBufSize,
+                                [out] DWORD *pcbBytesNeeded);
 
+
   /* Function 20 */
   DWORD ScmrGetServiceDisplayNameW([in] handle_t BindingHandle,
                                    [in] SC_HANDLE hSCManager,

Modified: trunk/reactos/lib/advapi32/service/scm.c
--- trunk/reactos/lib/advapi32/service/scm.c	2005-12-18 18:14:48 UTC (rev 20254)
+++ trunk/reactos/lib/advapi32/service/scm.c	2005-12-18 19:50:53 UTC (rev 20255)
@@ -204,7 +204,7 @@
 /**********************************************************************
  *  ControlService
  *
- * @unimplemented
+ * @implemented
  */
 BOOL STDCALL
 ControlService(SC_HANDLE hService,
@@ -262,20 +262,19 @@
  */
 SC_HANDLE
 STDCALL
-CreateServiceA(
-    SC_HANDLE   hSCManager,
-    LPCSTR      lpServiceName,
-    LPCSTR      lpDisplayName,
-    DWORD       dwDesiredAccess,
-    DWORD       dwServiceType,
-    DWORD       dwStartType,
-    DWORD       dwErrorControl,
-    LPCSTR      lpBinaryPathName,
-    LPCSTR      lpLoadOrderGroup,
-    LPDWORD     lpdwTagId,
-    LPCSTR      lpDependencies,
-    LPCSTR      lpServiceStartName,
-    LPCSTR      lpPassword)
+CreateServiceA(SC_HANDLE hSCManager,
+               LPCSTR lpServiceName,
+               LPCSTR lpDisplayName,
+               DWORD dwDesiredAccess,
+               DWORD dwServiceType,
+               DWORD dwStartType,
+               DWORD dwErrorControl,
+               LPCSTR lpBinaryPathName,
+               LPCSTR lpLoadOrderGroup,
+               LPDWORD lpdwTagId,
+               LPCSTR lpDependencies,
+               LPCSTR lpServiceStartName,
+               LPCSTR lpPassword)
 {
     SC_HANDLE RetVal = NULL;
     LPWSTR lpServiceNameW = NULL;
@@ -364,20 +363,19 @@
     MultiByteToWideChar(CP_ACP, 0, lpPassword, -1, lpPasswordW, len);
 
     RetVal = CreateServiceW(hSCManager,
-                   lpServiceNameW,
-                   lpDisplayNameW,
-                   dwDesiredAccess,
-                   dwServiceType,
-                   dwStartType,
-                   dwErrorControl,
-                   lpBinaryPathNameW,
-                   lpLoadOrderGroupW,
-                   lpdwTagId,
-                   lpDependenciesW,
-                   lpServiceStartNameW,
-                   lpPasswordW);
+                            lpServiceNameW,
+                            lpDisplayNameW,
+                            dwDesiredAccess,
+                            dwServiceType,
+                            dwStartType,
+                            dwErrorControl,
+                            lpBinaryPathNameW,
+                            lpLoadOrderGroupW,
+                            lpdwTagId,
+                            lpDependenciesW,
+                            lpServiceStartNameW,
+                            lpPasswordW);
 
-
 cleanup:
     HeapFree(GetProcessHeap(), 0, lpServiceNameW);
     HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
@@ -521,13 +519,12 @@
  */
 BOOL
 STDCALL
-EnumDependentServicesW(
-    SC_HANDLE       hService,
-    DWORD           dwServiceState,
-    LPENUM_SERVICE_STATUSW  lpServices,
-    DWORD           cbBufSize,
-    LPDWORD         pcbBytesNeeded,
-    LPDWORD         lpServicesReturned)
+EnumDependentServicesW(SC_HANDLE hService,
+                       DWORD dwServiceState,
+                       LPENUM_SERVICE_STATUSW lpServices,
+                       DWORD cbBufSize,
+                       LPDWORD pcbBytesNeeded,
+                       LPDWORD lpServicesReturned)
 {
     DPRINT1("EnumDependentServicesW is unimplemented\n");
     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
@@ -542,7 +539,7 @@
  */
 BOOL
 STDCALL
-EnumServiceGroupW (
+EnumServiceGroupW(
     DWORD   Unknown0,
     DWORD   Unknown1,
     DWORD   Unknown2,
@@ -566,7 +563,7 @@
  */
 BOOL
 STDCALL
-EnumServicesStatusA (
+EnumServicesStatusA(
     SC_HANDLE               hSCManager,
     DWORD                   dwServiceType,
     DWORD                   dwServiceState,
@@ -583,6 +580,58 @@
 
 
 /**********************************************************************
+ *  EnumServicesStatusW
+ *
+ * @unimplemented
+ */
+BOOL
+STDCALL
+EnumServicesStatusW(SC_HANDLE hSCManager,
+                    DWORD dwServiceType,
+                    DWORD dwServiceState,
+                    LPENUM_SERVICE_STATUSW lpServices,
+                    DWORD cbBufSize,
+                    LPDWORD pcbBytesNeeded,
+                    LPDWORD lpServicesReturned,
+                    LPDWORD lpResumeHandle)
+{
+#if 0
+    DWORD dwError = ERROR_SUCCESS;
+
+    DPRINT1("EnumServicesStatusW() called\n");
+
+    HandleBind();
+
+    dwError = ScmrEnumServicesStatusW(BindingHandle,
+                                      (unsigned int)hSCManager,
+                                      dwServiceType,
+                                      dwServiceState,
+                                      (unsigned char *)lpServices,
+                                      cbBufSize,
+                                      pcbBytesNeeded,
+                                      lpServicesReturned,
+                                      lpResumeHandle);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrEnumServicesStatusW() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+
+
+    DPRINT1("ScmrEnumServicesStatusW() done\n");
+
+    return TRUE;
+#endif
+
+    DPRINT1("EnumServicesStatusW is unimplemented\n");
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return FALSE;
+}
+
+
+/**********************************************************************
  *  EnumServicesStatusExA
  *
  * @unimplemented
@@ -631,29 +680,6 @@
 
 
 /**********************************************************************
- *  EnumServicesStatusW
- *
- * @unimplemented
- */
-BOOL
-STDCALL
-EnumServicesStatusW(
-    SC_HANDLE               hSCManager,
-    DWORD                   dwServiceType,
-    DWORD                   dwServiceState,
-    LPENUM_SERVICE_STATUSW  lpServices,
-    DWORD                   cbBufSize,
-    LPDWORD                 pcbBytesNeeded,
-    LPDWORD                 lpServicesReturned,
-    LPDWORD                 lpResumeHandle)
-{
-    DPRINT1("EnumServicesStatusW is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
-}
-
-
-/**********************************************************************
  *  GetServiceDisplayNameA
  *
  * @unimplemented
@@ -1007,30 +1033,67 @@
 /**********************************************************************
  *  QueryServiceConfigW
  *
- * @unimplemented
+ * @implemented
  */
 BOOL
 STDCALL
-QueryServiceConfigW(
-    SC_HANDLE       hService,
-    LPQUERY_SERVICE_CONFIGW lpServiceConfig,
-    DWORD                   cbBufSize,
-    LPDWORD                 pcbBytesNeeded)
+QueryServiceConfigW(SC_HANDLE hService,
+                    LPQUERY_SERVICE_CONFIGW lpServiceConfig,
+                    DWORD cbBufSize,
+                    LPDWORD pcbBytesNeeded)
 {
-    DPRINT1("QueryServiceConfigW is unimplemented\n");
-    if (lpServiceConfig && cbBufSize >= sizeof(QUERY_SERVICE_CONFIGW))
+    DWORD dwError;
+
+    DPRINT("QueryServiceConfigW(%p, %p, %lu, %p)\n",
+           hService, lpServiceConfig, cbBufSize, pcbBytesNeeded);
+
+    HandleBind();
+
+    /* Call to services.exe using RPC */
+    dwError = ScmrQueryServiceConfigW(BindingHandle,
+                                      (unsigned int)hService,
+                                      (unsigned char *)lpServiceConfig,
+                                      cbBufSize,
+                                      pcbBytesNeeded);
+    if (dwError != ERROR_SUCCESS)
     {
-        memset(lpServiceConfig, 0, *pcbBytesNeeded);
-        return TRUE;
-    }
-    else
-    {
-        *pcbBytesNeeded = sizeof(QUERY_SERVICE_CONFIGW);
-        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        DPRINT("ScmrQueryServiceConfigW() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
         return FALSE;
     }
+
+    /* Adjust the pointers */
+    if (lpServiceConfig->lpBinaryPathName)
+        lpServiceConfig->lpBinaryPathName =
+            (LPWSTR)((ULONG_PTR)lpServiceConfig +
+                     (ULONG_PTR)lpServiceConfig->lpBinaryPathName);
+
+    if (lpServiceConfig->lpLoadOrderGroup)
+        lpServiceConfig->lpLoadOrderGroup =
+            (LPWSTR)((ULONG_PTR)lpServiceConfig +
+                     (ULONG_PTR)lpServiceConfig->lpLoadOrderGroup);
+
+    if (lpServiceConfig->lpDependencies)
+        lpServiceConfig->lpDependencies =
+            (LPWSTR)((ULONG_PTR)lpServiceConfig +
+                     (ULONG_PTR)lpServiceConfig->lpDependencies);
+
+    if (lpServiceConfig->lpServiceStartName)
+        lpServiceConfig->lpServiceStartName =
+            (LPWSTR)((ULONG_PTR)lpServiceConfig +
+                     (ULONG_PTR)lpServiceConfig->lpServiceStartName);
+
+    if (lpServiceConfig->lpDisplayName)
+        lpServiceConfig->lpDisplayName =
+           (LPWSTR)((ULONG_PTR)lpServiceConfig +
+                    (ULONG_PTR)lpServiceConfig->lpDisplayName);
+
+    DPRINT("QueryServiceConfigW() done\n");
+
+    return TRUE;
 }
 
+
 /**********************************************************************
  *  QueryServiceConfig2W
  *

Modified: trunk/reactos/subsys/system/services/database.c
--- trunk/reactos/subsys/system/services/database.c	2005-12-18 18:14:48 UTC (rev 20254)
+++ trunk/reactos/subsys/system/services/database.c	2005-12-18 19:50:53 UTC (rev 20255)
@@ -51,6 +51,7 @@
 LIST_ENTRY ServiceListHead;
 
 static RTL_RESOURCE DatabaseLock;
+static DWORD dwResumeCount = 1;
 
 
 /* FUNCTIONS *****************************************************************/
@@ -113,6 +114,35 @@
 }
 
 
+PSERVICE
+ScmGetServiceEntryByResumeCount(DWORD dwResumeCount)
+{
+    PLIST_ENTRY ServiceEntry;
+    PSERVICE CurrentService;
+
+    DPRINT("ScmGetServiceEntryByResumeCount() called\n");
+
+    ServiceEntry = ServiceListHead.Flink;
+    while (ServiceEntry != &ServiceListHead)
+    {
+        CurrentService = CONTAINING_RECORD(ServiceEntry,
+                                           SERVICE,
+                                           ServiceListEntry);
+        if (CurrentService->dwResumeCount > dwResumeCount)
+        {
+            DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
+            return CurrentService;
+        }
+
+        ServiceEntry = ServiceEntry->Flink;
+    }
+
+    DPRINT("Couldn't find a matching service\n");
+
+    return NULL;
+}
+
+
 static NTSTATUS STDCALL
 CreateGroupOrderListRoutine(PWSTR ValueName,
                             ULONG ValueType,
@@ -233,6 +263,9 @@
     lpService->lpServiceName = lpService->szServiceName;
     lpService->lpDisplayName = lpService->lpServiceName;
 
+    /* Set the resume count */
+    lpService->dwResumeCount = dwResumeCount++;
+
     /* Append service entry */
     InsertTailList(&ServiceListHead,
                    &lpService->ServiceListEntry);

Modified: trunk/reactos/subsys/system/services/driver.c
--- trunk/reactos/subsys/system/services/driver.c	2005-12-18 18:14:48 UTC (rev 20254)
+++ trunk/reactos/subsys/system/services/driver.c	2005-12-18 19:50:53 UTC (rev 20255)
@@ -71,6 +71,145 @@
 
 
 DWORD
+ScmGetDriverStatus(PSERVICE lpService,
+                   LPSERVICE_STATUS lpServiceStatus)
+{
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING DirName;
+    HANDLE DirHandle;
+    NTSTATUS Status = STATUS_SUCCESS;
+    POBJECT_DIRECTORY_INFORMATION DirInfo;
+    ULONG BufferLength;
+    ULONG DataLength;
+    ULONG Index;
+    DWORD dwError = ERROR_SUCCESS;
+    BOOLEAN bFound = FALSE;
+
+    DPRINT1("ScmGetDriverStatus() called\n");
+
+    memset(lpServiceStatus, 0, sizeof(SERVICE_STATUS));
+
+    if (lpService->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
+    {
+        RtlInitUnicodeString(&DirName,
+                             L"\\Driver");
+    }
+    else
+    {
+        RtlInitUnicodeString(&DirName,
+                             L"\\FileSystem");
+    }
+
+    InitializeObjectAttributes(&ObjectAttributes,
+                               &DirName,
+                               0,
+                               NULL,
+                               NULL);
+
+    Status = NtOpenDirectoryObject(&DirHandle,
+                                   DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
+                                   &ObjectAttributes);
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("NtOpenDirectoryObject() failed!\n");
+        return RtlNtStatusToDosError(Status);
+    }
+
+    BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
+                   2 * MAX_PATH * sizeof(WCHAR);
+    DirInfo = HeapAlloc(GetProcessHeap(),
+                        HEAP_ZERO_MEMORY,
+                        BufferLength);
+
+    Index = 0;
+    while (TRUE)
+    {
+        Status = NtQueryDirectoryObject(DirHandle,
+                                        DirInfo,
+                                        BufferLength,
+                                        TRUE,
+                                        FALSE,
+                                        &Index,
+                                        &DataLength);
+        if (Status == STATUS_NO_MORE_ENTRIES)
+        {
+            DPRINT("No more services\n");
+            break;
+        }
+
+        if (!NT_SUCCESS(Status))
+            break;
+
+        DPRINT("Comparing: '%S'  '%wZ'\n", lpService->lpServiceName, &DirInfo->ObjectName);
+
+        if (_wcsicmp(lpService->lpServiceName, DirInfo->ObjectName.Buffer) == 0)
+        {
+            DPRINT1("Found: '%S'  '%wZ'\n",
+                    lpService->lpServiceName, &DirInfo->ObjectName);
+            bFound = TRUE;
+
+            break;
+        }
+    }
+
+    HeapFree(GetProcessHeap(),
+             0,
+             DirInfo);
+    NtClose(DirHandle);
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("Status: %lx\n", Status);
+        return RtlNtStatusToDosError(Status);
+    }
+
+    if ((bFound == TRUE) &&
+        (lpService->Status.dwCurrentState != SERVICE_STOP_PENDING))
+    {
+        if (lpService->Status.dwCurrentState == SERVICE_STOPPED)
+        {
+            lpService->Status.dwWin32ExitCode = ERROR_SUCCESS;
+            lpService->Status.dwServiceSpecificExitCode = ERROR_SUCCESS;
+            lpService->Status.dwCheckPoint = 0;
+            lpService->Status.dwWaitHint = 0;
+            lpService->Status.dwControlsAccepted = 0;
+        }
+        else
+        {
+            lpService->Status.dwCurrentState = SERVICE_RUNNING;
+            lpService->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
+
+            if (lpService->Status.dwWin32ExitCode == ERROR_SERVICE_NEVER_STARTED)
+                lpService->Status.dwWin32ExitCode = ERROR_SUCCESS;
+        }
+    }
+    else
+    {
+        lpService->Status.dwCurrentState = SERVICE_STOPPED;
+        lpService->Status.dwControlsAccepted = 0;
+        lpService->Status.dwCheckPoint = 0;
+        lpService->Status.dwWaitHint = 0;
+
+        if (lpService->Status.dwCurrentState == SERVICE_STOP_PENDING)
+            lpService->Status.dwWin32ExitCode = ERROR_SUCCESS;
+        else
+            lpService->Status.dwWin32ExitCode = ERROR_GEN_FAILURE;
+    }
+
+    if (lpServiceStatus != NULL)
+    {
+        memcpy(lpServiceStatus,
+               &lpService->Status,
+               sizeof(SERVICE_STATUS));
+    }
+
+    DPRINT1("ScmGetDriverStatus() done (Error: %lu)\n", dwError);
+
+    return ERROR_SUCCESS;
+}
+
+
+DWORD
 ScmControlDriver(PSERVICE lpService,
                  DWORD dwControl,
                  LPSERVICE_STATUS lpServiceStatus)
@@ -97,7 +236,8 @@
             break;
 
         case SERVICE_CONTROL_INTERROGATE:
-            dwError = ERROR_INVALID_SERVICE_CONTROL;
+            dwError = ScmGetDriverStatus(lpService,
+                                         lpServiceStatus);
             break;
 
         default:

Modified: trunk/reactos/subsys/system/services/rpcserver.c
--- trunk/reactos/subsys/system/services/rpcserver.c	2005-12-18 18:14:48 UTC (rev 20254)
+++ trunk/reactos/subsys/system/services/rpcserver.c	2005-12-18 19:50:53 UTC (rev 20255)
@@ -639,7 +639,8 @@
                                  sizeof(DWORD));
         if (dwError != ERROR_SUCCESS)
             goto done;
-        /* FIXME: lpService->dwType = dwServiceType; */
+
+        lpService->Status.dwServiceType = dwServiceType;
     }
 
     if (dwStartType != SERVICE_NO_CHANGE)
@@ -653,6 +654,7 @@
                                  sizeof(DWORD));
         if (dwError != ERROR_SUCCESS)
             goto done;
+
         lpService->dwStartType = dwStartType;
     }
 
@@ -667,6 +669,7 @@
                                  sizeof(DWORD));
         if (dwError != ERROR_SUCCESS)
             goto done;
+
         lpService->dwErrorControl = dwErrorControl;
     }
 
@@ -1032,6 +1035,92 @@
 }
 
 
+/* 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;
+
+    DPRINT1("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;
+
+    /* Lock the service list shared */
+
+    lpService = ScmGetServiceEntryByResumeCount(*lpResumeHandle);
+    if (lpService == NULL)
+    {
+        dwError = ERROR_MORE_DATA; /* Hack! */
+        goto done;
+    }
+
+    DPRINT1("Service name: %S\n", lpService->lpServiceName);
+
+//    DPRINT1("Display name: %S\n", lpService->lpDisplayName);
+
+
+    *lpResumeHandle = lpService->dwResumeCount;
+
+done:;
+    /* Unlock the service list */
+
+
+    DPRINT1("ScmrEnumServicesStatusW() done (Error %lu)\n", dwError);
+
+    return dwError;
+}
+
+
 /* Function 15 */
 unsigned long
 ScmrOpenSCManagerW(handle_t BindingHandle,
@@ -1147,6 +1236,149 @@
 }
 
 
+/* Function 17 */
+unsigned long
+ScmrQueryServiceConfigW(handle_t BindingHandle,
+                        unsigned int hService,
+                        unsigned char *lpServiceConfig, /* [out, unique, size_is(cbBufSize)] */
+                        unsigned long cbBufSize,        /* [in] */
+                        unsigned long *pcbBytesNeeded)  /* [out] */
+{
+    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("ScmrQueryServiceConfigW() 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_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;
+
+    dwError = ScmReadString(hServiceKey,
+                            L"ImagePath",
+                            &lpImagePath);
+    if (dwError != ERROR_SUCCESS)
+        goto Done;
+
+    dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
+
+    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 20 */
 unsigned long
 ScmrGetServiceDisplayNameW(handle_t BindingHandle,
@@ -1160,11 +1392,11 @@
     DWORD dwLength;
     DWORD dwError;
 
-    DPRINT1("ScmrGetServiceDisplayNameW() called\n");
-    DPRINT1("hSCManager = %x\n", hSCManager);
-    DPRINT1("lpServiceName: %S\n", lpServiceName);
-    DPRINT1("lpDisplayName: %p\n", lpDisplayName);
-    DPRINT1("*lpcchBuffer: %lu\n", *lpcchBuffer);
+    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)
@@ -1210,11 +1442,11 @@
     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)
@@ -1313,7 +1545,6 @@
 }
 
 
-
 void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)
 {
     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);

Modified: trunk/reactos/subsys/system/services/services.h
--- trunk/reactos/subsys/system/services/services.h	2005-12-18 18:14:48 UTC (rev 20254)
+++ trunk/reactos/subsys/system/services/services.h	2005-12-18 19:50:53 UTC (rev 20255)
@@ -16,6 +16,7 @@
     LPWSTR lpDisplayName;
     LPWSTR lpServiceGroup;
     BOOL bDeleted;
+    DWORD dwResumeCount;
 
     SERVICE_STATUS Status;
     DWORD dwStartType;
@@ -71,6 +72,7 @@
 
 PSERVICE ScmGetServiceEntryByName(LPWSTR lpServiceName);
 PSERVICE ScmGetServiceEntryByDisplayName(LPWSTR lpDisplayName);
+PSERVICE ScmGetServiceEntryByResumeCount(DWORD dwResumeCount);
 DWORD ScmCreateNewServiceRecord(LPWSTR lpServiceName,
                                 PSERVICE *lpServiceRecord);
 DWORD ScmMarkServiceForDelete(PSERVICE pService);