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>
This commit is contained in:
Alexandre Julliard 2018-04-27 16:23:39 +02:00
parent c102efbc35
commit 460b4e7adf
3 changed files with 55 additions and 90 deletions

View File

@ -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 );

View File

@ -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,107 +1027,73 @@ 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 )
{
struct user_object *ptr;
WND *win;
WORD index = *hwnd ? USER_HANDLE_TO_INDEX( *hwnd ) + 1 : 0;
USER_Lock();
while (index < NB_USER_HANDLES)
{
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();
return NULL;
}
/***********************************************************************
* destroy_thread_windows
*
* Destroy all window owned by the current thread.
*/
void destroy_thread_windows(void)
{
WND *wndPtr;
HWND *list;
HMENU menu = 0, sys_menu = 0;
struct window_surface *surface = NULL;
WORD index;
HWND hwnd = 0, *list;
HMENU menu, sys_menu;
struct window_surface *surface;
int i;
/* free child windows */
if ((list = WIN_ListChildren( hwnd )))
while ((wndPtr = next_thread_window( &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 */
/* destroy the client-side storage */
index = USER_HANDLE_TO_INDEX(hwnd);
if (index >= NB_USER_HANDLES) return;
USER_Lock();
if ((wndPtr = user_handles[index]))
{
if ((wndPtr->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) menu = (HMENU)wndPtr->wIDmenu;
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;
wndPtr->surface = NULL;
InterlockedCompareExchangePointer( &user_handles[index], NULL, wndPtr );
}
USER_Unlock();
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 );
}
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 */
/***********************************************************************
* destroy_thread_child_windows
*
* Destroy child windows upon exit of its thread.
*/
static void destroy_thread_child_windows( HWND hwnd )
{
HWND *list;
int i;
if (WIN_IsCurrentThread( hwnd ))
{
destroy_thread_window( hwnd );
}
else if ((list = WIN_ListChildren( hwnd )))
{
for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
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 );
}
}
/***********************************************************************
* 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] ))
{
HWND owner = GetWindow( list[i], GW_OWNER );
if (owner && WIN_IsCurrentThread( owner )) WIN_SetOwner( list[i], 0 );
}
}
for (i = 0; list[i]; i++) destroy_thread_child_windows( list[i] );
HeapFree( GetProcessHeap(), 0, list );
}
/***********************************************************************
* WIN_FixCoordinates
*

View File

@ -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;