From b2d118d4f1e8fcb43f20453df2d8545a6f1b637f Mon Sep 17 00:00:00 2001 From: Alexandre Julliard <julliard@winehq.org> Date: Thu, 21 Nov 2024 11:02:26 +0100 Subject: [PATCH] win32u: Implement the remaining arguments of NtUserBuildHwndList(). --- dlls/win32u/main.c | 2 +- dlls/win32u/tests/win32u.c | 216 +++++++++++++++++++++++++++++---- dlls/win32u/window.c | 18 +-- dlls/wow64win/user.c | 12 +- include/ntuser.h | 2 +- include/wine/server_protocol.h | 24 +++- server/protocol.def | 12 ++ server/request_handlers.h | 9 ++ server/request_trace.h | 17 +++ server/user.c | 2 +- server/user.h | 2 + server/window.c | 97 +++++++++++++++ 12 files changed, 372 insertions(+), 41 deletions(-) diff --git a/dlls/win32u/main.c b/dlls/win32u/main.c index 5246da89991..11628dcccca 100644 --- a/dlls/win32u/main.c +++ b/dlls/win32u/main.c @@ -1127,7 +1127,7 @@ NTSTATUS SYSCALL_API NtUserBuildHimcList( UINT thread_id, UINT count, HIMC *buff SYSCALL_FUNC( NtUserBuildHimcList ); } -NTSTATUS SYSCALL_API NtUserBuildHwndList( HDESK desktop, ULONG unk2, ULONG unk3, ULONG unk4, +NTSTATUS SYSCALL_API NtUserBuildHwndList( HDESK desktop, HWND hwnd, BOOL children, BOOL non_immersive, ULONG thread_id, ULONG count, HWND *buffer, ULONG *size ) { SYSCALL_FUNC( NtUserBuildHwndList ); diff --git a/dlls/win32u/tests/win32u.c b/dlls/win32u/tests/win32u.c index 631b722ea22..aa517a32ae8 100644 --- a/dlls/win32u/tests/win32u.c +++ b/dlls/win32u/tests/win32u.c @@ -496,71 +496,241 @@ static BOOL WINAPI count_win( HWND hwnd, LPARAM lparam ) static void test_NtUserBuildHwndList(void) { - ULONG size, desktop_windows_cnt; - HWND buf[512], hwnd; + ULONG i, size, count, desktop_windows_cnt; + HWND buf[512], hwnd, msg, msg_window, child, child2, grandchild; NTSTATUS status; - size = 0; - status = NtUserBuildHwndList( 0, 0, 0, 0, GetCurrentThreadId(), ARRAYSIZE(buf), buf, &size ); + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, 0, FALSE, FALSE, GetCurrentThreadId(), ARRAYSIZE(buf), buf, &size ); ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); ok( size == 1, "size = %lu\n", size ); - ok( buf[0] == HWND_BOTTOM, "buf[0] = %p\n", buf[0] ); + ok( buf[size - 1] == HWND_BOTTOM, "buf[size - 1] = %p\n", buf[size - 1] ); + + msg = CreateWindowExA( 0, "static", "", WS_POPUP, 0,0,0,0,HWND_MESSAGE,0,0, NULL ); + msg_window = GetAncestor( msg, GA_PARENT ); - hwnd = CreateWindowExA( 0, "static", NULL, WS_POPUP, 0,0,0,0,GetDesktopWindow(),0,0, NULL ); + hwnd = CreateWindowExA( 0, "static", "test static", WS_POPUP, 0,0,0,0,GetDesktopWindow(),0,0, NULL ); + child = CreateWindowExA( 0, "static", "child static", WS_CHILD, 0,0,0,0,hwnd,0,0, NULL ); + child2 = CreateWindowExA( 0, "static", "child2 static", WS_CHILD, 0,0,0,0,hwnd,0,0, NULL ); + grandchild = CreateWindowExA( 0, "static", "grandchild static", WS_CHILD, 0,0,0,0,child,0,0, NULL ); - size = 0; - status = NtUserBuildHwndList( 0, 0, 0, 0, GetCurrentThreadId(), ARRAYSIZE(buf), buf, &size ); + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, 0, FALSE, FALSE, GetCurrentThreadId(), ARRAYSIZE(buf), buf, &size ); ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); ok( size == 3, "size = %lu\n", size ); ok( buf[0] == hwnd, "buf[0] = %p\n", buf[0] ); - ok( buf[2] == HWND_BOTTOM, "buf[0] = %p\n", buf[2] ); + ok( buf[size - 1] == HWND_BOTTOM, "buf[size - 1] = %p\n", buf[size - 1] ); - size = 0; - status = NtUserBuildHwndList( 0, 0, 0, 0, GetCurrentThreadId(), 3, buf, &size ); + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, 0, FALSE, FALSE, GetCurrentThreadId(), 3, buf, &size ); ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); ok( size == 3, "size = %lu\n", size ); - size = 0; - status = NtUserBuildHwndList( 0, 0, 0, 0, GetCurrentThreadId(), 2, buf, &size ); + size = 0xdeadbeef; + memset( buf, 0xcc, sizeof(buf) ); + status = NtUserBuildHwndList( 0, 0, FALSE, FALSE, GetCurrentThreadId(), 2, buf, &size ); ok( status == STATUS_BUFFER_TOO_SMALL, "NtUserBuildHwndList failed: %#lx\n", status ); ok( size == 3, "size = %lu\n", size ); + ok( HandleToUlong(buf[0]) == 0xcccccccc, "buf[0] initialized\n" ); - size = 0; - status = NtUserBuildHwndList( 0, 0, 0, 0, GetCurrentThreadId(), 1, buf, &size ); + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, 0, FALSE, FALSE, GetCurrentThreadId(), 1, buf, &size ); ok( status == STATUS_BUFFER_TOO_SMALL, "NtUserBuildHwndList failed: %#lx\n", status ); ok( size == 3, "size = %lu\n", size ); desktop_windows_cnt = 0; EnumDesktopWindows( 0, count_win, (LPARAM)&desktop_windows_cnt ); - size = 0; - status = NtUserBuildHwndList( 0, 0, 0, 1, 0, ARRAYSIZE(buf), buf, &size ); + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, 0, FALSE, TRUE, 0, ARRAYSIZE(buf), buf, &size ); ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); + todo_wine /* EnumDesktopWindows also returns message windows */ ok( size == desktop_windows_cnt + 1, "size = %lu, expected %lu\n", size, desktop_windows_cnt + 1 ); desktop_windows_cnt = 0; EnumDesktopWindows( GetThreadDesktop( GetCurrentThreadId() ), count_win, (LPARAM)&desktop_windows_cnt ); - size = 0; - status = NtUserBuildHwndList( GetThreadDesktop(GetCurrentThreadId()), 0, 0, 1, 0, + size = 0xdeadbeef; + status = NtUserBuildHwndList( GetThreadDesktop(GetCurrentThreadId()), 0, FALSE, TRUE, 0, ARRAYSIZE(buf), buf, &size ); ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); ok( size == desktop_windows_cnt + 1, "size = %lu, expected %lu\n", size, desktop_windows_cnt + 1 ); + for (i = 0; i < size; i++) if (buf[i] == msg_window) break; + ok( i == size, "message window was enumerated\n" ); - size = 0; - status = NtUserBuildHwndList( GetThreadDesktop(GetCurrentThreadId()), 0, 0, 0, 0, + size = 0xdeadbeef; + status = NtUserBuildHwndList( GetThreadDesktop(GetCurrentThreadId()), 0, FALSE, FALSE, 0, ARRAYSIZE(buf), buf, &size ); ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); todo_wine ok( size > desktop_windows_cnt + 1, "size = %lu, expected %lu\n", size, desktop_windows_cnt + 1 ); size = 0xdeadbeef; - status = NtUserBuildHwndList( UlongToHandle(0xdeadbeef), 0, 0, 0, 0, + status = NtUserBuildHwndList( GetThreadDesktop(GetCurrentThreadId()), hwnd, FALSE, TRUE, 0, + ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); + ok( size == desktop_windows_cnt + 1, "size = %lu, expected %lu\n", size, desktop_windows_cnt + 1 ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( GetThreadDesktop(GetCurrentThreadId()), 0, TRUE, TRUE, 0, ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); + ok( size == 1, "size = %lu\n", size ); + ok( buf[size - 1] == HWND_BOTTOM, "buf[size - 1] = %p\n", buf[size - 1] ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, 0, TRUE, TRUE, 0, ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); + ok( size == desktop_windows_cnt + 1, "size = %lu, expected %lu\n", size, desktop_windows_cnt + 1 ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( UlongToHandle(0xdeadbeef), 0, FALSE, FALSE, 0, + ARRAYSIZE(buf), buf, &size ); + ok( status == STATUS_INVALID_HANDLE, "NtUserBuildHwndList failed: %#lx\n", status ); + ok( size == 0xdeadbeef, "size = %lu\n", size ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, GetDesktopWindow(), TRUE, FALSE, 0, ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); + ok( size > 4, "size = %lu\n", size ); + for (i = 0; i < size; i++) + { + if (buf[i] != hwnd) continue; + ok( buf[i] == hwnd, "buf[i] = %p / %p\n", buf[i], hwnd ); + ok( buf[i + 1] == child, "buf[i + 1] = %p / %p\n", buf[i + 1], child ); + ok( buf[i + 2] == grandchild, "buf[i + 2] = %p / %p\n", buf[i + 2], grandchild ); + ok( buf[i + 3] == child2, "buf[i + 3] = %p / %p\n", buf[i + 3], child2 ); + break; + } + ok( i < size, "window not found\n" ); + ok( buf[size - 1] == HWND_BOTTOM, "buf[size - 1] = %p\n", buf[size - 1] ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, 0, FALSE, FALSE, GetCurrentThreadId(), ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); + ok( size >= 2, "size = %lu\n", size ); + ok( buf[0] == hwnd, "buf[0] = %p / %p\n", buf[0], hwnd ); + ok( buf[1] != child, "buf[1] = %p\n", buf[1] ); + ok( buf[size - 1] == HWND_BOTTOM, "buf[size - 1] = %p\n", buf[size - 1] ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, hwnd, TRUE, FALSE, 0, ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); + ok( size == 4, "size = %lu\n", size ); + ok( buf[0] == child, "buf[0] = %p / %p\n", buf[0], child ); + ok( buf[1] == grandchild, "buf[1] = %p / %p\n", buf[1], grandchild ); + ok( buf[2] == child2, "buf[2] = %p / %p\n", buf[2], child2 ); + ok( buf[size - 1] == HWND_BOTTOM, "buf[size - 1] = %p\n", buf[size - 1] ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, child, FALSE, FALSE, 0, ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); + ok( size == 3, "size = %lu\n", size ); + ok( buf[0] == child, "buf[0] = %p / %p\n", buf[0], child ); + ok( buf[1] == child2, "buf[1] = %p / %p\n", buf[1], child2 ); + ok( buf[size - 1] == HWND_BOTTOM, "buf[size - 1] = %p\n", buf[size - 1] ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, grandchild, FALSE, FALSE, 0, ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); + ok( size == 2, "size = %lu\n", size ); + ok( buf[0] == grandchild, "buf[0] = %p / %p\n", buf[0], grandchild ); + ok( buf[size - 1] == HWND_BOTTOM, "buf[size - 1] = %p\n", buf[size - 1] ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, grandchild, TRUE, FALSE, 0, ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); + ok( size == 1, "size = %lu\n", size ); + ok( buf[size - 1] == HWND_BOTTOM, "buf[size - 1] = %p\n", buf[size - 1] ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, hwnd, FALSE, FALSE, 0, ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); + ok( size > 2, "size = %lu\n", size ); + ok( buf[0] == hwnd, "buf[0] = %p / %p\n", buf[0], hwnd ); + /* ... followed by other siblings */ + ok( buf[size - 1] == HWND_BOTTOM, "buf[size - 1] = %p\n", buf[size - 1] ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, hwnd, FALSE, FALSE, GetCurrentThreadId(), ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); + ok( size == 2 || size == 3, "size = %lu\n", size ); + ok( buf[0] == hwnd, "buf[0] = %p / %p\n", buf[0], hwnd ); + /* ... possibly followed by IME window */ + ok( buf[size - 1] == HWND_BOTTOM, "buf[size - 1] = %p\n", buf[size - 1] ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, GetDesktopWindow(), FALSE, FALSE, 0, ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); + ok( size > 2, "size = %lu\n", size ); + ok( buf[0] == GetDesktopWindow(), "buf[0] = %p / %p\n", buf[0], GetDesktopWindow() ); + /* ... followed by desktop window siblings */ + for (i = 0; i < size; i++) if (buf[i] == msg_window) break; + ok( i < size, "message window was not enumerated\n" ); + count = size - i; + ok( buf[size - 1] == HWND_BOTTOM, "buf[size - 1] = %p\n", buf[size - 1] ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, msg_window, FALSE, FALSE, 0, ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); + ok( size == count, "size = %lu / %lu\n", size, count ); + ok( buf[0] == msg_window, "buf[0] = %p / %p\n", buf[0], msg_window ); + for (i = 0; i < size; i++) if (buf[i] == GetDesktopWindow()) break; + ok( i == size, "desktop window was enumerated\n" ); + /* ... followed by msg window siblings */ + ok( buf[size - 1] == HWND_BOTTOM, "buf[size - 1] = %p\n", buf[size - 1] ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, GetDesktopWindow(), TRUE, FALSE, 0, ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); + /* includes all desktop window children */ + ok( size > desktop_windows_cnt + 1, "size = %lu, expected %lu\n", size, desktop_windows_cnt + 1 ); + for (i = 0; i < size; i++) + { + ok( buf[i] != GetDesktopWindow(), "desktop window enumerated\n" ); + ok( buf[i] != msg_window, "message window enumerated\n" ); + } + for (i = 0; i < size; i++) if (buf[i] == hwnd) break; + ok( i < size, "window was not enumerated\n" ); + for (i = 0; i < size; i++) if (buf[i] == child) break; + ok( i < size, "child window was not enumerated\n" ); + for (i = 0; i < size; i++) if (buf[i] == grandchild) break; + ok( i < size, "grandchild window was not enumerated\n" ); + ok( buf[size - 1] == HWND_BOTTOM, "buf[size - 1] = %p\n", buf[size - 1] ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, msg_window, TRUE, FALSE, 0, ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#lx\n", status ); + /* includes all HWND_MESSAGE windows */ + ok( size > 1, "size = %lu\n", size ); + for (i = 0; i < size; i++) + { + ok( buf[i] != GetDesktopWindow(), "desktop window enumerated\n" ); + ok( buf[i] != msg_window, "message window enumerated\n" ); + ok( buf[i] != hwnd, "window enumerated\n" ); + ok( buf[i] != child, "child window enumerated\n" ); + ok( buf[i] != grandchild, "grandchild window enumerated\n" ); + } + ok( buf[size - 1] == HWND_BOTTOM, "buf[size - 1] = %p\n", buf[size - 1] ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, (HWND)0xdeadbeef, FALSE, FALSE, 0, ARRAYSIZE(buf), buf, &size ); + ok( status == STATUS_INVALID_HANDLE, "NtUserBuildHwndList failed: %#lx\n", status ); + ok( size == 0xdeadbeef, "size = %lu\n", size ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( GetThreadDesktop(GetCurrentThreadId()), (HWND)0xdeadbeef, + FALSE, FALSE, 0, ARRAYSIZE(buf), buf, &size ); + ok( status == STATUS_INVALID_HANDLE, "NtUserBuildHwndList failed: %#lx\n", status ); + ok( size == 0xdeadbeef, "size = %lu\n", size ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( 0, 0, FALSE, FALSE, 0xdeadbeef, ARRAYSIZE(buf), buf, &size ); ok( status == STATUS_INVALID_HANDLE, "NtUserBuildHwndList failed: %#lx\n", status ); ok( size == 0xdeadbeef, "size = %lu\n", size ); DestroyWindow( hwnd ); + DestroyWindow( msg ); } static BOOL CALLBACK enum_names( LPWSTR name, LPARAM lp ) @@ -580,7 +750,7 @@ static void test_NtUserBuildNameList(void) struct ntuser_name_list *buffer; WCHAR *p; NTSTATUS status; - ULONG i, count, ret_size, expect, size = offsetof( struct ntuser_name_list, strings[256] ); + ULONG i, count, ret_size, expect, size = offsetof( struct ntuser_name_list, strings[1024] ); buffer = malloc( size ); memset( buffer, 0xcc, size ); diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index eb313528f69..59f12a439c2 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -2969,24 +2969,26 @@ BOOL WINAPI NtUserSetWindowPlacement( HWND hwnd, const WINDOWPLACEMENT *wpl ) /***************************************************************************** * NtUserBuildHwndList (win32u.@) */ -NTSTATUS WINAPI NtUserBuildHwndList( HDESK desktop, ULONG unk2, ULONG unk3, ULONG unk4, +NTSTATUS WINAPI NtUserBuildHwndList( HDESK desktop, HWND hwnd, BOOL children, BOOL non_immersive, ULONG thread_id, ULONG count, HWND *buffer, ULONG *size ) { user_handle_t *list = (user_handle_t *)buffer; int i; NTSTATUS status; - SERVER_START_REQ( get_window_children ) + SERVER_START_REQ( get_window_list ) { - req->desktop = wine_server_obj_handle( desktop ); - req->tid = thread_id; - if (count) wine_server_set_reply( req, list, (count - 1) * sizeof(user_handle_t) ); + req->desktop = wine_server_obj_handle( desktop ); + req->handle = wine_server_user_handle( hwnd ); + req->tid = thread_id; + req->children = children; + if (count) wine_server_set_reply( req, list, (count - 1) * sizeof(*list) ); status = wine_server_call( req ); - if (status && status != STATUS_BUFFER_TOO_SMALL) return status; - *size = reply->count + 1; + if (!status || status == STATUS_BUFFER_TOO_SMALL) *size = reply->count + 1; } SERVER_END_REQ; - if (*size > count) return STATUS_BUFFER_TOO_SMALL; + + if (status) return status; /* start from the end since HWND is potentially larger than user_handle_t */ for (i = *size - 2; i >= 0; i--) diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 1daa577775b..28944f15d07 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -1611,9 +1611,9 @@ NTSTATUS WINAPI wow64_NtUserBuildHimcList( UINT *args ) NTSTATUS WINAPI wow64_NtUserBuildHwndList( UINT *args ) { HDESK desktop = get_handle( &args ); - ULONG unk2 = get_ulong( &args ); - ULONG unk3 = get_ulong( &args ); - ULONG unk4 = get_ulong( &args ); + HWND hwnd = get_handle( &args ); + BOOL children = get_ulong( &args ); + BOOL non_immersive = get_ulong( &args ); ULONG thread_id = get_ulong( &args ); ULONG count = get_ulong( &args ); UINT32 *buffer32 = get_ptr( &args ); @@ -1625,11 +1625,11 @@ NTSTATUS WINAPI wow64_NtUserBuildHwndList( UINT *args ) if (!(buffer = Wow64AllocateTemp( count * sizeof(*buffer) ))) return STATUS_NO_MEMORY; - if ((status = NtUserBuildHwndList( desktop, unk2, unk3, unk4, thread_id, count, buffer, size ))) + if ((status = NtUserBuildHwndList( desktop, hwnd, children, non_immersive, + thread_id, count, buffer, size ))) return status; - for (i = 0; i < *size; i++) - buffer32[i] = HandleToUlong( buffer[i] ); + for (i = 0; i < *size; i++) buffer32[i] = HandleToUlong( buffer[i] ); return status; } diff --git a/include/ntuser.h b/include/ntuser.h index 9ed470e2fc5..2475792e702 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -705,7 +705,7 @@ W32KAPI UINT WINAPI NtUserAssociateInputContext( HWND hwnd, HIMC ctx, ULONG f W32KAPI BOOL WINAPI NtUserAttachThreadInput( DWORD from, DWORD to, BOOL attach ); W32KAPI HDC WINAPI NtUserBeginPaint( HWND hwnd, PAINTSTRUCT *ps ); W32KAPI NTSTATUS WINAPI NtUserBuildHimcList( UINT thread_id, UINT count, HIMC *buffer, UINT *size ); -W32KAPI NTSTATUS WINAPI NtUserBuildHwndList( HDESK desktop, ULONG unk2, ULONG unk3, ULONG unk4, +W32KAPI NTSTATUS WINAPI NtUserBuildHwndList( HDESK desktop, HWND hwnd, BOOL children, BOOL non_immersive, ULONG thread_id, ULONG count, HWND *buffer, ULONG *size ); W32KAPI NTSTATUS WINAPI NtUserBuildNameList( HWINSTA winsta, ULONG size, struct ntuser_name_list *buffer, ULONG *ret_size ); W32KAPI NTSTATUS WINAPI NtUserBuildPropList( HWND hwnd, ULONG count, struct ntuser_property_list *buffer, ULONG *ret_count ); diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h index 075d41b9467..f0b9571aaed 100644 --- a/include/wine/server_protocol.h +++ b/include/wine/server_protocol.h @@ -3479,6 +3479,25 @@ struct get_window_parents_reply +struct get_window_list_request +{ + struct request_header __header; + obj_handle_t desktop; + user_handle_t handle; + thread_id_t tid; + int children; + char __pad_28[4]; +}; +struct get_window_list_reply +{ + struct reply_header __header; + int count; + /* VARARG(windows,user_handles); */ + char __pad_12[4]; +}; + + + struct get_window_children_request { struct request_header __header; @@ -6003,6 +6022,7 @@ enum request REQ_set_window_info, REQ_set_parent, REQ_get_window_parents, + REQ_get_window_list, REQ_get_window_children, REQ_get_window_children_from_point, REQ_get_window_tree, @@ -6300,6 +6320,7 @@ union generic_request struct set_window_info_request set_window_info_request; struct set_parent_request set_parent_request; struct get_window_parents_request get_window_parents_request; + struct get_window_list_request get_window_list_request; struct get_window_children_request get_window_children_request; struct get_window_children_from_point_request get_window_children_from_point_request; struct get_window_tree_request get_window_tree_request; @@ -6595,6 +6616,7 @@ union generic_reply struct set_window_info_reply set_window_info_reply; struct set_parent_reply set_parent_reply; struct get_window_parents_reply get_window_parents_reply; + struct get_window_list_reply get_window_list_reply; struct get_window_children_reply get_window_children_reply; struct get_window_children_from_point_reply get_window_children_from_point_reply; struct get_window_tree_reply get_window_tree_reply; @@ -6738,6 +6760,6 @@ union generic_reply struct set_keyboard_repeat_reply set_keyboard_repeat_reply; }; -#define SERVER_PROTOCOL_VERSION 849 +#define SERVER_PROTOCOL_VERSION 850 #endif /* __WINE_WINE_SERVER_PROTOCOL_H */ diff --git a/server/protocol.def b/server/protocol.def index 0abbb48f3b3..8082ad0f7cd 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2571,6 +2571,18 @@ enum message_type @END +/* Get a list of window siblings or children */ +@REQ(get_window_list) + obj_handle_t desktop; /* handle to desktop */ + user_handle_t handle; /* handle to window to start from */ + thread_id_t tid; /* thread owning the listed windows */ + int children; /* enumerate children? */ +@REPLY + int count; /* total count of windows */ + VARARG(windows,user_handles); /* window handles */ +@END + + /* Get a list of the window children */ @REQ(get_window_children) obj_handle_t desktop; /* handle to desktop */ diff --git a/server/request_handlers.h b/server/request_handlers.h index c5c5b387946..5f2a5518fe7 100644 --- a/server/request_handlers.h +++ b/server/request_handlers.h @@ -156,6 +156,7 @@ DECL_HANDLER(get_window_info); DECL_HANDLER(set_window_info); DECL_HANDLER(set_parent); DECL_HANDLER(get_window_parents); +DECL_HANDLER(get_window_list); DECL_HANDLER(get_window_children); DECL_HANDLER(get_window_children_from_point); DECL_HANDLER(get_window_tree); @@ -450,6 +451,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = (req_handler)req_set_window_info, (req_handler)req_set_parent, (req_handler)req_get_window_parents, + (req_handler)req_get_window_list, (req_handler)req_get_window_children, (req_handler)req_get_window_children_from_point, (req_handler)req_get_window_tree, @@ -1494,6 +1496,13 @@ C_ASSERT( offsetof(struct get_window_parents_request, handle) == 12 ); C_ASSERT( sizeof(struct get_window_parents_request) == 16 ); C_ASSERT( offsetof(struct get_window_parents_reply, count) == 8 ); C_ASSERT( sizeof(struct get_window_parents_reply) == 16 ); +C_ASSERT( offsetof(struct get_window_list_request, desktop) == 12 ); +C_ASSERT( offsetof(struct get_window_list_request, handle) == 16 ); +C_ASSERT( offsetof(struct get_window_list_request, tid) == 20 ); +C_ASSERT( offsetof(struct get_window_list_request, children) == 24 ); +C_ASSERT( sizeof(struct get_window_list_request) == 32 ); +C_ASSERT( offsetof(struct get_window_list_reply, count) == 8 ); +C_ASSERT( sizeof(struct get_window_list_reply) == 16 ); C_ASSERT( offsetof(struct get_window_children_request, desktop) == 12 ); C_ASSERT( offsetof(struct get_window_children_request, parent) == 16 ); C_ASSERT( offsetof(struct get_window_children_request, atom) == 20 ); diff --git a/server/request_trace.h b/server/request_trace.h index c099d709fe7..76adb66cec8 100644 --- a/server/request_trace.h +++ b/server/request_trace.h @@ -1762,6 +1762,20 @@ static void dump_get_window_parents_reply( const struct get_window_parents_reply dump_varargs_user_handles( ", parents=", cur_size ); } +static void dump_get_window_list_request( const struct get_window_list_request *req ) +{ + fprintf( stderr, " desktop=%04x", req->desktop ); + fprintf( stderr, ", handle=%08x", req->handle ); + fprintf( stderr, ", tid=%04x", req->tid ); + fprintf( stderr, ", children=%d", req->children ); +} + +static void dump_get_window_list_reply( const struct get_window_list_reply *req ) +{ + fprintf( stderr, " count=%d", req->count ); + dump_varargs_user_handles( ", windows=", cur_size ); +} + static void dump_get_window_children_request( const struct get_window_children_request *req ) { fprintf( stderr, " desktop=%04x", req->desktop ); @@ -3474,6 +3488,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = (dump_func)dump_set_window_info_request, (dump_func)dump_set_parent_request, (dump_func)dump_get_window_parents_request, + (dump_func)dump_get_window_list_request, (dump_func)dump_get_window_children_request, (dump_func)dump_get_window_children_from_point_request, (dump_func)dump_get_window_tree_request, @@ -3768,6 +3783,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = (dump_func)dump_set_window_info_reply, (dump_func)dump_set_parent_reply, (dump_func)dump_get_window_parents_reply, + (dump_func)dump_get_window_list_reply, (dump_func)dump_get_window_children_reply, (dump_func)dump_get_window_children_from_point_reply, (dump_func)dump_get_window_tree_reply, @@ -4062,6 +4078,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = "set_window_info", "set_parent", "get_window_parents", + "get_window_list", "get_window_children", "get_window_children_from_point", "get_window_tree", diff --git a/server/user.c b/server/user.c index c529fc729de..2d038a6ddbf 100644 --- a/server/user.c +++ b/server/user.c @@ -67,7 +67,7 @@ static inline struct user_handle *alloc_user_entry(void) struct user_handle *new_handles; /* grow array by 50% (but at minimum 32 entries) */ int growth = max( 32, allocated_handles / 2 ); - int new_size = min( allocated_handles + growth, (LAST_USER_HANDLE-FIRST_USER_HANDLE+1) >> 1 ); + int new_size = min( allocated_handles + growth, MAX_USER_HANDLES ); if (new_size <= allocated_handles) return NULL; if (!(new_handles = realloc( handles, new_size * sizeof(*handles) ))) return NULL; diff --git a/server/user.h b/server/user.h index c4778d810ec..a57e11b5a97 100644 --- a/server/user.h +++ b/server/user.h @@ -43,6 +43,8 @@ enum user_object #define DESKTOP_ATOM ((atom_t)32769) +#define MAX_USER_HANDLES ((LAST_USER_HANDLE - FIRST_USER_HANDLE + 1) >> 1) + struct winstation { struct object obj; /* object header */ diff --git a/server/window.c b/server/window.c index 5d84f3e55c7..1ddf47c5bfd 100644 --- a/server/window.c +++ b/server/window.c @@ -904,6 +904,60 @@ static int is_point_in_window( struct window *win, int *x, int *y, unsigned int return 1; } +/* helper for get_window_list */ +static void append_window_to_list( struct window *win, struct thread *thread, user_handle_t *handles, + unsigned int *count, unsigned int max_count ) +{ + if (thread && win->thread != thread) return; + if (*count < max_count) handles[*count] = win->handle; + (*count)++; +} + +/* fill an array with the handles of siblings or children */ +static void get_window_list( struct desktop *desktop, struct window *win, struct thread *thread, + int children, user_handle_t *handles, + unsigned int *count, unsigned int max_count ) +{ + struct list *ptr; + struct window *child; + + if (desktop) /* top-level windows of specified desktop */ + { + if (children) return; + if (!desktop->top_window) return; + LIST_FOR_EACH_ENTRY( child, &desktop->top_window->children, struct window, entry ) + append_window_to_list( child, thread, handles, count, max_count ); + } + else if (!win) /* top-level windows of current desktop */ + { + if (!(win = get_desktop_window( current ))) return; + LIST_FOR_EACH_ENTRY( child, &win->children, struct window, entry ) + append_window_to_list( child, thread, handles, count, max_count ); + } + else if (children) /* children (recursively) of specified window */ + { + LIST_FOR_EACH_ENTRY( child, &win->children, struct window, entry ) + { + append_window_to_list( child, thread, handles, count, max_count ); + get_window_list( NULL, child, thread, TRUE, handles, count, max_count ); + } + } + else if (!is_desktop_window( win )) /* siblings starting from specified window */ + { + for (ptr = &win->entry; ptr; ptr = list_next( &win->parent->children, ptr )) + { + struct window *sibling = LIST_ENTRY( ptr, struct window, entry ); + append_window_to_list( sibling, thread, handles, count, max_count ); + } + } + else /* desktop window siblings */ + { + append_window_to_list( win, thread, handles, count, max_count ); + if (win == win->desktop->top_window && win->desktop->msg_window) + append_window_to_list( win->desktop->msg_window, thread, handles, count, max_count ); + } +} + /* fill an array with the handles of the children of a specified window */ static unsigned int get_children_windows( struct window *parent, atom_t atom, thread_id_t tid, user_handle_t *handles, unsigned int max_count ) @@ -2380,6 +2434,49 @@ DECL_HANDLER(get_window_parents) } +/* get a list of window siblings or children */ +DECL_HANDLER(get_window_list) +{ + struct window *win = NULL; + struct desktop *desktop = NULL; + struct thread *thread = NULL; + user_handle_t *data; + unsigned int count = 0, max_count = get_reply_max_size() / sizeof(*data); + + if (req->handle && !(win = get_window( req->handle ))) + { + set_error( STATUS_INVALID_HANDLE ); + return; + } + if (req->tid && !(thread = get_thread_from_id( req->tid ))) + { + set_error( STATUS_INVALID_HANDLE ); + return; + } + if (req->desktop && !(desktop = get_desktop_obj( current->process, req->desktop, DESKTOP_ENUMERATE ))) + { + if (thread) release_object( thread ); + return; + } + + max_count = min( max_count, MAX_USER_HANDLES ); + if ((data = mem_alloc( max_count * sizeof(*data) ))) + { + get_window_list( desktop, win, thread, req->children, data, &count, max_count ); + if (count > max_count) + { + free( data ); + set_error( STATUS_BUFFER_TOO_SMALL ); + } + else set_reply_data_ptr( data, count * sizeof(*data) ); + reply->count = count; + } + + if (thread) release_object( thread ); + if (desktop) release_object( desktop ); +} + + /* get a list of the window children */ DECL_HANDLER(get_window_children) { -- GitLab