From: Andrew Eikum aeikum@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@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;