Signed-off-by: Paul Gofman pgofman@codeweavers.com --- Supersedes 217103.
USER_Driver->pThreadDetach() destroys thread data part of which (e. g., display) is still present in window data in winex11.drv and accessible through hwnd. That causes all sort of hangs and crashes when, for instance, the windows is still used for Vulkan rendering (even if only to tear down the device and swapchain). Besides, the windows destroyed in destroy_thread_windows() are still considered valid in the server until thread terminates and, e. g., calling IsWindow() on already destroyed window will still show that as valid between destroy_thread_windows() and thread termination. Then, it looks like a few objects referenced in WND structure are getting leaked.
It looks like WIN_DestroyWindow() does everything which is needed. The message(s) it may send to the window being destroyed do not matter as the messages to the thread being destroyed are filtered out anyway.
dlls/user32/user_main.c | 4 +++- dlls/user32/win.c | 51 +++++++++-------------------------------- 2 files changed, 14 insertions(+), 41 deletions(-)
diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index 30e5d154d3d..f4b0f110dc2 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -358,9 +358,11 @@ static void thread_detach(void) exiting_thread_id = GetCurrentThreadId();
WDML_NotifyThreadDetach(); - USER_Driver->pThreadDetach();
destroy_thread_windows(); + + USER_Driver->pThreadDetach(); + CloseHandle( thread_info->server_queue ); HeapFree( GetProcessHeap(), 0, thread_info->wmchar_data ); HeapFree( GetProcessHeap(), 0, thread_info->key_state ); diff --git a/dlls/user32/win.c b/dlls/user32/win.c index 5e89f4c2c97..43207484790 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -1181,24 +1181,25 @@ LRESULT WIN_DestroyWindow( HWND hwnd ) /*********************************************************************** * next_thread_window */ -static WND *next_thread_window( HWND *hwnd ) +static HWND first_thread_window(void) { struct user_object *ptr; + HWND ret = NULL; + WORD index; WND *win; - WORD index = *hwnd ? USER_HANDLE_TO_INDEX( *hwnd ) + 1 : 0;
USER_Lock(); - while (index < NB_USER_HANDLES) + for (index = 0; index < NB_USER_HANDLES; ++index) { - if (!(ptr = user_handles[index++])) continue; + if (!(ptr = user_handles[index])) continue; if (ptr->type != USER_WINDOW) continue; win = (WND *)ptr; if (win->tid != GetCurrentThreadId()) continue; - *hwnd = ptr->handle; - return win; + ret = ptr->handle; + break; } USER_Unlock(); - return NULL; + return ret; }
@@ -1209,40 +1210,10 @@ static WND *next_thread_window( HWND *hwnd ) */ void destroy_thread_windows(void) { - WND *wndPtr; - HWND hwnd = 0, *list; - HMENU menu, sys_menu; - struct window_surface *surface; - int i; - - while ((wndPtr = next_thread_window( &hwnd ))) - { - /* destroy the client-side storage */ + HWND hwnd;
- list = WIN_ListChildren( hwnd ); - menu = ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) ? (HMENU)wndPtr->wIDmenu : 0; - sys_menu = wndPtr->hSysMenu; - free_dce( wndPtr->dce, hwnd ); - surface = wndPtr->surface; - InterlockedCompareExchangePointer( &user_handles[USER_HANDLE_TO_INDEX(hwnd)], NULL, wndPtr ); - WIN_ReleasePtr( wndPtr ); - HeapFree( GetProcessHeap(), 0, wndPtr ); - if (menu) DestroyMenu( menu ); - if (sys_menu) DestroyMenu( sys_menu ); - if (surface) - { - register_window_surface( surface, NULL ); - window_surface_release( surface ); - } - - /* free child windows */ - - if (!list) continue; - for (i = 0; list[i]; i++) - if (!WIN_IsCurrentThread( list[i] )) - SendNotifyMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 ); - HeapFree( GetProcessHeap(), 0, list ); - } + while ((hwnd = first_thread_window())) + WIN_DestroyWindow( hwnd ); }