advapi32: Fix EnumServicesStatusEx on Wow64.

Signed-off-by: Hans Leidekker <hans@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
oldstable
Hans Leidekker 2017-11-07 14:10:40 +01:00 committed by Alexandre Julliard
parent ac0744d450
commit 445996d31b
3 changed files with 85 additions and 22 deletions

View File

@ -1893,9 +1893,11 @@ 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;
ENUM_SERVICE_STATUS_PROCESSW dummy_status;
DWORD err, i, offset, buflen, count, total_size = 0;
ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
struct enum_service_status_process *entry;
const WCHAR *str;
BYTE *buf;
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));
@ -1910,18 +1912,24 @@ EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD st
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
/* make sure we pass a valid buffer pointer */
if (!services || size < sizeof(*services))
if (!needed || !returned)
{
buffer = (BYTE *)&dummy_status;
size = sizeof(dummy_status);
SetLastError( ERROR_INVALID_ADDRESS );
return FALSE;
}
/* make sure we pass a valid pointer */
buflen = max( size, sizeof(*services) );
if (!(buf = heap_alloc( buflen )))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return FALSE;
}
__TRY
{
err = svcctl_EnumServicesStatusExW( hmngr, SC_ENUM_PROCESS_INFO, type, state, buffer, size, needed,
returned, resume_handle, group );
err = svcctl_EnumServicesStatusExW( hmngr, SC_ENUM_PROCESS_INFO, type, state, buf, buflen, needed,
&count, resume_handle, group );
}
__EXCEPT(rpc_filter)
{
@ -1929,20 +1937,68 @@ EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD st
}
__ENDTRY
*returned = 0;
if (err != ERROR_SUCCESS)
{
/* double the needed size to fit the potentially larger ENUM_SERVICE_STATUS_PROCESSW */
if (err == ERROR_MORE_DATA) *needed *= 2;
heap_free( buf );
SetLastError( err );
return FALSE;
}
for (i = 0; i < *returned; i++)
entry = (struct enum_service_status_process *)buf;
for (i = 0; i < count; 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);
total_size += sizeof(*services);
if (entry->service_name)
{
str = (const WCHAR *)(buf + entry->service_name);
total_size += (strlenW( str ) + 1) * sizeof(WCHAR);
}
if (entry->display_name)
{
str = (const WCHAR *)(buf + entry->display_name);
total_size += (strlenW( str ) + 1) * sizeof(WCHAR);
}
entry++;
}
if (total_size > size)
{
heap_free( buf );
*needed = total_size;
SetLastError( ERROR_MORE_DATA );
return FALSE;
}
offset = count * sizeof(*services);
entry = (struct enum_service_status_process *)buf;
for (i = 0; i < count; i++)
{
DWORD str_size;
str = (const WCHAR *)(buf + entry->service_name);
str_size = (strlenW( str ) + 1) * sizeof(WCHAR);
services[i].lpServiceName = (WCHAR *)((char *)services + offset);
memcpy( services[i].lpServiceName, str, str_size );
offset += str_size;
if (!entry->display_name) services[i].lpDisplayName = NULL;
else
{
str = (const WCHAR *)(buf + entry->display_name);
str_size = (strlenW( str ) + 1) * sizeof(WCHAR);
services[i].lpDisplayName = (WCHAR *)((char *)services + offset);
memcpy( services[i].lpDisplayName, str, str_size );
offset += str_size;
}
services[i].ServiceStatusProcess = entry->service_status_process;
entry++;
}
heap_free( buf );
*needed = 0;
*returned = count;
return TRUE;
}

View File

@ -218,6 +218,13 @@ struct enum_service_status
SERVICE_STATUS service_status;
};
struct enum_service_status_process
{
DWORD service_name;
DWORD display_name;
SERVICE_STATUS_PROCESS service_status_process;
};
typedef struct _SERVICE_RPC_REQUIRED_PRIVILEGES_INFO {
DWORD cbRequiredPrivileges;
[size_is(cbRequiredPrivileges)] BYTE *pRequiredPrivileges;

View File

@ -1461,7 +1461,7 @@ DWORD __cdecl svcctl_EnumServicesStatusExW(
DWORD_PTR offset;
struct sc_manager_handle *manager;
struct service_entry *service;
ENUM_SERVICE_STATUS_PROCESSW *s;
struct enum_service_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));
@ -1489,7 +1489,7 @@ DWORD __cdecl 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(*s);
total_size += (strlenW(service->name) + 1) * sizeof(WCHAR);
if (service->config.lpDisplayName)
{
@ -1505,8 +1505,8 @@ DWORD __cdecl 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_service_status_process *)buffer;
offset = num_services * sizeof(*s);
LIST_FOR_EACH_ENTRY(service, &manager->db->services, struct service_entry, entry)
{
if ((service->status.dwServiceType & type) && map_state(service->status.dwCurrentState, state)
@ -1514,18 +1514,18 @@ DWORD __cdecl 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 += sz;
if (!service->config.lpDisplayName) s->lpDisplayName = NULL;
if (!service->config.lpDisplayName) s->display_name = 0;
else
{
sz = (strlenW(service->config.lpDisplayName) + 1) * sizeof(WCHAR);
memcpy(buffer + offset, service->config.lpDisplayName, sz);
s->lpDisplayName = (WCHAR *)offset;
s->display_name = offset;
offset += sz;
}
fill_status_process(&s->ServiceStatusProcess, service);
fill_status_process(&s->service_status_process, service);
s++;
}
}