Keep track of the windows and hooks used by a thread to properly
refuse to change the thread desktop when it's in use.
This commit is contained in:
parent
52736b4743
commit
92fec7b67a
|
@ -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 );
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue