From: Rémi Bernon rbernon@codeweavers.com
--- dlls/win32u/winstation.c | 103 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 101 insertions(+), 2 deletions(-)
diff --git a/dlls/win32u/winstation.c b/dlls/win32u/winstation.c index 3e71218200a..cfa5121a80c 100644 --- a/dlls/win32u/winstation.c +++ b/dlls/win32u/winstation.c @@ -22,9 +22,14 @@ #pragma makedep unix #endif
+#include <assert.h> +#include <stdarg.h> +#include <stddef.h> + +#include <pthread.h> + #include "ntstatus.h" #define WIN32_NO_STATUS -#include <stdarg.h> #include "windef.h" #include "winbase.h" #include "ntuser.h" @@ -40,6 +45,96 @@ WINE_DECLARE_DEBUG_CHANNEL(win);
#define DESKTOP_ALL_ACCESS 0x01ff
+struct session_block +{ + struct list entry; /* entry in the session block list */ + const char *data; /* base pointer for the mmaped data */ + SIZE_T offset; /* offset of data in the session shared mapping */ + SIZE_T size; /* size of the mmaped data */ +}; + +static pthread_mutex_t session_lock = PTHREAD_MUTEX_INITIALIZER; +static struct list session_blocks = LIST_INIT(session_blocks); + +static NTSTATUS map_shared_session_block( SIZE_T offset, SIZE_T size, struct session_block **ret ) +{ + static const WCHAR nameW[] = + { + '\','K','e','r','n','e','l','O','b','j','e','c','t','s','\', + '_','_','w','i','n','e','_','s','e','s','s','i','o','n',0 + }; + UNICODE_STRING name = RTL_CONSTANT_STRING( nameW ); + LARGE_INTEGER off = {.QuadPart = offset}; + struct session_block *block; + OBJECT_ATTRIBUTES attr; + unsigned int status; + HANDLE handle; + + assert( offset + size > offset ); + + if (!(block = calloc( 1, sizeof(*block) ))) return STATUS_NO_MEMORY; + + InitializeObjectAttributes( &attr, &name, 0, NULL, NULL ); + if (!(status = NtOpenSection( &handle, SECTION_MAP_READ, &attr ))) + { + if (!(status = NtMapViewOfSection( handle, GetCurrentProcess(), (void **)&block->data, 0, 0, + &off, &block->size, ViewUnmap, 0, PAGE_READONLY ))) + { + list_add_tail( &session_blocks, &block->entry ); + block->offset = off.QuadPart; + assert( block->offset + block->size > block->offset ); + } + NtClose( handle ); + } + + if (status) free( block ); + else *ret = block; + return status; +} + +static NTSTATUS find_shared_session_block( SIZE_T offset, SIZE_T size, struct session_block **ret ) +{ + struct session_block *block; + UINT status; + + assert( offset + size > offset ); + + pthread_mutex_lock( &session_lock ); + + LIST_FOR_EACH_ENTRY( block, &session_blocks, struct session_block, entry ) + { + if (block->offset < offset && offset + size <= block->offset + block->size) + { + *ret = block; + pthread_mutex_unlock( &session_lock ); + return STATUS_SUCCESS; + } + } + + status = map_shared_session_block( offset, size, ret ); + + pthread_mutex_unlock( &session_lock ); + + return status; +} + +static NTSTATUS set_shared_object_cache( obj_locator_t locator, const shared_object_t **object_cache, UINT64 *id ) +{ + const shared_object_t *object = NULL; + struct session_block *block; + NTSTATUS status; + + if (!locator.id) status = STATUS_INVALID_HANDLE; + else if (!(status = find_shared_session_block( locator.offset, sizeof(*object), &block ))) + { + object = (const shared_object_t *)(block->data + locator.offset - block->offset); + *id = locator.id; /* return the expected id separately from the object itself */ + } + + *object_cache = object; + return status; +} + BOOL is_virtual_desktop(void) { HANDLE desktop = NtUserGetThreadDesktop( GetCurrentThreadId() ); @@ -249,11 +344,12 @@ HDESK WINAPI NtUserGetThreadDesktop( DWORD thread ) BOOL WINAPI NtUserSetThreadDesktop( HDESK handle ) { BOOL ret, was_virtual_desktop = is_virtual_desktop(); + obj_locator_t locator = {0};
SERVER_START_REQ( set_thread_desktop ) { req->handle = wine_server_obj_handle( handle ); - ret = !wine_server_call_err( req ); + if ((ret = !wine_server_call_err( req ))) locator = reply->locator; } SERVER_END_REQ;
@@ -261,6 +357,9 @@ 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; + const shared_object_t *cache; + UINT64 id; + set_shared_object_cache( locator, &cache, &id ); thread_info->client_info.top_window = 0; thread_info->client_info.msg_window = 0; if (key_state_info) key_state_info->time = 0;