Alexandre Julliard : user32: Destroy thread windows by going through the handle table.

Alexandre Julliard julliard at winehq.org
Fri Apr 27 13:26:03 CDT 2018


Module: wine
Branch: master
Commit: 460b4e7adfef5280289f34b895e8d953e0d60579
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=460b4e7adfef5280289f34b895e8d953e0d60579

Author: Alexandre Julliard <julliard at 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 at 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;




More information about the wine-cvs mailing list