-- v2: win32u: Read class name from the shared memory object. server: Keep a class object locator in the window shared object. win32u: Use NtUserGetClass(Long|Name)W in needs_ime_window. server: Write class name to the shared memory object. server: Create a shared object for window classes.
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/class.c | 19 +++++++++++++++++++ server/class.c | 43 ++++++++++++++++++++++++++++++------------- server/protocol.def | 9 ++++++++- 3 files changed, 57 insertions(+), 14 deletions(-)
diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c index 6148fb6821d..fd6cd8b57a5 100644 --- a/dlls/win32u/class.c +++ b/dlls/win32u/class.c @@ -63,6 +63,7 @@ typedef struct tagCLASS 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;
/* Built-in class descriptor */ @@ -455,6 +456,8 @@ ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING *nam DWORD flags, DWORD *wow ) { const BOOL is_builtin = fnid, ansi = flags; + const shared_object_t *shared; + struct obj_locator locator; HINSTANCE instance; HICON sm_icon = 0; CLASS *class; @@ -505,6 +508,7 @@ ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING *nam req->atom = wine_server_add_atom( req, name ); req->name_offset = version->Length / sizeof(WCHAR); ret = !wine_server_call_err( req ); + locator = reply->locator; atom = reply->atom; } SERVER_END_REQ; @@ -514,6 +518,20 @@ ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING *nam return 0; }
+ if (!(shared = find_shared_session_object( locator.id, locator.offset ))) + { + ERR( "Failed to get shared session object for window class\n" ); + SERVER_START_REQ( destroy_class ) + { + req->instance = wine_server_client_ptr( instance ); + wine_server_add_data( req, name->Buffer, name->Length ); + wine_server_call( req ); + } + SERVER_END_REQ; + free( class ); + return 0; + } + /* Other non-null values must be set by caller */ if (wc->hIcon && !wc->hIconSm) sm_icon = CopyImage( wc->hIcon, IMAGE_ICON, @@ -537,6 +555,7 @@ ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING *nam class->atom = atom; class->winproc = alloc_winproc( wc->lpfnWndProc, ansi ); if (client_menu_name) class->menu_name = *client_menu_name; + class->shared = shared; release_class_ptr( class ); return atom; } diff --git a/server/class.c b/server/class.c index 2a520bded17..9db68fdced6 100644 --- a/server/class.c +++ b/server/class.c @@ -35,23 +35,26 @@ #include "object.h" #include "process.h" #include "user.h" +#include "file.h" #include "winuser.h" #include "winternl.h"
struct window_class { - struct list entry; /* entry in process list */ - struct process *process; /* process owning the class */ - int count; /* reference count */ - int local; /* local class? */ - atom_t atom; /* class atom */ - atom_t base_atom; /* base class atom for versioned class */ - mod_handle_t instance; /* module instance */ - unsigned int style; /* class style */ - int win_extra; /* number of window extra bytes */ - client_ptr_t client_ptr; /* pointer to class in client address space */ - int nb_extra_bytes; /* number of extra bytes */ - char extra_bytes[1]; /* extra bytes storage */ + struct list entry; /* entry in process list */ + struct winstation *winstation; /* winstation the class was created on */ + struct process *process; /* process owning the class */ + int count; /* reference count */ + int local; /* local class? */ + atom_t atom; /* class atom */ + atom_t base_atom; /* base class atom for versioned class */ + mod_handle_t instance; /* module instance */ + unsigned int style; /* class style */ + int win_extra; /* number of window extra bytes */ + client_ptr_t client_ptr; /* pointer to class in client address space */ + class_shm_t *shared; /* class in session shared memory */ + int nb_extra_bytes; /* number of extra bytes */ + char extra_bytes[1]; /* extra bytes storage */ };
static struct window_class *create_class( struct process *process, int extra_bytes, int local ) @@ -65,12 +68,24 @@ static struct window_class *create_class( struct process *process, int extra_byt class->local = local; class->nb_extra_bytes = extra_bytes; memset( class->extra_bytes, 0, extra_bytes ); + + if (!(class->shared = alloc_shared_object())) goto failed; + SHARED_WRITE_BEGIN( class->shared, class_shm_t ) + { + shared->placeholder = 0; + } + SHARED_WRITE_END; + /* other fields are initialized by caller */
/* local classes have priority so we put them first in the list */ if (local) list_add_head( &process->classes, &class->entry ); else list_add_tail( &process->classes, &class->entry ); return class; + +failed: + free( class ); + return NULL; }
static void destroy_class( struct window_class *class ) @@ -81,6 +96,7 @@ static void destroy_class( struct window_class *class ) release_atom( table, class->base_atom ); list_remove( &class->entry ); release_object( class->process ); + if (class->shared) free_shared_object( class->shared ); free( class ); }
@@ -212,7 +228,8 @@ DECL_HANDLER(create_class) class->style = req->style; class->win_extra = req->win_extra; class->client_ptr = req->client_ptr; - reply->atom = base_atom; + reply->locator = get_shared_object_locator( class->shared ); + reply->atom = base_atom; }
/* destroy a window class */ diff --git a/server/protocol.def b/server/protocol.def index b87b7d6515a..5b2b1709499 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1014,6 +1014,11 @@ typedef volatile struct unsigned __int64 keystate_serial; /* keystate update counter at last sync */ } input_shm_t;
+typedef volatile struct +{ + int placeholder; +} class_shm_t; + typedef volatile struct { unsigned int dpi_context; /* DPI awareness context */ @@ -1024,6 +1029,7 @@ typedef volatile union desktop_shm_t desktop; queue_shm_t queue; input_shm_t input; + class_shm_t class; window_shm_t window; } object_shm_t;
@@ -3238,7 +3244,8 @@ enum caret_state data_size_t name_offset; /* base class name offset for specified atom */ VARARG(name,unicode_str); /* class name */ @REPLY - atom_t atom; /* resulting class atom */ + struct obj_locator locator; /* locator for the shared class object */ + atom_t atom; /* resulting class atom */ @END
From: Rémi Bernon rbernon@codeweavers.com
--- server/atom.c | 5 ++--- server/class.c | 33 +++++++++++++++++++++++++++------ server/protocol.def | 6 +++++- 3 files changed, 34 insertions(+), 10 deletions(-)
diff --git a/server/atom.c b/server/atom.c index 0bba828e300..307634124f5 100644 --- a/server/atom.c +++ b/server/atom.c @@ -42,7 +42,6 @@ #define MIN_HASH_SIZE 4 #define MAX_HASH_SIZE 0x200
-#define MAX_ATOM_LEN (255 * sizeof(WCHAR)) #define MIN_STR_ATOM 0xc000 #define MAX_ATOMS 0x4000
@@ -289,7 +288,7 @@ atom_t add_atom( struct atom_table *table, const struct unicode_str *str ) set_error( STATUS_OBJECT_NAME_INVALID ); return 0; } - if (str->len > MAX_ATOM_LEN) + if (str->len > MAX_ATOM_LEN * sizeof(WCHAR)) { set_error( STATUS_INVALID_PARAMETER ); return 0; @@ -352,7 +351,7 @@ atom_t find_atom( struct atom_table *table, const struct unicode_str *str ) set_error( STATUS_OBJECT_NAME_INVALID ); return 0; } - if (str->len > MAX_ATOM_LEN) + if (str->len > MAX_ATOM_LEN * sizeof(WCHAR)) { set_error( STATUS_INVALID_PARAMETER ); return 0; diff --git a/server/class.c b/server/class.c index 9db68fdced6..0e336bab897 100644 --- a/server/class.c +++ b/server/class.c @@ -57,7 +57,8 @@ struct window_class char extra_bytes[1]; /* extra bytes storage */ };
-static struct window_class *create_class( struct process *process, int extra_bytes, int local ) +static struct window_class *create_class( struct process *process, int extra_bytes, int local, + struct unicode_str *name, unsigned int name_offset ) { struct window_class *class;
@@ -72,7 +73,9 @@ static struct window_class *create_class( struct process *process, int extra_byt if (!(class->shared = alloc_shared_object())) goto failed; SHARED_WRITE_BEGIN( class->shared, class_shm_t ) { - shared->placeholder = 0; + memcpy( (void *)shared->name, name->str, name->len ); + shared->name_offset = name_offset; + shared->name_len = name->len; } SHARED_WRITE_END;
@@ -174,6 +177,17 @@ client_ptr_t get_class_client_ptr( struct window_class *class ) return class->client_ptr; }
+static struct unicode_str integral_atom_name( WCHAR *buffer, atom_t atom ) +{ + struct unicode_str name; + char tmp[16]; + int ret = snprintf( tmp, sizeof(tmp), "#%u", atom ); + for (int i = ret; i >= 0; i--) buffer[i] = tmp[i]; + name.len = ret * sizeof(WCHAR); + name.str = buffer; + return name; +} + /* create a window class */ DECL_HANDLER(create_class) { @@ -181,14 +195,21 @@ DECL_HANDLER(create_class) struct unicode_str name = get_req_unicode_str(); struct atom_table *table = get_user_atom_table(); atom_t atom = req->atom, base_atom; + unsigned int offset = 0; + WCHAR buffer[16];
+ if (atom && !name.len) name = integral_atom_name( buffer, atom ); if (!atom && !(atom = add_atom( table, &name ))) return;
if (req->name_offset && req->name_offset < name.len / sizeof(WCHAR)) { - name.str += req->name_offset; - name.len -= req->name_offset * sizeof(WCHAR); - if (!(base_atom = add_atom( table, &name ))) + struct unicode_str base = name; + + offset = req->name_offset; + base.str += offset; + base.len -= offset * sizeof(WCHAR); + + if (!(base_atom = add_atom( table, &base ))) { release_atom( table, atom ); return; @@ -216,7 +237,7 @@ DECL_HANDLER(create_class) return; }
- if (!(class = create_class( current->process, req->extra, req->local ))) + if (!(class = create_class( current->process, req->extra, req->local, &name, offset ))) { release_atom( table, atom ); release_atom( table, base_atom ); diff --git a/server/protocol.def b/server/protocol.def index 5b2b1709499..4e6f08d1d4a 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -971,6 +971,8 @@ union udp_endpoint /****************************************************************/ /* shared session mapping structures */
+#define MAX_ATOM_LEN 255 + struct shared_cursor { int x; /* cursor position */ @@ -1016,7 +1018,9 @@ typedef volatile struct
typedef volatile struct { - int placeholder; + 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 */ } class_shm_t;
typedef volatile struct
From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/class.c | 12 ------------ dlls/win32u/imm.c | 11 +++++++++++ dlls/win32u/ntuser_private.h | 1 - 3 files changed, 11 insertions(+), 13 deletions(-)
diff --git a/dlls/win32u/class.c b/dlls/win32u/class.c index fd6cd8b57a5..6d05ba38239 100644 --- a/dlls/win32u/class.c +++ b/dlls/win32u/class.c @@ -1029,18 +1029,6 @@ WORD get_class_word( HWND hwnd, INT offset ) return get_class_long_size( hwnd, offset, sizeof(WORD), TRUE ); }
-BOOL needs_ime_window( HWND hwnd ) -{ - static const WCHAR imeW[] = {'I','M','E',0}; - CLASS *class; - BOOL ret; - - if (!(class = get_class_ptr( hwnd, FALSE ))) return FALSE; - ret = !(class->style & CS_IME) && wcscmp( imeW, class->name ); - release_class_ptr( class ); - return ret; -} - static const struct builtin_class_descr desktop_builtin_class = { .name = "#32769", /* DESKTOP_CLASS_ATOM */ diff --git a/dlls/win32u/imm.c b/dlls/win32u/imm.c index cd94f56d678..c7eeaf49d5c 100644 --- a/dlls/win32u/imm.c +++ b/dlls/win32u/imm.c @@ -274,6 +274,17 @@ static struct imm_thread_data *get_imm_thread_data(void) return thread_info->imm_thread_data; }
+static BOOL needs_ime_window( HWND hwnd ) +{ + static const WCHAR imeW[] = {'I','M','E'}; + WCHAR nameW[MAX_ATOM_LEN + 1]; + UNICODE_STRING name = RTL_CONSTANT_STRING(nameW); + + if (NtUserGetClassLongW( hwnd, GCL_STYLE ) & CS_IME) return TRUE; + name.Length = NtUserGetClassName( hwnd, FALSE, &name ) * sizeof(WCHAR); + return name.Length != sizeof(imeW) || wcsnicmp( name.Buffer, imeW, ARRAY_SIZE(imeW) ); +} + BOOL register_imm_window( HWND hwnd ) { struct imm_thread_data *thread_data; diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index f5559c5ca4f..537cfb15ce1 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -180,7 +180,6 @@ WNDPROC get_winproc( WNDPROC proc, BOOL ansi ); void get_winproc_params( struct win_proc_params *params, BOOL fixup_ansi_dst ); struct dce *get_class_dce( struct tagCLASS *class ); struct dce *set_class_dce( struct tagCLASS *class, struct dce *dce ); -BOOL needs_ime_window( HWND hwnd ); 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 );
From: Rémi Bernon rbernon@codeweavers.com
--- server/class.c | 5 +++-- server/protocol.def | 13 +++++++------ server/user.h | 4 ++-- server/window.c | 4 +++- 4 files changed, 15 insertions(+), 11 deletions(-)
diff --git a/server/class.c b/server/class.c index 0e336bab897..5a10238ecb8 100644 --- a/server/class.c +++ b/server/class.c @@ -129,14 +129,15 @@ static struct window_class *find_class( struct process *process, atom_t atom, mo return NULL; }
-struct window_class *grab_class( struct process *process, atom_t atom, - mod_handle_t instance, int *extra_bytes ) +struct window_class *grab_class( struct process *process, atom_t atom, mod_handle_t instance, + int *extra_bytes, struct obj_locator *locator ) { struct window_class *class = find_class( process, atom, instance ); if (class) { class->count++; *extra_bytes = class->win_extra; + *locator = get_shared_object_locator( class->shared ); } else set_error( STATUS_INVALID_HANDLE ); return class; diff --git a/server/protocol.def b/server/protocol.def index 4e6f08d1d4a..b750b151474 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -971,6 +971,12 @@ union udp_endpoint /****************************************************************/ /* shared session mapping structures */
+struct obj_locator +{ + object_id_t id; /* object unique id, object data is valid if != 0 */ + mem_size_t offset; /* offset of the object in session shared memory */ +}; + #define MAX_ATOM_LEN 255
struct shared_cursor @@ -1025,6 +1031,7 @@ typedef volatile struct
typedef volatile struct { + struct obj_locator class; /* object locator for the window class shared object */ unsigned int dpi_context; /* DPI awareness context */ } window_shm_t;
@@ -1049,12 +1056,6 @@ typedef volatile struct struct user_entry user_entries[MAX_USER_HANDLES]; } session_shm_t;
-struct obj_locator -{ - object_id_t id; /* object unique id, object data is valid if != 0 */ - mem_size_t offset; /* offset of the object in session shared memory */ -}; - /****************************************************************/ /* Request declarations */
diff --git a/server/user.h b/server/user.h index 0ebda06b49b..73b10aaf5ac 100644 --- a/server/user.h +++ b/server/user.h @@ -188,8 +188,8 @@ extern struct window_class *get_window_class( user_handle_t window ); /* window class functions */
extern void destroy_process_classes( struct process *process ); -extern struct window_class *grab_class( struct process *process, atom_t atom, - mod_handle_t instance, int *extra_bytes ); +extern struct window_class *grab_class( struct process *process, atom_t atom, mod_handle_t instance, + int *extra_bytes, struct obj_locator *locator ); extern void release_class( struct window_class *class ); extern int is_desktop_class( struct window_class *class ); extern int is_message_class( struct window_class *class ); diff --git a/server/window.c b/server/window.c index e237d40a153..9f871ed9494 100644 --- a/server/window.c +++ b/server/window.c @@ -618,10 +618,11 @@ static struct window *create_window( struct window *parent, struct window *owner struct window *win = NULL; struct desktop *desktop; struct window_class *class; + struct obj_locator class_locator;
if (!(desktop = get_thread_desktop( current, DESKTOP_CREATEWINDOW ))) return NULL;
- if (!(class = grab_class( current->process, atom, class_instance, &extra_bytes ))) + if (!(class = grab_class( current->process, atom, class_instance, &extra_bytes, &class_locator ))) { release_object( desktop ); return NULL; @@ -683,6 +684,7 @@ static struct window *create_window( struct window *parent, struct window *owner if (!(win->shared = alloc_shared_object())) goto failed; SHARED_WRITE_BEGIN( win->shared, window_shm_t ) { + shared->class = class_locator; shared->dpi_context = NTUSER_DPI_PER_MONITOR_AWARE; } SHARED_WRITE_END;
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