Module: wine Branch: master Commit: 460b4e7adfef5280289f34b895e8d953e0d60579 URL: https://source.winehq.org/git/wine.git/?a=commit;h=460b4e7adfef5280289f34b89...
Author: Alexandre Julliard julliard@winehq.org Date: Fri Apr 27 16:23:39 2018 +0200
user32: Destroy thread windows by going through the handle table.
This makes sure we catch child windows that may not have been deleted yet.
Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/user32/user_main.c | 3 +- dlls/user32/win.c | 124 ++++++++++++++++++------------------------------ dlls/user32/win.h | 2 +- 3 files changed, 47 insertions(+), 82 deletions(-)
diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index 418359a..e287150 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -374,8 +374,7 @@ static void thread_detach(void) WDML_NotifyThreadDetach(); USER_Driver->pThreadDetach();
- if (thread_info->top_window) WIN_DestroyThreadWindows( thread_info->top_window ); - if (thread_info->msg_window) WIN_DestroyThreadWindows( thread_info->msg_window ); + destroy_thread_windows(); 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 0272566..17a72d2 100644 --- a/dlls/user32/win.c +++ b/dlls/user32/win.c @@ -287,8 +287,8 @@ static void free_window_handle( HWND hwnd ) SERVER_START_REQ( destroy_window ) { req->handle = wine_server_user_handle( hwnd ); - if (wine_server_call_err( req )) ptr = NULL; - else InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr ); + wine_server_call( req ); + InterlockedCompareExchangePointer( &user_handles[index], NULL, ptr ); } SERVER_END_REQ; USER_Unlock(); @@ -1027,104 +1027,70 @@ LRESULT WIN_DestroyWindow( HWND hwnd )
/*********************************************************************** - * destroy_thread_window - * - * Destroy a window upon exit of its thread. + * next_thread_window */ -static void destroy_thread_window( HWND hwnd ) +static WND *next_thread_window( HWND *hwnd ) { - WND *wndPtr; - HWND *list; - HMENU menu = 0, sys_menu = 0; - struct window_surface *surface = NULL; - WORD index; - - /* free child windows */ - - if ((list = WIN_ListChildren( hwnd ))) - { - int i; - for (i = 0; list[i]; i++) - { - if (WIN_IsCurrentThread( list[i] )) destroy_thread_window( list[i] ); - else SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 ); - } - HeapFree( GetProcessHeap(), 0, list ); - } - - /* destroy the client-side storage */ + struct user_object *ptr; + WND *win; + WORD index = *hwnd ? USER_HANDLE_TO_INDEX( *hwnd ) + 1 : 0;
- index = USER_HANDLE_TO_INDEX(hwnd); - if (index >= NB_USER_HANDLES) return; USER_Lock(); - if ((wndPtr = user_handles[index])) + while (index < NB_USER_HANDLES) { - if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu; - sys_menu = wndPtr->hSysMenu; - free_dce( wndPtr->dce, hwnd ); - surface = wndPtr->surface; - wndPtr->surface = NULL; - InterlockedCompareExchangePointer( &user_handles[index], NULL, wndPtr ); + 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; } USER_Unlock(); - - 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 ); - } + return NULL; }
/*********************************************************************** - * destroy_thread_child_windows + * destroy_thread_windows * - * Destroy child windows upon exit of its thread. + * Destroy all window owned by the current thread. */ -static void destroy_thread_child_windows( HWND hwnd ) +void destroy_thread_windows(void) { - HWND *list; + WND *wndPtr; + HWND hwnd = 0, *list; + HMENU menu, sys_menu; + struct window_surface *surface; int i;
- if (WIN_IsCurrentThread( hwnd )) - { - destroy_thread_window( hwnd ); - } - else if ((list = WIN_ListChildren( hwnd ))) + while ((wndPtr = next_thread_window( &hwnd ))) { - for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] ); - HeapFree( GetProcessHeap(), 0, list ); - } -} + /* destroy the client-side storage */
- -/*********************************************************************** - * WIN_DestroyThreadWindows - * - * Destroy all children of 'wnd' owned by the current thread. - */ -void WIN_DestroyThreadWindows( HWND hwnd ) -{ - HWND *list; - int i; - - if (!(list = WIN_ListChildren( hwnd ))) return; - - /* reset owners of top-level windows */ - for (i = 0; list[i]; i++) - { - if (!WIN_IsCurrentThread( list[i] )) + 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) { - HWND owner = GetWindow( list[i], GW_OWNER ); - if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 ); + register_window_surface( surface, NULL ); + window_surface_release( surface ); } - }
- for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] ); - HeapFree( GetProcessHeap(), 0, list ); + /* free child windows */ + + if (!list) continue; + for (i = 0; list[i]; i++) + if (!WIN_IsCurrentThread( list[i] )) + SendMessageW( list[i], WM_WINE_DESTROYWINDOW, 0, 0 ); + HeapFree( GetProcessHeap(), 0, list ); + } }
diff --git a/dlls/user32/win.h b/dlls/user32/win.h index 0c7fcc8..65cb921 100644 --- a/dlls/user32/win.h +++ b/dlls/user32/win.h @@ -96,7 +96,7 @@ extern ULONG WIN_SetStyle( HWND hwnd, ULONG set_bits, ULONG clear_bits ) DECLSPE extern BOOL WIN_GetRectangles( HWND hwnd, enum coords_relative relative, RECT *rectWindow, RECT *rectClient ) DECLSPEC_HIDDEN; extern void map_window_region( HWND from, HWND to, HRGN hrgn ) DECLSPEC_HIDDEN; extern LRESULT WIN_DestroyWindow( HWND hwnd ) DECLSPEC_HIDDEN; -extern void WIN_DestroyThreadWindows( HWND hwnd ) DECLSPEC_HIDDEN; +extern void destroy_thread_windows(void) DECLSPEC_HIDDEN; extern HWND WIN_CreateWindowEx( CREATESTRUCTW *cs, LPCWSTR className, HINSTANCE module, BOOL unicode ) DECLSPEC_HIDDEN; extern BOOL WIN_IsWindowDrawable( HWND hwnd, BOOL ) DECLSPEC_HIDDEN; extern HWND *WIN_ListChildren( HWND hwnd ) DECLSPEC_HIDDEN;