From: Andrew Eikum aeikum@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/user32/menu.c | 141 +++++++++++++++++++++++++---------------------- dlls/user32/tests/menu.c | 4 +- 2 files changed, 77 insertions(+), 68 deletions(-)
diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c index c8d30eba17..284e48fab5 100644 --- a/dlls/user32/menu.c +++ b/dlls/user32/menu.c @@ -62,13 +62,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(menu); WINE_DECLARE_DEBUG_CHANNEL(accel);
+typedef struct _POPUPMENU POPUPMENU; + /* Menu item structure */ typedef struct { /* ----------- MENUITEMINFO Stuff ----------- */ UINT fType; /* Item type. */ UINT fState; /* Item state. */ UINT_PTR wID; /* Item id. */ - HMENU hSubMenu; /* Pop-up menu. */ + POPUPMENU *submenu; /* Pop-up menu. */ HBITMAP hCheckBit; /* Bitmap when checked. */ HBITMAP hUnCheckBit; /* Bitmap when unchecked. */ LPWSTR text; /* Item text. */ @@ -84,7 +86,8 @@ typedef struct { } MENUITEM;
/* Popup menu structure */ -typedef struct { +struct _POPUPMENU +{ struct user_object obj; WORD wFlags; /* Menu flags (MF_POPUP, MF_SYSMENU) */ WORD Width; /* Width of the whole menu */ @@ -107,7 +110,7 @@ typedef struct { DWORD dwMenuData; /* application defined value */ HMENU hSysMenuOwner; /* Handle to the dummy sys menu holder */ WORD textOffset; /* Offset of text when items have both bitmaps and text */ -} POPUPMENU, *LPPOPUPMENU; +};
/* internal flags for menu tracking */
@@ -229,8 +232,8 @@ static void do_debug_print_menuitem(const char *prefix, const MENUITEM *mp, if (mp) { UINT flags = mp->fType; TRACE( "{ ID=0x%lx", mp->wID); - if ( mp->hSubMenu) - TRACE( ", Sub=%p", mp->hSubMenu); + if ( mp->submenu) + TRACE( ", Sub=%p", mp->submenu); if (flags) { int count = 0; TRACE( ", fType="); @@ -570,7 +573,7 @@ static MENUITEM *MENU_FindItem( POPUPMENU **pmenu, UINT *nPos, UINT wFlags ) { if (item->fType & MF_POPUP) { - POPUPMENU *submenu = MENU_GetMenu(item->hSubMenu); + POPUPMENU *submenu = item->submenu; MENUITEM *subitem = MENU_FindItem( &submenu, nPos, wFlags ); if (subitem) { @@ -617,12 +620,12 @@ static UINT MENU_FindSubMenu( POPUPMENU **pmenu, POPUPMENU *subTarget ) item = menu->items; for (i = 0; i < menu->nItems; i++, item++) { if(!(item->fType & MF_POPUP)) continue; - if (item->hSubMenu == MENU_GetHandle(subTarget)) + if (item->submenu == subTarget) { return i; } else { - POPUPMENU *submenu = MENU_GetMenu(item->hSubMenu); + POPUPMENU *submenu = item->submenu; UINT pos = MENU_FindSubMenu( &submenu, subTarget ); if (pos != NO_SELECTED_ITEM) { *pmenu = submenu; @@ -1131,7 +1134,7 @@ static void MENU_CalcItemSize( HDC hdc, MENUITEM *lpitem, HWND hwndOwner, * * Calculate the size of a popup menu. */ -static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, UINT max_height ) +static void MENU_PopupMenuCalcSize( POPUPMENU *lppop, UINT max_height ) { MENUITEM *lpitem; HDC hdc; @@ -1237,7 +1240,7 @@ static void MENU_PopupMenuCalcSize( LPPOPUPMENU lppop, UINT max_height ) * Calculate the size of the menu bar. */ static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, - LPPOPUPMENU lppop, HWND hwndOwner ) + POPUPMENU *lppop, HWND hwndOwner ) { MENUITEM *lpitem; UINT start, i, helpPos; @@ -1807,7 +1810,7 @@ static void MENU_DrawPopupMenu( HWND hwnd, HDC hdc, HMENU hmenu ) */ UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd ) { - LPPOPUPMENU lppop; + POPUPMENU *lppop; HMENU hMenu = GetMenu(hwnd);
lppop = MENU_GetMenu( hMenu ); @@ -1943,7 +1946,7 @@ static BOOL MENU_ShowPopup( HWND hwndOwner, POPUPMENU *menu, UINT id, UINT flags * MENU_EnsureMenuItemVisible */ static void -MENU_EnsureMenuItemVisible(LPPOPUPMENU lppop, UINT wIndex, HDC hdc) +MENU_EnsureMenuItemVisible(POPUPMENU *lppop, UINT wIndex, HDC hdc) { if (lppop->bScrolling) { @@ -2254,7 +2257,7 @@ static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu) /*********************************************************************** * MENU_GetSubPopup * - * Return the handle of the selected sub-popup menu (if any). + * Return the selected sub-popup menu (if any). */ static POPUPMENU *MENU_GetSubPopup( POPUPMENU *menu ) { @@ -2264,7 +2267,7 @@ static POPUPMENU *MENU_GetSubPopup( POPUPMENU *menu )
item = &menu->items[menu->FocusedItem]; if ((item->fType & MF_POPUP) && (item->fState & MF_MOUSESELECT)) - return MENU_GetMenu(item->hSubMenu); + return item->submenu;
return NULL; } @@ -2291,7 +2294,7 @@ static void MENU_HideSubPopups( HWND hwndOwner, POPUPMENU *menu, if (!(item->fType & MF_POPUP) || !(item->fState & MF_MOUSESELECT)) return; item->fState &= ~MF_MOUSESELECT; - submenu = MENU_GetMenu(item->hSubMenu); + submenu = item->submenu; } else return;
if (!submenu) return; @@ -2336,7 +2339,7 @@ static POPUPMENU *MENU_ShowSubPopup( HWND hwndOwner, POPUPMENU *menu,
/* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */ if (!(wFlags & TPM_NONOTIFY)) - SendMessageW( hwndOwner, WM_INITMENUPOPUP, (WPARAM)item->hSubMenu, + SendMessageW( hwndOwner, WM_INITMENUPOPUP, (WPARAM)MENU_GetHandle(item->submenu), MAKELPARAM( menu->FocusedItem, IS_SYSTEM_MENU(menu) ));
item = &menu->items[menu->FocusedItem]; @@ -2361,7 +2364,7 @@ static POPUPMENU *MENU_ShowSubPopup( HWND hwndOwner, POPUPMENU *menu,
if (IS_SYSTEM_MENU(menu)) { - MENU_InitSysMenuPopup(item->hSubMenu, + MENU_InitSysMenuPopup(MENU_GetHandle(item->submenu), GetWindowLongW( menu->hWnd, GWL_STYLE ), GetClassLongW( menu->hWnd, GCL_STYLE));
@@ -2405,13 +2408,13 @@ static POPUPMENU *MENU_ShowSubPopup( HWND hwndOwner, POPUPMENU *menu, /* use default alignment for submenus */ wFlags &= ~(TPM_CENTERALIGN | TPM_RIGHTALIGN | TPM_VCENTERALIGN | TPM_BOTTOMALIGN);
- MENU_InitPopup( hwndOwner, MENU_GetMenu(item->hSubMenu), wFlags ); + MENU_InitPopup( hwndOwner, item->submenu, wFlags );
- MENU_ShowPopup( hwndOwner, MENU_GetMenu(item->hSubMenu), menu->FocusedItem, wFlags, + MENU_ShowPopup( hwndOwner, item->submenu, menu->FocusedItem, wFlags, rect.left, rect.top, rect.right, rect.bottom ); if (selectFirst) - MENU_MoveSelection( hwndOwner, MENU_GetMenu(item->hSubMenu), ITEM_NEXT ); - return MENU_GetMenu(item->hSubMenu); + MENU_MoveSelection( hwndOwner, item->submenu, ITEM_NEXT ); + return item->submenu; }
@@ -2452,7 +2455,7 @@ static POPUPMENU *MENU_PtMenu( POPUPMENU *menu, POINT pt ) ret = (item != NO_SELECTED_ITEM && (menu->items[item].fType & MF_POPUP) && (menu->items[item].fState & MF_MOUSESELECT)) - ? MENU_PtMenu(MENU_GetMenu(menu->items[item].hSubMenu), pt) : 0; + ? MENU_PtMenu(menu->items[item].submenu, pt) : 0;
if (!ret) /* check the current window (avoiding WM_HITTEST) */ { @@ -2490,7 +2493,7 @@ static INT MENU_ExecFocusedItem( MTRACKER* pmt, POPUPMENU *menu, UINT wFlags )
item = &menu->items[menu->FocusedItem];
- TRACE("menu %p wID %08lx hSubMenu %p fType %04x\n", menu, item->wID, item->hSubMenu, item->fType); + TRACE("menu %p wID %08lx hSubMenu %p fType %04x\n", menu, item->wID, item->submenu, item->fType);
if (!(item->fType & MF_POPUP)) { @@ -3568,7 +3571,7 @@ UINT MENU_GetMenuBarHeight( HWND hwnd, UINT menubarWidth, { HDC hdc; RECT rectBar; - LPPOPUPMENU lppop; + POPUPMENU *lppop;
TRACE("HWND %p, width %d, at (%d, %d).\n", hwnd, menubarWidth, orgX, orgY );
@@ -3771,7 +3774,7 @@ UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags ) debug_print_menuitem (" item: ", item, ""); if (item->fType & MF_POPUP) { - menu = MENU_GetMenu( item->hSubMenu ); + menu = item->submenu; if (!menu) return -1; else return (menu->nItems << 8) | ((item->fState|item->fType) & 0xff); } @@ -3790,7 +3793,7 @@ UINT WINAPI GetMenuState( HMENU hMenu, UINT wItemID, UINT wFlags ) */ INT WINAPI GetMenuItemCount( HMENU hMenu ) { - LPPOPUPMENU menu = MENU_GetMenu(hMenu); + POPUPMENU *menu = MENU_GetMenu(hMenu); if (!menu) return -1; TRACE("(%p) returning %d\n", hMenu, menu->nItems ); return menu->nItems; @@ -3940,7 +3943,7 @@ BOOL WINAPI RemoveMenu( HMENU hMenu, UINT nPos, UINT wFlags )
/* Remove item */ if (item->fType & MF_POPUP) - MENU_ReleaseMenu(MENU_GetMenu(item->hSubMenu)); + MENU_ReleaseMenu(item->submenu);
MENU_FreeItemData( item );
@@ -3974,9 +3977,9 @@ BOOL WINAPI DeleteMenu( HMENU hMenu, UINT nPos, UINT wFlags ) POPUPMENU *menu = MENU_GetMenu(hMenu); MENUITEM *item = MENU_FindItem( &menu, &nPos, wFlags ); if (!item) return FALSE; - if (item->fType & MF_POPUP) DestroyMenu( item->hSubMenu ); + if (item->fType & MF_POPUP) DestroyMenu( MENU_GetHandle(item->submenu) ); /* nPos is now the position of the item */ - RemoveMenu( hMenu, nPos, wFlags | MF_BYPOSITION ); + RemoveMenu( MENU_GetHandle(menu), nPos, wFlags | MF_BYPOSITION ); return TRUE; }
@@ -4088,7 +4091,7 @@ BOOL WINAPI SetMenuItemBitmaps( HMENU hMenu, UINT nPos, UINT wFlags, HMENU WINAPI CreateMenu(void) { HMENU hMenu; - LPPOPUPMENU menu; + POPUPMENU *menu;
if (!(menu = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*menu) ))) return 0; menu->FocusedItem = NO_SELECTED_ITEM; @@ -4128,8 +4131,8 @@ static BOOL MENU_ReleaseMenu( POPUPMENU *lppop ) if (item->fType & MF_POPUP) { /* Release handle if it hasn't already been released. */ - if (!MENU_ReleaseMenu(MENU_GetMenu(item->hSubMenu))) - DestroyMenu(item->hSubMenu); + if (!MENU_ReleaseMenu(item->submenu)) + DestroyMenu(MENU_GetHandle(item->submenu)); } MENU_FreeItemData( item ); } @@ -4300,7 +4303,7 @@ BOOL WINAPI GetMenuBarInfo( HWND hwnd, LONG idObject, LONG idItem, PMENUBARINFO pmbi->fFocused = menu->FocusedItem == idItem - 1; if (pmbi->fFocused && (menu->items[idItem - 1].fType & MF_POPUP)) { - menu = MENU_GetMenu(menu->items[idItem - 1].hSubMenu); + menu = menu->items[idItem - 1].submenu; if (menu) pmbi->hwndMenu = menu->hWnd; } @@ -4337,7 +4340,7 @@ BOOL MENU_SetMenu( HWND hWnd, HMENU hMenu )
if (hMenu != 0) { - LPPOPUPMENU lpmenu; + POPUPMENU *lpmenu;
if (!(lpmenu = MENU_GetMenu(hMenu))) return FALSE;
@@ -4373,7 +4376,7 @@ HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos )
if (!(lpmi = MENU_FindItem(&menu, (UINT *)&nPos, MF_BYPOSITION))) return 0; if (!(lpmi->fType & MF_POPUP)) return 0; - return lpmi->hSubMenu; + return MENU_GetHandle(lpmi->submenu); }
@@ -4382,7 +4385,7 @@ HMENU WINAPI GetSubMenu( HMENU hMenu, INT nPos ) */ BOOL WINAPI DrawMenuBar( HWND hWnd ) { - LPPOPUPMENU lppop; + POPUPMENU *lppop; HMENU hMenu;
if (!IsWindow( hWnd )) @@ -4410,7 +4413,7 @@ BOOL WINAPI DrawMenuBar( HWND hWnd ) */ DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont) { - LPPOPUPMENU lppop; + POPUPMENU *lppop; UINT i,retvalue; HFONT hfontOld = 0; BOOL flat_menu = FALSE; @@ -4560,7 +4563,7 @@ HMENU WINAPI LoadMenuIndirectA( LPCVOID template ) */ BOOL WINAPI IsMenu(HMENU hmenu) { - LPPOPUPMENU menu = MENU_GetMenu(hmenu); + POPUPMENU *menu = MENU_GetMenu(hmenu);
if (!menu) { @@ -4662,7 +4665,7 @@ static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos, lpmii->wID = menu->wID;
if (lpmii->fMask & MIIM_SUBMENU) - lpmii->hSubMenu = menu->hSubMenu; + lpmii->hSubMenu = MENU_GetHandle(menu->submenu); else { /* hSubMenu is always cleared * (not on Win9x/ME ) */ @@ -4759,13 +4762,13 @@ static int MENU_depth( POPUPMENU *pmenu, int depth) item = pmenu->items; subdepth = depth; for( i = 0; i < pmenu->nItems && subdepth <= MAXMENUDEPTH; i++, item++){ - POPUPMENU *psubmenu = item->hSubMenu ? MENU_GetMenu( item->hSubMenu) : NULL; - if( psubmenu){ - int bdepth = MENU_depth( psubmenu, depth); + if (item->submenu) + { + int bdepth = MENU_depth(item->submenu, depth); if( bdepth > subdepth) subdepth = bdepth; } if( subdepth > MAXMENUDEPTH) - TRACE("<- hmenu %p\n", item->hSubMenu); + TRACE("<- menu %p\n", item->submenu); } return subdepth; } @@ -4804,22 +4807,30 @@ static BOOL SetMenuItemInfo_common(MENUITEM * menu, if (lpmii->fMask & MIIM_ID) 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); - if (subMenu) { - if( MENU_depth( subMenu, 0) > MAXMENUDEPTH) { + if (lpmii->fMask & MIIM_SUBMENU) + { + if ((menu->fType & MF_POPUP) && menu->submenu) + { + MENU_ReleaseMenu(menu->submenu); + menu->submenu = NULL; + } + if (lpmii->hSubMenu) + { + menu->submenu = MENU_GetMenu(lpmii->hSubMenu); + if (menu->submenu) + { + if (MENU_depth( menu->submenu, 0) > MAXMENUDEPTH) + { ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n"); - menu->hSubMenu = 0; + menu->submenu = NULL; return FALSE; } - subMenu->wFlags |= MF_POPUP; - menu->fType |= MF_POPUP; - InterlockedIncrement(&subMenu->refcount); - } else { + menu->submenu->wFlags |= MF_POPUP; + menu->fType |= MF_POPUP; + InterlockedIncrement(&menu->submenu->refcount); + } + else + { SetLastError( ERROR_INVALID_PARAMETER); return FALSE; } @@ -5012,11 +5023,11 @@ UINT WINAPI GetMenuDefaultItem(HMENU hmenu, UINT bypos, UINT flags) /* default: don't return disabled items */ if ( (!(GMDI_USEDISABLED & flags)) && (item->fState & MFS_DISABLED )) return -1;
- /* search rekursiv when needed */ + /* search recursively when needed */ if ( (item->fType & MF_POPUP) && (flags & GMDI_GOINTOPOPUPS) ) { UINT ret; - ret = GetMenuDefaultItem( item->hSubMenu, bypos, flags ); + ret = GetMenuDefaultItem( MENU_GetHandle(item->submenu), bypos, flags ); if ( -1 != ret ) return ret;
/* when item not found in submenu, return the popup item */ @@ -5150,10 +5161,10 @@ BOOL WINAPI GetMenuItemRect(HWND hwnd, HMENU hMenu, UINT uItem, RECT *rect) * actually use the items to draw the menu * (recalculate and/or redraw) */ -static BOOL menu_SetMenuInfo( HMENU hMenu, LPCMENUINFO lpmi) +static BOOL menu_SetMenuInfo( POPUPMENU *menu, LPCMENUINFO lpmi) { - POPUPMENU *menu; - if( !(menu = MENU_GetMenu(hMenu))) return FALSE; + if (!menu) + return FALSE;
if (lpmi->fMask & MIM_BACKGROUND) menu->hbrBack = lpmi->hbrBack; @@ -5175,7 +5186,7 @@ static BOOL menu_SetMenuInfo( HMENU hMenu, LPCMENUINFO lpmi) MENUITEM *item = menu->items; for( i = menu->nItems; i; i--, item++) if( item->fType & MF_POPUP) - menu_SetMenuInfo( item->hSubMenu, lpmi); + menu_SetMenuInfo( item->submenu, lpmi); } return TRUE; } @@ -5183,7 +5194,7 @@ static BOOL menu_SetMenuInfo( HMENU hMenu, LPCMENUINFO lpmi) BOOL WINAPI SetMenuInfo (HMENU hMenu, LPCMENUINFO lpmi) { TRACE("(%p %p)\n", hMenu, lpmi); - if( lpmi && (lpmi->cbSize == sizeof( MENUINFO)) && (menu_SetMenuInfo( hMenu, lpmi))) { + if( lpmi && (lpmi->cbSize == sizeof( MENUINFO)) && (menu_SetMenuInfo( MENU_GetMenu(hMenu), lpmi))) { if( lpmi->fMask & MIM_STYLE) { if (lpmi->dwStyle & MNS_AUTODISMISS) FIXME("MNS_AUTODISMISS unimplemented\n"); if (lpmi->dwStyle & MNS_DRAGDROP) FIXME("MNS_DRAGDROP unimplemented\n"); @@ -5237,7 +5248,7 @@ BOOL WINAPI GetMenuInfo (HMENU hMenu, LPMENUINFO lpmi) */ BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID) { - LPPOPUPMENU menu; + POPUPMENU *menu;
TRACE("(%p 0x%08x)\n", hMenu, dwContextHelpID);
@@ -5255,7 +5266,7 @@ BOOL WINAPI SetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpID) */ DWORD WINAPI GetMenuContextHelpId( HMENU hMenu ) { - LPPOPUPMENU menu; + POPUPMENU *menu;
TRACE("(%p)\n", hMenu);
diff --git a/dlls/user32/tests/menu.c b/dlls/user32/tests/menu.c index 0f6e8618a6..6a6de9de8c 100644 --- a/dlls/user32/tests/menu.c +++ b/dlls/user32/tests/menu.c @@ -634,9 +634,7 @@ static void test_subpopup_locked_by_menu(void)
/* but TrackPopupMenu still works! */ ret = TrackPopupMenu( hmenu, TPM_RETURNCMD, 100,100, 0, hwnd, NULL); - todo_wine { - ok( ret == itemid , "TrackPopupMenu returned %d error is %d\n", ret, GetLastError()); - } + ok( ret == itemid , "TrackPopupMenu returned %#x error is %d\n", ret, GetLastError());
/* clean up */ DestroyMenu( hmenu);