1
0
Fork 0
mirror of synced 2025-03-07 03:53:26 +01:00

server: Fix rawinput buffer sizes and alignment on WoW64.

This commit is contained in:
Rémi Bernon 2024-01-27 11:25:41 +01:00 committed by Alexandre Julliard
parent 2eb8950392
commit 1664ad7d50
7 changed files with 90 additions and 146 deletions

View file

@ -1924,12 +1924,9 @@ static LRESULT CALLBACK rawinputbuffer_wndproc(HWND hwnd, UINT msg, WPARAM wpara
if (is_wow64)
{
RAWINPUT64 *rawinput = (RAWINPUT64 *)(buffer + i * rawinput_size);
flaky_wine_if(is_wow64)
ok_eq( RIM_TYPEKEYBOARD, rawinput->header.dwType, UINT, "%u" );
flaky_wine_if(is_wow64)
ok_eq( rawinput_size, rawinput->header.dwSize, UINT, "%u" );
ok_eq( wparam, rawinput->header.wParam, WPARAM, "%Iu" );
flaky_wine_if(is_wow64)
ok_eq( i + 2, rawinput->data.keyboard.MakeCode, WPARAM, "%Iu" );
}
else

View file

@ -42,7 +42,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(rawinput);
#ifdef _WIN64
typedef RAWINPUTHEADER RAWINPUTHEADER64;
typedef RAWINPUT RAWINPUT64;
#else
typedef struct
{
@ -51,17 +50,6 @@ typedef struct
ULONGLONG hDevice;
ULONGLONG wParam;
} RAWINPUTHEADER64;
typedef struct
{
RAWINPUTHEADER64 header;
union
{
RAWMOUSE mouse;
RAWKEYBOARD keyboard;
RAWHID hid;
} data;
} RAWINPUT64;
#endif
static struct rawinput_thread_data *get_rawinput_thread_data(void)
@ -529,104 +517,35 @@ UINT WINAPI NtUserGetRawInputDeviceInfo( HANDLE handle, UINT command, void *data
*/
UINT WINAPI NtUserGetRawInputBuffer( RAWINPUT *data, UINT *data_size, UINT header_size )
{
unsigned int count = 0, remaining, rawinput_size, next_size, overhead;
struct rawinput_thread_data *thread_data;
struct hardware_msg_data *msg_data;
RAWINPUT *rawinput;
int i;
UINT count;
if (NtCurrentTeb()->WowTebOffset)
rawinput_size = sizeof(RAWINPUTHEADER64);
else
rawinput_size = sizeof(RAWINPUTHEADER);
overhead = rawinput_size - sizeof(RAWINPUTHEADER);
TRACE( "data %p, data_size %p, header_size %u\n", data, data_size, header_size );
if (header_size != sizeof(RAWINPUTHEADER))
{
WARN( "Invalid structure size %u.\n", header_size );
RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
return ~0u;
return -1;
}
if (!data_size)
{
RtlSetLastWin32Error( ERROR_INVALID_PARAMETER );
return ~0u;
return -1;
}
if (!data)
{
TRACE( "data %p, data_size %p (%u), header_size %u\n", data, data_size, *data_size, header_size );
SERVER_START_REQ( get_rawinput_buffer )
{
req->rawinput_size = rawinput_size;
req->buffer_size = 0;
if (wine_server_call( req )) return ~0u;
*data_size = reply->next_size;
}
SERVER_END_REQ;
return 0;
}
/* with old WOW64 mode we didn't go through the WOW64 thunks, patch the header size here */
if (NtCurrentTeb()->WowTebOffset) header_size = sizeof(RAWINPUTHEADER64);
if (!(thread_data = get_rawinput_thread_data())) return ~0u;
rawinput = thread_data->buffer;
/* first RAWINPUT block in the buffer is used for WM_INPUT message data */
msg_data = (struct hardware_msg_data *)NEXTRAWINPUTBLOCK(rawinput);
SERVER_START_REQ( get_rawinput_buffer )
{
req->rawinput_size = rawinput_size;
req->buffer_size = *data_size;
wine_server_set_reply( req, msg_data, RAWINPUT_BUFFER_SIZE - rawinput->header.dwSize );
if (wine_server_call( req )) return ~0u;
next_size = reply->next_size;
count = reply->count;
req->header_size = header_size;
if ((req->read_data = !!data)) wine_server_set_reply( req, data, *data_size );
if (!wine_server_call_err( req )) count = reply->count;
else count = -1;
*data_size = reply->next_size;
}
SERVER_END_REQ;
remaining = *data_size;
for (i = 0; i < count; ++i)
{
data->header.dwSize = remaining;
if (!rawinput_from_hardware_message( data, msg_data )) break;
if (overhead)
{
/* Under WoW64, GetRawInputBuffer always gives 64-bit RAWINPUT structs. */
RAWINPUT64 *ri64 = (RAWINPUT64 *)data;
memmove( (char *)&data->data + overhead, &data->data,
data->header.dwSize - sizeof(RAWINPUTHEADER) );
ri64->header.dwSize += overhead;
/* Need to copy wParam before hDevice so it's not overwritten. */
ri64->header.wParam = data->header.wParam;
#ifdef _WIN64
ri64->header.hDevice = data->header.hDevice;
#else
ri64->header.hDevice = HandleToULong(data->header.hDevice);
#endif
}
remaining -= data->header.dwSize;
data = NEXTRAWINPUTBLOCK(data);
msg_data = (struct hardware_msg_data *)((char *)msg_data + msg_data->size);
}
if (!next_size)
{
if (!count)
*data_size = 0;
else
next_size = rawinput_size;
}
if (next_size && *data_size <= next_size)
{
RtlSetLastWin32Error( ERROR_INSUFFICIENT_BUFFER );
*data_size = next_size;
count = ~0u;
}
TRACE( "data %p, data_size %p (%u), header_size %u, count %u\n",
data, data_size, *data_size, header_size, count );
return count;
}

View file

@ -5438,8 +5438,8 @@ struct get_cursor_history_reply
struct get_rawinput_buffer_request
{
struct request_header __header;
data_size_t rawinput_size;
data_size_t buffer_size;
data_size_t header_size;
int read_data;
char __pad_20[4];
};
struct get_rawinput_buffer_reply
@ -6492,7 +6492,7 @@ union generic_reply
/* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 792
#define SERVER_PROTOCOL_VERSION 793
/* ### protocol_version end ### */

View file

@ -3768,8 +3768,8 @@ struct handle_info
/* Batch read rawinput message data */
@REQ(get_rawinput_buffer)
data_size_t rawinput_size; /* size of RAWINPUT structure */
data_size_t buffer_size; /* size of output buffer */
data_size_t header_size; /* size of RAWINPUTHEADER structure */
int read_data; /* read the rawinput buffer data */
@REPLY
data_size_t next_size; /* minimum size to get next message data */
unsigned int count;

View file

@ -1866,7 +1866,6 @@ static void rawkeyboard_init( struct rawinput *rawinput, RAWKEYBOARD *keyboard,
case VK_RCONTROL:
keyboard->VKey = VK_CONTROL;
break;
case VK_LMENU:
case VK_RMENU:
keyboard->VKey = VK_MENU;
@ -3541,52 +3540,81 @@ DECL_HANDLER(get_cursor_history)
DECL_HANDLER(get_rawinput_buffer)
{
const size_t align = is_machine_64bit( current->process->machine ) ? 7 : 3;
data_size_t buffer_size = get_reply_max_size() & ~align;
struct thread_input *input = current->queue->input;
data_size_t size = 0, next_size = 0, pos = 0;
struct list *ptr;
char *buf, *tmp;
int count = 0, buf_size = 16 * sizeof(struct hardware_msg_data);
struct message *msg, *next_msg;
int count = 0;
char *buffer;
if (!req->buffer_size) buf = NULL;
else if (!(buf = mem_alloc( buf_size ))) return;
ptr = list_head( &input->msg_list );
while (ptr)
if (req->header_size != sizeof(RAWINPUTHEADER))
{
struct message *msg = LIST_ENTRY( ptr, struct message, entry );
struct hardware_msg_data *data = msg->data;
data_size_t extra_size = data->size - sizeof(*data);
ptr = list_next( &input->msg_list, ptr );
if (msg->msg != WM_INPUT) continue;
next_size = req->rawinput_size + extra_size;
if (size + next_size > req->buffer_size) break;
if (pos + data->size > get_reply_max_size()) break;
if (pos + data->size > buf_size)
{
buf_size += buf_size / 2 + extra_size;
if (!(tmp = realloc( buf, buf_size )))
{
free( buf );
set_error( STATUS_NO_MEMORY );
return;
}
buf = tmp;
}
memcpy( buf + pos, data, data->size );
list_remove( &msg->entry );
free_message( msg );
size += next_size;
pos += sizeof(*data) + extra_size;
count++;
set_error( STATUS_INVALID_PARAMETER );
return;
}
reply->next_size = next_size;
reply->count = count;
set_reply_data_ptr( buf, pos );
if (!req->read_data)
{
LIST_FOR_EACH_ENTRY( msg, &input->msg_list, struct message, entry )
{
if (msg->msg == WM_INPUT)
{
struct hardware_msg_data *msg_data = msg->data;
data_size_t size = msg_data->size - sizeof(*msg_data);
reply->next_size = sizeof(RAWINPUTHEADER) + size;
break;
}
}
}
else if ((buffer = mem_alloc( buffer_size )))
{
size_t total_size = 0, next_size = 0;
reply->next_size = get_reply_max_size();
LIST_FOR_EACH_ENTRY_SAFE( msg, next_msg, &input->msg_list, struct message, entry )
{
if (msg->msg == WM_INPUT)
{
RAWINPUT *rawinput = (RAWINPUT *)(buffer + total_size);
struct hardware_msg_data *msg_data = msg->data;
data_size_t data_size = msg_data->size - sizeof(*msg_data);
if (total_size + sizeof(RAWINPUTHEADER) + data_size > buffer_size)
{
next_size = sizeof(RAWINPUTHEADER) + data_size;
break;
}
rawinput->header.dwSize = sizeof(RAWINPUTHEADER) + data_size;
rawinput->header.dwType = msg_data->rawinput.type;
rawinput->header.hDevice = UlongToHandle(msg_data->rawinput.device);
rawinput->header.wParam = msg_data->rawinput.wparam;
memcpy( &rawinput->header + 1, msg_data + 1, data_size );
total_size += (rawinput->header.dwSize + align) & ~align;
list_remove( &msg->entry );
free_message( msg );
count++;
}
}
if (!next_size)
{
if (count) next_size = sizeof(RAWINPUT);
else reply->next_size = 0;
}
if (next_size && get_reply_max_size() <= next_size)
{
set_error( STATUS_BUFFER_TOO_SMALL );
reply->next_size = next_size;
}
reply->count = count;
set_reply_data_ptr( buffer, total_size );
}
}
DECL_HANDLER(update_rawinput_devices)

View file

@ -2285,8 +2285,8 @@ C_ASSERT( FIELD_OFFSET(struct set_cursor_reply, last_change) == 48 );
C_ASSERT( sizeof(struct set_cursor_reply) == 56 );
C_ASSERT( sizeof(struct get_cursor_history_request) == 16 );
C_ASSERT( sizeof(struct get_cursor_history_reply) == 8 );
C_ASSERT( FIELD_OFFSET(struct get_rawinput_buffer_request, rawinput_size) == 12 );
C_ASSERT( FIELD_OFFSET(struct get_rawinput_buffer_request, buffer_size) == 16 );
C_ASSERT( FIELD_OFFSET(struct get_rawinput_buffer_request, header_size) == 12 );
C_ASSERT( FIELD_OFFSET(struct get_rawinput_buffer_request, read_data) == 16 );
C_ASSERT( sizeof(struct get_rawinput_buffer_request) == 24 );
C_ASSERT( FIELD_OFFSET(struct get_rawinput_buffer_reply, next_size) == 8 );
C_ASSERT( FIELD_OFFSET(struct get_rawinput_buffer_reply, count) == 12 );

View file

@ -4482,8 +4482,8 @@ static void dump_get_cursor_history_reply( const struct get_cursor_history_reply
static void dump_get_rawinput_buffer_request( const struct get_rawinput_buffer_request *req )
{
fprintf( stderr, " rawinput_size=%u", req->rawinput_size );
fprintf( stderr, ", buffer_size=%u", req->buffer_size );
fprintf( stderr, " header_size=%u", req->header_size );
fprintf( stderr, ", read_data=%d", req->read_data );
}
static void dump_get_rawinput_buffer_reply( const struct get_rawinput_buffer_reply *req )