The desktop of a new thread should be set from the process initial desktop, not from the parent thread. Fixed a couple of bugs in the desktop name handling.
diff --git a/dlls/user/tests/winstation.c b/dlls/user/tests/winstation.c index d40ae19..2855448 100644 --- a/dlls/user/tests/winstation.c +++ b/dlls/user/tests/winstation.c
@@ -42,6 +42,8 @@ trace( "obj %p type '%s'\n", obj, buffer ); } +static HDESK initial_desktop; + static DWORD CALLBACK thread( LPVOID arg ) { HDESK d1, d2; @@ -49,6 +51,7 @@ ok( hwnd != 0, "CreateWindow failed\n" ); d1 = GetThreadDesktop(GetCurrentThreadId()); trace( "thread %p desktop: %p\n", arg, d1 ); + ok( d1 == initial_desktop, "thread %p doesn't use initial desktop\n", arg ); if (0) /* FIXME: this should be todo_wine but it would break the rest of the test */ { @@ -150,6 +153,7 @@ /* desktops */ d1 = GetThreadDesktop(GetCurrentThreadId()); + initial_desktop = d1; ok( GetThreadDesktop(GetCurrentThreadId()) == d1, "GetThreadDesktop returned different handles\n" ); @@ -201,8 +205,8 @@ ok( d1 == d2, "got different handles after close\n" ); } - trace( "thread 1 desktop: %p\n", d2 ); - print_object( d2 ); + trace( "thread 1 desktop: %p\n", d1 ); + print_object( d1 ); hthread = CreateThread( NULL, 0, thread, (LPVOID)2, 0, &id ); Sleep(1000); trace( "get other thread desktop: %p\n", GetThreadDesktop(id) );
diff --git a/server/handle.c b/server/handle.c index 347960d..efcbe27 100644 --- a/server/handle.c +++ b/server/handle.c
@@ -56,7 +56,7 @@ static struct handle_table *global_table; /* reserved handle access rights */ -#define RESERVED_SHIFT 25 +#define RESERVED_SHIFT 26 #define RESERVED_INHERIT (HANDLE_FLAG_INHERIT << RESERVED_SHIFT) #define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE << RESERVED_SHIFT) #define RESERVED_ALL (RESERVED_INHERIT | RESERVED_CLOSE_PROTECT)
diff --git a/server/process.c b/server/process.c index e69fe1b..f2b4012 100644 --- a/server/process.c +++ b/server/process.c
@@ -281,6 +281,7 @@ process->peb = NULL; process->ldt_copy = NULL; process->winstation = 0; + process->desktop = 0; process->exe.file = NULL; process->exe.dbg_offset = 0; process->exe.dbg_size = 0; @@ -379,7 +380,8 @@ /* connect to the window station and desktop */ connect_process_winstation( process, NULL, 0 ); - connect_thread_desktop( current, NULL, 0 ); + connect_process_desktop( process, NULL, 0 ); + current->desktop = process->desktop; /* set the process console */ if (!set_process_console( process, parent_thread, info, reply )) return NULL;
diff --git a/server/process.h b/server/process.h index c82848b..3949bc4 100644 --- a/server/process.h +++ b/server/process.h
@@ -73,6 +73,7 @@ struct event *idle_event; /* event for input idle */ struct msg_queue *queue; /* main message queue */ obj_handle_t winstation; /* main handle to process window station */ + obj_handle_t desktop; /* handle to desktop to use for new threads */ struct token *token; /* security token associated with this process */ struct process_dll exe; /* main exe file */ struct list dlls; /* list of loaded dlls */
diff --git a/server/thread.c b/server/thread.c index 9d69bf1..3fb06c5 100644 --- a/server/thread.c +++ b/server/thread.c
@@ -137,7 +137,6 @@ thread->priority = THREAD_PRIORITY_NORMAL; thread->affinity = 1; thread->suspend = 0; - thread->desktop = 0; thread->creation_time = time(NULL); thread->exit_time = 0; @@ -159,6 +158,7 @@ init_thread_structure( thread ); thread->process = (struct process *)grab_object( process ); + thread->desktop = process->desktop; if (!current) current = thread; if (!booting_thread) /* first thread ever */ @@ -834,7 +834,6 @@ if ((thread = create_thread( request_fd, current->process ))) { if (req->suspend) thread->suspend++; - thread->desktop = current->desktop; reply->tid = get_thread_id( thread ); if ((reply->handle = alloc_handle( current->process, thread, THREAD_ALL_ACCESS, req->inherit )))
diff --git a/server/user.h b/server/user.h index ff8af79..ec83199 100644 --- a/server/user.h +++ b/server/user.h
@@ -121,7 +121,7 @@ /* windows station functions */ extern void connect_process_winstation( struct process *process, const WCHAR *name, size_t len ); -extern void connect_thread_desktop( struct thread *thread, const WCHAR *name, size_t len ); +extern void connect_process_desktop( struct process *process, const WCHAR *name, size_t len ); extern void close_thread_desktop( struct thread *thread ); #endif /* __WINE_SERVER_USER_H */
diff --git a/server/winstation.c b/server/winstation.c index 57b5d45..7e7adab 100644 --- a/server/winstation.c +++ b/server/winstation.c
@@ -162,7 +162,7 @@ if (!(full_name = mem_alloc( *res_len ))) return NULL; memcpy( full_name, winstation_name, winstation_len ); full_name[winstation_len / sizeof(WCHAR)] = '\\'; - memcpy( full_name + (winstation_len + 1) / sizeof(WCHAR), name, len ); + memcpy( full_name + winstation_len / sizeof(WCHAR) + 1, name, len ); return full_name; } @@ -207,21 +207,17 @@ release_object( desktop->winstation ); } -/* close a desktop handle if allowed */ -static void close_desktop_handle( struct process *process, obj_handle_t handle ) +/* check if a desktop handle is currently used by the process */ +static int is_desktop_in_use( struct process *process, obj_handle_t handle ) { struct thread *thread; - /* make sure it's not in use by any thread in the process */ + if (process->desktop == handle) return 1; + LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry ) - { - if (thread->desktop == handle) - { - set_error( STATUS_DEVICE_BUSY ); - return; - } - } - close_handle( process, handle, NULL ); + if (thread->desktop == handle) return 1; + + return 0; } /* connect a process to its window station */ @@ -262,14 +258,13 @@ clear_error(); /* ignore errors */ } -/* connect a thread to its desktop */ -void connect_thread_desktop( struct thread *thread, const WCHAR *name, size_t len ) +/* connect a process to its main desktop */ +void connect_process_desktop( struct process *process, const WCHAR *name, size_t len ) { struct desktop *desktop; struct winstation *winstation; - struct process *process = thread->process; - if (thread->desktop) return; /* already has one */ + if (process->desktop) return; /* already has one */ if ((winstation = get_process_winstation( process, WINSTA_CREATEDESKTOP ))) { @@ -282,7 +277,7 @@ } if ((desktop = create_desktop( name, len, 0, winstation ))) { - thread->desktop = alloc_handle( process, desktop, DESKTOP_ALL_ACCESS, FALSE ); + process->desktop = alloc_handle( process, desktop, DESKTOP_ALL_ACCESS, FALSE ); release_object( desktop ); } release_object( winstation ); @@ -296,8 +291,8 @@ obj_handle_t handle = thread->desktop; thread->desktop = 0; - if (handle) close_desktop_handle( thread->process, handle ); - clear_error(); /* ignore errors */ + if (handle && !is_desktop_in_use( thread->process, handle )) + close_handle( thread->process, handle, NULL ); } @@ -413,7 +408,10 @@ if ((desktop = (struct desktop *)get_handle_obj( current->process, req->handle, 0, &desktop_ops ))) { - close_desktop_handle( current->process, req->handle ); + if (!is_desktop_in_use( current->process, req->handle )) + close_handle( current->process, req->handle, NULL ); + else + set_error( STATUS_DEVICE_BUSY ); release_object( desktop ); } } @@ -479,8 +477,8 @@ /* if there is a backslash return the part of the name after it */ if (name && (ptr = memchrW( name, '\\', len ))) { + len -= (ptr + 1 - name) * sizeof(WCHAR); name = ptr + 1; - len -= (ptr - name) * sizeof(WCHAR); } if (name) set_reply_data( name, min( len, get_reply_max_size() )); }