From 2656d667a802a4264bb79dae6e56378ce0b807a5 Mon Sep 17 00:00:00 2001 From: Jacek Caban Date: Thu, 31 Mar 2022 15:36:15 +0200 Subject: [PATCH] user32: Move unpack_message call to User32CallWindowProc. Signed-off-by: Jacek Caban Signed-off-by: Huw Davies Signed-off-by: Alexandre Julliard --- dlls/user32/message.c | 412 +++-------------------------------- dlls/user32/winproc.c | 486 +++++++++++++++++++++++++++++++++++++++++- dlls/win32u/message.c | 2 + include/ntuser.h | 1 + 4 files changed, 511 insertions(+), 390 deletions(-) diff --git a/dlls/user32/message.c b/dlls/user32/message.c index c3a99159c4f..11a4ac89885 100644 --- a/dlls/user32/message.c +++ b/dlls/user32/message.c @@ -290,14 +290,6 @@ static inline void push_string( struct packed_message *data, LPCWSTR str ) push_data( data, str, (lstrlenW(str) + 1) * sizeof(WCHAR) ); } -/* make sure that the buffer contains a valid null-terminated Unicode string */ -static inline BOOL check_string( LPCWSTR str, size_t size ) -{ - for (size /= sizeof(WCHAR); size; size--, str++) - if (!*str) return TRUE; - return FALSE; -} - /* pack a pointer into a 32/64 portable format */ static inline ULONGLONG pack_ptr( const void *ptr ) { @@ -311,22 +303,6 @@ static inline void *unpack_ptr( ULONGLONG ptr64 ) return (void *)(ULONG_PTR)ptr64; } -/* make sure that there is space for 'size' bytes in buffer, growing it if needed */ -static inline void *get_buffer_space( void **buffer, size_t size ) -{ - void *ret; - - if (*buffer) - { - if (!(ret = HeapReAlloc( GetProcessHeap(), 0, *buffer, size ))) - HeapFree( GetProcessHeap(), 0, *buffer ); - } - else ret = HeapAlloc( GetProcessHeap(), 0, size ); - - *buffer = ret; - return ret; -} - /* check whether a combobox expects strings or ids in CB_ADDSTRING/CB_INSERTSTRING */ static inline BOOL combobox_has_strings( HWND hwnd ) { @@ -938,7 +914,7 @@ static size_t pack_message( HWND hwnd, UINT message, WPARAM wparam, LPARAM lpara /*********************************************************************** - * unpack_message + * unpack_message * * Unpack a message received from another process. */ @@ -950,116 +926,6 @@ static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lpa switch(message) { - case WM_NCCREATE: - case WM_CREATE: - { - CREATESTRUCTW cs; - WCHAR *str = (WCHAR *)(&ps->cs + 1); - if (size < sizeof(ps->cs)) return FALSE; - size -= sizeof(ps->cs); - cs.lpCreateParams = unpack_ptr( ps->cs.lpCreateParams ); - cs.hInstance = unpack_ptr( ps->cs.hInstance ); - cs.hMenu = wine_server_ptr_handle( ps->cs.hMenu ); - cs.hwndParent = wine_server_ptr_handle( ps->cs.hwndParent ); - cs.cy = ps->cs.cy; - cs.cx = ps->cs.cx; - cs.y = ps->cs.y; - cs.x = ps->cs.x; - cs.style = ps->cs.style; - cs.dwExStyle = ps->cs.dwExStyle; - cs.lpszName = unpack_ptr( ps->cs.lpszName ); - cs.lpszClass = unpack_ptr( ps->cs.lpszClass ); - if (ps->cs.lpszName >> 16) - { - if (!check_string( str, size )) return FALSE; - cs.lpszName = str; - size -= (lstrlenW(str) + 1) * sizeof(WCHAR); - str += lstrlenW(str) + 1; - } - if (ps->cs.lpszClass >> 16) - { - if (!check_string( str, size )) return FALSE; - cs.lpszClass = str; - } - memcpy( &ps->cs, &cs, sizeof(cs) ); - break; - } - case WM_GETTEXT: - case WM_ASKCBFORMATNAME: - if (!get_buffer_space( buffer, (*wparam * sizeof(WCHAR)) )) return FALSE; - break; - case WM_WININICHANGE: - if (!*lparam) return TRUE; - /* fall through */ - case WM_SETTEXT: - case WM_DEVMODECHANGE: - case CB_DIR: - case LB_DIR: - case LB_ADDFILE: - case EM_REPLACESEL: - if (!check_string( *buffer, size )) return FALSE; - break; - case WM_GETMINMAXINFO: - minsize = sizeof(MINMAXINFO); - break; - case WM_DRAWITEM: - { - DRAWITEMSTRUCT dis; - if (size < sizeof(ps->dis)) return FALSE; - dis.CtlType = ps->dis.CtlType; - dis.CtlID = ps->dis.CtlID; - dis.itemID = ps->dis.itemID; - dis.itemAction = ps->dis.itemAction; - dis.itemState = ps->dis.itemState; - dis.hwndItem = wine_server_ptr_handle( ps->dis.hwndItem ); - dis.hDC = wine_server_ptr_handle( ps->dis.hDC ); - dis.rcItem = ps->dis.rcItem; - dis.itemData = (ULONG_PTR)unpack_ptr( ps->dis.itemData ); - memcpy( &ps->dis, &dis, sizeof(dis) ); - break; - } - case WM_MEASUREITEM: - { - MEASUREITEMSTRUCT mis; - if (size < sizeof(ps->mis)) return FALSE; - mis.CtlType = ps->mis.CtlType; - mis.CtlID = ps->mis.CtlID; - mis.itemID = ps->mis.itemID; - mis.itemWidth = ps->mis.itemWidth; - mis.itemHeight = ps->mis.itemHeight; - mis.itemData = (ULONG_PTR)unpack_ptr( ps->mis.itemData ); - memcpy( &ps->mis, &mis, sizeof(mis) ); - break; - } - case WM_DELETEITEM: - { - DELETEITEMSTRUCT dls; - if (size < sizeof(ps->dls)) return FALSE; - dls.CtlType = ps->dls.CtlType; - dls.CtlID = ps->dls.CtlID; - dls.itemID = ps->dls.itemID; - dls.hwndItem = wine_server_ptr_handle( ps->dls.hwndItem ); - dls.itemData = (ULONG_PTR)unpack_ptr( ps->dls.itemData ); - memcpy( &ps->dls, &dls, sizeof(dls) ); - break; - } - case WM_COMPAREITEM: - { - COMPAREITEMSTRUCT cis; - if (size < sizeof(ps->cis)) return FALSE; - cis.CtlType = ps->cis.CtlType; - cis.CtlID = ps->cis.CtlID; - cis.hwndItem = wine_server_ptr_handle( ps->cis.hwndItem ); - cis.itemID1 = ps->cis.itemID1; - cis.itemData1 = (ULONG_PTR)unpack_ptr( ps->cis.itemData1 ); - cis.itemID2 = ps->cis.itemID2; - cis.itemData2 = (ULONG_PTR)unpack_ptr( ps->cis.itemData2 ); - cis.dwLocaleId = ps->cis.dwLocaleId; - memcpy( &ps->cis, &cis, sizeof(cis) ); - break; - } - case WM_WINDOWPOSCHANGING: - case WM_WINDOWPOSCHANGED: case WM_WINE_SETWINDOWPOS: { WINDOWPOS wp; @@ -1074,210 +940,6 @@ static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lpa memcpy( &ps->wp, &wp, sizeof(wp) ); break; } - case WM_COPYDATA: - { - COPYDATASTRUCT cds; - if (size < sizeof(ps->cds)) return FALSE; - cds.dwData = (ULONG_PTR)unpack_ptr( ps->cds.dwData ); - if (ps->cds.lpData) - { - cds.cbData = ps->cds.cbData; - cds.lpData = &ps->cds + 1; - minsize = sizeof(ps->cds) + cds.cbData; - } - else - { - cds.cbData = 0; - cds.lpData = 0; - } - memcpy( &ps->cds, &cds, sizeof(cds) ); - break; - } - case WM_NOTIFY: - /* WM_NOTIFY cannot be sent across processes (MSDN) */ - return FALSE; - case WM_HELP: - { - HELPINFO hi; - if (size < sizeof(ps->hi)) return FALSE; - hi.cbSize = sizeof(hi); - hi.iContextType = ps->hi.iContextType; - hi.iCtrlId = ps->hi.iCtrlId; - hi.hItemHandle = wine_server_ptr_handle( ps->hi.hItemHandle ); - hi.dwContextId = (ULONG_PTR)unpack_ptr( ps->hi.dwContextId ); - hi.MousePos = ps->hi.MousePos; - memcpy( &ps->hi, &hi, sizeof(hi) ); - break; - } - case WM_STYLECHANGING: - case WM_STYLECHANGED: - minsize = sizeof(STYLESTRUCT); - break; - case WM_NCCALCSIZE: - if (!*wparam) minsize = sizeof(RECT); - else - { - NCCALCSIZE_PARAMS ncp; - WINDOWPOS wp; - if (size < sizeof(ps->ncp)) return FALSE; - ncp.rgrc[0] = ps->ncp.rgrc[0]; - ncp.rgrc[1] = ps->ncp.rgrc[1]; - ncp.rgrc[2] = ps->ncp.rgrc[2]; - wp.hwnd = wine_server_ptr_handle( ps->ncp.hwnd ); - wp.hwndInsertAfter = wine_server_ptr_handle( ps->ncp.hwndInsertAfter ); - wp.x = ps->ncp.x; - wp.y = ps->ncp.y; - wp.cx = ps->ncp.cx; - wp.cy = ps->ncp.cy; - wp.flags = ps->ncp.flags; - ncp.lppos = (WINDOWPOS *)((NCCALCSIZE_PARAMS *)&ps->ncp + 1); - memcpy( &ps->ncp, &ncp, sizeof(ncp) ); - *ncp.lppos = wp; - } - break; - case WM_GETDLGCODE: - if (*lparam) - { - MSG msg; - if (size < sizeof(ps->msg)) return FALSE; - msg.hwnd = wine_server_ptr_handle( ps->msg.hwnd ); - msg.message = ps->msg.message; - msg.wParam = (ULONG_PTR)unpack_ptr( ps->msg.wParam ); - msg.lParam = (ULONG_PTR)unpack_ptr( ps->msg.lParam ); - msg.time = ps->msg.time; - msg.pt = ps->msg.pt; - memcpy( &ps->msg, &msg, sizeof(msg) ); - break; - } - return TRUE; - case SBM_SETSCROLLINFO: - minsize = sizeof(SCROLLINFO); - break; - case SBM_GETSCROLLINFO: - if (!get_buffer_space( buffer, sizeof(SCROLLINFO ))) return FALSE; - break; - case SBM_GETSCROLLBARINFO: - if (!get_buffer_space( buffer, sizeof(SCROLLBARINFO ))) return FALSE; - break; - case EM_GETSEL: - case SBM_GETRANGE: - case CB_GETEDITSEL: - if (*wparam || *lparam) - { - if (!get_buffer_space( buffer, 2*sizeof(DWORD) )) return FALSE; - if (*wparam) *wparam = (WPARAM)*buffer; - if (*lparam) *lparam = (LPARAM)((DWORD *)*buffer + 1); - } - return TRUE; - case EM_GETRECT: - case LB_GETITEMRECT: - case CB_GETDROPPEDCONTROLRECT: - if (!get_buffer_space( buffer, sizeof(RECT) )) return FALSE; - break; - case EM_SETRECT: - case EM_SETRECTNP: - minsize = sizeof(RECT); - break; - case EM_GETLINE: - { - WORD len; - if (size < sizeof(WORD)) return FALSE; - len = *(WORD *)*buffer; - if (!get_buffer_space( buffer, (len + 1) * sizeof(WCHAR) )) return FALSE; - *lparam = (LPARAM)*buffer + sizeof(WORD); /* don't erase WORD at start of buffer */ - return TRUE; - } - case EM_SETTABSTOPS: - case LB_SETTABSTOPS: - if (!*wparam) return TRUE; - minsize = *wparam * sizeof(UINT); - break; - case CB_ADDSTRING: - case CB_INSERTSTRING: - case CB_FINDSTRING: - case CB_FINDSTRINGEXACT: - case CB_SELECTSTRING: - case LB_ADDSTRING: - case LB_INSERTSTRING: - case LB_FINDSTRING: - case LB_FINDSTRINGEXACT: - case LB_SELECTSTRING: - if (!*buffer) return TRUE; - if (!check_string( *buffer, size )) return FALSE; - break; - case CB_GETLBTEXT: - { - size = sizeof(ULONG_PTR); - if (combobox_has_strings( hwnd )) - size = (SendMessageW( hwnd, CB_GETLBTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR); - if (!get_buffer_space( buffer, size )) return FALSE; - break; - } - case LB_GETTEXT: - { - size = sizeof(ULONG_PTR); - if (listbox_has_strings( hwnd )) - size = (SendMessageW( hwnd, LB_GETTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR); - if (!get_buffer_space( buffer, size )) return FALSE; - break; - } - case LB_GETSELITEMS: - if (!get_buffer_space( buffer, *wparam * sizeof(UINT) )) return FALSE; - break; - case WM_NEXTMENU: - { - MDINEXTMENU mnm; - if (size < sizeof(ps->mnm)) return FALSE; - mnm.hmenuIn = wine_server_ptr_handle( ps->mnm.hmenuIn ); - mnm.hmenuNext = wine_server_ptr_handle( ps->mnm.hmenuNext ); - mnm.hwndNext = wine_server_ptr_handle( ps->mnm.hwndNext ); - memcpy( &ps->mnm, &mnm, sizeof(mnm) ); - break; - } - case WM_SIZING: - case WM_MOVING: - minsize = sizeof(RECT); - if (!get_buffer_space( buffer, sizeof(RECT) )) return FALSE; - break; - case WM_MDICREATE: - { - MDICREATESTRUCTW mcs; - WCHAR *str = (WCHAR *)(&ps->mcs + 1); - if (size < sizeof(ps->mcs)) return FALSE; - size -= sizeof(ps->mcs); - - mcs.szClass = unpack_ptr( ps->mcs.szClass ); - mcs.szTitle = unpack_ptr( ps->mcs.szTitle ); - mcs.hOwner = unpack_ptr( ps->mcs.hOwner ); - mcs.x = ps->mcs.x; - mcs.y = ps->mcs.y; - mcs.cx = ps->mcs.cx; - mcs.cy = ps->mcs.cy; - mcs.style = ps->mcs.style; - mcs.lParam = (LPARAM)unpack_ptr( ps->mcs.lParam ); - if (ps->mcs.szClass >> 16) - { - if (!check_string( str, size )) return FALSE; - mcs.szClass = str; - size -= (lstrlenW(str) + 1) * sizeof(WCHAR); - str += lstrlenW(str) + 1; - } - if (ps->mcs.szTitle >> 16) - { - if (!check_string( str, size )) return FALSE; - mcs.szTitle = str; - } - memcpy( &ps->mcs, &mcs, sizeof(mcs) ); - break; - } - case WM_MDIGETACTIVE: - if (!*lparam) return TRUE; - if (!get_buffer_space( buffer, sizeof(BOOL) )) return FALSE; - break; - case WM_DEVICECHANGE: - if (!(*wparam & 0x8000)) return TRUE; - minsize = sizeof(DEV_BROADCAST_HDR); - break; case WM_WINE_KEYBOARD_LL_HOOK: case WM_WINE_MOUSE_LL_HOOK: { @@ -1291,48 +953,8 @@ static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lpa memcpy( &ps->hook, &h_extra, sizeof(h_extra) ); break; } - case WM_NCPAINT: - if (*wparam <= 1) return TRUE; - FIXME( "WM_NCPAINT hdc unpacking not supported\n" ); - return FALSE; - case WM_PAINT: - if (!*wparam) return TRUE; - /* fall through */ - - /* these contain an HFONT */ - case WM_SETFONT: - case WM_GETFONT: - /* these contain an HDC */ - case WM_ERASEBKGND: - case WM_ICONERASEBKGND: - case WM_CTLCOLORMSGBOX: - case WM_CTLCOLOREDIT: - case WM_CTLCOLORLISTBOX: - case WM_CTLCOLORBTN: - case WM_CTLCOLORDLG: - case WM_CTLCOLORSCROLLBAR: - case WM_CTLCOLORSTATIC: - case WM_PRINT: - case WM_PRINTCLIENT: - /* these contain an HGLOBAL */ - case WM_PAINTCLIPBOARD: - case WM_SIZECLIPBOARD: - /* these contain HICON */ - case WM_GETICON: - case WM_SETICON: - case WM_QUERYDRAGICON: - case WM_QUERYPARKICON: - /* these contain pointers */ - case WM_DROPOBJECT: - case WM_QUERYDROPOBJECT: - case WM_DRAGLOOP: - case WM_DRAGSELECT: - case WM_DRAGMOVE: - FIXME( "msg %x (%s) not supported yet\n", message, SPY_GetMsgName(message, hwnd) ); - return FALSE; - default: - return TRUE; /* message doesn't need any unpacking */ + return TRUE; /* message doesn't need any unpacking */ } /* default exit for most messages: check minsize and store buffer in lparam */ @@ -2043,10 +1665,11 @@ static BOOL init_window_call_params( struct win_proc_params *params, HWND hwnd, * Call a window procedure and the corresponding hooks. */ static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, - BOOL unicode, BOOL same_thread, enum wm_char_mapping mapping ) + BOOL unicode, BOOL same_thread, enum wm_char_mapping mapping, + BOOL needs_unpack, void *buffer, size_t size ) { struct user_thread_info *thread_info = get_user_thread_info(); - struct win_proc_params params; + struct win_proc_params p, *params = &p; LRESULT result = 0; CWPSTRUCT cwp; CWPRETSTRUCT cwpret; @@ -2054,15 +1677,23 @@ static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar if (msg & 0x80000000) return handle_internal_message( hwnd, msg, wparam, lparam ); + if (!needs_unpack) size = 0; if (!WIN_IsCurrentThread( hwnd )) return 0; - if (!init_window_call_params( ¶ms, hwnd, msg, wparam, lparam, &result, !unicode, mapping )) + if (size && !(params = HeapAlloc( GetProcessHeap(), 0, sizeof(*params) + size ))) return 0; + if (!init_window_call_params( params, hwnd, msg, wparam, lparam, &result, !unicode, mapping )) + { + if (params != &p) HeapFree( GetProcessHeap(), 0, params ); return 0; + } + + params->needs_unpack = needs_unpack; + if (size) memcpy( params + 1, buffer, size ); /* first the WH_CALLWNDPROC hook */ cwp.lParam = lparam; cwp.wParam = wparam; cwp.message = msg; - cwp.hwnd = params.hwnd; + cwp.hwnd = params->hwnd; HOOK_CallHooks( WH_CALLWNDPROC, HC_ACTION, same_thread, (LPARAM)&cwp, unicode ); if (thread_info->recursion_count <= MAX_WINPROC_RECURSION) @@ -2070,17 +1701,19 @@ static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar thread_info->recursion_count++; /* now call the window procedure */ - User32CallWindowProc( ¶ms, sizeof(params) ); + User32CallWindowProc( params, sizeof(*params) + size ); thread_info->recursion_count--; } + if (params != &p) HeapFree( GetProcessHeap(), 0, params ); + /* and finally the WH_CALLWNDPROCRET hook */ cwpret.lResult = result; cwpret.lParam = lparam; cwpret.wParam = wparam; cwpret.message = msg; - cwpret.hwnd = params.hwnd; + cwpret.hwnd = params->hwnd; HOOK_CallHooks( WH_CALLWNDPROCRET, HC_ACTION, same_thread, (LPARAM)&cwpret, unicode ); return result; } @@ -2521,6 +2154,7 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, NTSTATUS res; size_t size = 0; const message_data_t *msg_data = buffer; + BOOL needs_unpack = FALSE; thread_info->msg_source = prev_source; @@ -2586,6 +2220,7 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, if (!unpack_message( info.msg.hwnd, info.msg.message, &info.msg.wParam, &info.msg.lParam, &buffer, size )) continue; + needs_unpack = TRUE; break; case MSG_CALLBACK: info.flags = ISMEX_CALLBACK; @@ -2662,6 +2297,7 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, reply_message( &info, 0, &info.msg ); continue; } + needs_unpack = TRUE; break; case MSG_HARDWARE: if (size >= sizeof(msg_data->hardware)) @@ -2724,7 +2360,7 @@ static int peek_message( MSG *msg, HWND hwnd, UINT first, UINT last, UINT flags, thread_info->msg_source = msg_source_unavailable; result = call_window_proc( info.msg.hwnd, info.msg.message, info.msg.wParam, info.msg.lParam, (info.type != MSG_ASCII), FALSE, - WMCHAR_MAP_RECVMESSAGE ); + WMCHAR_MAP_RECVMESSAGE, needs_unpack, buffer, size ); if (thread_info->receive_info == &info ) NtUserCallTwoParam( result, (UINT_PTR)&info.msg, NtUserReplyMessage ); @@ -3038,7 +2674,7 @@ static BOOL send_message( struct send_message_info *info, DWORD_PTR *res_ptr, BO if (info->dest_tid == GetCurrentThreadId()) { result = call_window_proc( info->hwnd, info->msg, info->wparam, info->lparam, - unicode, TRUE, info->wm_char ); + unicode, TRUE, info->wm_char, FALSE, NULL, 0 ); if (info->type == MSG_CALLBACK) call_sendmsg_callback( info->callback, info->hwnd, info->msg, info->data, result ); ret = TRUE; diff --git a/dlls/user32/winproc.c b/dlls/user32/winproc.c index c26a765f689..636030edb08 100644 --- a/dlls/user32/winproc.c +++ b/dlls/user32/winproc.c @@ -29,15 +29,32 @@ #include "wingdi.h" #include "controls.h" #include "win.h" +#include "dbt.h" #include "user_private.h" #include "wine/asm.h" #include "wine/debug.h" -WINE_DECLARE_DEBUG_CHANNEL(msg); +WINE_DEFAULT_DEBUG_CHANNEL(msg); WINE_DECLARE_DEBUG_CHANNEL(relay); #define WINPROC_PROC16 ((void *)1) /* placeholder for 16-bit window procs */ +union packed_structs +{ + struct packed_CREATESTRUCTW cs; + struct packed_DRAWITEMSTRUCT dis; + struct packed_MEASUREITEMSTRUCT mis; + struct packed_DELETEITEMSTRUCT dls; + struct packed_COMPAREITEMSTRUCT cis; + struct packed_WINDOWPOS wp; + struct packed_COPYDATASTRUCT cds; + struct packed_HELPINFO hi; + struct packed_NCCALCSIZE_PARAMS ncp; + struct packed_MSG msg; + struct packed_MDINEXTMENU mnm; + struct packed_MDICREATESTRUCTW mcs; +}; + static inline void *get_buffer( void *static_buffer, size_t size, size_t need ) { if (size >= need) return static_buffer; @@ -788,9 +805,474 @@ static void dispatch_win_proc_params( struct win_proc_params *params ) SetThreadDpiAwarenessContext( context ); } +/* make sure that there is space for 'size' bytes in buffer, growing it if needed */ +static inline void *get_buffer_space( void **buffer, size_t size, size_t prev_size ) +{ + if (prev_size > size && !(*buffer = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL; + return *buffer; +} + +/* check whether a combobox expects strings or ids in CB_ADDSTRING/CB_INSERTSTRING */ +static inline BOOL combobox_has_strings( HWND hwnd ) +{ + DWORD style = GetWindowLongA( hwnd, GWL_STYLE ); + return (!(style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) || (style & CBS_HASSTRINGS)); +} + +/* check whether a listbox expects strings or ids in LB_ADDSTRING/LB_INSERTSTRING */ +static inline BOOL listbox_has_strings( HWND hwnd ) +{ + DWORD style = GetWindowLongA( hwnd, GWL_STYLE ); + return (!(style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE)) || (style & LBS_HASSTRINGS)); +} + +/* unpack a potentially 64-bit pointer, returning 0 when truncated */ +static inline void *unpack_ptr( ULONGLONG ptr64 ) +{ + if ((ULONG_PTR)ptr64 != ptr64) return 0; + return (void *)(ULONG_PTR)ptr64; +} + +/* convert a server handle to a generic handle */ +static inline HANDLE unpack_handle( UINT handle ) +{ + return (HANDLE)(INT_PTR)(int)handle; +} + +/* make sure that the buffer contains a valid null-terminated Unicode string */ +static inline BOOL check_string( LPCWSTR str, size_t size ) +{ + for (size /= sizeof(WCHAR); size; size--, str++) + if (!*str) return TRUE; + return FALSE; +} + +/*********************************************************************** + * unpack_message + * + * Unpack a message received from another process. + */ +static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lparam, + void **buffer, size_t size ) +{ + size_t minsize = 0, prev_size = size; + union packed_structs *ps = *buffer; + + switch(message) + { + case WM_NCCREATE: + case WM_CREATE: + { + CREATESTRUCTW cs; + WCHAR *str = (WCHAR *)(&ps->cs + 1); + if (size < sizeof(ps->cs)) return FALSE; + size -= sizeof(ps->cs); + cs.lpCreateParams = unpack_ptr( ps->cs.lpCreateParams ); + cs.hInstance = unpack_ptr( ps->cs.hInstance ); + cs.hMenu = unpack_handle( ps->cs.hMenu ); + cs.hwndParent = unpack_handle( ps->cs.hwndParent ); + cs.cy = ps->cs.cy; + cs.cx = ps->cs.cx; + cs.y = ps->cs.y; + cs.x = ps->cs.x; + cs.style = ps->cs.style; + cs.dwExStyle = ps->cs.dwExStyle; + cs.lpszName = unpack_ptr( ps->cs.lpszName ); + cs.lpszClass = unpack_ptr( ps->cs.lpszClass ); + if (ps->cs.lpszName >> 16) + { + if (!check_string( str, size )) return FALSE; + cs.lpszName = str; + size -= (lstrlenW(str) + 1) * sizeof(WCHAR); + str += lstrlenW(str) + 1; + } + if (ps->cs.lpszClass >> 16) + { + if (!check_string( str, size )) return FALSE; + cs.lpszClass = str; + } + memcpy( &ps->cs, &cs, sizeof(cs) ); + break; + } + case WM_GETTEXT: + case WM_ASKCBFORMATNAME: + if (!get_buffer_space( buffer, (*wparam * sizeof(WCHAR)), size )) return FALSE; + break; + case WM_WININICHANGE: + if (!*lparam) return TRUE; + /* fall through */ + case WM_SETTEXT: + case WM_DEVMODECHANGE: + case CB_DIR: + case LB_DIR: + case LB_ADDFILE: + case EM_REPLACESEL: + if (!check_string( *buffer, size )) return FALSE; + break; + case WM_GETMINMAXINFO: + minsize = sizeof(MINMAXINFO); + break; + case WM_DRAWITEM: + { + DRAWITEMSTRUCT dis; + if (size < sizeof(ps->dis)) return FALSE; + dis.CtlType = ps->dis.CtlType; + dis.CtlID = ps->dis.CtlID; + dis.itemID = ps->dis.itemID; + dis.itemAction = ps->dis.itemAction; + dis.itemState = ps->dis.itemState; + dis.hwndItem = unpack_handle( ps->dis.hwndItem ); + dis.hDC = unpack_handle( ps->dis.hDC ); + dis.rcItem = ps->dis.rcItem; + dis.itemData = (ULONG_PTR)unpack_ptr( ps->dis.itemData ); + memcpy( &ps->dis, &dis, sizeof(dis) ); + break; + } + case WM_MEASUREITEM: + { + MEASUREITEMSTRUCT mis; + if (size < sizeof(ps->mis)) return FALSE; + mis.CtlType = ps->mis.CtlType; + mis.CtlID = ps->mis.CtlID; + mis.itemID = ps->mis.itemID; + mis.itemWidth = ps->mis.itemWidth; + mis.itemHeight = ps->mis.itemHeight; + mis.itemData = (ULONG_PTR)unpack_ptr( ps->mis.itemData ); + memcpy( &ps->mis, &mis, sizeof(mis) ); + break; + } + case WM_DELETEITEM: + { + DELETEITEMSTRUCT dls; + if (size < sizeof(ps->dls)) return FALSE; + dls.CtlType = ps->dls.CtlType; + dls.CtlID = ps->dls.CtlID; + dls.itemID = ps->dls.itemID; + dls.hwndItem = unpack_handle( ps->dls.hwndItem ); + dls.itemData = (ULONG_PTR)unpack_ptr( ps->dls.itemData ); + memcpy( &ps->dls, &dls, sizeof(dls) ); + break; + } + case WM_COMPAREITEM: + { + COMPAREITEMSTRUCT cis; + if (size < sizeof(ps->cis)) return FALSE; + cis.CtlType = ps->cis.CtlType; + cis.CtlID = ps->cis.CtlID; + cis.hwndItem = unpack_handle( ps->cis.hwndItem ); + cis.itemID1 = ps->cis.itemID1; + cis.itemData1 = (ULONG_PTR)unpack_ptr( ps->cis.itemData1 ); + cis.itemID2 = ps->cis.itemID2; + cis.itemData2 = (ULONG_PTR)unpack_ptr( ps->cis.itemData2 ); + cis.dwLocaleId = ps->cis.dwLocaleId; + memcpy( &ps->cis, &cis, sizeof(cis) ); + break; + } + case WM_WINDOWPOSCHANGING: + case WM_WINDOWPOSCHANGED: + { + WINDOWPOS wp; + if (size < sizeof(ps->wp)) return FALSE; + wp.hwnd = unpack_handle( ps->wp.hwnd ); + wp.hwndInsertAfter = unpack_handle( ps->wp.hwndInsertAfter ); + wp.x = ps->wp.x; + wp.y = ps->wp.y; + wp.cx = ps->wp.cx; + wp.cy = ps->wp.cy; + wp.flags = ps->wp.flags; + memcpy( &ps->wp, &wp, sizeof(wp) ); + break; + } + case WM_COPYDATA: + { + COPYDATASTRUCT cds; + if (size < sizeof(ps->cds)) return FALSE; + cds.dwData = (ULONG_PTR)unpack_ptr( ps->cds.dwData ); + if (ps->cds.lpData) + { + cds.cbData = ps->cds.cbData; + cds.lpData = &ps->cds + 1; + minsize = sizeof(ps->cds) + cds.cbData; + } + else + { + cds.cbData = 0; + cds.lpData = 0; + } + memcpy( &ps->cds, &cds, sizeof(cds) ); + break; + } + case WM_NOTIFY: + /* WM_NOTIFY cannot be sent across processes (MSDN) */ + return FALSE; + case WM_HELP: + { + HELPINFO hi; + if (size < sizeof(ps->hi)) return FALSE; + hi.cbSize = sizeof(hi); + hi.iContextType = ps->hi.iContextType; + hi.iCtrlId = ps->hi.iCtrlId; + hi.hItemHandle = unpack_handle( ps->hi.hItemHandle ); + hi.dwContextId = (ULONG_PTR)unpack_ptr( ps->hi.dwContextId ); + hi.MousePos = ps->hi.MousePos; + memcpy( &ps->hi, &hi, sizeof(hi) ); + break; + } + case WM_STYLECHANGING: + case WM_STYLECHANGED: + minsize = sizeof(STYLESTRUCT); + break; + case WM_NCCALCSIZE: + if (!*wparam) minsize = sizeof(RECT); + else + { + NCCALCSIZE_PARAMS ncp; + WINDOWPOS wp; + if (size < sizeof(ps->ncp)) return FALSE; + ncp.rgrc[0] = ps->ncp.rgrc[0]; + ncp.rgrc[1] = ps->ncp.rgrc[1]; + ncp.rgrc[2] = ps->ncp.rgrc[2]; + wp.hwnd = unpack_handle( ps->ncp.hwnd ); + wp.hwndInsertAfter = unpack_handle( ps->ncp.hwndInsertAfter ); + wp.x = ps->ncp.x; + wp.y = ps->ncp.y; + wp.cx = ps->ncp.cx; + wp.cy = ps->ncp.cy; + wp.flags = ps->ncp.flags; + ncp.lppos = (WINDOWPOS *)((NCCALCSIZE_PARAMS *)&ps->ncp + 1); + memcpy( &ps->ncp, &ncp, sizeof(ncp) ); + *ncp.lppos = wp; + } + break; + case WM_GETDLGCODE: + if (*lparam) + { + MSG msg; + if (size < sizeof(ps->msg)) return FALSE; + msg.hwnd = unpack_handle( ps->msg.hwnd ); + msg.message = ps->msg.message; + msg.wParam = (ULONG_PTR)unpack_ptr( ps->msg.wParam ); + msg.lParam = (ULONG_PTR)unpack_ptr( ps->msg.lParam ); + msg.time = ps->msg.time; + msg.pt = ps->msg.pt; + memcpy( &ps->msg, &msg, sizeof(msg) ); + break; + } + return TRUE; + case SBM_SETSCROLLINFO: + minsize = sizeof(SCROLLINFO); + break; + case SBM_GETSCROLLINFO: + if (!get_buffer_space( buffer, sizeof(SCROLLINFO), size )) return FALSE; + break; + case SBM_GETSCROLLBARINFO: + if (!get_buffer_space( buffer, sizeof(SCROLLBARINFO), size )) return FALSE; + break; + case EM_GETSEL: + case SBM_GETRANGE: + case CB_GETEDITSEL: + if (*wparam || *lparam) + { + if (!get_buffer_space( buffer, 2*sizeof(DWORD), size )) return FALSE; + if (*wparam) *wparam = (WPARAM)*buffer; + if (*lparam) *lparam = (LPARAM)((DWORD *)*buffer + 1); + } + return TRUE; + case EM_GETRECT: + case LB_GETITEMRECT: + case CB_GETDROPPEDCONTROLRECT: + if (!get_buffer_space( buffer, sizeof(RECT), size )) return FALSE; + break; + case EM_SETRECT: + case EM_SETRECTNP: + minsize = sizeof(RECT); + break; + case EM_GETLINE: + { + WORD len; + if (size < sizeof(WORD)) return FALSE; + len = *(WORD *)*buffer; + if (!get_buffer_space( buffer, (len + 1) * sizeof(WCHAR), size )) return FALSE; + *lparam = (LPARAM)*buffer + sizeof(WORD); /* don't erase WORD at start of buffer */ + return TRUE; + } + case EM_SETTABSTOPS: + case LB_SETTABSTOPS: + if (!*wparam) return TRUE; + minsize = *wparam * sizeof(UINT); + break; + case CB_ADDSTRING: + case CB_INSERTSTRING: + case CB_FINDSTRING: + case CB_FINDSTRINGEXACT: + case CB_SELECTSTRING: + case LB_ADDSTRING: + case LB_INSERTSTRING: + case LB_FINDSTRING: + case LB_FINDSTRINGEXACT: + case LB_SELECTSTRING: + if (!*buffer) return TRUE; + if (!check_string( *buffer, size )) return FALSE; + break; + case CB_GETLBTEXT: + { + size = sizeof(ULONG_PTR); + if (combobox_has_strings( hwnd )) + size = (SendMessageW( hwnd, CB_GETLBTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR); + if (!get_buffer_space( buffer, size, prev_size )) return FALSE; + break; + } + case LB_GETTEXT: + { + size = sizeof(ULONG_PTR); + if (listbox_has_strings( hwnd )) + size = (SendMessageW( hwnd, LB_GETTEXTLEN, *wparam, 0 ) + 1) * sizeof(WCHAR); + if (!get_buffer_space( buffer, size, prev_size )) return FALSE; + break; + } + case LB_GETSELITEMS: + if (!get_buffer_space( buffer, *wparam * sizeof(UINT), size )) return FALSE; + break; + case WM_NEXTMENU: + { + MDINEXTMENU mnm; + if (size < sizeof(ps->mnm)) return FALSE; + mnm.hmenuIn = unpack_handle( ps->mnm.hmenuIn ); + mnm.hmenuNext = unpack_handle( ps->mnm.hmenuNext ); + mnm.hwndNext = unpack_handle( ps->mnm.hwndNext ); + memcpy( &ps->mnm, &mnm, sizeof(mnm) ); + break; + } + case WM_SIZING: + case WM_MOVING: + minsize = sizeof(RECT); + if (!get_buffer_space( buffer, sizeof(RECT), size )) return FALSE; + break; + case WM_MDICREATE: + { + MDICREATESTRUCTW mcs; + WCHAR *str = (WCHAR *)(&ps->mcs + 1); + if (size < sizeof(ps->mcs)) return FALSE; + size -= sizeof(ps->mcs); + + mcs.szClass = unpack_ptr( ps->mcs.szClass ); + mcs.szTitle = unpack_ptr( ps->mcs.szTitle ); + mcs.hOwner = unpack_ptr( ps->mcs.hOwner ); + mcs.x = ps->mcs.x; + mcs.y = ps->mcs.y; + mcs.cx = ps->mcs.cx; + mcs.cy = ps->mcs.cy; + mcs.style = ps->mcs.style; + mcs.lParam = (LPARAM)unpack_ptr( ps->mcs.lParam ); + if (ps->mcs.szClass >> 16) + { + if (!check_string( str, size )) return FALSE; + mcs.szClass = str; + size -= (lstrlenW(str) + 1) * sizeof(WCHAR); + str += lstrlenW(str) + 1; + } + if (ps->mcs.szTitle >> 16) + { + if (!check_string( str, size )) return FALSE; + mcs.szTitle = str; + } + memcpy( &ps->mcs, &mcs, sizeof(mcs) ); + break; + } + case WM_MDIGETACTIVE: + if (!*lparam) return TRUE; + if (!get_buffer_space( buffer, sizeof(BOOL), size )) return FALSE; + break; + case WM_DEVICECHANGE: + if (!(*wparam & 0x8000)) return TRUE; + minsize = sizeof(DEV_BROADCAST_HDR); + break; + case WM_NCPAINT: + if (*wparam <= 1) return TRUE; + FIXME( "WM_NCPAINT hdc unpacking not supported\n" ); + return FALSE; + case WM_PAINT: + if (!*wparam) return TRUE; + /* fall through */ + + /* these contain an HFONT */ + case WM_SETFONT: + case WM_GETFONT: + /* these contain an HDC */ + case WM_ERASEBKGND: + case WM_ICONERASEBKGND: + case WM_CTLCOLORMSGBOX: + case WM_CTLCOLOREDIT: + case WM_CTLCOLORLISTBOX: + case WM_CTLCOLORBTN: + case WM_CTLCOLORDLG: + case WM_CTLCOLORSCROLLBAR: + case WM_CTLCOLORSTATIC: + case WM_PRINT: + case WM_PRINTCLIENT: + /* these contain an HGLOBAL */ + case WM_PAINTCLIPBOARD: + case WM_SIZECLIPBOARD: + /* these contain HICON */ + case WM_GETICON: + case WM_SETICON: + case WM_QUERYDRAGICON: + case WM_QUERYPARKICON: + /* these contain pointers */ + case WM_DROPOBJECT: + case WM_QUERYDROPOBJECT: + case WM_DRAGLOOP: + case WM_DRAGSELECT: + case WM_DRAGMOVE: + FIXME( "msg %x (%s) not supported yet\n", message, SPY_GetMsgName(message, hwnd) ); + return FALSE; + + default: + return TRUE; /* message doesn't need any unpacking */ + } + + /* default exit for most messages: check minsize and store buffer in lparam */ + if (size < minsize) return FALSE; + *lparam = (LPARAM)*buffer; + return TRUE; +} + BOOL WINAPI User32CallWindowProc( struct win_proc_params *params, ULONG size ) { - dispatch_win_proc_params( params ); + + if (params->needs_unpack) + { + char stack_buffer[128]; + void *buffer; + LRESULT result; + MSG msg; + + if (size > sizeof(*params)) + { + size -= sizeof(*params); + buffer = params + 1; + } + else + { + size = sizeof(stack_buffer); + buffer = stack_buffer; + } + if (!unpack_message( params->hwnd, params->msg, ¶ms->wparam, + ¶ms->lparam, &buffer, size )) + return 0; + params->result = &result; + + msg.hwnd = params->hwnd; + msg.message = params->msg; + msg.wParam = params->wparam; + msg.lParam = params->lparam; + dispatch_win_proc_params( params ); + + NtUserCallTwoParam( result, (UINT_PTR)&msg, NtUserReplyMessage ); + if (buffer != stack_buffer && buffer != params + 1) + HeapFree( GetProcessHeap(), 0, buffer ); + } + else dispatch_win_proc_params( params ); return TRUE; } diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 2a582d7c85b..0253eacc152 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -96,6 +96,7 @@ static BOOL init_win_proc_params( struct win_proc_params *params, HWND hwnd, UIN params->lparam = lparam; params->ansi = params->ansi_dst = ansi; params->is_dialog = FALSE; + params->needs_unpack = FALSE; params->mapping = WMCHAR_MAP_CALLWINDOWPROC; params->dpi_awareness = get_window_dpi_awareness_context( params->hwnd ); get_winproc_params( params ); @@ -129,6 +130,7 @@ static BOOL init_window_call_params( struct win_proc_params *params, HWND hwnd, params->lparam = lParam; params->result = result; params->ansi = ansi; + params->needs_unpack = FALSE; params->mapping = mapping; params->dpi_awareness = get_window_dpi_awareness_context( params->hwnd ); return TRUE; diff --git a/include/ntuser.h b/include/ntuser.h index 48b41b0a6b6..c618723f79e 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -89,6 +89,7 @@ struct win_proc_params BOOL ansi; BOOL ansi_dst; BOOL is_dialog; + BOOL needs_unpack; enum wm_char_mapping mapping; DPI_AWARENESS_CONTEXT dpi_awareness; WNDPROC procA;