Jacek Caban : win32u: Implement NtUserBuildHwndList.

Alexandre Julliard julliard at winehq.org
Thu Dec 23 16:01:32 CST 2021


Module: wine
Branch: master
Commit: 2d56b0a93ce89e8f6e85e1011bac3c3afd6643ed
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=2d56b0a93ce89e8f6e85e1011bac3c3afd6643ed

Author: Jacek Caban <jacek at 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 at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at 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,




More information about the wine-cvs mailing list