[PATCH 4/7] server: Don't destroy child windows from live other threads.
Rémi Bernon
rbernon at codeweavers.com
Fri Oct 15 04:47:59 CDT 2021
Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
dlls/user32/tests/msg.c | 4 ++--
dlls/user32/tests/win.c | 7 ------
server/window.c | 52 +++++++++++++++++++++++++++++++++++++----
3 files changed, 50 insertions(+), 13 deletions(-)
diff --git a/dlls/user32/tests/msg.c b/dlls/user32/tests/msg.c
index cc362623cf1..57cb9685254 100644
--- a/dlls/user32/tests/msg.c
+++ b/dlls/user32/tests/msg.c
@@ -9034,7 +9034,7 @@ static DWORD CALLBACK create_grand_child_thread( void *param )
ok( !ret, "WaitForSingleObject returned %x, error: %u\n", ret, GetLastError() );
ok( IsWindow( hchild ), "Child window already destroyed\n" );
flush_events();
- todo_wine ok( !IsWindow( hchild ), "Child window not destroyed\n" );
+ ok( !IsWindow( hchild ), "Child window not destroyed\n" );
return 0;
}
@@ -9221,7 +9221,7 @@ static void test_interthread_messages(void)
CloseHandle( wnd_event.stop_event );
CloseHandle( wnd_event.ready_event );
flush_events();
- ok_sequence( WmExitThreadSeq, "destroy child on thread exit", TRUE );
+ ok_sequence( WmExitThreadSeq, "destroy child on thread exit", FALSE );
log_all_parent_messages--;
DestroyWindow( wnd_event.hwnd );
diff --git a/dlls/user32/tests/win.c b/dlls/user32/tests/win.c
index 00e20719ba7..b2f3f48a504 100644
--- a/dlls/user32/tests/win.c
+++ b/dlls/user32/tests/win.c
@@ -828,7 +828,6 @@ static void test_thread_exit_destroy(void)
ok( GetActiveWindow() == adopter, "GetActiveWindow %p, expected %p\n", GetActiveWindow(), adopter );
todo_wine
ok( GetFocus() == adopter, "GetFocus %p, expected %p\n", GetFocus(), adopter );
- todo_wine
ok( GetCapture() == child1, "GetCapture %p, expected %p\n", GetCapture(), child1 );
SetActiveWindow( child1 );
@@ -839,7 +838,6 @@ static void test_thread_exit_destroy(void)
ok( GetActiveWindow() == adopter, "GetActiveWindow %p, expected %p\n", GetActiveWindow(), adopter );
todo_wine
ok( GetFocus() == adopter, "GetFocus %p, expected %p\n", GetFocus(), adopter );
- todo_wine
ok( GetCapture() == child1, "GetCapture %p, expected %p\n", GetCapture(), child1 );
SetLastError( 0xdeadbeef );
@@ -883,10 +881,8 @@ static void test_thread_exit_destroy(void)
ok( wndproc == old_wndproc, "GetWindowLongPtrW GWLP_WNDPROC returned %p\n", wndproc );
tmp = GetPropW( child1, L"myprop" );
- todo_wine
ok( HandleToULong(tmp) == 0xdeadbeef, "GetPropW returned %p\n", tmp );
tmp = GetPropW( child2, L"myprop" );
- todo_wine
ok( HandleToULong(tmp) == 0xdeadbeef, "GetPropW returned %p\n", tmp );
/* destroying child1 ourselves succeeds */
@@ -918,7 +914,6 @@ static void test_thread_exit_destroy(void)
rgn = CreateRectRgn( 5, 5, 15, 15 );
SetLastError( 0xdeadbeef );
ret = SetWindowRgn( child2, rgn, TRUE );
- todo_wine
ok( ret, "SetWindowRgn failed, error %u\n", GetLastError() );
DeleteObject( rgn );
@@ -943,13 +938,11 @@ static void test_thread_exit_destroy(void)
ok( HandleToULong(tmp) == 0, "GetPropW returned %p\n", tmp );
ret = IsWindow( child2 );
- todo_wine
ok( !ret, "IsWindow returned %u\n", ret );
ret = IsWindow( child3 );
todo_wine
ok( !ret, "IsWindow returned %u\n", ret );
ret = DestroyWindow( child2 );
- todo_wine
ok( !ret, "DestroyWindow returned %u\n", ret );
DestroyWindow( adopter );
diff --git a/server/window.c b/server/window.c
index 2ed4aa57d1a..8fcc2fdde2c 100644
--- a/server/window.c
+++ b/server/window.c
@@ -144,6 +144,12 @@ static inline int is_desktop_window( const struct window *win )
return win && !win->parent && win->is_desktop;
}
+/* check if window has lost its parent */
+static inline int is_orphan_window( const struct window *win )
+{
+ return !win->parent && !win->is_desktop;
+}
+
/* get next window in Z-order list */
static inline struct window *get_next_window( struct window *win )
{
@@ -689,6 +695,7 @@ static int is_visible( const struct window *win )
{
while (win)
{
+ if (is_orphan_window( win )) return 0;
if (!(win->style & WS_VISIBLE)) return 0;
win = win->parent;
/* if parent is minimized children are not visible */
@@ -1196,6 +1203,7 @@ static int get_window_visible_rect( struct window *win, rectangle_t *rect, int f
*rect = frame ? win->window_rect : win->client_rect;
if (!(win->style & WS_VISIBLE)) return 0;
+ if (is_orphan_window( win )) return 0;
if (is_desktop_window( win )) return 1;
while (!is_desktop_window( win->parent ))
@@ -1893,9 +1901,25 @@ void destroy_window( struct window *win )
/* destroy all children */
while (!list_empty(&win->children))
- destroy_window( LIST_ENTRY( list_head(&win->children), struct window, entry ));
+ {
+ struct window *child = LIST_ENTRY( list_head( &win->children ), struct window, entry );
+ if (!child->thread || child->thread == win->thread) destroy_window( child );
+ else
+ {
+ list_remove( &child->entry );
+ child->parent = NULL;
+ }
+ }
while (!list_empty(&win->unlinked))
- destroy_window( LIST_ENTRY( list_head(&win->unlinked), struct window, entry ));
+ {
+ struct window *child = LIST_ENTRY( list_head( &win->unlinked ), struct window, entry );
+ if (!child->thread || child->thread == win->thread) destroy_window( child );
+ else
+ {
+ list_remove( &child->entry );
+ child->parent = NULL;
+ }
+ }
/* reset global window pointers, if the corresponding window is destroyed */
if (win == shell_window) shell_window = NULL;
@@ -1938,6 +1962,11 @@ DECL_HANDLER(create_window)
reply->handle = 0;
if (req->parent && !(parent = get_window( req->parent ))) return;
+ if (parent && is_orphan_window( parent ))
+ {
+ set_error( STATUS_INVALID_PARAMETER );
+ return;
+ }
if (req->owner)
{
@@ -1988,8 +2017,7 @@ DECL_HANDLER(set_parent)
if (!(win = get_window( req->handle ))) return;
if (req->parent && !(parent = get_window( req->parent ))) return;
-
- if (is_desktop_window(win))
+ if (!win->parent)
{
set_error( STATUS_INVALID_PARAMETER );
return;
@@ -2110,6 +2138,12 @@ DECL_HANDLER(set_window_info)
struct window *win = get_window( req->handle );
if (!win) return;
+ if (is_orphan_window( win ))
+ {
+ set_error( STATUS_INVALID_PARAMETER );
+ return;
+ }
+
if (req->flags && is_desktop_window(win) && win->thread != current)
{
set_error( STATUS_ACCESS_DENIED );
@@ -2291,6 +2325,11 @@ DECL_HANDLER(set_window_pos)
unsigned int flags = req->swp_flags;
if (!win) return;
+ if (is_orphan_window( win ))
+ {
+ set_error( STATUS_INVALID_PARAMETER );
+ return;
+ }
if (is_desktop_window(win)) flags |= SWP_NOZORDER; /* no Z order for the desktop */
if (!(flags & SWP_NOZORDER))
@@ -2479,6 +2518,11 @@ DECL_HANDLER(get_visible_region)
struct window *top, *win = get_window( req->window );
if (!win) return;
+ if (is_orphan_window( win ))
+ {
+ set_error( STATUS_INVALID_PARAMETER );
+ return;
+ }
top = get_top_clipping_window( win );
if ((region = get_visible_region( win, req->flags )))
--
2.33.0
More information about the wine-devel
mailing list