Module: wine Branch: master Commit: 2d56b0a93ce89e8f6e85e1011bac3c3afd6643ed URL: https://source.winehq.org/git/wine.git/?a=commit;h=2d56b0a93ce89e8f6e85e1011...
Author: Jacek Caban jacek@codeweavers.com Date: Tue Dec 21 20:31:29 2021 +0100
win32u: Implement NtUserBuildHwndList.
Fixes Quake Champions, spotted by Paul Gofman.
Signed-off-by: Jacek Caban jacek@codeweavers.com Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/win32u/syscall.c | 1 + dlls/win32u/tests/win32u.c | 82 +++++++++++++++++++++++++++++++++++++++- dlls/win32u/win32u.spec | 2 +- dlls/win32u/window.c | 31 +++++++++++++++ dlls/wow64win/Makefile.in | 2 +- dlls/wow64win/syscall.h | 1 + dlls/wow64win/user.c | 25 ++++++++++++ dlls/wow64win/wow64win_private.h | 2 + include/ntuser.h | 2 + 9 files changed, 144 insertions(+), 4 deletions(-)
diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index 3dd37bcf90d..69d0e1ff66f 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -103,6 +103,7 @@ static void * const syscalls[] = NtGdiTransformPoints, NtUserAddClipboardFormatListener, NtUserAttachThreadInput, + NtUserBuildHwndList, NtUserCloseDesktop, NtUserCloseWindowStation, NtUserCreateDesktopEx, diff --git a/dlls/win32u/tests/win32u.c b/dlls/win32u/tests/win32u.c index 13c732b7748..22ce38e2391 100644 --- a/dlls/win32u/tests/win32u.c +++ b/dlls/win32u/tests/win32u.c @@ -104,12 +104,90 @@ static void test_window_props(void) DestroyWindow( hwnd ); }
+static BOOL WINAPI count_win( HWND hwnd, LPARAM lparam ) +{ + ULONG *cnt = (ULONG *)lparam; + (*cnt)++; + return TRUE; +} + +static void test_NtUserBuildHwndList(void) +{ + ULONG size, desktop_windows_cnt; + HWND buf[512], hwnd; + NTSTATUS status; + + size = 0; + status = NtUserBuildHwndList( 0, 0, 0, 0, GetCurrentThreadId(), ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#x\n", status ); + ok( size == 1, "size = %u\n", size ); + ok( buf[0] == HWND_BOTTOM, "buf[0] = %p\n", buf[0] ); + + hwnd = CreateWindowExA( 0, "static", NULL, WS_POPUP, 0,0,0,0,GetDesktopWindow(),0,0, NULL ); + + size = 0; + status = NtUserBuildHwndList( 0, 0, 0, 0, GetCurrentThreadId(), ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#x\n", status ); + ok( size == 3, "size = %u\n", size ); + ok( buf[0] == hwnd, "buf[0] = %p\n", buf[0] ); + ok( buf[2] == HWND_BOTTOM, "buf[0] = %p\n", buf[2] ); + + size = 0; + status = NtUserBuildHwndList( 0, 0, 0, 0, GetCurrentThreadId(), 3, buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#x\n", status ); + ok( size == 3, "size = %u\n", size ); + + size = 0; + status = NtUserBuildHwndList( 0, 0, 0, 0, GetCurrentThreadId(), 2, buf, &size ); + ok( status == STATUS_BUFFER_TOO_SMALL, "NtUserBuildHwndList failed: %#x\n", status ); + ok( size == 3, "size = %u\n", size ); + + size = 0; + status = NtUserBuildHwndList( 0, 0, 0, 0, GetCurrentThreadId(), 1, buf, &size ); + ok( status == STATUS_BUFFER_TOO_SMALL, "NtUserBuildHwndList failed: %#x\n", status ); + ok( size == 3, "size = %u\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 ); + ok( !status, "NtUserBuildHwndList failed: %#x\n", status ); + ok( size == desktop_windows_cnt + 1, "size = %u, expected %u\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, + ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#x\n", status ); + ok( size == desktop_windows_cnt + 1, "size = %u, expected %u\n", size, desktop_windows_cnt + 1 ); + + size = 0; + status = NtUserBuildHwndList( GetThreadDesktop(GetCurrentThreadId()), 0, 0, 0, 0, + ARRAYSIZE(buf), buf, &size ); + ok( !status, "NtUserBuildHwndList failed: %#x\n", status ); + todo_wine + ok( size > desktop_windows_cnt + 1, "size = %u, expected %u\n", size, desktop_windows_cnt + 1 ); + + size = 0xdeadbeef; + status = NtUserBuildHwndList( UlongToHandle(0xdeadbeef), 0, 0, 0, 0, + ARRAYSIZE(buf), buf, &size ); + ok( status == STATUS_INVALID_HANDLE, "NtUserBuildHwndList failed: %#x\n", status ); + ok( size == 0xdeadbeef, "size = %u\n", size ); + + DestroyWindow( hwnd ); +} + START_TEST(win32u) { /* native win32u.dll fails if user32 is not loaded, so make sure it's fully initialized */ GetDesktopWindow();
- test_NtUserEnumDisplayDevices(); /* Must run before test_NtUserCloseWindowStation. */ - test_NtUserCloseWindowStation(); + test_NtUserEnumDisplayDevices(); test_window_props(); + test_NtUserBuildHwndList(); + + test_NtUserCloseWindowStation(); } diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index e13148af633..5ea2d3afc84 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -763,7 +763,7 @@ @ stub NtUserBlockInput @ stub NtUserBroadcastThemeChangeEvent @ stub NtUserBuildHimcList -@ stub NtUserBuildHwndList +@ stdcall -syscall NtUserBuildHwndList(long long long long long long ptr ptr) @ stub NtUserBuildNameList @ stub NtUserBuildPropList @ stub NtUserCalcMenuBar diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index a84ceeefaf5..e880594d98c 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -23,6 +23,8 @@ #pragma makedep unix #endif
+#include "ntstatus.h" +#define WIN32_NO_STATUS #include "win32u_private.h" #include "wine/server.h"
@@ -115,3 +117,32 @@ BOOL WINAPI NtUserGetLayeredWindowAttributes( HWND hwnd, COLORREF *key, BYTE *al
return ret; } + +/***************************************************************************** + * NtUserBuildHwndList (win32u.@) + */ +NTSTATUS WINAPI NtUserBuildHwndList( HDESK desktop, ULONG unk2, ULONG unk3, ULONG unk4, + 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 ) + { + 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) ); + status = wine_server_call( req ); + if (status && status != STATUS_BUFFER_TOO_SMALL) return status; + *size = reply->count + 1; + } + SERVER_END_REQ; + if (*size > count) return STATUS_BUFFER_TOO_SMALL; + + /* start from the end since HWND is potentially larger than user_handle_t */ + for (i = *size - 2; i >= 0; i--) + buffer[i] = wine_server_ptr_handle( list[i] ); + buffer[*size - 1] = HWND_BOTTOM; + return STATUS_SUCCESS; +} diff --git a/dlls/wow64win/Makefile.in b/dlls/wow64win/Makefile.in index 99301c4edf1..ce8c42f06f6 100644 --- a/dlls/wow64win/Makefile.in +++ b/dlls/wow64win/Makefile.in @@ -1,5 +1,5 @@ MODULE = wow64win.dll -IMPORTS = win32u ntdll winecrt0 +IMPORTS = wow64 win32u ntdll winecrt0
EXTRADLLFLAGS = -nodefaultlibs -Wl,--image-base,0x6f200000
diff --git a/dlls/wow64win/syscall.h b/dlls/wow64win/syscall.h index 87ba42bc3cc..54919f7b3fd 100644 --- a/dlls/wow64win/syscall.h +++ b/dlls/wow64win/syscall.h @@ -90,6 +90,7 @@ SYSCALL_ENTRY( NtGdiTransformPoints ) \ SYSCALL_ENTRY( NtUserAddClipboardFormatListener ) \ SYSCALL_ENTRY( NtUserAttachThreadInput ) \ + SYSCALL_ENTRY( NtUserBuildHwndList ) \ SYSCALL_ENTRY( NtUserCloseDesktop ) \ SYSCALL_ENTRY( NtUserCloseWindowStation ) \ SYSCALL_ENTRY( NtUserCreateDesktopEx ) \ diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 2f791ddda59..02623d089a4 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -181,6 +181,31 @@ NTSTATUS WINAPI wow64_NtUserRemoveProp( UINT *args ) return HandleToUlong( NtUserRemoveProp( hwnd, str )); }
+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 ); + ULONG thread_id = get_ulong( &args ); + ULONG count = get_ulong( &args ); + UINT32 *buffer32 = get_ptr( &args ); + ULONG *size = get_ptr( &args ); + + HWND *buffer; + ULONG i; + NTSTATUS status; + + if (!(buffer = Wow64AllocateTemp( count * sizeof(*buffer) ))) return STATUS_NO_MEMORY; + + if ((status = NtUserBuildHwndList( desktop, unk2, unk3, unk4, thread_id, count, buffer, size ))) + return status; + + for (i = 0; i < *size; i++) + buffer32[i] = HandleToUlong( buffer[i] ); + return status; +} + NTSTATUS WINAPI wow64_NtUserGetLayeredWindowAttributes( UINT *args ) { HWND hwnd = get_handle( &args ); diff --git a/dlls/wow64win/wow64win_private.h b/dlls/wow64win/wow64win_private.h index 3a6156f41b2..9127085b7b4 100644 --- a/dlls/wow64win/wow64win_private.h +++ b/dlls/wow64win/wow64win_private.h @@ -27,6 +27,8 @@ ALL_WIN32_SYSCALLS #undef SYSCALL_ENTRY
+void * WINAPI Wow64AllocateTemp( SIZE_T size ); + struct object_attr64 { OBJECT_ATTRIBUTES attr; diff --git a/include/ntuser.h b/include/ntuser.h index ca430e7b6b1..a9dd8d2e3fd 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -105,6 +105,8 @@ C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) HKL WINAPI NtUserActivateKeyboardLayout( HKL layout, UINT flags ); BOOL WINAPI NtUserAddClipboardFormatListener( HWND hwnd ); BOOL WINAPI NtUserAttachThreadInput( DWORD from, DWORD to, BOOL attach ); +NTSTATUS WINAPI NtUserBuildHwndList( HDESK desktop, ULONG unk2, ULONG unk3, ULONG unk4, + ULONG thread_id, ULONG count, HWND *buffer, ULONG *size ); ULONG_PTR WINAPI NtUserCallOneParam( ULONG_PTR arg, ULONG code ); ULONG_PTR WINAPI NtUserCallTwoParam( ULONG_PTR arg1, ULONG_PTR arg2, ULONG code ); LONG WINAPI NtUserChangeDisplaySettings( UNICODE_STRING *devname, DEVMODEW *devmode, HWND hwnd,