From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/win32u/class.c | 4 +- dlls/win32u/ntuser_private.h | 3 +- dlls/win32u/window.c | 78 +++++++++--------------------------- include/ntuser.h | 1 - server/protocol.def | 9 +++++ server/window.c | 40 +++++++++++++----- 6 files changed, 63 insertions(+), 72 deletions(-) diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c index 43663797f4a..2159a6ad101 100644 --- a/dlls/win32u/class.c +++ b/dlls/win32u/class.c @@ -1074,10 +1074,10 @@ WORD get_class_word( HWND hwnd, INT offset ) return get_class_long_size( hwnd, offset, sizeof(WORD), TRUE ); } -DWORD get_builtin_class_extra( enum ntuser_client_procs proc ) +ATOM get_builtin_class_atom( enum ntuser_client_procs proc ) { get_desktop_window(); /* create the desktop window to trigger builtin class registration */ - return builtin_classes[proc].extra; + return builtin_classes[proc].atom; } /*********************************************************************** diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index eb612e31bc1..98ed3afd852 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -76,7 +76,6 @@ typedef struct tagWND int clip_clients; /* Has client surfaces that needs to be clipped out */ int cbWndExtra; /* class cbWndExtra at window creation */ DWORD_PTR userdata; /* User private data */ - int private_len; /* length of private extra bytes range */ DWORD wExtra[1]; /* Window extra bytes */ } WND; @@ -198,7 +197,7 @@ struct dce *set_class_dce( struct tagCLASS *class, struct dce *dce ); extern atom_t wine_server_add_atom( void *req, UNICODE_STRING *str ); extern BOOL is_desktop_class( UNICODE_STRING *name ); extern BOOL is_message_class( UNICODE_STRING *name ); -extern DWORD get_builtin_class_extra( enum ntuser_client_procs proc ); +extern ATOM get_builtin_class_atom( enum ntuser_client_procs proc ); extern void register_builtin_classes(void); extern void register_desktop_class(void); diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 5832cc603f6..79d2c7f168d 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1113,26 +1113,22 @@ static HWND get_last_active_popup( HWND hwnd ) return retval; } -static LONG_PTR get_win_data( const void *ptr, UINT size ) +static BOOL get_window_extra( HWND hwnd, WND *win, INT offset, UINT size, LONG_PTR *ret, BOOL internal ) { - if (size == sizeof(WORD)) - { - WORD ret; - memcpy( &ret, ptr, sizeof(ret) ); - return ret; - } - else if (size == sizeof(DWORD)) - { - DWORD ret; - memcpy( &ret, ptr, sizeof(ret) ); - return ret; - } - else + struct object_lock lock = OBJECT_LOCK_INIT; + const window_shm_t *window_shm = NULL; + BOOL valid = FALSE; + UINT status; + + while ((status = get_shared_window( hwnd, &lock, &window_shm )) == STATUS_PENDING) { - LONG_PTR ret; - memcpy( &ret, ptr, sizeof(ret) ); - return ret; + valid = offset >= (internal ? 0 : window_shm->private_size) && offset <= (int)(win->cbWndExtra - size); + if (valid) memcpy( ret, (char *)win->wExtra + offset, size ); } + + if (status) RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE ); + else if (!valid) RtlSetLastWin32Error( ERROR_INVALID_INDEX ); + return valid; } /* helper for set_window_long */ @@ -1227,15 +1223,7 @@ static LONG_PTR get_window_long_size( HWND hwnd, INT offset, UINT size, BOOL ans if (offset >= 0) { - if (offset > (int)(win->cbWndExtra - size) || - (!internal && offset < win->private_len)) - { - WARN("Invalid offset %d\n", offset ); - release_win_ptr( win ); - RtlSetLastWin32Error( ERROR_INVALID_INDEX ); - return 0; - } - retval = get_win_data( (char *)win->wExtra + offset, size ); + if (!get_window_extra( hwnd, win, offset, size, &retval, internal )) retval = 0; release_win_ptr( win ); return retval; } @@ -1486,15 +1474,12 @@ static LONG_PTR set_window_long_internal( HWND hwnd, INT offset, UINT size, case GWLP_USERDATA: break; default: - if (offset < 0 || offset > (int)(win->cbWndExtra - size) || - (!internal && offset < win->private_len)) + if (!get_window_extra( hwnd, win, offset, size, &retval, internal )) { - WARN("Invalid offset %d\n", offset ); release_win_ptr( win ); - RtlSetLastWin32Error( ERROR_INVALID_INDEX ); return 0; } - else if (get_win_data( (char *)win->wExtra + offset, size ) == newval) + if (retval == newval) { /* already set to the same value */ release_win_ptr( win ); @@ -1582,41 +1567,18 @@ LONG_PTR set_window_long( HWND hwnd, INT offset, UINT size, LONG_PTR newval, BOO */ BOOL WINAPI NtUserSetWindowFNID( HWND hwnd, WORD fnid ) { - DWORD len = get_builtin_class_extra( fnid & 0x7fff ); - WND *win; BOOL ret; TRACE( "%p %x\n", hwnd, fnid ); - if (!(win = get_win_ptr( hwnd ))) - { - RtlSetLastWin32Error( ERROR_INVALID_WINDOW_HANDLE ); - return FALSE; - } - - if (win == WND_DESKTOP || win == WND_OTHER_PROCESS) - { - RtlSetLastWin32Error( ERROR_ACCESS_DENIED ); - return FALSE; - } - - if (win->private_len) - { - ret = win->private_len == len; - release_win_ptr( win ); - if (!ret) RtlSetLastWin32Error( ERROR_INVALID_PARAMETER ); - return ret; - } - - SERVER_START_REQ( set_window_info ) + SERVER_START_REQ( set_window_fnid ) { req->handle = wine_server_user_handle( hwnd ); - req->offset = GWLP_FNID_INTERNAL; - req->new_info = len; - if ((ret = !wine_server_call_err( req ))) win->private_len = len; + req->fnid = fnid; + req->atom = get_builtin_class_atom( fnid & 0x7fff ); + ret = !wine_server_call_err( req ); } SERVER_END_REQ; - release_win_ptr( win ); return ret; } diff --git a/include/ntuser.h b/include/ntuser.h index 846f75b7975..2bbf77a4cf1 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -658,7 +658,6 @@ enum wine_internal_message #define IMN_WINE_SET_COMP_STRING 0x0010 /* not compatible with Windows */ -#define GWLP_FNID_INTERNAL (-1000) #define MAKE_FNID(index) ((WORD)(0x8000 | (index))) /* builtin IME driver calls */ diff --git a/server/protocol.def b/server/protocol.def index 673383f7463..8ccaacdd9d1 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1068,6 +1068,7 @@ typedef volatile struct struct obj_locator class; /* object locator for the window class shared object */ unsigned int dpi_context; /* DPI awareness context */ unsigned int fnid; /* builtin class FNID, or 0 */ + data_size_t private_size; /* length of private extra bytes range */ } window_shm_t; typedef volatile union @@ -2694,6 +2695,14 @@ enum message_type @END +/* Set the window builtin class FNID */ +@REQ(set_window_fnid) + user_handle_t handle; /* handle to the window */ + unsigned int fnid; /* builtin class FNID */ + atom_t atom; /* class atom */ +@END + + /* Set the parent of a window */ @REQ(set_parent) user_handle_t handle; /* handle to the window */ diff --git a/server/window.c b/server/window.c index f6a91466e98..b08b45daa30 100644 --- a/server/window.c +++ b/server/window.c @@ -92,7 +92,6 @@ struct window int prop_inuse; /* number of in-use window properties */ int prop_alloc; /* number of allocated window properties */ struct property *properties; /* window properties array */ - int private_len; /* length of private extra bytes range */ int nb_extra_bytes; /* number of extra bytes */ char *extra_bytes; /* extra bytes storage */ window_shm_t *shared; /* window in session shared memory */ @@ -680,7 +679,6 @@ static struct window *create_window( struct window *parent, struct window *owner win->prop_inuse = 0; win->prop_alloc = 0; win->properties = NULL; - win->private_len = fnid ? extra_bytes : 0; win->nb_extra_bytes = 0; win->extra_bytes = NULL; win->shared = NULL; @@ -691,9 +689,10 @@ static struct window *create_window( struct window *parent, struct window *owner if (!(win->shared = alloc_shared_object( sizeof(*win->shared) ))) goto failed; SHARED_WRITE_BEGIN( win->shared, window_shm_t ) { - shared->class = class_locator; - shared->dpi_context = NTUSER_DPI_PER_MONITOR_AWARE; - shared->fnid = fnid; + shared->class = class_locator; + shared->dpi_context = NTUSER_DPI_PER_MONITOR_AWARE; + shared->fnid = fnid; + shared->private_size = fnid ? extra_bytes : 0; } SHARED_WRITE_END; @@ -2279,6 +2278,32 @@ DECL_HANDLER(create_window) } +/* Set the window builtin class FNID */ +DECL_HANDLER(set_window_fnid) +{ + struct obj_locator class_locator; + struct window_class *class; + struct window *win; + int extra_bytes; + + if (!(win = get_window( req->handle ))) return; + if (is_desktop_window( win ) && win->thread != current) return set_error( STATUS_ACCESS_DENIED ); + if (win->shared->fnid && win->shared->fnid != req->fnid) return set_error( STATUS_INVALID_PARAMETER ); + if (!req->fnid) return set_error( STATUS_INVALID_PARAMETER ); + + if (!(class = grab_class( current->process, req->atom, 0, &extra_bytes, &class_locator ))) return; + + SHARED_WRITE_BEGIN( win->shared, window_shm_t ) + { + shared->fnid = req->fnid; + shared->private_size = extra_bytes; + } + SHARED_WRITE_END; + + release_class( class ); +} + + /* set the parent of a window */ DECL_HANDLER(set_parent) { @@ -2402,7 +2427,7 @@ DECL_HANDLER(get_window_info) default: if (req->size > sizeof(reply->info) || req->offset < 0 || req->offset > win->nb_extra_bytes - (int)req->size || - req->offset < win->private_len) + req->offset < win->shared->private_size) { set_win32_error( ERROR_INVALID_INDEX ); break; @@ -2469,9 +2494,6 @@ DECL_HANDLER(set_window_info) reply->old_info = win->user_data; win->user_data = req->new_info; break; - case GWLP_FNID_INTERNAL: - win->private_len = req->new_info; - break; default: if (req->size > sizeof(req->new_info) || req->offset < 0 || req->offset > win->nb_extra_bytes - (int)req->size) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10999