[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