From: Eric Pouech epouech@codeweavers.com
Signed-off-by: Eric Pouech epouech@codeweavers.com --- dlls/dbghelp/tests/dbghelp.c | 50 ++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 5 deletions(-)
diff --git a/dlls/dbghelp/tests/dbghelp.c b/dlls/dbghelp/tests/dbghelp.c index 13cd173e761..e41dd5f94a0 100644 --- a/dlls/dbghelp/tests/dbghelp.c +++ b/dlls/dbghelp/tests/dbghelp.c @@ -31,6 +31,42 @@ static WCHAR wow64_directory[MAX_PATH];
static BOOL (*WINAPI pIsWow64Process2)(HANDLE, USHORT*, USHORT*);
+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; +} + #if defined(__i386__) || defined(__x86_64__)
static DWORD CALLBACK stack_walk_thread(void *arg) @@ -373,14 +409,18 @@ static BOOL wrapper_EnumerateLoadedModulesW64(HANDLE proc, PENUMLOADED_MODULES_C { BOOL ret; int retry; + int retry_count = !strcmp(winetest_platform, "wine") ? 1 : 5;
- for (retry = !strcmp(winetest_platform, "wine") ? 1 : 5; retry >= 0; retry--) + for (retry = retry_count - 1; retry >= 0; retry--) { ret = EnumerateLoadedModulesW64(proc, cb, usr); if (ret || GetLastError() != STATUS_INFO_LENGTH_MISMATCH) break; Sleep(10); } + if (retry + 1 < retry_count) + trace("used wrapper retry: ret=%d retry=%d top=%d\n", ret, retry, retry_count); + return ret; }
@@ -789,8 +829,8 @@ static void test_loaded_modules(void) ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); ok(ret, "CreateProcess failed: %lu\n", GetLastError());
- ret = WaitForInputIdle(pi.hProcess, 5000); - ok(!ret, "wait timed out\n"); + ret = wait_process_window_visible(pi.hProcess, pi.dwProcessId, 5000); + ok(ret, "wait timed out\n");
ret = SymInitialize(pi.hProcess, NULL, FALSE); ok(ret, "SymInitialize failed: %lu\n", GetLastError()); @@ -869,8 +909,8 @@ static void test_loaded_modules(void) ret = CreateProcessA(NULL, buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); if (ret) { - ret = WaitForInputIdle(pi.hProcess, 5000); - ok(!ret, "wait timed out\n"); + ret = wait_process_window_visible(pi.hProcess, pi.dwProcessId, 5000); + ok(ret, "wait timed out\n");
ret = SymInitialize(pi.hProcess, NULL, FALSE); ok(ret, "SymInitialize failed: %lu\n", GetLastError());
we have a couple of tests failing when reading child process module list with STATUS_INFO_LENGTH_MISMATCH or STATUS_PARTIAL_COPY
one tentative approach had been added to dbghelp/tests for work around it by retrying the failing API call when this happen (search for wrapper_XXX)
there's still pending areas requiring some attention (symrefreshmodulelist in dbghelp, psapi enumprocessmoduleex...)
https://bugs.winehq.org/show_bug.cgi?id=54717
one explanation could be that all the modules in the child process are not loaded yet, and the module enumeration fails on window. msdn documentation is scarce
this only interesting bit I found is here
https://learn.microsoft.com/en-us/windows/win32/api/tlhelp32/nf-tlhelp32-cre...
it reads
```plaintext For example, if the loader data table in the target process is corrupted or not initialized, or if the module list changes during the function call as a result of DLLs being loaded or unloaded, the function might fail with ERROR_BAD_LENGTH or other error code. Ensure that the target process was not started in a suspended state, and try calling the function again. If the function fails with ERROR_BAD_LENGTH when called with TH32CS_SNAPMODULE or TH32CS_SNAPMODULE32, call the function again until it succeeds. ```
this patch tries another approach by waiting until a window in the child process is visible
I ran a couple of tests for symrefreshmodulelist and couldn't get an error. we still more tries (on a longer period) to see if it's a fruitful approach or not
I also trace whether the retry mechanism is used
the tests are not changed (we just wait a bit longer for the child before testing)
if fruitful, we could remove the existing wrapper in dbghelp/test and fix psapi accordingly