Commit 92fec7b6 authored by Alexandre Julliard's avatar Alexandre Julliard

Keep track of the windows and hooks used by a thread to properly

refuse to change the thread desktop when it's in use.
parent 52736b47
......@@ -64,12 +64,9 @@ static DWORD CALLBACK thread( LPVOID arg )
trace( "created desktop %p\n", d2 );
ok( d2 != 0, "CreateDesktop failed\n" );
todo_wine
{
SetLastError( 0xdeadbeef );
ok( !SetThreadDesktop( d2 ), "set thread desktop succeeded with existing window\n" );
ok( GetLastError() == ERROR_BUSY, "bad last error %ld\n", GetLastError() );
}
SetLastError( 0xdeadbeef );
ok( !SetThreadDesktop( d2 ), "set thread desktop succeeded with existing window\n" );
ok( GetLastError() == ERROR_BUSY, "bad last error %ld\n", GetLastError() );
DestroyWindow( hwnd );
ok( SetThreadDesktop( d2 ), "set thread desktop failed\n" );
......
......@@ -125,6 +125,7 @@ static struct hook *add_hook( struct thread *thread, int index, int global )
hook->thread = thread ? (struct thread *)grab_object( thread ) : NULL;
hook->index = index;
list_add_head( &table->hooks[index], &hook->chain );
if (thread) thread->desktop_users++;
return hook;
}
......@@ -133,7 +134,12 @@ static void free_hook( struct hook *hook )
{
free_user_handle( hook->handle );
if (hook->module) free( hook->module );
if (hook->thread) release_object( hook->thread );
if (hook->thread)
{
assert( hook->thread->desktop_users > 0 );
hook->thread->desktop_users--;
release_object( hook->thread );
}
if (hook->process) release_object( hook->process );
release_object( hook->owner );
list_remove( &hook->chain );
......
......@@ -140,6 +140,7 @@ inline static void init_thread_structure( struct thread *thread )
thread->suspend = 0;
thread->creation_time = time(NULL);
thread->exit_time = 0;
thread->desktop_users = 0;
list_init( &thread->mutex_list );
list_init( &thread->system_apc );
......
......@@ -83,6 +83,7 @@ struct thread
int affinity; /* affinity mask */
int suspend; /* suspend count */
obj_handle_t desktop; /* desktop handle */
int desktop_users; /* number of objects using the thread desktop */
time_t creation_time; /* Thread creation time */
time_t exit_time; /* Thread exit time */
struct token *token; /* security token associated with this thread */
......
......@@ -311,6 +311,8 @@ static void destroy_window( struct window *win )
if (win == shell_listview) shell_listview = NULL;
if (win == progman_window) progman_window = NULL;
if (win == taskman_window) taskman_window = NULL;
assert( win->thread->desktop_users > 0 );
win->thread->desktop_users--;
free_user_handle( win->handle );
destroy_properties( win );
list_remove( &win->entry );
......@@ -376,6 +378,7 @@ static struct window *create_window( struct window *parent, struct window *owner
/* put it on parent unlinked list */
if (parent) list_add_head( &parent->unlinked, &win->entry );
current->desktop_users++;
return win;
failed:
......@@ -1303,6 +1306,7 @@ DECL_HANDLER(create_window)
if (!top_window)
{
if (!(top_window = create_window( NULL, NULL, req->atom, req->instance ))) return;
current->desktop_users--;
top_window->thread = NULL; /* no thread owns the desktop */
top_window->style = WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
}
......
......@@ -175,6 +175,13 @@ static WCHAR *build_desktop_name( const WCHAR *name, size_t len,
return full_name;
}
/* retrieve a pointer to a desktop object */
inline static struct desktop *get_desktop_obj( struct process *process, obj_handle_t handle,
unsigned int access )
{
return (struct desktop *)get_handle_obj( process, handle, access, &desktop_ops );
}
/* create a desktop object */
static struct desktop *create_desktop( const WCHAR *name, size_t len, unsigned int flags,
struct winstation *winstation )
......@@ -426,14 +433,39 @@ DECL_HANDLER(get_thread_desktop)
/* set the thread current desktop */
DECL_HANDLER(set_thread_desktop)
{
struct desktop *desktop;
struct desktop *old_desktop, *new_desktop;
struct winstation *winstation;
if ((desktop = (struct desktop *)get_handle_obj( current->process, req->handle, 0, &desktop_ops )))
if (!(winstation = get_process_winstation( current->process, 0 /* FIXME: access rights? */ )))
return;
if (!(new_desktop = get_desktop_obj( current->process, req->handle, 0 )))
{
/* FIXME: should we close the old one? */
current->desktop = req->handle;
release_object( desktop );
release_object( winstation );
return;
}
if (new_desktop->winstation != winstation)
{
set_error( STATUS_ACCESS_DENIED );
release_object( new_desktop );
release_object( winstation );
return;
}
/* check if we are changing to a new desktop */
if (!(old_desktop = get_desktop_obj( current->process, current->desktop, 0)))
clear_error(); /* ignore error */
/* when changing desktop, we can't have any users on the current one */
if (old_desktop != new_desktop && current->desktop_users > 0)
set_error( STATUS_DEVICE_BUSY );
else
current->desktop = req->handle; /* FIXME: should we close the old one? */
if (old_desktop) release_object( old_desktop );
release_object( new_desktop );
release_object( winstation );
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment