From f0a821a1aed95e3b2404e49c732191e5c4a36822 Mon Sep 17 00:00:00 2001 From: Paul Vriens Date: Thu, 21 Aug 2008 17:18:41 +0200 Subject: [PATCH] advapi32/tests: Add tests for EnumServicesStatusExA. --- dlls/advapi32/tests/service.c | 401 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 401 insertions(+) diff --git a/dlls/advapi32/tests/service.c b/dlls/advapi32/tests/service.c index 5280a22aab4..4225e350e31 100644 --- a/dlls/advapi32/tests/service.c +++ b/dlls/advapi32/tests/service.c @@ -34,6 +34,9 @@ static const CHAR spooler[] = "Spooler"; /* Should be available on all platforms */ static BOOL (WINAPI *pChangeServiceConfig2A)(SC_HANDLE,DWORD,LPVOID); +static BOOL (WINAPI *pEnumServicesStatusExA)(SC_HANDLE, SC_ENUM_TYPE, DWORD, + DWORD, LPBYTE, DWORD, LPDWORD, + LPDWORD, LPDWORD, LPCSTR); static BOOL (WINAPI *pQueryServiceConfig2A)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD); static BOOL (WINAPI *pQueryServiceConfig2W)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD); static BOOL (WINAPI *pQueryServiceStatusEx)(SC_HANDLE, SC_STATUS_TYPE, LPBYTE, @@ -44,6 +47,7 @@ static void init_function_pointers(void) HMODULE hadvapi32 = GetModuleHandleA("advapi32.dll"); pChangeServiceConfig2A = (void*)GetProcAddress(hadvapi32, "ChangeServiceConfig2A"); + pEnumServicesStatusExA= (void*)GetProcAddress(hadvapi32, "EnumServicesStatusExA"); pQueryServiceConfig2A= (void*)GetProcAddress(hadvapi32, "QueryServiceConfig2A"); pQueryServiceConfig2W= (void*)GetProcAddress(hadvapi32, "QueryServiceConfig2W"); pQueryServiceStatusEx= (void*)GetProcAddress(hadvapi32, "QueryServiceStatusEx"); @@ -959,6 +963,7 @@ static void test_enum_svc(void) DWORD drivercountactive, servicecountactive; DWORD drivercountinactive, servicecountinactive; ENUM_SERVICE_STATUS *services; + ENUM_SERVICE_STATUS_PROCESS *exservices; INT i; /* All NULL or wrong */ @@ -1301,6 +1306,402 @@ static void test_enum_svc(void) } CloseServiceHandle(scm_handle); + + /* More or less the same for EnumServicesStatusExA */ + + /* All NULL or wrong */ + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(NULL, 1, 0, 0, NULL, 0, NULL, NULL, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_LEVEL, + "Expected ERROR_INVALID_LEVEL, got %d\n", GetLastError()); + + /* All NULL or wrong, just the info level is correct */ + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(NULL, 0, 0, 0, NULL, 0, NULL, NULL, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(GetLastError() == ERROR_INVALID_HANDLE, + "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError()); + + /* Open the service control manager with not enough rights at first */ + scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT); + + /* Valid handle and info level but rest is still NULL or wrong */ + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, NULL, 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()); + + /* Don't specify the two required pointers */ + needed = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, &needed, NULL, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(needed == 0xdeadbeef, "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()); + + /* Don't specify the two required pointers */ + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, NULL, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + 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()); + } + + /* No valid servicetype and servicestate */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + todo_wine + { + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* No valid servicestate */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, 0, NULL, 0, + &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + todo_wine + { + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* No valid servicetype */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, SERVICE_STATE_ALL, NULL, 0, + &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + todo_wine + { + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(GetLastError() == ERROR_INVALID_PARAMETER, + "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError()); + } + + /* No valid servicetype and servicestate and unknown service group */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, 0, 0, NULL, 0, &needed, + &returned, NULL, "deadbeef_group"); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + todo_wine + { + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + 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 = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + ok(GetLastError() == ERROR_ACCESS_DENIED, + "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + + /* All parameters are correct, access rights are wrong but the + * group name won't be checked yet. + */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL, "deadbeef_group"); + ok(!ret, "Expected failure\n"); + todo_wine + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + ok(GetLastError() == ERROR_ACCESS_DENIED, + "Expected ERROR_ACCESS_DENIED, got %d\n", GetLastError()); + + /* Open the service control manager with the needed rights */ + CloseServiceHandle(scm_handle); + scm_handle = OpenSCManagerA(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE); + + /* All parameters are correct and the group will be checked */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL, "deadbeef_group"); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected number of service to be set to 0, got %d\n", returned); + todo_wine + { + ok(needed == 0, "Expected needed buffer size to be set to 0, got %d\n", needed); + ok(GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST, + "Expected ERROR_SERVICE_DOES_NOT_EXIST, got %d\n", GetLastError()); + } + + /* TODO: Create a test that makes sure we enumerate all services that don't + * belong to a group. (specifying ""). + */ + + /* All parameters are correct. Request the needed buffer size */ + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + ok(returned == 0, "Expected no service returned, got %d\n", returned); + todo_wine + { + ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size\n"); + ok(GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + } + + /* Store the needed bytes */ + tempneeded = needed; + + /* Allocate the correct needed bytes */ + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + bufsize = needed; + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + (BYTE*)exservices, bufsize, &needed, &returned, NULL, NULL); + todo_wine + { + ok(ret, "Expected success\n"); + ok(needed == 0, "Expected needed buffer to be 0 as we are done\n"); + ok(returned == tempreturned, "Expected the same number of service from this function\n"); + ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || + GetLastError() == 0xdeadbeef /* NT4, XP and Vista */ || + GetLastError() == ERROR_IO_PENDING /* W2K */, + "Unexpected last error %d\n", GetLastError()); + } + HeapFree(GetProcessHeap(), 0, exservices); + + /* Store the number of returned services */ + tempreturned = returned; + + /* Allocate less then the needed bytes and don't specify a resume handle */ + exservices = HeapAlloc(GetProcessHeap(), 0, tempneeded - 1); + bufsize = tempneeded - 1; + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + (BYTE*)exservices, bufsize, &needed, &returned, NULL, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size\n"); + ok(returned == (tempreturned - 1), "Expected one service less to be returned\n"); + ok(GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + } + HeapFree(GetProcessHeap(), 0, exservices); + + /* Allocate less then the needed bytes, this time with a correct resume handle */ + exservices = HeapAlloc(GetProcessHeap(), 0, tempneeded - 1); + bufsize = tempneeded - 1; + needed = 0xdeadbeef; + returned = 0xdeadbeef; + resume = 0; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + (BYTE*)exservices, bufsize, &needed, &returned, &resume, NULL); + ok(!ret, "Expected failure\n"); + todo_wine + { + ok(needed != 0xdeadbeef && needed > 0, "Expected the needed buffer size\n"); + ok(returned == (tempreturned - 1), "Expected one service less to be returned\n"); + ok(resume, "Expected a resume handle\n"); + ok(GetLastError() == ERROR_MORE_DATA, + "Expected ERROR_MORE_DATA, got %d\n", GetLastError()); + } + HeapFree(GetProcessHeap(), 0, exservices); + + /* Fetch that last service but pass a bigger buffer size */ + exservices = HeapAlloc(GetProcessHeap(), 0, tempneeded); + bufsize = tempneeded; + needed = 0xdeadbeef; + returned = 0xdeadbeef; + SetLastError(0xdeadbeef); + ret = pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + (BYTE*)exservices, bufsize, &needed, &returned, &resume, NULL); + todo_wine + { + ok(ret, "Expected success\n"); + ok(needed == 0, "Expected needed buffer to be 0 as we are done\n"); + ok(returned == 1, "Expected only 1 service to be returned\n"); + ok(GetLastError() == ERROR_SUCCESS /* W2K3 */ || + GetLastError() == 0xdeadbeef /* NT4, XP and Vista */ || + GetLastError() == ERROR_IO_PENDING /* W2K */, + "Unexpected last error %d\n", GetLastError()); + } + ok(resume == 0, "Expected the resume handle to be 0\n"); + HeapFree(GetProcessHeap(), 0, exservices); + + /* See if things add up */ + + /* Get the number of active driver services */ + pEnumServicesStatusExA(scm_handle, 0, SERVICE_DRIVER, SERVICE_ACTIVE, + NULL, 0, &needed, &returned, NULL, NULL); + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + pEnumServicesStatusExA(scm_handle, 0, SERVICE_DRIVER, SERVICE_ACTIVE, + (BYTE*)exservices, bufsize, &needed, &returned, NULL, NULL); + HeapFree(GetProcessHeap(), 0, exservices); + + /* Store the number of active driver services */ + drivercountactive = returned; + + /* Get the number of inactive driver services */ + pEnumServicesStatusExA(scm_handle, 0, SERVICE_DRIVER, SERVICE_INACTIVE, + NULL, 0, &needed, &returned, NULL, NULL); + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + pEnumServicesStatusExA(scm_handle, 0, SERVICE_DRIVER, SERVICE_INACTIVE, + (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); + HeapFree(GetProcessHeap(), 0, exservices); + + drivercountinactive = returned; + + /* Get the number of driver services */ + pEnumServicesStatusExA(scm_handle, 0, SERVICE_DRIVER, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL, NULL); + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + pEnumServicesStatusExA(scm_handle, 0, SERVICE_DRIVER, SERVICE_STATE_ALL, + (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); + HeapFree(GetProcessHeap(), 0, exservices); + + /* Check if total is the same as active and inactive driver services */ + ok(returned == (drivercountactive + drivercountinactive), + "Something wrong in the calculation\n"); + + /* Get the number of active win32 services */ + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_ACTIVE, + NULL, 0, &needed, &returned, NULL, NULL); + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_ACTIVE, + (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); + HeapFree(GetProcessHeap(), 0, exservices); + + servicecountactive = returned; + + /* Get the number of inactive win32 services */ + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_INACTIVE, + NULL, 0, &needed, &returned, NULL, NULL); + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_INACTIVE, + (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); + HeapFree(GetProcessHeap(), 0, exservices); + + servicecountinactive = returned; + + /* Get the number of win32 services */ + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + NULL, 0, &needed, &returned, NULL, NULL); + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32, SERVICE_STATE_ALL, + (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); + HeapFree(GetProcessHeap(), 0, exservices); + + /* Check if total is the same as active and inactive win32 services */ + ok(returned == (servicecountactive + servicecountinactive), + "Something wrong in the calculation\n"); + + /* Get the number of all services */ + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32 | SERVICE_DRIVER, + SERVICE_STATE_ALL, NULL, 0, &needed, &returned, NULL, NULL); + exservices = HeapAlloc(GetProcessHeap(), 0, needed); + pEnumServicesStatusExA(scm_handle, 0, SERVICE_WIN32 | SERVICE_DRIVER, + SERVICE_STATE_ALL, (BYTE*)exservices, needed, &needed, &returned, NULL, NULL); + + /* Check if total is the same as all those single calls */ + ok(returned == (drivercountactive + drivercountinactive + servicecountactive + servicecountinactive), + "Something wrong in the calculation\n"); + + /* Loop through all those returned services */ + for (i = 0; i < returned; i++) + { + SERVICE_STATUS_PROCESS status = exservices[i].ServiceStatusProcess; + + + /* lpServiceName and lpDisplayName should always be filled */ + ok(lstrlenA(exservices[i].lpServiceName) > 0, "Expected a service name\n"); + ok(lstrlenA(exservices[i].lpDisplayName) > 0, "Expected a display name\n"); + + /* Decrement the counters to see if the functions calls return the + * same numbers as the contents of these structures. + * Check some process id specifics. + */ + if (status.dwServiceType & (SERVICE_FILE_SYSTEM_DRIVER | SERVICE_KERNEL_DRIVER)) + { + if (status.dwCurrentState == SERVICE_RUNNING) + drivercountactive--; + else + drivercountinactive--; + + /* We shouldn't have a process id for drivers */ + ok(status.dwProcessId == 0, + "This driver shouldn't have an associated process id\n"); + } + + if (status.dwServiceType & (SERVICE_WIN32_OWN_PROCESS | SERVICE_WIN32_SHARE_PROCESS)) + { + if (status.dwCurrentState == SERVICE_RUNNING) + { + /* We expect a process id for every running service */ + ok(status.dwProcessId > 0, "Expected a process id for this running service (%s)\n", + exservices[i].lpServiceName); + + servicecountactive--; + } + else + { + /* We shouldn't have a process id for inactive services */ + ok(status.dwProcessId == 0, "This service shouldn't have an associated process id\n"); + + servicecountinactive--; + } + } + } + HeapFree(GetProcessHeap(), 0, exservices); + + ok(drivercountactive == 0, "Active driver mismatch\n"); + ok(drivercountinactive == 0, "Inactive driver mismatch\n"); + ok(servicecountactive == 0, "Active services mismatch\n"); + ok(servicecountinactive == 0, "Inactive services mismatch\n"); + + CloseServiceHandle(scm_handle); } static void test_close(void) -- 2.11.4.GIT