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>
This commit is contained in:
Jacek Caban 2021-12-21 20:31:29 +01:00 committed by Alexandre Julliard
parent d96975d649
commit 2d56b0a93c
9 changed files with 144 additions and 4 deletions

View File

@ -103,6 +103,7 @@ static void * const syscalls[] =
NtGdiTransformPoints,
NtUserAddClipboardFormatListener,
NtUserAttachThreadInput,
NtUserBuildHwndList,
NtUserCloseDesktop,
NtUserCloseWindowStation,
NtUserCreateDesktopEx,

View File

@ -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();
}

View File

@ -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

View File

@ -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;
}

View File

@ -1,5 +1,5 @@
MODULE = wow64win.dll
IMPORTS = win32u ntdll winecrt0
IMPORTS = wow64 win32u ntdll winecrt0
EXTRADLLFLAGS = -nodefaultlibs -Wl,--image-base,0x6f200000

View File

@ -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 ) \

View File

@ -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 );

View File

@ -27,6 +27,8 @@
ALL_WIN32_SYSCALLS
#undef SYSCALL_ENTRY
void * WINAPI Wow64AllocateTemp( SIZE_T size );
struct object_attr64
{
OBJECT_ATTRIBUTES attr;

View File

@ -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,