[PATCH 1/6] user32: Add internal reference counting to menu structs

Nikolay Sivov nsivov at codeweavers.com
Tue Apr 10 01:36:50 CDT 2018


From: Andrew Eikum <aeikum at codeweavers.com>

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/user32/menu.c | 50 +++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 39 insertions(+), 11 deletions(-)

diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c
index 99a99c0395..0aa4fb7ee5 100644
--- a/dlls/user32/menu.c
+++ b/dlls/user32/menu.c
@@ -98,6 +98,7 @@ typedef struct {
     UINT        nScrollPos;   /* Current scroll position */
     UINT        nTotalHeight; /* Total height of menu items inside menu */
     RECT        items_rect;   /* Rectangle within which the items lie.  Excludes margins and scroll arrows */
+    LONG        refcount;
     /* ------------ MENUINFO members ------ */
     DWORD	dwStyle;	/* Extended menu style */
     UINT	cyMax;		/* max height of the whole menu, 0 is screen height */
@@ -180,6 +181,7 @@ static BOOL fEndMenu = FALSE;
 DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont);
 
 static BOOL SetMenuItemInfo_common( MENUITEM *, const MENUITEMINFOW *, BOOL);
+static BOOL MENU_ReleaseMenu( POPUPMENU *lppop );
 
 /*********************************************************************
  * menu class descriptor
@@ -3978,7 +3980,9 @@ BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
     if (!(item = MENU_FindItem( &hMenu, &nPos, wFlags ))) return FALSE;
     if (!(menu = MENU_GetMenu(hMenu))) return FALSE;
 
-      /* Remove item */
+    /* Remove item */
+    if ((item->fType & MF_POPUP) && item->hSubMenu)
+        MENU_ReleaseMenu(MENU_GetMenu(item->hSubMenu));
 
     MENU_FreeItemData( item );
 
@@ -4127,6 +4131,7 @@ HMENU WINAPI CreateMenu(void)
 
     if (!(menu = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*menu) ))) return 0;
     menu->FocusedItem = NO_SELECTED_ITEM;
+    menu->refcount = 1;
 
     if (!(hMenu = alloc_user_handle( &menu->obj, USER_MENU ))) HeapFree( GetProcessHeap(), 0, menu );
 
@@ -4135,18 +4140,16 @@ HMENU WINAPI CreateMenu(void)
     return hMenu;
 }
 
-
-/**********************************************************************
- *         DestroyMenu    (USER32.@)
- */
-BOOL WINAPI DestroyMenu( HMENU hMenu )
+static BOOL MENU_ReleaseMenu( POPUPMENU *lppop )
 {
-    LPPOPUPMENU lppop;
+    LONG ref;
 
-    TRACE("(%p)\n", hMenu);
+    if (!lppop)
+        return FALSE;
 
-    if (!(lppop = free_user_handle( hMenu, USER_MENU ))) return FALSE;
-    if (lppop == OBJ_OTHER_PROCESS) return FALSE;
+    ref = InterlockedDecrement(&lppop->refcount);
+    if (ref)
+        return FALSE;
 
     /* DestroyMenu should not destroy system menu popup owner */
     if ((lppop->wFlags & (MF_POPUP | MF_SYSMENU)) == MF_POPUP && lppop->hWnd)
@@ -4161,15 +4164,37 @@ BOOL WINAPI DestroyMenu( HMENU hMenu )
         MENUITEM *item = lppop->items;
         for (i = lppop->nItems; i > 0; i--, item++)
         {
-            if (item->fType & MF_POPUP) DestroyMenu(item->hSubMenu);
+            if (item->fType & MF_POPUP)
+            {
+                /* Release handle if it hasn't already been released. */
+                if (!MENU_ReleaseMenu(MENU_GetMenu(item->hSubMenu)))
+                    DestroyMenu(item->hSubMenu);
+            }
             MENU_FreeItemData( item );
         }
         HeapFree( GetProcessHeap(), 0, lppop->items );
     }
     HeapFree( GetProcessHeap(), 0, lppop );
+
     return TRUE;
 }
 
+/**********************************************************************
+ *         DestroyMenu    (USER32.@)
+ */
+BOOL WINAPI DestroyMenu( HMENU hMenu )
+{
+    POPUPMENU *lppop;
+
+    TRACE("(%p)\n", hMenu);
+
+    if (!(lppop = free_user_handle( hMenu, USER_MENU ))) return FALSE;
+    if (lppop == OBJ_OTHER_PROCESS) return FALSE;
+
+    MENU_ReleaseMenu(lppop);
+
+    return TRUE;
+}
 
 /**********************************************************************
  *         GetSystemMenu    (USER32.@)
@@ -4817,6 +4842,8 @@ static BOOL SetMenuItemInfo_common(MENUITEM * menu,
 	menu->wID = lpmii->wID;
 
     if (lpmii->fMask & MIIM_SUBMENU) {
+        if ((menu->fType & MF_POPUP) && menu->hSubMenu)
+            MENU_ReleaseMenu(MENU_GetMenu(menu->hSubMenu));
 	menu->hSubMenu = lpmii->hSubMenu;
 	if (menu->hSubMenu) {
 	    POPUPMENU *subMenu = MENU_GetMenu(menu->hSubMenu);
@@ -4828,6 +4855,7 @@ static BOOL SetMenuItemInfo_common(MENUITEM * menu,
                 }
 		subMenu->wFlags |= MF_POPUP;
 		menu->fType |= MF_POPUP;
+                InterlockedIncrement(&subMenu->refcount);
 	    } else {
                 SetLastError( ERROR_INVALID_PARAMETER);
                 return FALSE;
-- 
2.16.3




More information about the wine-devel mailing list