From: Rémi Bernon <rbernon@codeweavers.com> --- dlls/win32u/class.c | 64 +++++++++++++++++++++++++-------------------- server/class.c | 31 ++++++++++++++++++++-- server/protocol.def | 10 ++++++- 3 files changed, 74 insertions(+), 31 deletions(-) diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c index 1212e1c3e0c..973b06c1117 100644 --- a/dlls/win32u/class.c +++ b/dlls/win32u/class.c @@ -48,8 +48,6 @@ typedef struct tagCLASS struct list entry; /* Entry in class list */ BOOL local; /* Local class? */ struct dce *dce; /* Opaque pointer to class DCE */ - HICON hIcon; /* Default icon */ - HICON hIconSm; /* Default small icon */ HICON icon_internal; /* internal small icon, derived from hIcon */ struct client_menu_name *menu_name; /* Default menu name */ const shared_object_t *shared; /* class object in session shared memory */ @@ -559,7 +557,18 @@ ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING *nam user_lock(); SERVER_START_REQ( create_class ) { - req->local = class->local; + user_handle_t icon, icon_sm; + if (class->local) req->flags |= CREATE_CLASS_LOCAL; + if ((icon = wine_server_user_handle( wc->hIcon ))) + { + wine_server_add_data( req, &icon, sizeof(icon) ); + req->flags |= CREATE_CLASS_ICON; + } + if ((icon_sm = wine_server_user_handle( wc->hIconSm ))) + { + wine_server_add_data( req, &icon_sm, sizeof(icon_sm) ); + req->flags |= CREATE_CLASS_ICONSM; + } req->style = wc->style; req->cursor = wine_server_user_handle( wc->hCursor ); req->background = wine_server_user_handle( wc->hbrBackground ); @@ -598,8 +607,6 @@ ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING *nam debugstr_w(wc->lpszClassName), debugstr_us(name), atom, wc->lpfnWndProc, instance, wc->hbrBackground, wc->style, wc->cbClsExtra, wc->cbWndExtra, class ); - class->hIcon = wc->hIcon; - class->hIconSm = wc->hIconSm; class->icon_internal = icon_internal; class->menu_name = menu_name; class->shared = shared; @@ -684,8 +691,8 @@ ATOM WINAPI NtUserGetClassInfoEx( HINSTANCE instance, UNICODE_STRING *name, WNDC wc->cbClsExtra = class_shm->cls_extra; wc->cbWndExtra = class_shm->win_extra; wc->hInstance = (instance == user32_module) ? 0 : instance; - wc->hIcon = class->hIcon; - wc->hIconSm = class->hIconSm; + wc->hIcon = wine_server_ptr_handle( class_shm->icon ); + wc->hIconSm = wine_server_ptr_handle( class_shm->icon_small ); wc->hCursor = wine_server_ptr_handle( class_shm->cursor ); wc->hbrBackground = wine_server_ptr_handle( class_shm->background ); wc->lpszMenuName = (WCHAR *)class->menu_name; @@ -841,6 +848,8 @@ static ULONG_PTR set_class_long_size( HWND hwnd, INT offset, LONG_PTR newval, UI case GCL_STYLE: case GCLP_HBRBACKGROUND: case GCLP_HCURSOR: + case GCLP_HICON: + case GCLP_HICONSM: case GCLP_HMODULE: set_server_info( hwnd, offset, newval, size, &retval ); break; @@ -853,16 +862,6 @@ static ULONG_PTR set_class_long_size( HWND hwnd, INT offset, LONG_PTR newval, UI if (!set_server_info( hwnd, offset, newval, size, &retval )) break; retval = (ULONG_PTR)get_winproc( (WNDPROC)retval, ansi ); break; - case GCLP_HICON: - retval = (ULONG_PTR)class->hIcon; - if (retval == newval) break; - class->hIcon = (HICON)newval; - break; - case GCLP_HICONSM: - retval = (ULONG_PTR)class->hIconSm; - if (retval == newval) break; - class->hIconSm = (HICON)newval; - break; case GCL_CBCLSEXTRA: /* cannot change this one */ RtlSetLastWin32Error( ERROR_INVALID_PARAMETER ); break; @@ -874,7 +873,17 @@ static ULONG_PTR set_class_long_size( HWND hwnd, INT offset, LONG_PTR newval, UI if (offset == GCLP_HICON || offset == GCLP_HICONSM) { - HICON icon = class->hIcon, icon_small = class->hIconSm; + struct object_lock lock = OBJECT_LOCK_INIT; + HICON icon = 0, icon_small = 0; + const class_shm_t *class_shm; + NTSTATUS status; + + while ((status = get_shared_class( class, &lock, &class_shm )) == STATUS_PENDING) + { + icon_small = wine_server_get_ptr( class_shm->icon_small ); + icon = wine_server_get_ptr( class_shm->icon ); + } + NtUserDestroyCursor( class->icon_internal, 0 ); class->icon_internal = icon_small ? 0 : create_small_icon( icon ); } @@ -914,6 +923,7 @@ static ULONG_PTR get_class_long_shm( HWND hwnd, INT offset, UINT size, BOOL ansi ULONG_PTR ret = 0; BOOL valid = TRUE; NTSTATUS status; + CLASS *class; while ((status = get_shared_window_class( hwnd, &lock, &class_shm )) == STATUS_PENDING) { @@ -925,6 +935,8 @@ static ULONG_PTR get_class_long_shm( HWND hwnd, INT offset, UINT size, BOOL ansi case GCL_CBCLSEXTRA: ret = class_shm->cls_extra; break; case GCL_CBWNDEXTRA: ret = class_shm->win_extra; break; case GCLP_HMODULE: ret = class_shm->instance; break; + case GCLP_HICON: ret = class_shm->icon; break; + case GCLP_HICONSM: ret = class_shm->icon_small; break; case GCLP_HCURSOR: ret = class_shm->cursor; break; case GCLP_HBRBACKGROUND: ret = class_shm->background; break; default: @@ -945,6 +957,12 @@ static ULONG_PTR get_class_long_shm( HWND hwnd, INT offset, UINT size, BOOL ansi return 0; } + if (offset == GCLP_HICONSM && !ret && (class = get_class_ptr( hwnd, FALSE ))) + { + ret = (UINT_PTR)class->icon_internal; + release_class_ptr( class ); + } + return ret; } @@ -955,8 +973,6 @@ static ULONG_PTR get_class_long_size( HWND hwnd, INT offset, UINT size, BOOL ans switch (offset) { - case GCLP_HICONSM: - case GCLP_HICON: case GCLP_MENUNAME: break; default: @@ -976,8 +992,6 @@ static ULONG_PTR get_class_long_size( HWND hwnd, INT offset, UINT size, BOOL ans { switch (offset) { - case GCLP_HICON: - case GCLP_HICONSM: case GCLP_MENUNAME: FIXME( "offset %d not supported on other process window %p\n", offset, hwnd ); break; @@ -993,12 +1007,6 @@ static ULONG_PTR get_class_long_size( HWND hwnd, INT offset, UINT size, BOOL ans switch(offset) { - case GCLP_HICON: - retvalue = (ULONG_PTR)class->hIcon; - break; - case GCLP_HICONSM: - retvalue = (ULONG_PTR)(class->hIconSm ? class->hIconSm : class->icon_internal); - break; case GCLP_MENUNAME: retvalue = (ULONG_PTR)class->menu_name; break; diff --git a/server/class.c b/server/class.c index 59fc4aecc1e..0a802651a90 100644 --- a/server/class.c +++ b/server/class.c @@ -181,10 +181,27 @@ DECL_HANDLER(create_class) struct window_class *class; struct unicode_str name = get_req_unicode_str(); struct atom_table *table = get_user_atom_table(); + int local = !!(req->flags & CREATE_CLASS_LOCAL); + user_handle_t icon = 0, icon_small = 0; atom_t atom = req->atom, base_atom; unsigned int name_offset = 0; WCHAR buffer[16]; + if (req->flags & CREATE_CLASS_ICON) + { + if (name.len < sizeof(icon)) return set_error( STATUS_INVALID_PARAMETER ); + memcpy( &icon, name.str, sizeof(icon) ); + name.str += sizeof(icon) / sizeof(WCHAR); + name.len -= sizeof(icon); + } + if (req->flags & CREATE_CLASS_ICONSM) + { + if (name.len < sizeof(icon_small)) return set_error( STATUS_INVALID_PARAMETER ); + memcpy( &icon_small, name.str, sizeof(icon_small) ); + name.str += sizeof(icon_small) / sizeof(WCHAR); + name.len -= sizeof(icon_small); + } + if (atom && !name.len) name = integral_atom_name( buffer, atom ); if (!atom && !(atom = add_atom( table, &name ))) return; @@ -208,7 +225,7 @@ DECL_HANDLER(create_class) } class = find_class( current->process, atom, req->instance ); - if (class && !class->local == !req->local) + if (class && !class->local == !local) { set_win32_error( ERROR_CLASS_ALREADY_EXISTS ); release_atom( table, atom ); @@ -224,7 +241,7 @@ DECL_HANDLER(create_class) return; } - if (!(class = create_class( current->process, req->local, req->cls_extra ))) + if (!(class = create_class( current->process, local, req->cls_extra ))) { release_atom( table, atom ); release_atom( table, base_atom ); @@ -246,6 +263,8 @@ DECL_HANDLER(create_class) shared->wndproc = req->wndproc; shared->win_extra = req->win_extra; shared->cls_extra = req->cls_extra; + shared->icon = icon; + shared->icon_small = icon_small; memset( (void *)shared->extra, 0, req->cls_extra ); } SHARED_WRITE_END; @@ -325,6 +344,14 @@ DECL_HANDLER(set_class_info) reply->old_info = shared->background; shared->background = req->new_info; break; + case GCLP_HICON: + reply->old_info = shared->icon; + shared->icon = req->new_info; + break; + case GCLP_HICONSM: + reply->old_info = shared->icon_small; + shared->icon_small = req->new_info; + break; default: if (req->size > sizeof(req->new_info) || req->offset < 0 || req->offset > class->shared->cls_extra - (int)req->size) diff --git a/server/protocol.def b/server/protocol.def index 4aab2d11cf1..e5afcefd791 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1047,6 +1047,8 @@ typedef volatile struct unsigned int win_extra; /* number of window extra bytes */ user_handle_t cursor; /* default cursor */ user_handle_t background; /* default background */ + user_handle_t icon; /* default icon */ + user_handle_t icon_small; /* default cursor (small) */ mod_handle_t instance; /* module instance */ data_size_t name_offset; /* offset in WCHAR of the unversioned class name, constant */ data_size_t name_len; /* len in bytes of the class name, constant */ @@ -3269,7 +3271,7 @@ enum caret_state /* Create a window class */ @REQ(create_class) - int local; /* is it a local class? */ + unsigned int flags; /* flags, see below */ atom_t atom; /* class atom */ unsigned int style; /* class style */ user_handle_t cursor; /* class default cursor */ @@ -3280,12 +3282,18 @@ enum caret_state short int cls_extra; /* number of extra class bytes */ short int win_extra; /* number of window extra bytes */ data_size_t name_offset; /* base class name offset for specified atom */ + VARARG(icon,uints); /* class default icon */ + VARARG(icon_small,uints); /* class default icon (small) */ VARARG(name,unicode_str); /* class name */ @REPLY struct obj_locator locator; /* locator for the shared class object */ atom_t atom; /* resulting class atom */ @END +#define CREATE_CLASS_LOCAL 1 +#define CREATE_CLASS_ICON 2 +#define CREATE_CLASS_ICONSM 4 + /* Destroy a window class */ @REQ(destroy_class) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10959