[PATCH 2/2] user32: Use WM_INPUT message hw_id as RAWINPUT handle.

Rémi Bernon rbernon at codeweavers.com
Mon Jul 6 05:04:50 CDT 2020


This fixes the GetRawInputData regression introduced with
359ee2ecc21b08e4118f0f77b3a208e4b5e1e63d where the message data couldn't
be read twice, while keeping the overwrite logic it introduced.

This also adds some SetLastError to fix some unit tests todos.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=49522
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/user32/message.c      | 11 +++++-----
 dlls/user32/rawinput.c     | 43 +++++++++++++++++++++++++-------------
 dlls/user32/tests/input.c  |  7 -------
 dlls/user32/user_private.h | 10 +++++++--
 4 files changed, 42 insertions(+), 29 deletions(-)

diff --git a/dlls/user32/message.c b/dlls/user32/message.c
index c5c7db667cf..9e0d3cd61db 100644
--- a/dlls/user32/message.c
+++ b/dlls/user32/message.c
@@ -2284,13 +2284,14 @@ static void accept_hardware_message( UINT hw_id, BOOL remove )
 }
 
 
-static BOOL process_rawinput_message( MSG *msg, const struct hardware_msg_data *msg_data )
+static BOOL process_rawinput_message( MSG *msg, UINT hw_id, const struct hardware_msg_data *msg_data )
 {
-    RAWINPUT *rawinput = rawinput_thread_data();
-    if (!rawinput_from_hardware_message(rawinput, msg_data))
+    struct rawinput_thread_data *thread_data = rawinput_thread_data();
+    if (!rawinput_from_hardware_message( thread_data->buffer, msg_data ))
         return FALSE;
 
-    msg->lParam = (LPARAM)rawinput;
+    thread_data->hw_id = hw_id;
+    msg->lParam = (LPARAM)hw_id;
     msg->pt = point_phys_to_win_dpi( msg->hwnd, msg->pt );
     return TRUE;
 }
@@ -2611,7 +2612,7 @@ static BOOL process_hardware_message( MSG *msg, UINT hw_id, const struct hardwar
     context = SetThreadDpiAwarenessContext( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE );
 
     if (msg->message == WM_INPUT)
-        ret = process_rawinput_message( msg, msg_data );
+        ret = process_rawinput_message( msg, hw_id, msg_data );
     else if (is_keyboard_message( msg->message ))
         ret = process_keyboard_message( msg, hw_id, hwnd_filter, first, last, remove );
     else if (is_mouse_message( msg->message ))
diff --git a/dlls/user32/rawinput.c b/dlls/user32/rawinput.c
index b5af008e885..a4208bf1407 100644
--- a/dlls/user32/rawinput.c
+++ b/dlls/user32/rawinput.c
@@ -223,12 +223,14 @@ static void find_devices(void)
 }
 
 
-RAWINPUT *rawinput_thread_data(void)
+struct rawinput_thread_data *rawinput_thread_data(void)
 {
     struct user_thread_info *thread_info = get_user_thread_info();
-    RAWINPUT *rawinput = thread_info->rawinput;
-    if (!rawinput) rawinput = thread_info->rawinput = HeapAlloc( GetProcessHeap(), 0, RAWINPUT_BUFFER_SIZE );
-    return rawinput;
+    struct rawinput_thread_data *data = thread_info->rawinput;
+    if (data) return data;
+    data = thread_info->rawinput = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                              RAWINPUT_BUFFER_SIZE + sizeof(struct user_thread_info) );
+    return data;
 }
 
 
@@ -453,43 +455,51 @@ BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(RAWINPUTDEVICE *devices, U
  */
 UINT WINAPI GetRawInputData(HRAWINPUT rawinput, UINT command, void *data, UINT *data_size, UINT header_size)
 {
-    RAWINPUT *ri = (RAWINPUT *)rawinput;
-    UINT s;
+    struct rawinput_thread_data *thread_data = rawinput_thread_data();
+    UINT size;
 
     TRACE("rawinput %p, command %#x, data %p, data_size %p, header_size %u.\n",
             rawinput, command, data, data_size, header_size);
 
-    if (!ri || !ri->header.dwSize)
+    if (!rawinput || thread_data->hw_id != (UINT_PTR)rawinput)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
         return ~0U;
+    }
 
     if (header_size != sizeof(RAWINPUTHEADER))
     {
         WARN("Invalid structure size %u.\n", header_size);
+        SetLastError(ERROR_INVALID_PARAMETER);
         return ~0U;
     }
 
     switch (command)
     {
     case RID_INPUT:
-        s = ri->header.dwSize;
+        size = thread_data->buffer->header.dwSize;
         break;
     case RID_HEADER:
-        s = sizeof(RAWINPUTHEADER);
+        size = sizeof(RAWINPUTHEADER);
         break;
     default:
+        SetLastError(ERROR_INVALID_PARAMETER);
         return ~0U;
     }
 
     if (!data)
     {
-        *data_size = s;
+        *data_size = size;
         return 0;
     }
 
-    if (*data_size < s) return ~0U;
-    memcpy(data, ri, s);
-    ri->header.dwSize = 0;
-    return s;
+    if (*data_size < size)
+    {
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        return ~0U;
+    }
+    memcpy(data, thread_data->buffer, size);
+    return size;
 }
 
 #ifdef _WIN64
@@ -513,6 +523,7 @@ typedef struct
 UINT WINAPI DECLSPEC_HOTPATCH GetRawInputBuffer(RAWINPUT *data, UINT *data_size, UINT header_size)
 {
     struct hardware_msg_data *msg_data;
+    struct rawinput_thread_data *thread_data;
     RAWINPUT *rawinput;
     UINT count = 0, rawinput_size, next_size, overhead;
     BOOL is_wow64;
@@ -551,8 +562,10 @@ UINT WINAPI DECLSPEC_HOTPATCH GetRawInputBuffer(RAWINPUT *data, UINT *data_size,
         return 0;
     }
 
-    if (!(rawinput = rawinput_thread_data())) return ~0U;
+    if (!(thread_data = 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 )
     {
diff --git a/dlls/user32/tests/input.c b/dlls/user32/tests/input.c
index fd401b330d5..d4b0e34fa91 100644
--- a/dlls/user32/tests/input.c
+++ b/dlls/user32/tests/input.c
@@ -1760,7 +1760,6 @@ static void test_GetRawInputData(void)
     SetLastError(0xdeadbeef);
     ret = GetRawInputData(NULL, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER));
     ok(ret == ~0U, "Expect ret %u, got %u\n", ~0U, ret);
-    todo_wine
     ok(GetLastError() == ERROR_INVALID_HANDLE, "GetRawInputData returned %08x\n", GetLastError());
 }
 
@@ -1916,36 +1915,30 @@ static LRESULT CALLBACK rawinputbuffer_wndproc(HWND hwnd, UINT msg, WPARAM wpara
             SetLastError(0xdeadbeef);
             count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, 0);
             ok(count == ~0U, "GetRawInputData succeeded\n");
-            todo_wine
             ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08x\n", GetLastError());
 
             SetLastError(0xdeadbeef);
             size = 0;
             count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER));
             ok(count == ~0U, "GetRawInputData succeeded\n");
-            todo_wine
             ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetRawInputData returned %08x\n", GetLastError());
 
             SetLastError(0xdeadbeef);
             size = sizeof(ri);
             count = GetRawInputData((HRAWINPUT)lparam, 0, &ri, &size, sizeof(RAWINPUTHEADER));
             ok(count == ~0U, "GetRawInputData succeeded\n");
-            todo_wine
             ok(GetLastError() == ERROR_INVALID_PARAMETER, "GetRawInputData returned %08x\n", GetLastError());
 
             SetLastError(0xdeadbeef);
             size = sizeof(ri);
             count = GetRawInputData((HRAWINPUT)lparam, RID_INPUT, &ri, &size, sizeof(RAWINPUTHEADER));
-            todo_wine
             ok(count == sizeof(ri), "GetRawInputData failed\n");
-            todo_wine
             ok(ri.data.mouse.lLastX == 6, "Unexpected rawinput data: %d\n", ri.data.mouse.lLastX);
             ok(GetLastError() == 0xdeadbeef, "GetRawInputData returned %08x\n", GetLastError());
         }
         else
         {
             ok(count == ~0U, "GetRawInputData succeeded\n");
-            todo_wine
             ok(GetLastError() == ERROR_INVALID_HANDLE, "GetRawInputData returned %08x\n", GetLastError());
         }
 
diff --git a/dlls/user32/user_private.h b/dlls/user32/user_private.h
index eb828203597..8fa54b9229a 100644
--- a/dlls/user32/user_private.h
+++ b/dlls/user32/user_private.h
@@ -173,6 +173,12 @@ struct wm_char_mapping_data
 /* hold up to 10s of 1kHz mouse rawinput events */
 #define RAWINPUT_BUFFER_SIZE (512*1024)
 
+struct rawinput_thread_data
+{
+    UINT     hw_id;     /* current rawinput message id */
+    RAWINPUT buffer[1]; /* rawinput message data buffer */
+};
+
 /* this is the structure stored in TEB->Win32ClientInfo */
 /* no attempt is made to keep the layout compatible with the Windows one */
 struct user_thread_info
@@ -196,7 +202,7 @@ struct user_thread_info
     struct user_key_state_info   *key_state;              /* Cache of global key state */
     HWND                          top_window;             /* Desktop window */
     HWND                          msg_window;             /* HWND_MESSAGE parent window */
-    RAWINPUT                     *rawinput;
+    struct rawinput_thread_data  *rawinput;               /* RawInput thread local data / buffer */
 };
 
 C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) );
@@ -236,7 +242,7 @@ struct tagWND;
 
 struct hardware_msg_data;
 extern BOOL rawinput_from_hardware_message(RAWINPUT *rawinput, const struct hardware_msg_data *msg_data);
-extern RAWINPUT *rawinput_thread_data(void);
+extern struct rawinput_thread_data *rawinput_thread_data(void);
 
 extern void CLIPBOARD_ReleaseOwner( HWND hwnd ) DECLSPEC_HIDDEN;
 extern BOOL FOCUS_MouseActivate( HWND hwnd ) DECLSPEC_HIDDEN;
-- 
2.27.0




More information about the wine-devel mailing list