From: Rémi Bernon rbernon@codeweavers.com
When the current thread is requested. --- dlls/win32u/message.c | 20 ++++++++++++ dlls/win32u/win32u_private.h | 1 + dlls/win32u/winstation.c | 63 ++++++++++++++++++++++++++++++++++++ 3 files changed, 84 insertions(+)
diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c index 7308dc1bfd6..88222c815da 100644 --- a/dlls/win32u/message.c +++ b/dlls/win32u/message.c @@ -2132,6 +2132,9 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR */ BOOL WINAPI NtUserGetGUIThreadInfo( DWORD id, GUITHREADINFO *info ) { + struct object_lock lock = OBJECT_LOCK_INIT; + const input_shm_t *input_shm; + NTSTATUS status; BOOL ret;
if (info->cbSize != sizeof(*info)) @@ -2140,6 +2143,23 @@ BOOL WINAPI NtUserGetGUIThreadInfo( DWORD id, GUITHREADINFO *info ) return FALSE; }
+ while ((status = get_shared_input( id, &lock, &input_shm )) == STATUS_PENDING) + { + info->flags = 0; + info->hwndActive = wine_server_ptr_handle( input_shm->active ); + info->hwndFocus = wine_server_ptr_handle( input_shm->focus ); + info->hwndCapture = wine_server_ptr_handle( input_shm->capture ); + info->hwndMenuOwner = wine_server_ptr_handle( input_shm->menu_owner ); + info->hwndMoveSize = wine_server_ptr_handle( input_shm->move_size ); + info->hwndCaret = wine_server_ptr_handle( input_shm->caret ); + info->rcCaret = wine_server_get_rect( input_shm->caret_rect ); + if (input_shm->menu_owner) info->flags |= GUI_INMENUMODE; + if (input_shm->move_size) info->flags |= GUI_INMOVESIZE; + if (input_shm->caret) info->flags |= GUI_CARETBLINKING; + } + + if (!status) return TRUE; + SERVER_START_REQ( get_thread_input_data ) { req->tid = id; diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 0165de27f13..0a82c2175ae 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -221,6 +221,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 BOOL is_virtual_desktop(void);
diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 1a1b37f6eda..2a85da9cf45 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -45,10 +45,17 @@ WINE_DECLARE_DEBUG_CHANNEL(win);
#define DESKTOP_ALL_ACCESS 0x01ff
+struct shared_input_cache +{ + const shared_object_t *object; + UINT64 id; +}; + struct session_thread_data { const shared_object_t *shared_desktop; /* thread desktop shared session cached object */ const shared_object_t *shared_queue; /* thread message queue shared session cached object */ + struct shared_input_cache shared_input; /* current thread input shared session cached object */ };
struct session_block @@ -254,6 +261,62 @@ NTSTATUS get_shared_queue( struct object_lock *lock, const queue_shm_t **queue_s return STATUS_SUCCESS; }
+static NTSTATUS try_get_shared_input( UINT tid, struct object_lock *lock, const input_shm_t **input_shm, + struct shared_input_cache *cache ) +{ + const shared_object_t *object; + BOOL valid = TRUE; + + if (!(object = cache->object)) + { + obj_locator_t locator; + + SERVER_START_REQ( get_thread_input ) + { + req->tid = tid; + 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)) return STATUS_INVALID_HANDLE; + memset( lock, 0, sizeof(*lock) ); + } + + /* check object validity by comparing ids, within the object seqlock */ + valid = cache->id == object->id; + + if (!lock->id || !shared_object_release_seqlock( object, lock->seq )) + { + shared_object_acquire_seqlock( object, &lock->seq ); + if (!(lock->id = object->id)) lock->id = -1; + *input_shm = &object->shm.input; + return STATUS_PENDING; + } + + if (!valid) memset( cache, 0, sizeof(*cache) ); /* object has been invalidated, clear the cache and start over */ + return STATUS_SUCCESS; +} + +NTSTATUS get_shared_input( UINT tid, struct object_lock *lock, const input_shm_t **input_shm ) +{ + struct session_thread_data *data = get_session_thread_data(); + struct shared_input_cache *cache; + UINT status; + + TRACE( "tid %u, lock %p, input_shm %p\n", tid, lock, input_shm ); + + if (tid == GetCurrentThreadId()) cache = &data->shared_input; + else return STATUS_INVALID_HANDLE; + + do { status = try_get_shared_input( tid, lock, input_shm, cache ); } + while (!status && !cache->id); + + return status; +} + BOOL is_virtual_desktop(void) { HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() );