From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/win32u_private.h | 1 + dlls/win32u/window.c | 31 +++++------------ dlls/win32u/winstation.c | 64 ++++++++++++++++++++++++++++++++++++ server/hook.c | 2 +- server/protocol.def | 9 ++++- server/user.c | 18 ++++++++-- server/user.h | 2 +- server/window.c | 3 +- 8 files changed, 100 insertions(+), 30 deletions(-)
diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 3bdfa47b439..a85f0b2e292 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -222,6 +222,7 @@ struct object_lock extern NTSTATUS get_shared_desktop( struct object_lock *lock, const desktop_shm_t **desktop_shm ); extern NTSTATUS get_shared_queue( struct object_lock *lock, const queue_shm_t **queue_shm ); extern NTSTATUS get_shared_input( UINT tid, struct object_lock *lock, const input_shm_t **input_shm ); +extern NTSTATUS get_shared_window( HWND hwnd, struct object_lock *lock, const window_shm_t **window_shm ); extern void set_shared_user_object( HANDLE handle, struct obj_locator locator );
extern BOOL is_virtual_desktop(void); diff --git a/dlls/win32u/window.c b/dlls/win32u/window.c index 6dbfaebb497..1eb8c5f40e9 100644 --- a/dlls/win32u/window.c +++ b/dlls/win32u/window.c @@ -182,36 +182,21 @@ HWND get_hwnd_message_parent(void) */ HWND get_full_window_handle( HWND hwnd ) { - WND *win; + struct object_lock lock = OBJECT_LOCK_INIT; + const window_shm_t *window_shm; + HWND handle = hwnd; + UINT status;
if (!hwnd || (ULONG_PTR)hwnd >> 16) return hwnd; if (LOWORD(hwnd) <= 1 || LOWORD(hwnd) == 0xffff) return hwnd; /* do sign extension for -2 and -3 */ if (LOWORD(hwnd) >= (WORD)-3) return (HWND)(LONG_PTR)(INT16)LOWORD(hwnd);
- if (!(win = get_win_ptr( hwnd ))) return hwnd; - - if (win == WND_DESKTOP) - { - if (LOWORD(hwnd) == LOWORD(get_desktop_window())) return get_desktop_window(); - else return get_hwnd_message_parent(); - } + while ((status = get_shared_window( hwnd, &lock, &window_shm )) == STATUS_PENDING) + handle = wine_server_ptr_handle( window_shm->handle ); + if (status) return hwnd;
- if (win != WND_OTHER_PROCESS) - { - hwnd = win->obj.handle; - release_win_ptr( win ); - } - else /* may belong to another process */ - { - SERVER_START_REQ( get_window_info ) - { - req->handle = wine_server_user_handle( hwnd ); - if (!wine_server_call_err( req )) hwnd = wine_server_ptr_handle( reply->full_handle ); - } - SERVER_END_REQ; - } - return hwnd; + return handle; }
/******************************************************************* diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 5850f1121f0..8060e4fb469 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -354,6 +354,70 @@ void set_shared_user_object( HANDLE handle, struct obj_locator locator ) pthread_mutex_unlock( &user_objects_lock ); }
+static NTSTATUS get_shared_user_object( HANDLE handle, unsigned int type, struct object_lock *lock, + const object_shm_t **object_shm ) +{ + WORD index = USER_HANDLE_TO_INDEX( handle ); + struct shared_user_object_cache *cache; + const shared_object_t *object; + UINT status = STATUS_SUCCESS; + BOOL valid = TRUE; + + if (index >= NB_USER_HANDLES) return STATUS_INVALID_PARAMETER; + cache = user_objects + index; + + pthread_mutex_lock( &user_objects_lock ); + if (!(object = cache->object)) + { + struct obj_locator locator; + + SERVER_START_REQ( get_shared_user_object ) + { + req->handle = wine_server_user_handle( handle ); + req->type = type; + wine_server_call( req ); + locator = reply->locator; + } + SERVER_END_REQ; + + cache->id = locator.id; + cache->object = find_shared_session_object( locator ); + if (!(object = cache->object)) status = STATUS_INVALID_HANDLE; + memset( lock, 0, sizeof(*lock) ); + } + + /* check object validity by comparing ids, within the object seqlock */ + if (!status) valid = cache->id == object->id; + pthread_mutex_unlock( &user_objects_lock ); + + if (!status && (!lock->id || !shared_object_release_seqlock( object, lock->seq ))) + { + shared_object_acquire_seqlock( object, &lock->seq ); + if (!(lock->id = object->id)) lock->id = -1; + *object_shm = &object->shm; + return STATUS_PENDING; + } + + if (!valid) + { + memset( cache, 0, sizeof(*cache) ); /* object has been invalidated, clear the cache */ + return STATUS_INVALID_HANDLE; + } + return status; +} + +NTSTATUS get_shared_window( HWND hwnd, struct object_lock *lock, const window_shm_t **window_shm ) +{ + const object_shm_t *object_shm; + UINT status = STATUS_SUCCESS; + + TRACE( "hwnd %p, lock %p, input_shm %p\n", hwnd, lock, window_shm ); + + status = get_shared_user_object( hwnd, NTUSER_OBJ_WINDOW, lock, &object_shm ); + if (status == STATUS_PENDING) *window_shm = &object_shm->window; + return status; +} + BOOL is_virtual_desktop(void) { struct object_lock lock = OBJECT_LOCK_INIT; diff --git a/server/hook.c b/server/hook.c index ffe7206369e..4583dc3f206 100644 --- a/server/hook.c +++ b/server/hook.c @@ -153,7 +153,7 @@ static struct hook *add_hook( struct desktop *desktop, struct process *process, } if (!(hook = mem_alloc( sizeof(*hook) ))) return NULL;
- if (!(hook->handle = alloc_user_handle( hook, USER_HOOK ))) + if (!(hook->handle = alloc_user_handle( hook, USER_HOOK, NULL ))) { free( hook ); return NULL; diff --git a/server/protocol.def b/server/protocol.def index 2d6c712d8dc..bb4e66aedb2 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -2578,7 +2578,6 @@ enum message_type @REQ(get_window_info) user_handle_t handle; /* handle to the window */ @REPLY - user_handle_t full_handle; /* full 32-bit handle */ user_handle_t last_active; /* last active popup */ process_id_t pid; /* process owning the window */ thread_id_t tid; /* thread owning the window */ @@ -2982,6 +2981,14 @@ enum coords_relative @END
+@REQ(get_shared_user_object) + obj_handle_t handle; /* handle to the object */ + unsigned int type; /* expected type of the object */ +@REPLY + struct obj_locator locator; +@END + + /* Get/set information about a user object (window station or desktop) */ @REQ(set_user_object_info) obj_handle_t handle; /* handle to the object */ diff --git a/server/user.c b/server/user.c index 2d038a6ddbf..163db4f20af 100644 --- a/server/user.c +++ b/server/user.c @@ -20,11 +20,13 @@
#include "thread.h" #include "user.h" +#include "file.h" #include "request.h"
struct user_handle { void *ptr; /* pointer to object */ + const volatile void *shm; /* object shared memory */ unsigned short type; /* object type (0 if free) */ unsigned short generation; /* generation counter */ }; @@ -84,17 +86,19 @@ static inline void *free_user_entry( struct user_handle *ptr ) void *ret; ret = ptr->ptr; ptr->ptr = freelist; + ptr->shm = NULL; ptr->type = 0; freelist = ptr; return ret; }
/* allocate a user handle for a given object */ -user_handle_t alloc_user_handle( void *ptr, enum user_object type ) +user_handle_t alloc_user_handle( void *ptr, enum user_object type, const volatile void *object_shm ) { struct user_handle *entry = alloc_user_entry(); if (!entry) return 0; entry->ptr = ptr; + entry->shm = object_shm; entry->type = type; if (++entry->generation >= 0xffff) entry->generation = 1; return entry_to_handle( entry ); @@ -179,7 +183,7 @@ void free_process_user_handles( struct process *process ) /* allocate an arbitrary user handle */ DECL_HANDLER(alloc_user_handle) { - reply->handle = alloc_user_handle( current->process, USER_CLIENT ); + reply->handle = alloc_user_handle( current->process, USER_CLIENT, NULL ); }
@@ -193,3 +197,13 @@ DECL_HANDLER(free_user_handle) else set_error( STATUS_INVALID_HANDLE ); } + +DECL_HANDLER(get_shared_user_object) +{ + struct user_handle *entry; + + if (!(entry = handle_to_entry( req->handle )) || entry->type != req->type || !entry->shm) + set_error( STATUS_INVALID_HANDLE ); + else + reply->locator = get_shared_object_locator( entry->shm ); +} diff --git a/server/user.h b/server/user.h index ce463b9395d..327fc25c427 100644 --- a/server/user.h +++ b/server/user.h @@ -99,7 +99,7 @@ struct desktop
/* user handles functions */
-extern user_handle_t alloc_user_handle( void *ptr, enum user_object type ); +extern user_handle_t alloc_user_handle( void *ptr, enum user_object type, const volatile void *object_shm ); extern void *get_user_object( user_handle_t handle, enum user_object type ); extern void *get_user_object_handle( user_handle_t *handle, enum user_object type ); extern user_handle_t get_user_full_handle( user_handle_t handle ); diff --git a/server/window.c b/server/window.c index 9357536aebf..f69e79b5d64 100644 --- a/server/window.c +++ b/server/window.c @@ -672,7 +672,7 @@ static struct window *create_window( struct window *parent, struct window *owner list_init( &win->unlinked );
if (!(win->shared = alloc_shared_object())) goto failed; - if (!(handle = alloc_user_handle( win, USER_WINDOW ))) goto failed; + if (!(handle = alloc_user_handle( win, USER_WINDOW, win->shared ))) goto failed; win->last_active = win->shared->handle;
SHARED_WRITE_BEGIN( win->shared, window_shm_t ) @@ -2345,7 +2345,6 @@ DECL_HANDLER(get_window_info)
if (!win) return;
- reply->full_handle = win->shared->handle; reply->last_active = win->shared->handle; reply->is_unicode = win->is_unicode; reply->dpi_context = win->dpi_context;