-- v2: user32/tests: Test cross-platform use of scroll functions.
From: Esme Povirk esme@codeweavers.com
--- dlls/user32/tests/scroll.c | 197 +++++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+)
diff --git a/dlls/user32/tests/scroll.c b/dlls/user32/tests/scroll.c index 481219665ec..88475795c28 100644 --- a/dlls/user32/tests/scroll.c +++ b/dlls/user32/tests/scroll.c @@ -785,6 +785,186 @@ static void test_subclass(void) DestroyWindow(hwnd); }
+static void read_process(HWND hMainWnd) +{ + SCROLLBARINFO sbi = {0}; + SCROLLINFO si; + BOOL ret; + RECT rect, intersection; + BOOL (WINAPI *pGetScrollBarInfo)(HWND, LONG, LPSCROLLBARINFO); + + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE; + si.nMin = si.nMax = si.nPos = (int)0xdeadbeef; + si.nPage = 0xdeadbeef; + ret = GetScrollInfo( hMainWnd, SB_HORZ, &si ); + todo_wine ok( ret, "GetScrollInfo should succeed\n" ); + + todo_wine ok( si.nMin == 1, "unexpected nMin %i\n", si.nMin ); + todo_wine ok( si.nMax == 10, "unexpected nMax %i\n", si.nMax ); + todo_wine ok( si.nPage == 3, "unexpected nPage %u\n", si.nPage ); + todo_wine ok( si.nPos == 4, "unexpected nPos %i\n", si.nPos ); + + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE; + si.nMin = si.nMax = si.nPos = (int)0xdeadbeef; + si.nPage = 0xdeadbeef; + ret = GetScrollInfo( hMainWnd, SB_VERT, &si ); + todo_wine ok( ret, "GetScrollInfo should succeed\n" ); + + todo_wine ok( si.nMin == 201, "unexpected nMin %i\n", si.nMin ); + todo_wine ok( si.nMax == 210, "unexpected nMax %i\n", si.nMax ); + todo_wine ok( si.nPage == 2, "unexpected nPage %u\n", si.nPage ); + todo_wine ok( si.nPos == 204, "unexpected nPos %i\n", si.nPos ); + + pGetScrollBarInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetScrollBarInfo"); + if (!pGetScrollBarInfo) + { + win_skip("GetScrollBarInfo is not available\n"); + return; + } + + ret = GetWindowRect( hMainWnd, &rect ); + ok( ret, "The GetWindowRect() call should not fail.\n" ); + + sbi.cbSize = sizeof(sbi); + sbi.rgstate[0] = 0xdeadbeef; + ret = pGetScrollBarInfo( hMainWnd, OBJID_HSCROLL, &sbi ); + todo_wine ok( ret, "The GetScrollBarInfo() call should not fail.\n" ); + + IntersectRect( &intersection, &sbi.rcScrollBar, &rect ); + todo_wine ok( EqualRect( &intersection, &sbi.rcScrollBar ), "hscroll rect %s outside window rect %s\n", + wine_dbgstr_rect( &sbi.rcScrollBar ), wine_dbgstr_rect( &rect )); + todo_wine ok( sbi.rcScrollBar.right - sbi.rcScrollBar.left > sbi.rcScrollBar.bottom - sbi.rcScrollBar.top, + "hscroll rect %s should have width > height\n", wine_dbgstr_rect( &rect )); + todo_wine ok( sbi.rgstate[0] == 0, "unexpected hscroll state %#lx\n", sbi.rgstate[0] ); + + sbi.cbSize = sizeof(sbi); + sbi.rgstate[0] = 0xdeadbeef; + ret = pGetScrollBarInfo( hMainWnd, OBJID_VSCROLL, &sbi ); + todo_wine ok( ret, "The GetScrollBarInfo() call should not fail.\n" ); + + IntersectRect( &intersection, &sbi.rcScrollBar, &rect ); + todo_wine ok( EqualRect( &intersection, &sbi.rcScrollBar ), "vscroll rect %s outside window rect %s\n", + wine_dbgstr_rect( &sbi.rcScrollBar ), wine_dbgstr_rect( &rect )); + todo_wine ok( sbi.rcScrollBar.right - sbi.rcScrollBar.left < sbi.rcScrollBar.bottom - sbi.rcScrollBar.top, + "vscroll rect %s should have width < height\n", wine_dbgstr_rect( &rect )); + todo_wine ok( sbi.rgstate[0] == 0, "unexpected vscroll state %#lx\n", sbi.rgstate[0] ); +} + +static DWORD WINAPI write_process(HWND hMainWnd) +{ + SCROLLBARINFO sbi; + SCROLLINFO si; + BOOL ret; + BOOL (WINAPI *pGetScrollBarInfo)(HWND, LONG, LPSCROLLBARINFO); + + si.cbSize = sizeof(si); + si.fMask = SIF_POS; + si.nPos = 6; + ret = SetScrollInfo( hMainWnd, SB_HORZ, &si, FALSE ); + todo_wine ok( ret, "SetScrollInfo should succeed\n" ); + + si.nPos = 206; + ret = SetScrollInfo( hMainWnd, SB_VERT, &si, FALSE ); + todo_wine ok( ret, "SetScrollInfo should succeed\n" ); + + si.nPos = 0xdeadbeef; + ret = GetScrollInfo( hMainWnd, SB_HORZ, &si ); + todo_wine ok( ret, "GetScrollInfo should succeed\n" ); + todo_wine ok( si.nPos == 6, "unexpected nPos %i\n", si.nPos ); + + si.nPos = 0xdeadbeef; + ret = GetScrollInfo( hMainWnd, SB_VERT, &si ); + todo_wine ok( ret, "GetScrollInfo should succeed\n" ); + todo_wine ok( si.nPos == 206, "unexpected nPos %i\n", si.nPos ); + + pGetScrollBarInfo = (void*)GetProcAddress(GetModuleHandleA("user32.dll"), "GetScrollBarInfo"); + if (!pGetScrollBarInfo) + { + win_skip("GetScrollBarInfo is not available\n"); + return 0; + } + + ret = EnableScrollBar( hMainWnd, SB_HORZ, ESB_DISABLE_BOTH ); + todo_wine ok( ret, "EnableScrollBar should succeed\n" ); + + ret = ShowScrollBar( hMainWnd, SB_VERT, FALSE ); + ok( ret, "ShowScrollBar should succeed\n" ); + + sbi.cbSize = sizeof(sbi); + sbi.rgstate[0] = 0xdeadbeef; + ret = pGetScrollBarInfo( hMainWnd, OBJID_HSCROLL, &sbi ); + todo_wine ok( ret, "The GetScrollBarInfo() call should not fail.\n" ); + todo_wine ok( sbi.rgstate[0] == STATE_SYSTEM_UNAVAILABLE, "unexpected hscroll state %#lx\n", sbi.rgstate[0] ); + + sbi.cbSize = sizeof(sbi); + sbi.rgstate[0] = 0xdeadbeef; + ret = pGetScrollBarInfo( hMainWnd, OBJID_VSCROLL, &sbi ); + todo_wine ok( ret, "The GetScrollBarInfo() call should not fail.\n" ); + todo_wine ok( sbi.rgstate[0] == STATE_SYSTEM_INVISIBLE, "unexpected vscroll state %#lx\n", sbi.rgstate[0] ); + + return 0; +} + +static void test_cross_process(const char* argv0) +{ + HWND hMainWnd; + BOOL ret; + SCROLLINFO si; + STARTUPINFOA startup_info = {0}; + PROCESS_INFORMATION process_info; + char path[MAX_PATH]; + + hMainWnd = create_main_test_wnd(); + + si.cbSize = sizeof(si); + si.fMask = SIF_PAGE|SIF_POS|SIF_RANGE; + si.nMin = 1; + si.nMax = 10; + si.nPage = 3; + si.nPos = 4; + SetScrollInfo( hMainWnd, SB_HORZ, &si, FALSE ); + + si.nMin = 201; + si.nMax = 210; + si.nPage = 2; + si.nPos = 204; + SetScrollInfo( hMainWnd, SB_VERT, &si, FALSE ); + + startup_info.cb = sizeof(startup_info); + sprintf( path, "%s scroll read_process %p", argv0, hMainWnd ); + ret = CreateProcessA( NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &startup_info, &process_info ); + ok(ret, "CreateProcess "%s" failed err %lu.\n", path, GetLastError()); + + /* Messages do not need to be processed to read info. */ + winetest_wait_child_process(process_info.hProcess); + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + + sprintf( path, "%s scroll write_process %p", argv0, hMainWnd ); + ret = CreateProcessA( NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &startup_info, &process_info ); + ok(ret, "CreateProcess "%s" failed err %lu.\n", path, GetLastError()); + + /* Modifying info requires a message loop. */ + while (MsgWaitForMultipleObjects( 1, &process_info.hProcess, FALSE, 5000, QS_SENDMESSAGE ) == 1) + { + MSG msg; + while (PeekMessageA( &msg, NULL, 0, 0, PM_REMOVE )) + { + TranslateMessage( &msg ); + DispatchMessageA( &msg ); + } + } + + winetest_wait_child_process(process_info.hProcess); + CloseHandle(process_info.hProcess); + CloseHandle(process_info.hThread); + + DestroyWindow( hScroll ); + DestroyWindow( hMainWnd ); +} + static void test_visual(void) { static const int color_indices[] = {COLOR_SCROLLBAR, COLOR_BTNFACE}; @@ -826,10 +1006,26 @@ static void test_visual(void)
START_TEST ( scroll ) { + char **argv; + int argc; WNDCLASSA wc; HMODULE hUxtheme; BOOL (WINAPI * pIsThemeActive)(VOID);
+ argc = winetest_get_mainargs(&argv); + if (argc >= 4 && (!strcmp( argv[2], "read_process" ) || !strcmp( argv[2], "write_process" ))) + { + long wnd_long = strtol( argv[3], NULL, 16 ); + HWND wnd = (HWND)(INT_PTR)wnd_long; + + if (!strcmp( argv[2], "read_process" )) + read_process( wnd ); + else + write_process( wnd ); + + return; + } + wc.style = CS_HREDRAW | CS_VREDRAW; wc.cbClsExtra = 0; wc.cbWndExtra = 0; @@ -849,6 +1045,7 @@ START_TEST ( scroll ) scrollbar_test_track(); test_SetScrollInfo(); test_subclass(); + test_cross_process( argv[0] );
/* Some test results vary depending of theming being active or not */ hUxtheme = LoadLibraryA("uxtheme.dll");
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=136589
Your paranoid android.
=== debian11 (32 bit report) ===
user32: scroll.c:836: Test succeeded inside todo block: hscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100) scroll.c:848: Test succeeded inside todo block: vscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100)
=== debian11 (32 bit ar:MA report) ===
user32: scroll.c:836: Test succeeded inside todo block: hscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100) scroll.c:848: Test succeeded inside todo block: vscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100)
=== debian11 (32 bit de report) ===
user32: scroll.c:836: Test succeeded inside todo block: hscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100) scroll.c:848: Test succeeded inside todo block: vscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100)
=== debian11 (32 bit fr report) ===
user32: scroll.c:836: Test succeeded inside todo block: hscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100) scroll.c:848: Test succeeded inside todo block: vscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100)
=== debian11 (32 bit he:IL report) ===
user32: scroll.c:836: Test succeeded inside todo block: hscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100) scroll.c:848: Test succeeded inside todo block: vscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100)
=== debian11 (32 bit hi:IN report) ===
user32: scroll.c:836: Test succeeded inside todo block: hscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100) scroll.c:848: Test succeeded inside todo block: vscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100)
=== debian11 (32 bit ja:JP report) ===
user32: scroll.c:836: Test succeeded inside todo block: hscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100) scroll.c:848: Test succeeded inside todo block: vscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100)
=== debian11 (32 bit zh:CN report) ===
user32: scroll.c:836: Test succeeded inside todo block: hscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100) scroll.c:848: Test succeeded inside todo block: vscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100)
=== debian11b (32 bit WoW report) ===
user32: scroll.c:836: Test succeeded inside todo block: hscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100) scroll.c:848: Test succeeded inside todo block: vscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100)
=== debian11b (64 bit WoW report) ===
user32: scroll.c:836: Test succeeded inside todo block: hscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100) scroll.c:848: Test succeeded inside todo block: vscroll rect (0,0)-(0,0) outside window rect (0,0)-(119,100)
On Tue Aug 22 18:14:38 2023 +0000, Esme Povirk wrote:
Testing showed that GetScrollBarInfo, at least, does not require a message pump on Windows.
Wrote some more complete tests. This will require both moving info to server for reading and internal messages for writing, it seems. I haven't gotten the writing part to do anything useful on Windows, so I'll probably stick with reading.
On Tue Aug 22 19:55:28 2023 +0000, Esme Povirk wrote:
Wrote some more complete tests. This will require both moving info to server for reading and internal messages for writing, it seems. I haven't gotten the writing part to do anything useful on Windows, so I'll probably stick with reading.
I think the whole scroll_info struct would need to be moved to the server, as well as some of the update logic to make it atomic. Tracking info may also have to be moved, but I haven't tested and I'm not sure how useful it is in practice. GetScrollBarInfo returns more information than that, but I guess that calculation should work from another thread.