Commit ae7d41bf authored by Hans Leidekker's avatar Hans Leidekker Committed by Alexandre Julliard

advapi32: Implement EnumServicesStatusA/W.

parent c287ed22
......@@ -1455,32 +1455,103 @@ BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffe
* EnumServicesStatusA [ADVAPI32.@]
*/
BOOL WINAPI
EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
DWORD cbBufSize, LPDWORD pcbBytesNeeded,
LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
services, DWORD size, LPDWORD needed, LPDWORD returned,
LPDWORD resume_handle )
{
FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
dwServiceType, dwServiceState, lpServices, cbBufSize,
pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
SetLastError (ERROR_ACCESS_DENIED);
return FALSE;
BOOL ret;
unsigned int i;
ENUM_SERVICE_STATUSW *servicesW = NULL;
DWORD sz, n;
char *p;
TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
returned, resume_handle);
if (size && !(servicesW = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return FALSE;
}
ret = EnumServicesStatusW( hmngr, type, state, servicesW, 2 * size, needed, returned, resume_handle );
if (!ret) goto done;
p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
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].ServiceStatus = servicesW[i].ServiceStatus;
}
ret = TRUE;
done:
HeapFree( GetProcessHeap(), 0, servicesW );
return ret;
}
/******************************************************************************
* EnumServicesStatusW [ADVAPI32.@]
*/
BOOL WINAPI
EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
DWORD cbBufSize, LPDWORD pcbBytesNeeded,
LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
services, DWORD size, LPDWORD needed, LPDWORD returned,
LPDWORD resume_handle )
{
FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
dwServiceType, dwServiceState, lpServices, cbBufSize,
pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
SetLastError (ERROR_ACCESS_DENIED);
return FALSE;
DWORD err, i;
TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
returned, resume_handle);
if (resume_handle)
FIXME("resume handle not supported\n");
if (!hmngr)
{
SetLastError( ERROR_INVALID_HANDLE );
return FALSE;
}
__TRY
{
err = svcctl_EnumServicesStatusW( hmngr, type, state, (BYTE *)services, size, needed, returned );
}
__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;
}
/******************************************************************************
......
......@@ -122,6 +122,12 @@ typedef struct _SERVICE_FAILURE_ACTIONSW {
#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")
typedef [switch_type(DWORD)] union
......@@ -220,7 +226,15 @@ typedef [switch_type(DWORD)] union
DWORD svcctl_EnumDependentServicesW(/* FIXME */);
/* Not compatible with Windows function 0x0e */
DWORD svcctl_EnumServicesStatusW(/* FIXME */);
DWORD svcctl_EnumServicesStatusW(
[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
);
/* Compatible with Windows function 0x0f */
DWORD svcctl_OpenSCManagerW(
......
......@@ -1115,6 +1115,103 @@ DWORD svcctl_UnlockServiceDatabase(
return ERROR_SUCCESS;
}
static BOOL map_state(DWORD state, DWORD mask)
{
switch (state)
{
case SERVICE_START_PENDING:
case SERVICE_STOP_PENDING:
case SERVICE_RUNNING:
case SERVICE_CONTINUE_PENDING:
case SERVICE_PAUSE_PENDING:
case SERVICE_PAUSED:
if (SERVICE_ACTIVE & mask) return TRUE;
break;
case SERVICE_STOPPED:
if (SERVICE_INACTIVE & mask) return TRUE;
break;
default:
WINE_ERR("unknown state %u\n", state);
break;
}
return FALSE;
}
DWORD svcctl_EnumServicesStatusW(
SC_RPC_HANDLE hmngr,
DWORD type,
DWORD state,
BYTE *buffer,
DWORD size,
LPDWORD needed,
LPDWORD returned)
{
DWORD err, sz, total_size, num_services;
DWORD_PTR offset;
struct sc_manager_handle *manager;
struct service_entry *service;
ENUM_SERVICE_STATUSW *s;
WINE_TRACE("(%p, 0x%x, 0x%x, %p, %u, %p, %p)\n", hmngr, type, state, buffer, size, needed, returned);
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);
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))
{
total_size += sizeof(ENUM_SERVICE_STATUSW);
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_STATUSW *)buffer;
offset = num_services * sizeof(ENUM_SERVICE_STATUSW);
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 */
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;
}
memcpy(&s->ServiceStatus, &service->status, sizeof(SERVICE_STATUS));
s++;
}
}
*returned = num_services;
*needed = 0;
scmdatabase_unlock(manager->db);
return ERROR_SUCCESS;
}
DWORD svcctl_QueryServiceObjectSecurity(
void)
{
......@@ -1159,14 +1256,6 @@ DWORD svcctl_EnumDependentServicesW(
return ERROR_CALL_NOT_IMPLEMENTED;
}
DWORD svcctl_EnumServicesStatusW(
void)
{
WINE_FIXME("\n");
return ERROR_CALL_NOT_IMPLEMENTED;
}
DWORD svcctl_QueryServiceLockStatusW(
void)
{
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment