From: Yuxuan Shui yshui@codeweavers.com
--- dlls/kernel32/tests/toolhelp.c | 179 ++++++++++++++++++++++++++++----- 1 file changed, 155 insertions(+), 24 deletions(-)
diff --git a/dlls/kernel32/tests/toolhelp.c b/dlls/kernel32/tests/toolhelp.c index 79dbb04ac88..fd5d308977d 100644 --- a/dlls/kernel32/tests/toolhelp.c +++ b/dlls/kernel32/tests/toolhelp.c @@ -30,6 +30,7 @@ #include "wine/test.h" #include "winuser.h" #include "winternl.h" +#include "winnls.h"
static char selfname[MAX_PATH];
@@ -360,35 +361,93 @@ static void test_thread(DWORD curr_pid, DWORD sub_pcs_pid) ok(!pThread32First( hSnapshot, &te ), "shouldn't return a thread\n"); }
-static const char* curr_expected_modules[] = +struct expected_module { + const char *module; + + /* + * 0 = C:\windows\system32\ + * 1 = C:\windows\syswow64\ + * 2 = don't check + */ + int wow64; +}; + +static struct expected_module curr_expected_modules[] = +{ + {"kernel32_test.exe", 2}, + {"kernel32.dll"}, + {"ntdll.dll"}, +}; + +static struct expected_module sub_expected_modules[] = { - "kernel32_test.exe", - "kernel32.dll", - "ntdll.dll" + {"kernel32_test.exe", 2}, + {"kernel32.dll"}, + {"shell32.dll"}, + {"ntdll.dll"}, };
-static const char* sub_expected_modules[] = +static struct expected_module msinfo32_32_expected_modules[] = { - "kernel32_test.exe", - "kernel32.dll", - "shell32.dll", - "ntdll.dll" + {"msinfo32.exe", 1}, + {"kernel32.dll", 1}, + {"shell32.dll", 1}, + {"ntdll.dll", 1}, + {"ntdll.dll"}, + {"wow64.dll"}, + {"wow64win.dll"}, + {"wow64cpu.dll"}, };
-static void test_module(DWORD pid, const char* expected[], unsigned num_expected) +static struct expected_module msinfo32_64_expected_modules[] = +{ + {"msinfo32.exe", 1}, + {"ntdll.dll"}, + {"wow64.dll"}, + {"wow64win.dll"}, + {"wow64cpu.dll"}, +}; + +static char syswow64[MAX_PATH], system32[MAX_PATH]; +static int syswow64_len, system32_len; + +static BOOL match_module(const MODULEENTRY32 *module, const struct expected_module *pattern) +{ + if (lstrcmpiA(module->szModule, pattern->module)) return FALSE; + if (pattern->wow64 == 2) return TRUE; + if (pattern->wow64 == 1) + { + if (lstrlenA(module->szExePath) < syswow64_len) return FALSE; + return CompareStringA(LOCALE_INVARIANT, NORM_IGNORECASE, module->szExePath, syswow64_len, + syswow64, syswow64_len) == CSTR_EQUAL; + } + if (lstrlenA(module->szExePath) < system32_len) return FALSE; + return CompareStringA(LOCALE_INVARIANT, NORM_IGNORECASE, module->szExePath, system32_len, + system32, system32_len) == CSTR_EQUAL; +} + +static void test_module(DWORD pid, struct expected_module expected[], unsigned num_expected, BOOL module32) { HANDLE hSnapshot; PROCESSENTRY32 pe; THREADENTRY32 te; MODULEENTRY32 me; + DWORD snapshot_flags = TH32CS_SNAPMODULE | (module32 ? TH32CS_SNAPMODULE32 : 0); unsigned found[32]; unsigned i; int num = 0;
ok(ARRAY_SIZE(found) >= num_expected, "Internal: bump found[] size\n");
- hSnapshot = pCreateToolhelp32Snapshot( TH32CS_SNAPMODULE, pid ); + hSnapshot = pCreateToolhelp32Snapshot( snapshot_flags, pid ); + + todo_if(module32 && winetest_platform_is_wine) ok(hSnapshot != INVALID_HANDLE_VALUE, "Cannot create snapshot\n"); + if (hSnapshot == INVALID_HANDLE_VALUE && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) + { + skip("CreateToolhelp32Snapshot doesn't support requested flags\n"); + return; + }
for (i = 0; i < num_expected; i++) found[i] = 0; me.dwSize = sizeof(me); @@ -400,13 +459,15 @@ static void test_module(DWORD pid, const char* expected[], unsigned num_expected me.th32ProcessID, me.modBaseAddr, me.modBaseSize, me.szExePath, me.szModule); ok(me.th32ProcessID == pid, "wrong returned process id\n"); for (i = 0; i < num_expected; i++) - if (!lstrcmpiA(expected[i], me.szModule)) found[i]++; + if (match_module(&me, &expected[i])) found[i]++; num++; } while (pModule32Next( hSnapshot, &me )); } - for (i = 0; i < num_expected; i++) + if (module32) ok(found[0] == 2, "Main exe was found %d time(s)\n", found[0]); + for (i = module32 ? 1 : 0; i < num_expected; i++) + /* main exe is listed twice if TH32CS_SNAPMODULE32 is set. */ ok(found[i] == 1, "Module %s is %s\n", - expected[i], found[i] ? "listed more than once" : "not listed"); + expected[i].module, found[i] ? "listed more than once" : "not listed");
/* check that first really resets the enumeration */ for (i = 0; i < num_expected; i++) found[i] = 0; @@ -418,13 +479,14 @@ static void test_module(DWORD pid, const char* expected[], unsigned num_expected trace("PID=%lx base=%p size=%lx %s %s\n", me.th32ProcessID, me.modBaseAddr, me.modBaseSize, me.szExePath, me.szModule); for (i = 0; i < num_expected; i++) - if (!lstrcmpiA(expected[i], me.szModule)) found[i]++; + if (match_module(&me, &expected[i])) found[i]++; num--; } while (pModule32Next( hSnapshot, &me )); } - for (i = 0; i < num_expected; i++) + if (module32) ok(found[0] == 2, "Main exe was found %d time(s)\n", found[0]); + for (i = module32 ? 1 : 0; i < num_expected; i++) ok(found[i] == 1, "Module %s is %s\n", - expected[i], found[i] ? "listed more than once" : "not listed"); + expected[i].module, found[i] ? "listed more than once" : "not listed"); ok(!num, "mismatch in counting\n");
pe.dwSize = sizeof(pe); @@ -437,6 +499,44 @@ static void test_module(DWORD pid, const char* expected[], unsigned num_expected ok(!pModule32First( hSnapshot, &me ), "shouldn't return a module\n"); }
+struct startup_cb +{ + DWORD pid; + HWND wnd; +}; + +static BOOL CALLBACK startup_cb_window(HWND wnd, LPARAM lParam) +{ + struct startup_cb *info = (struct startup_cb*)lParam; + DWORD pid; + + if (GetWindowThreadProcessId(wnd, &pid) && info->pid == pid && IsWindowVisible(wnd)) + { + info->wnd = wnd; + return FALSE; + } + return TRUE; +} + +static BOOL wait_process_window_visible(HANDLE proc, DWORD pid, DWORD timeout) +{ + DWORD max_tc = GetTickCount() + timeout; + BOOL ret = WaitForInputIdle(proc, timeout); + struct startup_cb info = {pid, NULL}; + + if (!ret) + { + do + { + if (EnumWindows(startup_cb_window, (LPARAM)&info)) + Sleep(100); + } while (!info.wnd && GetTickCount() < max_tc); + } + return info.wnd != NULL; +} + +static const BOOL is_win64 = sizeof(void*) > sizeof(int); + START_TEST(toolhelp) { DWORD pid = GetCurrentProcessId(); @@ -444,12 +544,18 @@ START_TEST(toolhelp) char *p, module[MAX_PATH]; char buffer[MAX_PATH + 21]; SECURITY_ATTRIBUTES sa; - PROCESS_INFORMATION info; - STARTUPINFOA startup; + PROCESS_INFORMATION info, info32 = {0}; + STARTUPINFOA startup, startup32 = {0}; HANDLE ev1, ev2; DWORD w; HANDLE hkernel32 = GetModuleHandleA("kernel32"); HANDLE hntdll = GetModuleHandleA("ntdll.dll"); + BOOL ret; + + syswow64_len = GetSystemWow64DirectoryA(syswow64, ARRAY_SIZE(syswow64)); + ok(syswow64_len, "Can't GetSystemWow64DirectoryA, %#lx\n", GetLastError()); + system32_len = GetSystemDirectoryA(system32, ARRAY_SIZE(system32)); + ok(system32_len, "Can't GetSystemDirectoryA, %#lx\n", GetLastError());
pCreateToolhelp32Snapshot = (VOID *) GetProcAddress(hkernel32, "CreateToolhelp32Snapshot"); pModule32First = (VOID *) GetProcAddress(hkernel32, "Module32First"); @@ -495,15 +601,40 @@ START_TEST(toolhelp) GetModuleFileNameA( 0, module, sizeof(module) ); if (!(p = strrchr( module, '\' ))) p = module; else p++; - curr_expected_modules[0] = p; - sub_expected_modules[0] = p; + curr_expected_modules[0].module = p; + sub_expected_modules[0].module = p;
test_process(pid, info.dwProcessId); test_thread(pid, info.dwProcessId); test_main_thread(pid, GetCurrentThreadId()); - test_module(pid, curr_expected_modules, ARRAY_SIZE(curr_expected_modules)); - test_module(info.dwProcessId, sub_expected_modules, ARRAY_SIZE(sub_expected_modules)); + test_module(pid, curr_expected_modules, ARRAY_SIZE(curr_expected_modules), FALSE); + test_module(info.dwProcessId, sub_expected_modules, ARRAY_SIZE(sub_expected_modules), FALSE); + if (is_win64) + { + lstrcpyA(buffer, syswow64); + strcat(buffer, "\msinfo32.exe"); + ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &startup32, &info32); + if (ret) + { + ret = wait_process_window_visible(info32.hProcess, info32.dwProcessId, 5000); + ok(ret, "wait timed out\n"); + + trace("testing 32bit\n"); + test_module(info32.dwProcessId, msinfo32_32_expected_modules, + ARRAY_SIZE(msinfo32_32_expected_modules), TRUE); + test_module(info32.dwProcessId, msinfo32_64_expected_modules, + ARRAY_SIZE(msinfo32_64_expected_modules), FALSE); + TerminateProcess(info32.hProcess, 0); + } + else + { + if (GetLastError() == ERROR_FILE_NOT_FOUND) + skip("Skip wow64 test on non compatible platform\n"); + else + ok(ret, "wow64 CreateProcess failed: %#lx\n", GetLastError()); + } + }
SetEvent(ev2); - wait_child_process( &info ); + wait_child_process(&info); }