From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/win32u/ntuser_private.h | 3 +- dlls/win32u/window.c | 58 +++++++++++------------------------- server/protocol.def | 1 + server/window.c | 16 ++++++---- 4 files changed, 30 insertions(+), 48 deletions(-) diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index eb612e31bc1..52d43ebb5de 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -74,9 +74,8 @@ typedef struct tagWND int swap_interval; /* OpenGL surface swap interval */ int pixel_format; /* Pixel format set by the graphics driver */ int clip_clients; /* Has client surfaces that needs to be clipped out */ - int cbWndExtra; /* class cbWndExtra at window creation */ + unsigned 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; diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 5832cc603f6..07b814b197e 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -1113,26 +1113,23 @@ 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, UINT 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 = size <= win->cbWndExtra && offset <= win->cbWndExtra - size && + (internal || offset >= window_shm->private_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 +1224,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 +1475,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 ); @@ -1600,20 +1586,12 @@ BOOL WINAPI NtUserSetWindowFNID( HWND hwnd, WORD fnid ) 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 ) { 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; + ret = !wine_server_call_err( req ); } SERVER_END_REQ; release_win_ptr( win ); diff --git a/server/protocol.def b/server/protocol.def index c2cfa64d86d..c6b4937ca3c 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1067,6 +1067,7 @@ typedef volatile struct { struct obj_locator class; /* object locator for the window class shared object */ unsigned int dpi_context; /* DPI awareness context */ + data_size_t private_size; /* length of private extra bytes range */ } window_shm_t; typedef volatile union diff --git a/server/window.c b/server/window.c index 5d2966453bf..0f19ccb87ee 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 */ @@ -678,7 +677,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 = 0; win->nb_extra_bytes = 0; win->extra_bytes = NULL; win->shared = NULL; @@ -689,8 +687,9 @@ 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->class = class_locator; + shared->dpi_context = NTUSER_DPI_PER_MONITOR_AWARE; + shared->private_size = 0; } SHARED_WRITE_END; @@ -2399,7 +2398,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; @@ -2467,7 +2466,12 @@ DECL_HANDLER(set_window_info) win->user_data = req->new_info; break; case GWLP_FNID_INTERNAL: - win->private_len = req->new_info; + if (win->shared->private_size) set_error( STATUS_INVALID_PARAMETER ); + else SHARED_WRITE_BEGIN( win->shared, window_shm_t ) + { + shared->private_size = req->new_info; + } + SHARED_WRITE_END; break; default: if (req->size > sizeof(req->new_info) || req->offset < 0 || -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10999