From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/class.c | 76 ++++++++++++++++++++++-------------- dlls/win32u/ntuser_private.h | 1 + dlls/win32u/window.c | 14 +++++++ server/protocol.def | 6 +-- 4 files changed, 64 insertions(+), 33 deletions(-)
diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c index 6d05ba38239..57e18cbfc18 100644 --- a/dlls/win32u/class.c +++ b/dlls/win32u/class.c @@ -60,8 +60,6 @@ typedef struct tagCLASS HCURSOR hCursor; /* Default cursor */ HBRUSH hbrBackground; /* Default background */ ATOM atom; /* name of the class */ - WCHAR name[MAX_ATOM_LEN + 1]; - WCHAR *basename; /* Base name for redirected classes, pointer within 'name'. */ struct client_menu_name menu_name; /* Default menu name */ const shared_object_t *shared; /* class object in session shared memory */ } CLASS; @@ -391,6 +389,31 @@ static CLASS *get_class_ptr( HWND hwnd, BOOL write_access ) return NULL; }
+static NTSTATUS get_shared_window_class( HWND hwnd, struct object_lock *lock, const class_shm_t **class_shm ) +{ + const shared_object_t *object; + + TRACE( "hwnd %p, lock %p, class_shm %p\n", hwnd, lock, class_shm ); + + if (lock->id) object = CONTAINING_RECORD( *class_shm, shared_object_t, shm.class ); + else + { + struct obj_locator locator = get_window_class_locator( hwnd ); + object = find_shared_session_object( locator.id, locator.offset ); + if (!object) return STATUS_INVALID_HANDLE; + } + + if (!lock->id || !shared_object_release_seqlock( object, lock->seq )) + { + shared_object_acquire_seqlock( object, &lock->seq ); + *class_shm = &object->shm.class; + lock->id = object->id; + return STATUS_PENDING; + } + + return STATUS_SUCCESS; +} + /*********************************************************************** * release_class_ptr */ @@ -399,6 +422,14 @@ static void release_class_ptr( CLASS *ptr ) user_unlock(); }
+static BOOL class_name_matches( CLASS *class, UNICODE_STRING *name ) +{ + /* class name is safe to read without shared object locking as it is constant */ + const WCHAR *class_name = (WCHAR *)class->shared->shm.class.name; + UINT len = class->shared->shm.class.name_len; + return name->Length == len && !wcsnicmp( class_name, name->Buffer, len / sizeof(WCHAR) ); +} + static CLASS *find_class( HINSTANCE module, UNICODE_STRING *name ) { ULONG_PTR instance = (UINT_PTR)module; @@ -408,8 +439,7 @@ static CLASS *find_class( HINSTANCE module, UNICODE_STRING *name ) user_lock(); LIST_FOR_EACH_ENTRY( class, &class_list, CLASS, entry ) { - if (wcsnicmp( class->name, name->Buffer, name->Length / sizeof(WCHAR) ) || - class->name[name->Length / sizeof(WCHAR)]) continue; + if (!class_name_matches( class, name )) continue; is_win16 = !(class->instance >> 16); if (!instance || !class->local || class->instance == instance || (!is_win16 && ((class->instance & ~0xffff) == (instance & ~0xffff)))) @@ -487,10 +517,6 @@ ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING *nam
if (!(class = calloc( 1, sizeof(CLASS) + wc->cbClsExtra ))) return 0;
- memcpy( class->name, name->Buffer, name->Length ); - class->name[name->Length / sizeof(WCHAR)] = 0; - class->basename = class->name + version->Length / sizeof(WCHAR); - class->style = wc->style; class->local = !is_builtin && !(wc->style & CS_GLOBALCLASS); class->cbWndExtra = wc->cbWndExtra; @@ -713,7 +739,11 @@ ATOM WINAPI NtUserRegisterWindowMessage( UNICODE_STRING *name ) */ INT WINAPI NtUserGetClassName( HWND hwnd, BOOL real, UNICODE_STRING *name ) { - CLASS *class; + struct object_lock lock = OBJECT_LOCK_INIT; + const class_shm_t *class_shm; + WCHAR buffer[MAX_ATOM_LEN]; + NTSTATUS status; + UINT len = 0; int ret;
TRACE( "%p %x %p\n", hwnd, real, name ); @@ -724,30 +754,16 @@ INT WINAPI NtUserGetClassName( HWND hwnd, BOOL real, UNICODE_STRING *name ) return 0; }
- if (!(class = get_class_ptr( hwnd, FALSE ))) return 0; - - if (class == OBJ_OTHER_PROCESS) + while ((status = get_shared_window_class( hwnd, &lock, &class_shm )) == STATUS_PENDING) { - ATOM atom = 0; - - SERVER_START_REQ( get_class_info ) - { - req->window = wine_server_user_handle( hwnd ); - req->offset = GCW_ATOM; - req->size = sizeof(atom); - wine_server_call_err( req ); - atom = reply->info; - } - SERVER_END_REQ; - - return NtUserGetAtomName( atom, name ); + len = class_shm->name_len - class_shm->name_offset * sizeof(WCHAR); + if (len) memcpy( buffer, (WCHAR *)class_shm->name + class_shm->name_offset, len ); }
- ret = min( name->MaximumLength / sizeof(WCHAR) - 1, lstrlenW(class->basename) ); - if (ret) memcpy( name->Buffer, class->basename, ret * sizeof(WCHAR) ); - name->Buffer[ret] = 0; - release_class_ptr( class ); - return ret; + ret = min( name->MaximumLength - sizeof(WCHAR), len ); + if (ret) memcpy( name->Buffer, buffer, ret ); + name->Buffer[ret / sizeof(WCHAR)] = 0; + return ret / sizeof(WCHAR); }
/* Set class info with the wine server. */ diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 537cfb15ce1..fc8f591ff71 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -235,6 +235,7 @@ static inline UINT win_get_flags( HWND hwnd ) return win_set_flags( hwnd, 0, 0 ); }
+struct obj_locator get_window_class_locator( HWND hwnd ); WND *get_win_ptr( HWND hwnd ); BOOL is_child( HWND parent, HWND child ); BOOL is_window( HWND hwnd ); diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 58bb27d75e4..6405cb3f8c5 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -149,6 +149,20 @@ static NTSTATUS get_shared_window( HANDLE handle, struct object_lock *lock, cons return STATUS_SUCCESS; }
+struct obj_locator get_window_class_locator( HWND hwnd ) +{ + struct object_lock lock = OBJECT_LOCK_INIT; + const window_shm_t *window_shm = NULL; + struct obj_locator locator = {0}; + NTSTATUS status; + + while ((status = get_shared_window( hwnd, &lock, &window_shm )) == STATUS_PENDING) + locator = window_shm->class; + if (status) memset( &locator, 0, sizeof(locator) ); + + return locator; +} + /*********************************************************************** * get_user_handle_ptr */ diff --git a/server/protocol.def b/server/protocol.def index b750b151474..35ad57d1fc3 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1024,9 +1024,9 @@ typedef volatile struct
typedef volatile struct { - WCHAR name[MAX_ATOM_LEN]; /* class name */ - data_size_t name_offset; /* offset in WCHAR of the unversioned class name */ - data_size_t name_len; /* len in bytes of the class name */ + WCHAR name[MAX_ATOM_LEN]; /* class name, constant */ + 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 */ } class_shm_t;
typedef volatile struct