From: Jacek Caban jacek@codeweavers.com
--- dlls/user32/winproc.c | 54 ++++++------ dlls/win32u/message.c | 187 +++++++++++++++++++++++++++++++++++++----- dlls/wow64win/user.c | 72 +++++++++++++++- 3 files changed, 262 insertions(+), 51 deletions(-)
diff --git a/dlls/user32/winproc.c b/dlls/user32/winproc.c index 36acd7b6382..8b5b65296f4 100644 --- a/dlls/user32/winproc.c +++ b/dlls/user32/winproc.c @@ -789,13 +789,18 @@ static inline BOOL check_string( LPCWSTR str, size_t size ) return FALSE; }
+static size_t string_size( const void *str, BOOL ansi ) +{ + return ansi ? strlen( str ) + 1 : (wcslen( str ) + 1) * sizeof(WCHAR); +} + /*********************************************************************** * 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 ) + void **buffer, size_t size, BOOL ansi ) { size_t minsize = 0, prev_size = size; union packed_structs *ps = *buffer; @@ -805,35 +810,18 @@ static BOOL unpack_message( HWND hwnd, UINT message, WPARAM *wparam, LPARAM *lpa 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) + CREATESTRUCTA *cs = *buffer; + char *str = (char *)(cs + 1); + + if (!IS_INTRESOURCE(cs->lpszName)) { - if (!check_string( str, size )) return FALSE; - cs.lpszName = str; - size -= (lstrlenW(str) + 1) * sizeof(WCHAR); - str += lstrlenW(str) + 1; + cs->lpszName = str; + str += string_size( str, ansi ); } - if (ps->cs.lpszClass >> 16) + if (!IS_INTRESOURCE(cs->lpszClass)) { - if (!check_string( str, size )) return FALSE; - cs.lpszClass = str; + cs->lpszClass = str; } - memcpy( *buffer, &cs, sizeof(cs) ); break; } case WM_GETTEXT: @@ -1186,6 +1174,7 @@ BOOL WINAPI User32CallWindowProc( struct win_proc_params *params, ULONG size ) if (params->needs_unpack) { char stack_buffer[128]; + size_t msg_size = size - sizeof(*params); void *buffer;
if (size > sizeof(*params)) @@ -1199,11 +1188,22 @@ BOOL WINAPI User32CallWindowProc( struct win_proc_params *params, ULONG size ) buffer = stack_buffer; } if (!unpack_message( params->hwnd, params->msg, ¶ms->wparam, - ¶ms->lparam, &buffer, size )) + ¶ms->lparam, &buffer, size, params->ansi )) return 0;
result = dispatch_win_proc_params( params );
+ switch (params->msg) + { + case WM_NCCREATE: + case WM_CREATE: + { + LRESULT *result_ptr = (LRESULT *)buffer - 1; + *result_ptr = result; + return NtCallbackReturn( result_ptr, sizeof(*result_ptr) + msg_size, TRUE ); + } + } + NtUserMessageCall( params->hwnd, params->msg, params->wparam, params->lparam, (void *)result, NtUserWinProcResult, FALSE ); if (buffer != stack_buffer && buffer != params + 1) diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 49ac4b2de94..3cb9c4107c1 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -255,7 +255,8 @@ static BOOL init_window_call_params( struct win_proc_params *params, HWND hwnd, return TRUE; }
-static LRESULT dispatch_win_proc_params( struct win_proc_params *params, size_t size ) +static LRESULT dispatch_win_proc_params( struct win_proc_params *params, size_t size, + void **client_ret, size_t *client_ret_size ) { struct ntuser_thread_info *thread_info = NtUserGetThreadInfo(); LRESULT result = 0; @@ -264,11 +265,19 @@ static LRESULT dispatch_win_proc_params( struct win_proc_params *params, size_t
if (thread_info->recursion_count > MAX_WINPROC_RECURSION) return 0; thread_info->recursion_count++; - KeUserModeCallback( NtUserCallWinProc, params, size, &ret_ptr, &ret_len ); - if (ret_len == sizeof(result)) result = *(LRESULT *)ret_ptr; - thread_info->recursion_count--; + + if (ret_len >= sizeof(result)) + { + result = *(LRESULT *)ret_ptr; + if (client_ret) + { + *client_ret = (LRESULT *)ret_ptr + 1; + *client_ret_size = ret_len - sizeof(result); + } + } + return result; }
@@ -346,6 +355,38 @@ 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) + { + cs.lpszName = str; + size -= (lstrlenW(str) + 1) * sizeof(WCHAR); + str += lstrlenW(str) + 1; + } + if (ps->cs.lpszClass >> 16) + { + cs.lpszClass = str; + } + memcpy( *buffer, &cs, sizeof(cs) ); + break; + } case WM_WINE_SETWINDOWPOS: { WINDOWPOS wp; @@ -1076,23 +1117,100 @@ static void unpack_reply( HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam, } }
+static size_t string_size( const void *str, BOOL ansi ) +{ + return ansi ? strlen( str ) + 1 : (wcslen( str ) + 1) * sizeof(WCHAR); +} + +static size_t copy_string( void *ptr, const void *str, BOOL ansi ) +{ + size_t size = string_size( str, ansi ); + memcpy( ptr, str, size ); + return size; +} + /*********************************************************************** - * copy_reply + * user_message_size * - * Copy a message reply received from client. + * Calculate size of packed message buffer. */ -static void copy_reply( LRESULT result, HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam, - WPARAM wparam_src, LPARAM lparam_src ) +static size_t user_message_size( UINT message, LPARAM lparam, BOOL ansi ) { - size_t copy_size = 0; + const void *lparam_ptr = (const void *)lparam; + size_t size = 0;
- switch(message) + switch (message) { case WM_NCCREATE: case WM_CREATE: + { + const CREATESTRUCTW *cs = lparam_ptr; + size = sizeof(*cs); + if (!IS_INTRESOURCE(cs->lpszName)) size += string_size( cs->lpszName, ansi ); + if (!IS_INTRESOURCE(cs->lpszClass)) size += string_size( cs->lpszClass, ansi ); + break; + } + } + + return size; +} + +/*********************************************************************** + * pack_user_message + * + * Copy message to a buffer for passing to client. + */ +static void pack_user_message( void *buffer, size_t size, UINT message, LPARAM lparam, BOOL ansi ) +{ + const void *lparam_ptr = (const void *)lparam; + void const *inline_ptr = (void *)0xffffffff; + + if (!size) return; + + switch (message) + { + case WM_NCCREATE: + case WM_CREATE: + { + CREATESTRUCTW *cs = buffer; + char *ptr = (char *)(cs + 1); + + memcpy( cs, lparam_ptr, sizeof(*cs) ); + if (!IS_INTRESOURCE(cs->lpszName)) + { + ptr += copy_string( ptr, cs->lpszName, ansi ); + cs->lpszName = inline_ptr; + } + if (!IS_INTRESOURCE(cs->lpszClass)) { - CREATESTRUCTW *dst = (CREATESTRUCTW *)lparam; - CREATESTRUCTW *src = (CREATESTRUCTW *)lparam_src; + copy_string( ptr, cs->lpszClass, ansi ); + cs->lpszClass = inline_ptr; + } + return; + } + } + +} + +/*********************************************************************** + * copy_user_result + * + * Copy a message result received from client. + */ +static void copy_user_result( void *buffer, size_t size, UINT message, WPARAM wparam, LPARAM lparam ) +{ + void *lparam_ptr = (void *)lparam; + + if (!size) return; + + switch (message) + { + case WM_NCCREATE: + case WM_CREATE: + if (size >= sizeof(CREATESTRUCTW)) + { + CREATESTRUCTW *dst = lparam_ptr; + const CREATESTRUCTW *src = buffer; dst->lpCreateParams = src->lpCreateParams; dst->hInstance = src->hInstance; dst->hMenu = src->hMenu; @@ -1106,6 +1224,23 @@ static void copy_reply( LRESULT result, HWND hwnd, UINT message, WPARAM wparam, /* don't allow changing name and class pointers */ } return; + default: + return; + } +} + +/*********************************************************************** + * copy_reply + * + * Copy a message reply received from client. + */ +static void copy_reply( LRESULT result, HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam, + WPARAM wparam_src, LPARAM lparam_src ) +{ + size_t copy_size = 0; + + switch(message) + { case WM_GETTEXT: case CB_GETLBTEXT: case LB_GETTEXT: @@ -1373,9 +1508,13 @@ static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar BOOL needs_unpack, void *buffer, size_t size ) { struct win_proc_params p, *params = &p; + BOOL ansi = !unicode && !needs_unpack; LRESULT result = 0; CWPSTRUCT cwp; CWPRETSTRUCT cwpret; + size_t packed_size = 0; + void *ret_ptr; + size_t ret_len = 0;
if (msg & 0x80000000) return handle_internal_message( hwnd, msg, wparam, lparam ); @@ -1383,6 +1522,9 @@ static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar if (!needs_unpack) size = 0; if (!is_current_thread_window( hwnd )) return 0;
+ packed_size = user_message_size( msg, lparam, ansi ); + if (packed_size) size = packed_size; + /* first the WH_CALLWNDPROC hook */ cwp.lParam = lparam; cwp.wParam = wparam; @@ -1397,15 +1539,18 @@ static LRESULT call_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpar return 0; }
- if (needs_unpack) - { - params->needs_unpack = TRUE; - params->ansi = FALSE; - if (size) memcpy( params + 1, buffer, size ); - } - result = dispatch_win_proc_params( params, sizeof(*params) + size ); + if (needs_unpack) params->ansi = FALSE; + params->needs_unpack = needs_unpack || packed_size; + if (packed_size) + pack_user_message( params + 1, packed_size, msg, lparam, ansi ); + else if (size) + memcpy( params + 1, buffer, size ); + + result = dispatch_win_proc_params( params, sizeof(*params) + size, &ret_ptr, &ret_len ); if (params != &p) free( params );
+ copy_user_result( ret_ptr, min( ret_len, packed_size ), msg, wparam, lparam ); + /* and finally the WH_CALLWNDPROCRET hook */ cwpret.lResult = result; cwpret.lParam = lparam; @@ -2750,7 +2895,7 @@ LRESULT WINAPI NtUserDispatchMessage( const MSG *msg ) if (!init_win_proc_params( ¶ms, msg->hwnd, msg->message, msg->wParam, NtGetTickCount(), FALSE )) return 0; - return dispatch_win_proc_params( ¶ms, sizeof(params) ); + return dispatch_win_proc_params( ¶ms, sizeof(params), NULL, NULL ); } if (msg->message == WM_SYSTIMER) { @@ -2772,7 +2917,7 @@ LRESULT WINAPI NtUserDispatchMessage( const MSG *msg )
if (init_window_call_params( ¶ms, msg->hwnd, msg->message, msg->wParam, msg->lParam, FALSE, WMCHAR_MAP_DISPATCHMESSAGE )) - retval = dispatch_win_proc_params( ¶ms, sizeof(params) ); + retval = dispatch_win_proc_params( ¶ms, sizeof(params), NULL, NULL ); else if (!is_window( msg->hwnd )) RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE ); else RtlSetLastWin32Error( ERROR_MESSAGE_SYNC_ONLY );
diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index fcd19c7f798..de221658a94 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -614,10 +614,66 @@ static NTSTATUS WINAPI wow64_NtUserCallWinEventHook( void *arg, ULONG size ) FIELD_OFFSET( struct win_event_hook_params32, module ) + size); }
+static size_t packed_message_64to32( UINT message, const void *params64, void *params32, size_t size ) +{ + if (!size) return 0; + + switch (message) + { + case WM_NCCREATE: + case WM_CREATE: + { + CREATESTRUCT32 *cs32 = params32; + const CREATESTRUCTW *cs64 = params64; + + createstruct_64to32( cs64, cs32 ); + size -= sizeof(*cs64); + if (size) memmove( cs32 + 1, cs64 + 1, size ); + return sizeof(*cs32) + size; + } + } + + memmove( params32, params64, size ); + return size; +} + +static size_t packed_result_32to64( UINT message, const void *params32, size_t size, void *params64 ) +{ + switch (message) + { + case WM_NCCREATE: + case WM_CREATE: + if (size >= sizeof(CREATESTRUCT32)) + { + const CREATESTRUCT32 *cs32 = params32; + CREATESTRUCTW *cs64 = params64; + + cs64->lpCreateParams = UlongToPtr( cs32->lpCreateParams ); + cs64->hInstance = UlongToPtr( cs32->hInstance ); + cs64->hMenu = LongToHandle( cs32->hMenu ); + cs64->hwndParent = LongToHandle( cs32->hwndParent ); + cs64->cy = cs32->cy; + cs64->cx = cs32->cx; + cs64->y = cs32->y; + cs64->x = cs32->x; + cs64->style = cs32->style; + cs64->dwExStyle = cs32->dwExStyle; + return sizeof(*cs64); + } + + default: + return 0; + } + + if (size) memcpy( params64, params32, size ); + return size; +} + static NTSTATUS WINAPI wow64_NtUserCallWinProc( void *arg, ULONG size ) { struct win_proc_params *params = arg; struct win_proc_params32 *params32 = arg; + size_t lparam_size = 0; LRESULT result = 0; void *ret_ptr; ULONG ret_len; @@ -625,13 +681,23 @@ static NTSTATUS WINAPI wow64_NtUserCallWinProc( void *arg, ULONG size )
win_proc_params_64to32( params, params32 ); if (size > sizeof(*params)) - memmove( params32 + 1, params + 1, size - sizeof(*params) ); + lparam_size = packed_message_64to32( params32->msg, params + 1, params32 + 1, + size - sizeof(*params) );
status = Wow64KiUserCallbackDispatcher( NtUserCallWinProc, params32, - size - sizeof(*params) + sizeof(*params32), + sizeof(*params32) + lparam_size, &ret_ptr, &ret_len );
- if (ret_len == sizeof(LONG)) result = *(LONG *)ret_ptr; + if (ret_len >= sizeof(LONG)) + { + LRESULT *result_ptr = arg; + result = *(LONG *)ret_ptr; + ret_len = packed_result_32to64( params32->msg, (LONG *)ret_ptr + 1, + ret_len - sizeof(LONG), result_ptr + 1 ); + *result_ptr = result; + return NtCallbackReturn( result_ptr, sizeof(*result_ptr) + ret_len, status ); + } + return NtCallbackReturn( &result, sizeof(result), status ); }