From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/ntuser_private.h | 1 + dlls/win32u/sysparams.c | 1 + dlls/win32u/win32u_private.h | 13 +++++ dlls/win32u/winstation.c | 102 +++++++++++++++++++++++++++++++++-- 4 files changed, 113 insertions(+), 4 deletions(-)
diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index 3b6cab5bdc9..27430c3478b 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -127,6 +127,7 @@ struct user_thread_info UINT spy_indent; /* Current spy indent */ BOOL clipping_cursor; /* thread is currently clipping */ DWORD clipping_reset; /* time when clipping was last reset */ + struct session_thread_data *session_data; /* shared session thread data */ };
C_ASSERT( sizeof(struct user_thread_info) <= sizeof(((TEB *)0)->Win32ClientInfo) ); diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c index 6c4223f0cdb..cb9920bb4d5 100644 --- a/dlls/win32u/sysparams.c +++ b/dlls/win32u/sysparams.c @@ -6151,6 +6151,7 @@ static void thread_detach(void) destroy_thread_windows(); cleanup_imm_thread(); NtClose( thread_info->server_queue ); + free( thread_info->session_data );
exiting_thread_id = 0; } diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 003d2fd5c24..4b7905639b7 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -193,6 +193,19 @@ extern void user_unlock(void); extern void user_check_not_lock(void);
/* winstation.c */ + +struct shared_session; + +struct object_lock +{ + UINT64 id; + const session_obj_t *shared; /* only valid when locked, read inside SHARED_READ_BEGIN */ + struct shared_session *session; /* only valid when locked */ +}; + +extern void object_lock_release( struct object_lock *lock ); +extern BOOL get_shared_desktop( struct object_lock *lock ); + extern BOOL is_virtual_desktop(void);
/* window.c */ diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 6b15ec3a560..84eb20bda60 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -43,6 +43,17 @@ WINE_DECLARE_DEBUG_CHANNEL(win);
#define DESKTOP_ALL_ACCESS 0x01ff
+struct object_info +{ + UINT64 id; + UINT index; +}; + +struct session_thread_data +{ + struct object_info shared_desktop; /* thread desktop shared session object info */ +}; + struct shared_session { LONG ref; @@ -53,6 +64,13 @@ struct shared_session static pthread_mutex_t session_lock = PTHREAD_MUTEX_INITIALIZER; static struct shared_session *shared_session;
+static struct session_thread_data *get_session_thread_data(void) +{ + struct user_thread_info *thread_info = get_user_thread_info(); + if (!thread_info->session_data) thread_info->session_data = calloc(1, sizeof(*thread_info->session_data)); + return thread_info->session_data; +} + static struct shared_session *shared_session_acquire( struct shared_session *session ) { int ref = InterlockedIncrement( &session->ref ); @@ -144,6 +162,82 @@ done: return session; }
+void object_lock_release( struct object_lock *lock ) +{ + shared_session_release( lock->session ); + memset( lock, 0, sizeof(*lock) ); + lock->id = -1; /* force object to be refreshed when retrying lock */ +} + +enum object_type +{ + OBJECT_TYPE_DESKTOP = 1, +}; + +static NTSTATUS get_thread_session_object_info( UINT tid, enum object_type type, + struct object_info *info ) +{ + NTSTATUS status; + + switch (type) + { + case OBJECT_TYPE_DESKTOP: + SERVER_START_REQ( get_thread_desktop ) + { + req->tid = tid; + if (!(status = wine_server_call( req ))) + { + info->id = reply->object_id; + info->index = reply->index; + } + } + SERVER_END_REQ; + break; + } + + return status; +} + +/* return a locked session object for a thread id and type */ +static BOOL get_thread_session_object( UINT tid, enum object_type type, struct object_info *info, + struct object_lock *lock ) +{ + struct shared_session *session; + BOOL valid = TRUE; + + TRACE( "tid %04x, type %u\n", tid, type ); + + while ((session = get_shared_session( !valid ))) + { + if (!info->id && get_thread_session_object_info( tid, type, info )) break; + if ((valid = info->index < session->object_capacity)) + { + lock->id = info->id; + lock->session = session; + lock->shared = &session->shared->objects[info->index]; + return TRUE; + } + shared_session_release( session ); + memset( info, 0, sizeof(*info) ); + } + + WARN( "Failed to find object type %u for thread %04x\n", type, tid ); + if (session) shared_session_release( session ); + memset( info, 0, sizeof(*info) ); + return FALSE; +} + +BOOL get_shared_desktop( struct object_lock *lock ) +{ + struct session_thread_data *data = get_session_thread_data(); + struct object_info *info = &data->shared_desktop; + + TRACE( "lock %p\n", lock ); + + if (lock->id) info->id = 0; /* invalidate info if the lock was abandoned due to id mismatch */ + return get_thread_session_object( GetCurrentThreadId(), OBJECT_TYPE_DESKTOP, info, lock ); +} + BOOL is_virtual_desktop(void) { HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() ); @@ -365,9 +459,13 @@ BOOL WINAPI NtUserSetThreadDesktop( HDESK handle ) { struct user_thread_info *thread_info = get_user_thread_info(); struct user_key_state_info *key_state_info = thread_info->key_state; + struct object_info *desktop_info = &get_session_thread_data()->shared_desktop; + struct object_lock lock = {0}; thread_info->client_info.top_window = 0; thread_info->client_info.msg_window = 0; if (key_state_info) key_state_info->time = 0; + memset( desktop_info, 0, sizeof(*desktop_info) ); + if (get_shared_desktop( &lock )) object_lock_release( &lock ); if (was_virtual_desktop != is_virtual_desktop()) update_display_cache( TRUE ); } return ret; @@ -734,16 +832,12 @@ void winstation_init(void) { RTL_USER_PROCESS_PARAMETERS *params = NtCurrentTeb()->Peb->ProcessParameters; WCHAR *winstation = NULL, *desktop = NULL, *buffer = NULL; - struct shared_session *session; HANDLE handle, dir = NULL; OBJECT_ATTRIBUTES attr; UNICODE_STRING str;
static const WCHAR winsta0[] = {'W','i','n','S','t','a','0',0};
- if ((session = get_shared_session( FALSE ))) - shared_session_release( session ); - if (params->Desktop.Length) { buffer = malloc( params->Desktop.Length + sizeof(WCHAR) );