advapi32: Implement EnumServicesStatusExA/W.

Hans Leidekker hans at codeweavers.com
Fri Oct 29 05:53:37 CDT 2010


---
 dlls/advapi32/service.c       |  128 +++++++++++++++++++++++++++++++++++------
 dlls/advapi32/tests/service.c |   52 ++--------------
 include/wine/svcctl.idl       |   11 ++++
 programs/services/rpc.c       |  104 +++++++++++++++++++++++++++++++++
 4 files changed, 233 insertions(+), 62 deletions(-)

diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c
index 6d96795..5d09d18 100644
--- a/dlls/advapi32/service.c
+++ b/dlls/advapi32/service.c
@@ -1558,31 +1558,125 @@ EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_ST
  * EnumServicesStatusExA [ADVAPI32.@]
  */
 BOOL WINAPI
-EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
-                      DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
-                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
-{
-    FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
-          dwServiceType, dwServiceState, lpServices, cbBufSize,
-          pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_a(pszGroupName));
-    if (lpServicesReturned) *lpServicesReturned = 0;
-    SetLastError (ERROR_ACCESS_DENIED);
-    return FALSE;
+EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
+                       LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
+                       LPDWORD resume_handle, LPCSTR group )
+{
+    BOOL ret;
+    unsigned int i;
+    ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
+    ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
+    WCHAR *groupW = NULL;
+    DWORD sz, n;
+    char *p;
+
+    TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
+          size, needed, returned, resume_handle, debugstr_a(group));
+
+    if (size && !(servicesW = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
+    {
+        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+        return FALSE;
+    }
+    if (group)
+    {
+        int len = MultiByteToWideChar( CP_ACP, 0, group, -1, NULL, 0 );
+        if (!(groupW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
+        {
+            SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+            HeapFree( GetProcessHeap(), 0, servicesW );
+            return FALSE;
+        }
+        MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) );
+    }
+
+    ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, 2 * size,
+                                 needed, returned, resume_handle, groupW );
+    if (!ret) goto done;
+
+    p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA);
+    n = size - (p - (char *)services);
+    ret = FALSE;
+    for (i = 0; i < *returned; i++)
+    {
+        sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
+        if (!sz) goto done;
+        services[i].lpServiceName = p;
+        p += sz;
+        n -= sz;
+        if (servicesW[i].lpDisplayName)
+        {
+            sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
+            if (!sz) goto done;
+            services[i].lpDisplayName = p;
+            p += sz;
+            n -= sz;
+        }
+        services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
+    }
+
+    ret = TRUE;
+
+done:
+    HeapFree( GetProcessHeap(), 0, servicesW );
+    HeapFree( GetProcessHeap(), 0, groupW );
+    return ret;
 }
 
 /******************************************************************************
  * EnumServicesStatusExW [ADVAPI32.@]
  */
 BOOL WINAPI
-EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
-                      DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
-                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
-{
-    FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
-          dwServiceType, dwServiceState, lpServices, cbBufSize,
-          pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_w(pszGroupName));
-    SetLastError (ERROR_ACCESS_DENIED);
-    return FALSE;
+EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
+                       LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
+                       LPDWORD resume_handle, LPCWSTR group )
+{
+    DWORD err, i;
+    ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
+
+    TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
+          size, needed, returned, resume_handle, debugstr_w(group));
+
+    if (resume_handle)
+        FIXME("resume handle not supported\n");
+
+    if (level != SC_ENUM_PROCESS_INFO)
+    {
+        SetLastError( ERROR_INVALID_LEVEL );
+        return FALSE;
+    }
+    if (!hmngr)
+    {
+        SetLastError( ERROR_INVALID_HANDLE );
+        return FALSE;
+    }
+
+    __TRY
+    {
+        err = svcctl_EnumServicesStatusExW( hmngr, type, state, buffer, size, needed,
+                                            returned, group );
+    }
+    __EXCEPT(rpc_filter)
+    {
+        err = map_exception_code( GetExceptionCode() );
+    }
+    __ENDTRY
+
+    if (err != ERROR_SUCCESS)
+    {
+        SetLastError( err );
+        return FALSE;
+    }
+
+    for (i = 0; i < *returned; i++)
+    {
+        /* convert buffer offsets into pointers */
+        services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
+        if (services[i].lpDisplayName)
+            services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
+    }
+
+    return TRUE;
 }
 
 /******************************************************************************
diff --git a/dlls/advapi32/tests/service.c b/dlls/advapi32/tests/service.c
index a171b31..5a4fabd 100644
--- a/dlls/advapi32/tests/service.c
+++ b/dlls/advapi32/tests/service.c
@@ -1398,7 +1398,6 @@ static void test_enum_svc(void)
     SetLastError(0xdeadbeef);
     ret = pEnumServicesStatusExA(NULL, 1, 0, 0, NULL, 0, NULL, NULL, NULL, NULL);
     ok(!ret, "Expected failure\n");
-    todo_wine
     ok(GetLastError() == ERROR_INVALID_LEVEL,
        "Expected ERROR_INVALID_LEVEL, got %d\n", GetLastError());
 
@@ -1406,7 +1405,6 @@ static void test_enum_svc(void)
     SetLastError(0xdeadbeef);
     ret = pEnumServicesStatusExA(NULL, 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL);
     ok(!ret, "Expected failure\n");
-    todo_wine
     ok(GetLastError() == ERROR_INVALID_HANDLE,
        "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
 
@@ -1417,7 +1415,6 @@ static void test_enum_svc(void)
     SetLastError(0xdeadbeef);
     ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL);
     ok(!ret, "Expected failure\n");
-    todo_wine
     ok(GetLastError() == ERROR_INVALID_ADDRESS ||
        GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
        "Unexpected last error %d\n", GetLastError());
@@ -1429,7 +1426,6 @@ static void test_enum_svc(void)
     ok(!ret, "Expected failure\n");
     ok(needed == 0xdeadbeef || broken(needed != 0xdeadbeef), /* nt4 */
        "Expected no change to the needed buffer variable\n");
-    todo_wine
     ok(GetLastError() == ERROR_INVALID_ADDRESS ||
        GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
        "Unexpected last error %d\n", GetLastError());
@@ -1439,13 +1435,10 @@ static void test_enum_svc(void)
     SetLastError(0xdeadbeef);
     ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, NULL, &returned, NULL, NULL);
     ok(!ret, "Expected failure\n");
-    todo_wine
-    {
     ok(returned == 0xdeadbeef, "Expected no change to the number of services variable\n");
     ok(GetLastError() == ERROR_INVALID_ADDRESS ||
        GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
        "Unexpected last error %d\n", GetLastError());
-    }
 
     /* No valid servicetype and servicestate */
     needed = 0xdeadbeef;
@@ -1454,13 +1447,10 @@ static void test_enum_svc(void)
     ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, &needed, &returned, NULL, NULL);
     ok(!ret, "Expected failure\n");
     ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned);
-    todo_wine
-    {
     ok(needed == 0 || broken(needed != 0), /* nt4 */
        "Expected needed buffer size to be set to 0, got %d\n", needed);
     ok(GetLastError() == ERROR_INVALID_PARAMETER,
        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
-    }
 
     /* No valid servicestate */
     needed = 0xdeadbeef;
@@ -1470,13 +1460,10 @@ static void test_enum_svc(void)
                                  &needed, &returned, NULL, NULL);
     ok(!ret, "Expected failure\n");
     ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned);
-    todo_wine
-    {
     ok(needed == 0 || broken(needed != 0), /* nt4 */
        "Expected needed buffer size to be set to 0, got %d\n", needed);
     ok(GetLastError() == ERROR_INVALID_PARAMETER,
        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
-    }
 
     /* No valid servicetype */
     needed = 0xdeadbeef;
@@ -1486,13 +1473,10 @@ static void test_enum_svc(void)
                                  &needed, &returned, NULL, NULL);
     ok(!ret, "Expected failure\n");
     ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned);
-    todo_wine
-    {
     ok(needed == 0 || broken(needed != 0), /* nt4 */
        "Expected needed buffer size to be set to 0, got %d\n", needed);
     ok(GetLastError() == ERROR_INVALID_PARAMETER,
        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
-    }
 
     /* No valid servicetype and servicestate and unknown service group */
     needed = 0xdeadbeef;
@@ -1502,13 +1486,10 @@ static void test_enum_svc(void)
                                  &returned, NULL, "deadbeef_group");
     ok(!ret, "Expected failure\n");
     ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned);
-    todo_wine
-    {
     ok(needed == 0 || broken(needed != 0), /* nt4 */
        "Expected needed buffer size to be set to 0, got %d\n", needed);
     ok(GetLastError() == ERROR_INVALID_PARAMETER,
        "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
-    }
 
     /* All parameters are correct but our access rights are wrong */
     needed = 0xdeadbeef;
@@ -1517,7 +1498,6 @@ static void test_enum_svc(void)
     ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL,
                                  NULL, 0, &needed, &returned, NULL, NULL);
     ok(!ret, "Expected failure\n");
-    todo_wine
     ok(needed == 0 || broken(needed != 0), /* nt4 */
        "Expected needed buffer size to be set to 0, got %d\n", needed);
     ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned);
@@ -1533,7 +1513,6 @@ static void test_enum_svc(void)
     ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL,
                                  NULL, 0, &needed, &returned, NULL, "deadbeef_group");
     ok(!ret, "Expected failure\n");
-    todo_wine
     ok(needed == 0 || broken(needed != 0), /* nt4 */
        "Expected needed buffer size to be set to 0, got %d\n", needed);
     ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned);
@@ -1552,12 +1531,9 @@ static void test_enum_svc(void)
                                  NULL, 0, &needed, &returned, NULL, "deadbeef_group");
     ok(!ret, "Expected failure\n");
     ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned);
-    todo_wine
-    {
     ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed);
     ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST,
        "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError());
-    }
 
     /* TODO: Create a test that makes sure we enumerate all services that don't
      * belong to a group. (specifying "").
@@ -1571,12 +1547,9 @@ static void test_enum_svc(void)
                                  NULL, 0, &needed, &returned, NULL, NULL);
     ok(!ret, "Expected failure\n");
     ok(returned == 0, "Expected no service returned, got %d\n", returned);
-    todo_wine
-    {
     ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size\n");
     ok(GetLastError() == ERROR_MORE_DATA,
        "Expected ERROR_MORE_DATA, got %d\n", GetLastError());
-    }
 
     /* Test to show we get the same needed buffer size for the W-call */
     neededW = 0xdeadbeef;
@@ -1595,12 +1568,9 @@ static void test_enum_svc(void)
     SetLastError(0xdeadbeef);
     ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL,
                                  (BYTE*)exservices, bufsize, &needed, &returned, NULL, NULL);
-    todo_wine
-    {
     ok(ret, "Expected success, got error %u\n", GetLastError());
     ok(needed == 0, "Expected needed buffer to be 0 as we are done\n");
     ok(returned == tempreturned, "Expected the same number of service from this function\n");
-    }
     HeapFree(GetProcessHeap(), 0, exservices);
 
     /* Store the number of returned services */
@@ -1615,13 +1585,10 @@ static void test_enum_svc(void)
     ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL,
                                  (BYTE*)exservices, bufsize, &needed, &returned, NULL, NULL);
     ok(!ret, "Expected failure\n");
-    todo_wine
-    {
     ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size\n");
     ok(returned < tempreturned, "Expected fewer services to be returned\n");
     ok(GetLastError() == ERROR_MORE_DATA,
        "Expected ERROR_MORE_DATA, got %d\n", GetLastError());
-    }
 
     /* Allocate less than the needed bytes, this time with a correct resume handle */
     bufsize = (tempreturned - 1) * sizeof(ENUM_SERVICE_STATUS);
@@ -1632,14 +1599,11 @@ static void test_enum_svc(void)
     ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL,
                                  (BYTE*)exservices, bufsize, &needed, &returned, &resume, NULL);
     ok(!ret, "Expected failure\n");
-    todo_wine
-    {
     ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size\n");
     ok(returned < tempreturned, "Expected fewer services to be returned\n");
-    ok(resume, "Expected a resume handle\n");
+    todo_wine ok(resume, "Expected a resume handle\n");
     ok(GetLastError() == ERROR_MORE_DATA,
        "Expected ERROR_MORE_DATA, got %d\n", GetLastError());
-    }
 
     /* Fetch that last service but pass a bigger buffer size */
     missing = tempreturned - returned;
@@ -1649,11 +1613,8 @@ static void test_enum_svc(void)
     SetLastError(0xdeadbeef);
     ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL,
                                  (BYTE*)exservices, bufsize, &needed, &returned, &resume, NULL);
-    todo_wine
-    {
     ok(ret, "Expected success, got error %u\n", GetLastError());
     ok(needed == 0, "Expected needed buffer to be 0 as we are done\n");
-    }
     ok(returned == missing, "Expected %u services to be returned\n", missing);
     ok(resume == 0, "Expected the resume handle to be 0\n");
     HeapFree(GetProcessHeap(), 0, exservices);
@@ -1693,18 +1654,19 @@ static void test_enum_svc(void)
        "Something wrong in the calculation\n");
 
     /* Get all drivers and services */
-    pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32 | SERVICE_DRIVER,
-                           SERVICE_STATE_ALL, NULL, 0, &needed, &returned, NULL, NULL);
+    ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32 | SERVICE_DRIVER,
+                                 SERVICE_STATE_ALL, NULL, 0, &needed, &returned, NULL, NULL);
+    ok(!ret, "Expected failure\n");
     exservices = HeapAlloc(GetProcessHeap(), 0, needed);
-    pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32 | SERVICE_DRIVER,
-                           SERVICE_STATE_ALL, (BYTE*)exservices, needed, &needed, &returned, NULL, NULL);
+    ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32 | SERVICE_DRIVER,
+                                 SERVICE_STATE_ALL, (BYTE*)exservices, needed, &needed, &returned, NULL, NULL);
+    ok(ret, "Expected success %u\n", GetLastError());
 
     /* Loop through all those returned drivers and services */
     for (i = 0; i < returned; i++)
     {
         SERVICE_STATUS_PROCESS status = exservices[i].ServiceStatusProcess;
 
-
         /* lpServiceName and lpDisplayName should always be filled */
         ok(lstrlenA(exservices[i].lpServiceName) > 0, "Expected a service name\n");
         ok(lstrlenA(exservices[i].lpDisplayName) > 0, "Expected a display name\n");
diff --git a/include/wine/svcctl.idl b/include/wine/svcctl.idl
index 8d6a092..895ee2e 100644
--- a/include/wine/svcctl.idl
+++ b/include/wine/svcctl.idl
@@ -352,4 +352,15 @@ typedef [switch_type(DWORD)] union
         [in] DWORD cbBufSize,
         [out] LPDWORD pcbBytesNeeded
     );
+
+    DWORD svcctl_EnumServicesStatusExW(
+        [in] SC_RPC_HANDLE hmngr,
+        [in] DWORD type,
+        [in] DWORD state,
+        [out,size_is(size)] BYTE *buffer,
+        [in] DWORD size,
+        [out] LPDWORD needed,
+        [out] LPDWORD returned,
+        [in,unique] LPCWSTR group
+    );
 }
diff --git a/programs/services/rpc.c b/programs/services/rpc.c
index 104aa8a..82dc8c6 100644
--- a/programs/services/rpc.c
+++ b/programs/services/rpc.c
@@ -1212,6 +1212,110 @@ DWORD svcctl_EnumServicesStatusW(
     return ERROR_SUCCESS;
 }
 
+struct service_entry *find_service_by_group(struct scmdatabase *db, const WCHAR *group)
+{
+    struct service_entry *service;
+    LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry)
+    {
+        if (service->config.lpLoadOrderGroup && !strcmpiW(group, service->config.lpLoadOrderGroup))
+            return service;
+    }
+    return NULL;
+}
+
+static BOOL match_group(const WCHAR *g1, const WCHAR *g2)
+{
+    if (!g2) return TRUE;
+    if (!g2[0] && (!g1 || !g1[0])) return TRUE;
+    if (g1 && !strcmpW(g1, g2)) return TRUE;
+    return FALSE;
+}
+
+DWORD svcctl_EnumServicesStatusExW(
+    SC_RPC_HANDLE hmngr,
+    DWORD type,
+    DWORD state,
+    BYTE *buffer,
+    DWORD size,
+    LPDWORD needed,
+    LPDWORD returned,
+    LPCWSTR group)
+{
+    DWORD err, sz, total_size, num_services;
+    DWORD_PTR offset;
+    struct sc_manager_handle *manager;
+    struct service_entry *service;
+    ENUM_SERVICE_STATUS_PROCESSW *s;
+
+    WINE_TRACE("(%p, 0x%x, 0x%x, %p, %u, %p, %p, %s)\n", hmngr, type, state, buffer, size,
+               needed, returned, wine_dbgstr_w(group));
+
+    if (!type || !state)
+        return ERROR_INVALID_PARAMETER;
+
+    if ((err = validate_scm_handle(hmngr, SC_MANAGER_ENUMERATE_SERVICE, &manager)) != ERROR_SUCCESS)
+        return err;
+
+    scmdatabase_lock_exclusive(manager->db);
+
+    if (group && !find_service_by_group(manager->db, group))
+    {
+        scmdatabase_unlock(manager->db);
+        return ERROR_SERVICE_DOES_NOT_EXIST;
+    }
+
+    total_size = num_services = 0;
+    LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
+    {
+        if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state)
+            && match_group(service->config.lpLoadOrderGroup, group))
+        {
+            total_size += sizeof(ENUM_SERVICE_STATUS_PROCESSW);
+            total_size += (strlenW(service->name) + 1) * sizeof(WCHAR);
+            if (service->config.lpDisplayName)
+            {
+                total_size += (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
+            }
+            num_services++;
+        }
+    }
+    *returned = 0;
+    *needed = total_size;
+    if (total_size > size)
+    {
+        scmdatabase_unlock(manager->db);
+        return ERROR_MORE_DATA;
+    }
+    s = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
+    offset = num_services * sizeof(ENUM_SERVICE_STATUS_PROCESSW);
+    LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
+    {
+        if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state)
+            && match_group(service->config.lpLoadOrderGroup, group))
+        {
+            sz = (strlenW(service->name) + 1) * sizeof(WCHAR);
+            memcpy(buffer + offset, service->name, sz);
+            s->lpServiceName = (WCHAR *)offset; /* store a buffer offset instead of a pointer */
+            offset += sz;
+
+            if (!service->config.lpDisplayName) s->lpDisplayName = NULL;
+            else
+            {
+                sz = (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
+                memcpy(buffer + offset, service->config.lpDisplayName, sz);
+                s->lpDisplayName = (WCHAR *)offset;
+                offset += sz;
+            }
+            s->ServiceStatusProcess = service->status;
+            s++;
+        }
+    }
+    *returned = num_services;
+    *needed = 0;
+    scmdatabase_unlock(manager->db);
+    return ERROR_SUCCESS;
+}
+
 DWORD svcctl_QueryServiceObjectSecurity(
     void)
 {
-- 
1.7.1






More information about the wine-patches mailing list