[2/2] advapi32: Use an architecture neutral structure to marshall service status information.

Hans Leidekker hans at codeweavers.com
Fri Jun 10 03:14:23 CDT 2011


ENUM_SERVICE_STATUSW and ENUM_SERVICE_STATUS_PROCESSW embed pointers so we cannot
use these structures on Wow64, where the service manager runs as a 64-bit process and
the querying process can be 32-bit.
---
 dlls/advapi32/service.c |  139 ++++++++++++++++++++++++++++++++++++-----------
 include/wine/svcctl.idl |   29 ++++++++---
 programs/services/rpc.c |   53 +++++++++++--------
 3 files changed, 160 insertions(+), 61 deletions(-)

diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c
index 47adf08..d2e1eb6 100644
--- a/dlls/advapi32/service.c
+++ b/dlls/advapi32/service.c
@@ -1513,15 +1513,33 @@ done:
     return ret;
 }
 
+static DWORD enum_services_status( SC_HANDLE hmngr, DWORD type, DWORD state, BYTE *buffer,
+                                   DWORD size, LPDWORD needed, LPDWORD returned )
+{
+    DWORD err;
+
+    __TRY
+    {
+        err = svcctl_EnumServicesStatusW( hmngr, type, state, buffer, size, needed, returned );
+    }
+    __EXCEPT(rpc_filter)
+    {
+        err = map_exception_code( GetExceptionCode() );
+    }
+    __ENDTRY
+
+    return err;
+}
+
 /******************************************************************************
  * EnumServicesStatusW [ADVAPI32.@]
  */
 BOOL WINAPI
-EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
-                     services, DWORD size, LPDWORD needed, LPDWORD returned,
-                     LPDWORD resume_handle )
+EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW services,
+                     DWORD size, LPDWORD needed, LPDWORD returned, LPDWORD resume_handle )
 {
-    DWORD err, i;
+    DWORD err, i, offset, len;
+    struct enum_services_status_process *s;
 
     TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
           returned, resume_handle);
@@ -1534,31 +1552,50 @@ EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_ST
         SetLastError( ERROR_INVALID_HANDLE );
         return FALSE;
     }
-
-    __TRY
+    err = enum_services_status( hmngr, type, state, NULL, 0, needed, returned );
+    if (err != ERROR_MORE_DATA)
     {
-        err = svcctl_EnumServicesStatusW( hmngr, type, state, (BYTE *)services, size, needed, returned );
+        SetLastError( err );
+        return FALSE;
     }
-    __EXCEPT(rpc_filter)
+    len = *needed;
+    if (!(s = HeapAlloc( GetProcessHeap(), 0, len )))
     {
-        err = map_exception_code( GetExceptionCode() );
+        SetLastError( ERROR_OUTOFMEMORY );
+        return FALSE;
     }
-    __ENDTRY
-
+    err = enum_services_status( hmngr, type, state, (BYTE *)s, len, needed, returned );
     if (err != ERROR_SUCCESS)
     {
+        HeapFree( GetProcessHeap(), 0, s );
         SetLastError( err );
         return FALSE;
     }
-
+    offset = *returned * sizeof(ENUM_SERVICE_STATUSW);
+    *needed = offset + (len - *returned * sizeof(struct enum_services_status_process));
+    if (size < *needed)
+    {
+        *returned = 0;
+        HeapFree( GetProcessHeap(), 0, s );
+        SetLastError( ERROR_MORE_DATA );
+        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);
+        services[i].lpServiceName = (WCHAR *)((char *)services + offset);
+        memcpy( services[i].lpServiceName, (char *)s + s[i].service_name_offset, s[i].service_name_size );
+        offset += s[i].service_name_size;
+        if (s[i].display_name_offset)
+        {
+            services[i].lpDisplayName = (WCHAR *)((char *)services + offset);
+            memcpy( services[i].lpDisplayName, (char *)s + s[i].display_name_offset, s[i].display_name_size );
+            offset += s[i].display_name_size;
+        }
+        else services[i].lpDisplayName = NULL;
+        memcpy( &services[i].ServiceStatus, &s[i].service_status_process, sizeof(SERVICE_STATUS) );
     }
-
+    HeapFree( GetProcessHeap(), 0, s );
+    *needed = 0;
     return TRUE;
 }
 
@@ -1631,6 +1668,25 @@ done:
     return ret;
 }
 
+static DWORD enum_services_status_ex( SC_HANDLE hmngr, DWORD type, DWORD state, BYTE *buffer,
+                                      DWORD size, LPDWORD needed, LPDWORD returned, LPCWSTR group )
+{
+    DWORD err;
+
+    __TRY
+    {
+        err = svcctl_EnumServicesStatusExW( hmngr, type, state, buffer, size, needed,
+                                            returned, group );
+    }
+    __EXCEPT(rpc_filter)
+    {
+        err = map_exception_code( GetExceptionCode() );
+    }
+    __ENDTRY
+
+    return err;
+}
+
 /******************************************************************************
  * EnumServicesStatusExW [ADVAPI32.@]
  */
@@ -1639,8 +1695,9 @@ EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD st
                        LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
                        LPDWORD resume_handle, LPCWSTR group )
 {
-    DWORD err, i;
+    DWORD err, i, offset, len;
     ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
+    struct enum_services_status_process *s;
 
     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));
@@ -1658,32 +1715,50 @@ EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD st
         SetLastError( ERROR_INVALID_HANDLE );
         return FALSE;
     }
-
-    __TRY
+    err = enum_services_status_ex( hmngr, type, state, NULL, 0, needed, returned, group );
+    if (err != ERROR_MORE_DATA)
     {
-        err = svcctl_EnumServicesStatusExW( hmngr, type, state, buffer, size, needed,
-                                            returned, group );
+        SetLastError( err );
+        return FALSE;
     }
-    __EXCEPT(rpc_filter)
+    len = *needed;
+    if (!(s = HeapAlloc( GetProcessHeap(), 0, len )))
     {
-        err = map_exception_code( GetExceptionCode() );
+        SetLastError( ERROR_OUTOFMEMORY );
+        return FALSE;
     }
-    __ENDTRY
-
+    err = enum_services_status_ex( hmngr, type, state, (BYTE *)s, len, needed, returned, group );
     if (err != ERROR_SUCCESS)
     {
+        HeapFree( GetProcessHeap(), 0, s );
         SetLastError( err );
         return FALSE;
     }
-
+    offset = *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSW);
+    *needed = offset + (len - *returned * sizeof(struct enum_services_status_process));
+    if (size < *needed)
+    {
+        *returned = 0;
+        HeapFree( GetProcessHeap(), 0, s );
+        SetLastError( ERROR_MORE_DATA );
+        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);
+        services[i].lpServiceName = (WCHAR *)((char *)services + offset);
+        memcpy( services[i].lpServiceName, (char *)s + s[i].service_name_offset, s[i].service_name_size );
+        offset += s[i].service_name_size;
+        if (s[i].display_name_offset)
+        {
+            services[i].lpDisplayName = (WCHAR *)((char *)services + offset);
+            memcpy( services[i].lpDisplayName, (char *)s + s[i].display_name_offset, s[i].display_name_size );
+            offset += s[i].display_name_size;
+        }
+        else services[i].lpDisplayName = NULL;
+        services[i].ServiceStatusProcess = s[i].service_status_process;
     }
-
+    HeapFree( GetProcessHeap(), 0, s );
+    *needed = 0;
     return TRUE;
 }
 
diff --git a/include/wine/svcctl.idl b/include/wine/svcctl.idl
index 895ee2e..d7981f4 100644
--- a/include/wine/svcctl.idl
+++ b/include/wine/svcctl.idl
@@ -86,6 +86,18 @@ typedef struct _SERVICE_STATUS {
   DWORD dwWaitHint;
 } SERVICE_STATUS, *LPSERVICE_STATUS;
 
+typedef struct _SERVICE_STATUS_PROCESS {
+  DWORD dwServiceType;
+  DWORD dwCurrentState;
+  DWORD dwControlsAccepted;
+  DWORD dwWin32ExitCode;
+  DWORD dwServiceSpecificExitCode;
+  DWORD dwCheckPoint;
+  DWORD dwWaitHint;
+  DWORD dwProcessId;
+  DWORD dwServiceFlags;
+} SERVICE_STATUS_PROCESS, *LPSERVICE_STATUS_PROCESS;
+
 typedef enum _SC_STATUS_TYPE {
   SC_STATUS_PROCESS_INFO      = 0
 } SC_STATUS_TYPE;
@@ -121,15 +133,18 @@ typedef struct _SERVICE_FAILURE_ACTIONSW {
 #define SERVICE_CONFIG_SERVICE_SID_INFO         5
 #define SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO 6
 #define SERVICE_CONFIG_PRESHUTDOWN_INFO         7
-
-typedef struct _ENUM_SERVICE_STATUSW {
-    LPWSTR          lpServiceName;
-    LPWSTR          lpDisplayName;
-    SERVICE_STATUS  ServiceStatus;
-} ENUM_SERVICE_STATUSW, *LPENUM_SERVICE_STATUSW;
-
 cpp_quote("#endif")
 
+/* architecture neutral version of ENUM_SERVICE_STATUS_PROCESSW */
+struct enum_services_status_process
+{
+    DWORD                  service_name_offset;
+    DWORD                  service_name_size;
+    DWORD                  display_name_offset;
+    DWORD                  display_name_size;
+    SERVICE_STATUS_PROCESS service_status_process;
+};
+
 typedef [switch_type(DWORD)] union
 {
   [case (SERVICE_CONFIG_DESCRIPTION)] SERVICE_DESCRIPTIONW descr;
diff --git a/programs/services/rpc.c b/programs/services/rpc.c
index 15ea7cf..07a03ac 100644
--- a/programs/services/rpc.c
+++ b/programs/services/rpc.c
@@ -1175,11 +1175,10 @@ DWORD svcctl_EnumServicesStatusW(
     LPDWORD needed,
     LPDWORD returned)
 {
-    DWORD err, sz, total_size, num_services;
-    DWORD_PTR offset;
+    DWORD err, sz, total_size, num_services, offset;
     struct sc_manager_handle *manager;
     struct service_entry *service;
-    ENUM_SERVICE_STATUSW *s;
+    struct enum_services_status_process *s;
 
     WINE_TRACE("(%p, 0x%x, 0x%x, %p, %u, %p, %p)\n", hmngr, type, state, buffer, size, needed, returned);
 
@@ -1196,7 +1195,7 @@ DWORD svcctl_EnumServicesStatusW(
     {
         if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state))
         {
-            total_size += sizeof(ENUM_SERVICE_STATUSW);
+            total_size += sizeof(struct enum_services_status_process);
             total_size += (strlenW(service->name) + 1) * sizeof(WCHAR);
             if (service->config.lpDisplayName)
             {
@@ -1212,26 +1211,31 @@ DWORD svcctl_EnumServicesStatusW(
         scmdatabase_unlock(manager->db);
         return ERROR_MORE_DATA;
     }
-    s = (ENUM_SERVICE_STATUSW *)buffer;
-    offset = num_services * sizeof(ENUM_SERVICE_STATUSW);
+    s = (struct enum_services_status_process *)buffer;
+    offset = num_services * sizeof(struct enum_services_status_process);
     LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
     {
         if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state))
         {
             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 */
+            s->service_name_offset = offset;
+            s->service_name_size = sz;
             offset += sz;
-
-            if (!service->config.lpDisplayName) s->lpDisplayName = NULL;
-            else
+            if (service->config.lpDisplayName)
             {
                 sz = (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
                 memcpy(buffer + offset, service->config.lpDisplayName, sz);
-                s->lpDisplayName = (WCHAR *)offset;
+                s->display_name_offset = offset;
+                s->display_name_size = sz;
                 offset += sz;
             }
-            memcpy(&s->ServiceStatus, &service->status, sizeof(SERVICE_STATUS));
+            else
+            {
+                s->display_name_offset = 0;
+                s->display_name_size = 0;
+            }
+            s->service_status_process = service->status;
             s++;
         }
     }
@@ -1274,7 +1278,7 @@ DWORD svcctl_EnumServicesStatusExW(
     DWORD_PTR offset;
     struct sc_manager_handle *manager;
     struct service_entry *service;
-    ENUM_SERVICE_STATUS_PROCESSW *s;
+    struct enum_services_status_process *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));
@@ -1299,7 +1303,7 @@ DWORD svcctl_EnumServicesStatusExW(
         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 += sizeof(struct enum_services_status_process);
             total_size += (strlenW(service->name) + 1) * sizeof(WCHAR);
             if (service->config.lpDisplayName)
             {
@@ -1315,8 +1319,8 @@ DWORD svcctl_EnumServicesStatusExW(
         scmdatabase_unlock(manager->db);
         return ERROR_MORE_DATA;
     }
-    s = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
-    offset = num_services * sizeof(ENUM_SERVICE_STATUS_PROCESSW);
+    s = (struct enum_services_status_process *)buffer;
+    offset = num_services * sizeof(struct enum_services_status_process);
     LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
     {
         if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state)
@@ -1324,18 +1328,23 @@ DWORD svcctl_EnumServicesStatusExW(
         {
             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 */
+            s->service_name_offset = offset;
+            s->service_name_size = sz;
             offset += sz;
-
-            if (!service->config.lpDisplayName) s->lpDisplayName = NULL;
-            else
+            if (service->config.lpDisplayName)
             {
                 sz = (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
                 memcpy(buffer + offset, service->config.lpDisplayName, sz);
-                s->lpDisplayName = (WCHAR *)offset;
+                s->display_name_offset = offset;
+                s->display_name_size = sz;
                 offset += sz;
             }
-            s->ServiceStatusProcess = service->status;
+            else
+            {
+                s->display_name_offset = 0;
+                s->display_name_size = 0;
+            }
+            s->service_status_process = service->status;
             s++;
         }
     }
-- 
1.7.4.1






More information about the wine-patches mailing list