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