[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