Implement QueryServiceConfigW.
authorEric Kohl <eric.kohl@reactos.org>
Sun, 18 Dec 2005 19:50:53 +0000 (19:50 +0000)
committerEric Kohl <eric.kohl@reactos.org>
Sun, 18 Dec 2005 19:50:53 +0000 (19:50 +0000)
svn path=/trunk/; revision=20255

reactos/include/idl/svcctl.idl
reactos/lib/advapi32/service/scm.c
reactos/subsys/system/services/database.c
reactos/subsys/system/services/driver.c
reactos/subsys/system/services/rpcserver.c
reactos/subsys/system/services/services.h

index bfdaa0f..311203e 100644 (file)
@@ -5,6 +5,7 @@
 //#include <windef.h>\r
 //#include <winsvc.h>\r
 \r
+#define BYTE unsigned char\r
 #define DWORD unsigned long\r
 #define BOOL unsigned long\r
 #define SC_HANDLE unsigned int\r
@@ -113,6 +114,25 @@ cpp_quote("#endif")
                            [in] DWORD dwPasswordLength,\r
                            [out] SC_HANDLE *hService);\r
 \r
+  /* Function 13 */\r
+  DWORD ScmrEnumDependentServicesW([in] handle_t BindingHandle,\r
+                                   [in] SC_HANDLE hService,\r
+                                   [in] DWORD dwServiceState,\r
+                                   [out, size_is(cbBufSize)] BYTE *lpServices,\r
+                                   [in] DWORD cbBufSize,\r
+                                   [out] LPDWORD pcbBytesNeeded,\r
+                                   [out] LPDWORD lpServicesReturned);\r
+\r
+  /* Function 14 */\r
+  DWORD ScmrEnumServicesStatusW([in] handle_t BindingHandle,\r
+                                [in] SC_HANDLE hSCManager,\r
+                                [in] DWORD dwServiceType,\r
+                                [in] DWORD dwServiceState,\r
+                                [out, size_is(dwBufSize)] BYTE *lpServices,\r
+                                [in] DWORD dwBufSize,\r
+                                [out] LPDWORD pcbBytesNeeded,\r
+                                [out] LPDWORD lpServicesReturned,\r
+                                [in, out] LPDWORD lpResumeHandle); /* FIXME: unique */\r
 \r
   /* Function 15 */\r
   DWORD ScmrOpenSCManagerW([in] handle_t BindingHandle,\r
@@ -128,6 +148,13 @@ cpp_quote("#endif")
                              [in] DWORD dwDesiredAccess,\r
                              [out] SC_HANDLE *hScm);\r
 \r
+  /* Function 17 */\r
+  DWORD ScmrQueryServiceConfigW([in] handle_t BindingHandle,\r
+                                [in] SC_HANDLE hService,\r
+                                [out, unique, size_is(cbBufSize)] BYTE *lpServiceConfig,\r
+                                [in] DWORD cbBufSize,\r
+                                [out] DWORD *pcbBytesNeeded);\r
+\r
 \r
   /* Function 20 */\r
   DWORD ScmrGetServiceDisplayNameW([in] handle_t BindingHandle,\r
index bbc8bdd..dc0f137 100644 (file)
@@ -204,7 +204,7 @@ CloseServiceHandle(SC_HANDLE hSCObject)
 /**********************************************************************
  *  ControlService
  *
- * @unimplemented
+ * @implemented
  */
 BOOL STDCALL
 ControlService(SC_HANDLE hService,
@@ -262,20 +262,19 @@ ControlServiceEx(IN SC_HANDLE hService,
  */
 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,19 +363,18 @@ CreateServiceA(
     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);
@@ -521,13 +519,12 @@ EnumDependentServicesA(
  */
 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 @@ EnumDependentServicesW(
  */
 BOOL
 STDCALL
-EnumServiceGroupW (
+EnumServiceGroupW(
     DWORD   Unknown0,
     DWORD   Unknown1,
     DWORD   Unknown2,
@@ -566,7 +563,7 @@ EnumServiceGroupW (
  */
 BOOL
 STDCALL
-EnumServicesStatusA (
+EnumServicesStatusA(
     SC_HANDLE               hSCManager,
     DWORD                   dwServiceType,
     DWORD                   dwServiceState,
@@ -582,6 +579,58 @@ EnumServicesStatusA (
 }
 
 
+/**********************************************************************
+ *  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
  *
@@ -630,29 +679,6 @@ EnumServicesStatusExW(SC_HANDLE  hSCManager,
 }
 
 
-/**********************************************************************
- *  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
  *
@@ -1007,30 +1033,67 @@ QueryServiceConfigA(
 /**********************************************************************
  *  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))
-    {
-        memset(lpServiceConfig, 0, *pcbBytesNeeded);
-        return TRUE;
-    }
-    else
+    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)
     {
-        *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
  *
index 8473509..efbe3d6 100644 (file)
@@ -51,6 +51,7 @@ LIST_ENTRY GroupListHead;
 LIST_ENTRY ServiceListHead;
 
 static RTL_RESOURCE DatabaseLock;
+static DWORD dwResumeCount = 1;
 
 
 /* FUNCTIONS *****************************************************************/
@@ -113,6 +114,35 @@ ScmGetServiceEntryByDisplayName(LPWSTR lpDisplayName)
 }
 
 
+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 @@ ScmCreateNewServiceRecord(LPWSTR lpServiceName,
     lpService->lpServiceName = lpService->szServiceName;
     lpService->lpDisplayName = lpService->lpServiceName;
 
+    /* Set the resume count */
+    lpService->dwResumeCount = dwResumeCount++;
+
     /* Append service entry */
     InsertTailList(&ServiceListHead,
                    &lpService->ServiceListEntry);
index 24c634b..9764200 100644 (file)
@@ -70,6 +70,145 @@ ScmUnloadDriver(PSERVICE lpService)
 }\r
 \r
 \r
+DWORD\r
+ScmGetDriverStatus(PSERVICE lpService,\r
+                   LPSERVICE_STATUS lpServiceStatus)\r
+{\r
+    OBJECT_ATTRIBUTES ObjectAttributes;\r
+    UNICODE_STRING DirName;\r
+    HANDLE DirHandle;\r
+    NTSTATUS Status = STATUS_SUCCESS;\r
+    POBJECT_DIRECTORY_INFORMATION DirInfo;\r
+    ULONG BufferLength;\r
+    ULONG DataLength;\r
+    ULONG Index;\r
+    DWORD dwError = ERROR_SUCCESS;\r
+    BOOLEAN bFound = FALSE;\r
+\r
+    DPRINT1("ScmGetDriverStatus() called\n");\r
+\r
+    memset(lpServiceStatus, 0, sizeof(SERVICE_STATUS));\r
+\r
+    if (lpService->Status.dwServiceType == SERVICE_KERNEL_DRIVER)\r
+    {\r
+        RtlInitUnicodeString(&DirName,\r
+                             L"\\Driver");\r
+    }\r
+    else\r
+    {\r
+        RtlInitUnicodeString(&DirName,\r
+                             L"\\FileSystem");\r
+    }\r
+\r
+    InitializeObjectAttributes(&ObjectAttributes,\r
+                               &DirName,\r
+                               0,\r
+                               NULL,\r
+                               NULL);\r
+\r
+    Status = NtOpenDirectoryObject(&DirHandle,\r
+                                   DIRECTORY_QUERY | DIRECTORY_TRAVERSE,\r
+                                   &ObjectAttributes);\r
+    if (!NT_SUCCESS(Status))\r
+    {\r
+        DPRINT1("NtOpenDirectoryObject() failed!\n");\r
+        return RtlNtStatusToDosError(Status);\r
+    }\r
+\r
+    BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +\r
+                   2 * MAX_PATH * sizeof(WCHAR);\r
+    DirInfo = HeapAlloc(GetProcessHeap(),\r
+                        HEAP_ZERO_MEMORY,\r
+                        BufferLength);\r
+\r
+    Index = 0;\r
+    while (TRUE)\r
+    {\r
+        Status = NtQueryDirectoryObject(DirHandle,\r
+                                        DirInfo,\r
+                                        BufferLength,\r
+                                        TRUE,\r
+                                        FALSE,\r
+                                        &Index,\r
+                                        &DataLength);\r
+        if (Status == STATUS_NO_MORE_ENTRIES)\r
+        {\r
+            DPRINT("No more services\n");\r
+            break;\r
+        }\r
+\r
+        if (!NT_SUCCESS(Status))\r
+            break;\r
+\r
+        DPRINT("Comparing: '%S'  '%wZ'\n", lpService->lpServiceName, &DirInfo->ObjectName);\r
+\r
+        if (_wcsicmp(lpService->lpServiceName, DirInfo->ObjectName.Buffer) == 0)\r
+        {\r
+            DPRINT1("Found: '%S'  '%wZ'\n",\r
+                    lpService->lpServiceName, &DirInfo->ObjectName);\r
+            bFound = TRUE;\r
+\r
+            break;\r
+        }\r
+    }\r
+\r
+    HeapFree(GetProcessHeap(),\r
+             0,\r
+             DirInfo);\r
+    NtClose(DirHandle);\r
+\r
+    if (!NT_SUCCESS(Status))\r
+    {\r
+        DPRINT1("Status: %lx\n", Status);\r
+        return RtlNtStatusToDosError(Status);\r
+    }\r
+\r
+    if ((bFound == TRUE) &&\r
+        (lpService->Status.dwCurrentState != SERVICE_STOP_PENDING))\r
+    {\r
+        if (lpService->Status.dwCurrentState == SERVICE_STOPPED)\r
+        {\r
+            lpService->Status.dwWin32ExitCode = ERROR_SUCCESS;\r
+            lpService->Status.dwServiceSpecificExitCode = ERROR_SUCCESS;\r
+            lpService->Status.dwCheckPoint = 0;\r
+            lpService->Status.dwWaitHint = 0;\r
+            lpService->Status.dwControlsAccepted = 0;\r
+        }\r
+        else\r
+        {\r
+            lpService->Status.dwCurrentState = SERVICE_RUNNING;\r
+            lpService->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;\r
+\r
+            if (lpService->Status.dwWin32ExitCode == ERROR_SERVICE_NEVER_STARTED)\r
+                lpService->Status.dwWin32ExitCode = ERROR_SUCCESS;\r
+        }\r
+    }\r
+    else\r
+    {\r
+        lpService->Status.dwCurrentState = SERVICE_STOPPED;\r
+        lpService->Status.dwControlsAccepted = 0;\r
+        lpService->Status.dwCheckPoint = 0;\r
+        lpService->Status.dwWaitHint = 0;\r
+\r
+        if (lpService->Status.dwCurrentState == SERVICE_STOP_PENDING)\r
+            lpService->Status.dwWin32ExitCode = ERROR_SUCCESS;\r
+        else\r
+            lpService->Status.dwWin32ExitCode = ERROR_GEN_FAILURE;\r
+    }\r
+\r
+    if (lpServiceStatus != NULL)\r
+    {\r
+        memcpy(lpServiceStatus,\r
+               &lpService->Status,\r
+               sizeof(SERVICE_STATUS));\r
+    }\r
+\r
+    DPRINT1("ScmGetDriverStatus() done (Error: %lu)\n", dwError);\r
+\r
+    return ERROR_SUCCESS;\r
+}\r
+\r
+\r
 DWORD\r
 ScmControlDriver(PSERVICE lpService,\r
                  DWORD dwControl,\r
@@ -97,7 +236,8 @@ ScmControlDriver(PSERVICE lpService,
             break;\r
 \r
         case SERVICE_CONTROL_INTERROGATE:\r
-            dwError = ERROR_INVALID_SERVICE_CONTROL;\r
+            dwError = ScmGetDriverStatus(lpService,\r
+                                         lpServiceStatus);\r
             break;\r
 \r
         default:\r
index 1e5d9b7..4367fc7 100644 (file)
@@ -639,7 +639,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 +654,7 @@ ScmrChangeServiceConfigW(handle_t BiningHandle,
                                  sizeof(DWORD));
         if (dwError != ERROR_SUCCESS)
             goto done;
+
         lpService->dwStartType = dwStartType;
     }
 
@@ -667,6 +669,7 @@ ScmrChangeServiceConfigW(handle_t BiningHandle,
                                  sizeof(DWORD));
         if (dwError != ERROR_SUCCESS)
             goto done;
+
         lpService->dwErrorControl = dwErrorControl;
     }
 
@@ -1032,6 +1035,92 @@ 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;
+
+    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 @@ ScmrOpenServiceW(handle_t BindingHandle,
 }
 
 
+/* 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 @@ ScmrGetServiceDisplayNameW(handle_t BindingHandle,
     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 @@ 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)
@@ -1313,7 +1545,6 @@ ScmrOpenServiceA(handle_t BindingHandle,
 }
 
 
-
 void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)
 {
     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
index 997ec6a..950a84e 100644 (file)
@@ -16,6 +16,7 @@ typedef struct _SERVICE
     LPWSTR lpDisplayName;
     LPWSTR lpServiceGroup;
     BOOL bDeleted;
+    DWORD dwResumeCount;
 
     SERVICE_STATUS Status;
     DWORD dwStartType;
@@ -71,6 +72,7 @@ VOID ScmAutoStartServices(VOID);
 
 PSERVICE ScmGetServiceEntryByName(LPWSTR lpServiceName);
 PSERVICE ScmGetServiceEntryByDisplayName(LPWSTR lpDisplayName);
+PSERVICE ScmGetServiceEntryByResumeCount(DWORD dwResumeCount);
 DWORD ScmCreateNewServiceRecord(LPWSTR lpServiceName,
                                 PSERVICE *lpServiceRecord);
 DWORD ScmMarkServiceForDelete(PSERVICE pService);