mirror of
https://github.com/reactos/wine.git
synced 2025-02-11 07:05:30 +00:00
advapi32: Implement EnumServicesStatusA/W.
This commit is contained in:
parent
c287ed2232
commit
ae7d41bfa2
@ -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;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
@ -1038,6 +1038,7 @@ static void test_enum_svc(void)
|
||||
DWORD tempneeded, tempreturned, missing;
|
||||
DWORD servicecountactive, servicecountinactive;
|
||||
ENUM_SERVICE_STATUS *services;
|
||||
ENUM_SERVICE_STATUSW *servicesW;
|
||||
ENUM_SERVICE_STATUS_PROCESS *exservices;
|
||||
UINT i;
|
||||
|
||||
@ -1045,7 +1046,12 @@ static void test_enum_svc(void)
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusA(NULL, 1, 0, NULL, 0, NULL, NULL, NULL);
|
||||
ok(!ret, "Expected failure\n");
|
||||
todo_wine
|
||||
ok(GetLastError() == ERROR_INVALID_HANDLE,
|
||||
"Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusW(NULL, 1, 0, NULL, 0, NULL, NULL, NULL);
|
||||
ok(!ret, "Expected failure\n");
|
||||
ok(GetLastError() == ERROR_INVALID_HANDLE,
|
||||
"Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
|
||||
|
||||
@ -1056,7 +1062,13 @@ static void test_enum_svc(void)
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusA(scm_handle, 1, 0, NULL, 0, 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());
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusW(scm_handle, 1, 0, NULL, 0, NULL, NULL, NULL);
|
||||
ok(!ret, "Expected failure\n");
|
||||
ok(GetLastError() == ERROR_INVALID_ADDRESS ||
|
||||
GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
|
||||
"Unexpected last error %d\n", GetLastError());
|
||||
@ -1067,7 +1079,15 @@ static void test_enum_svc(void)
|
||||
ret = EnumServicesStatusA(scm_handle, 0, 0, NULL, 0, NULL, &returned, NULL);
|
||||
ok(!ret, "Expected failure\n");
|
||||
ok(returned == 0xdeadbeef, "Expected no change to the number of services variable\n");
|
||||
todo_wine
|
||||
ok(GetLastError() == ERROR_INVALID_ADDRESS ||
|
||||
GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
|
||||
"Unexpected last error %d\n", GetLastError());
|
||||
|
||||
returned = 0xdeadbeef;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusW(scm_handle, 0, 0, NULL, 0, NULL, &returned, NULL);
|
||||
ok(!ret, "Expected failure\n");
|
||||
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());
|
||||
@ -1079,7 +1099,16 @@ 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());
|
||||
|
||||
needed = 0xdeadbeef;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusW(scm_handle, 0, 0, NULL, 0, &needed, NULL, NULL);
|
||||
ok(!ret, "Expected failure\n");
|
||||
ok(needed == 0xdeadbeef || broken(needed != 0xdeadbeef), /* nt4 */
|
||||
"Expected no change to the needed buffer variable\n");
|
||||
ok(GetLastError() == ERROR_INVALID_ADDRESS ||
|
||||
GetLastError() == ERROR_INVALID_PARAMETER /* NT4 */,
|
||||
"Unexpected last error %d\n", GetLastError());
|
||||
@ -1090,59 +1119,93 @@ static void test_enum_svc(void)
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusA(scm_handle, 0, 0, NULL, 0, &needed, &returned, 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 services to be set to 0, got %d\n", returned);
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
"Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
|
||||
}
|
||||
|
||||
/* No valid servicetype and servicestate */
|
||||
needed = 0xdeadbeef;
|
||||
returned = 0xdeadbeef;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusW(scm_handle, 0, 0, NULL, 0, &needed, &returned, NULL);
|
||||
ok(!ret, "Expected failure\n");
|
||||
ok(needed == 0 || broken(needed != 0), /* nt4 */
|
||||
"Expected needed buffer size to be set to 0, got %d\n", needed);
|
||||
ok(returned == 0 || broken(returned != 0), /* nt4 */
|
||||
"Expected number of services to be set to 0, got %d\n", returned);
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
"Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
|
||||
|
||||
/* No valid servicestate */
|
||||
needed = 0xdeadbeef;
|
||||
returned = 0xdeadbeef;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, 0, NULL, 0, &needed, &returned, 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 services to be set to 0, got %d\n", returned);
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
"Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
|
||||
}
|
||||
|
||||
/* No valid servicetype and servicestate */
|
||||
needed = 0xdeadbeef;
|
||||
returned = 0xdeadbeef;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusA(scm_handle, 0, SERVICE_STATE_ALL, NULL, 0,
|
||||
&needed, &returned, NULL);
|
||||
ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, 0, NULL, 0, &needed, &returned, NULL);
|
||||
ok(!ret, "Expected failure\n");
|
||||
ok(needed == 0 || broken(needed != 0), /* nt4 */
|
||||
"Expected needed buffer size to be set to 0, got %d\n", needed);
|
||||
ok(returned == 0 || broken(returned != 0), /* nt4 */
|
||||
"Expected number of services to be set to 0, got %d\n", returned);
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
"Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
|
||||
|
||||
/* No valid servicetype */
|
||||
needed = 0xdeadbeef;
|
||||
returned = 0xdeadbeef;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusA(scm_handle, 0, SERVICE_STATE_ALL, NULL, 0, &needed, &returned, 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 services to be set to 0, got %d\n", returned);
|
||||
ok(GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
"Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
|
||||
}
|
||||
|
||||
needed = 0xdeadbeef;
|
||||
returned = 0xdeadbeef;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusW(scm_handle, 0, SERVICE_STATE_ALL, NULL, 0, &needed, &returned, NULL);
|
||||
ok(!ret, "Expected failure\n");
|
||||
ok(needed == 0 || broken(needed != 0), /* nt4 */
|
||||
"Expected needed buffer size to be set to 0, got %d\n", needed);
|
||||
ok(returned == 0 || broken(returned != 0), /* nt4 */
|
||||
"Expected number of services to be set to 0, got %d\n", returned);
|
||||
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;
|
||||
returned = 0xdeadbeef;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0,
|
||||
&needed, &returned, NULL);
|
||||
ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &needed, &returned, 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 services to be set to 0, got %d\n", returned);
|
||||
}
|
||||
ok(GetLastError() == ERROR_ACCESS_DENIED,
|
||||
"Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
|
||||
|
||||
needed = 0xdeadbeef;
|
||||
returned = 0xdeadbeef;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &needed, &returned, NULL);
|
||||
ok(!ret, "Expected failure\n");
|
||||
ok(needed == 0 || broken(needed != 0), /* nt4 */
|
||||
"Expected needed buffer size to be set to 0, got %d\n", needed);
|
||||
ok(returned == 0 || broken(returned != 0), /* nt4 */
|
||||
"Expected number of services to be set to 0, got %d\n", returned);
|
||||
ok(GetLastError() == ERROR_ACCESS_DENIED,
|
||||
"Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError());
|
||||
|
||||
@ -1154,22 +1217,24 @@ static void test_enum_svc(void)
|
||||
needed = 0xdeadbeef;
|
||||
returned = 0xdeadbeef;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0,
|
||||
&needed, &returned, NULL);
|
||||
ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &needed, &returned, NULL);
|
||||
ok(!ret, "Expected failure\n");
|
||||
todo_wine
|
||||
{
|
||||
ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size for this one service\n");
|
||||
ok(returned == 0, "Expected no service returned, got %d\n", returned);
|
||||
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;
|
||||
ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0,
|
||||
&neededW, &returnedW, NULL);
|
||||
returnedW = 0xdeadbeef;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL, NULL, 0, &neededW, &returnedW, NULL);
|
||||
ok(!ret, "Expected failure\n");
|
||||
ok(neededW != 0xdeadbeef && neededW > 0, "Expected the needed buffer size for this one service\n");
|
||||
ok(neededW == needed, "Expected needed buffersize to be the same for A- and W-calls\n");
|
||||
ok(returnedW == 0, "Expected no service returned, got %d\n", returnedW);
|
||||
ok(GetLastError() == ERROR_MORE_DATA,
|
||||
"Expected ERROR_MORE_DATA, got %d\n", GetLastError());
|
||||
|
||||
/* Store the needed bytes */
|
||||
tempneeded = needed;
|
||||
@ -1182,17 +1247,26 @@ static void test_enum_svc(void)
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL,
|
||||
services, bufsize, &needed, &returned, 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 != 0xdeadbeef && returned > 0, "Expected some returned services\n");
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, services);
|
||||
|
||||
/* Store the number of returned services */
|
||||
tempreturned = returned;
|
||||
|
||||
servicesW = HeapAlloc(GetProcessHeap(), 0, neededW);
|
||||
bufsize = neededW;
|
||||
neededW = 0xdeadbeef;
|
||||
returnedW = 0xdeadbeef;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusW(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL,
|
||||
servicesW, bufsize, &neededW, &returnedW, NULL);
|
||||
ok(ret, "Expected success, got error %u\n", GetLastError());
|
||||
ok(neededW == 0, "Expected needed buffer to be 0 as we are done\n");
|
||||
ok(returnedW != 0xdeadbeef && returnedW > 0, "Expected some returned services\n");
|
||||
HeapFree(GetProcessHeap(), 0, servicesW);
|
||||
|
||||
/* Allocate less than the needed bytes and don't specify a resume handle */
|
||||
services = HeapAlloc(GetProcessHeap(), 0, tempneeded);
|
||||
bufsize = (tempreturned - 1) * sizeof(ENUM_SERVICE_STATUS);
|
||||
@ -1202,13 +1276,10 @@ static void test_enum_svc(void)
|
||||
ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL,
|
||||
services, bufsize, &needed, &returned, NULL);
|
||||
ok(!ret, "Expected failure\n");
|
||||
todo_wine
|
||||
{
|
||||
ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size for this one service\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);
|
||||
@ -1219,14 +1290,11 @@ static void test_enum_svc(void)
|
||||
ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL,
|
||||
services, bufsize, &needed, &returned, &resume);
|
||||
ok(!ret, "Expected failure\n");
|
||||
todo_wine
|
||||
{
|
||||
ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size for this one service\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 the missing services but pass a bigger buffer size */
|
||||
missing = tempreturned - returned;
|
||||
@ -1236,12 +1304,9 @@ static void test_enum_svc(void)
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = EnumServicesStatusA(scm_handle, SERVICE_WIN32, SERVICE_STATE_ALL,
|
||||
services, bufsize, &needed, &returned, &resume);
|
||||
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, services);
|
||||
|
||||
@ -1286,7 +1351,6 @@ static void test_enum_svc(void)
|
||||
HeapFree(GetProcessHeap(), 0, services);
|
||||
|
||||
/* Check if total is the same as active and inactive win32 services */
|
||||
todo_wine
|
||||
ok(returned == (servicecountactive + servicecountinactive),
|
||||
"Something wrong in the calculation\n");
|
||||
|
||||
@ -1323,11 +1387,8 @@ static void test_enum_svc(void)
|
||||
}
|
||||
HeapFree(GetProcessHeap(), 0, services);
|
||||
|
||||
todo_wine
|
||||
{
|
||||
ok(servicecountactive == 0, "Active services mismatch %u\n", servicecountactive);
|
||||
ok(servicecountinactive == 0, "Inactive services mismatch %u\n", servicecountinactive);
|
||||
}
|
||||
|
||||
CloseServiceHandle(scm_handle);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user