From: Jacek Caban jacek@codeweavers.com
Signed-off-by: Jacek Caban jacek@codeweavers.com --- dlls/user32/controls.h | 1 - dlls/user32/mdi.c | 4 +- dlls/user32/menu.c | 324 ++------------------------------ dlls/user32/user32.spec | 2 +- dlls/user32/user_main.c | 1 - dlls/win32u/menu.c | 346 ++++++++++++++++++++++++++++++++++- dlls/win32u/ntuser_private.h | 1 - dlls/win32u/syscall.c | 2 + dlls/win32u/win32u.spec | 4 +- dlls/wow64win/syscall.h | 2 + dlls/wow64win/user.c | 63 +++++++ include/ntuser.h | 10 + 12 files changed, 444 insertions(+), 316 deletions(-)
diff --git a/dlls/user32/controls.h b/dlls/user32/controls.h index 5dcdd9bb935..6e6d7b7d214 100644 --- a/dlls/user32/controls.h +++ b/dlls/user32/controls.h @@ -120,7 +120,6 @@ extern void MENU_TrackMouseMenuBar( HWND hwnd, INT ht, POINT pt ) DECLSPEC_HIDDE extern void MENU_TrackKbdMenuBar( HWND hwnd, UINT wParam, WCHAR wChar ) DECLSPEC_HIDDEN; extern UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd ) DECLSPEC_HIDDEN; extern void MENU_EndMenu(HWND) DECLSPEC_HIDDEN; -extern void free_menu_items( void *ptr ) DECLSPEC_HIDDEN;
/* nonclient area */ extern LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip) DECLSPEC_HIDDEN; diff --git a/dlls/user32/mdi.c b/dlls/user32/mdi.c index df470f74762..b856f054247 100644 --- a/dlls/user32/mdi.c +++ b/dlls/user32/mdi.c @@ -417,7 +417,7 @@ static LRESULT MDI_RefreshMenu(MDICLIENTINFO *ci) if (mii.wID == ci->idFirstChild) { TRACE("removing %u items including separator\n", count - i); - while (RemoveMenu(ci->hWindowMenu, i, MF_BYPOSITION)) + while (NtUserRemoveMenu( ci->hWindowMenu, i, MF_BYPOSITION )) /* nothing */;
break; @@ -935,7 +935,7 @@ static BOOL MDI_RestoreFrameMenu( HWND frame, HWND hChild ) TRUE, &menuInfo);
- RemoveMenu(menu,0,MF_BYPOSITION); + NtUserRemoveMenu( menu, 0, MF_BYPOSITION );
if ( (menuInfo.fType & MFT_BITMAP) && (LOWORD(menuInfo.dwTypeData)!=0) && diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c index 5e9d8df17f5..5101a095966 100644 --- a/dlls/user32/menu.c +++ b/dlls/user32/menu.c @@ -88,11 +88,6 @@ typedef struct /* Margins for popup menus */ #define MENU_MARGIN 3
-/* maximum allowed depth of any branch in the menu tree. - * This value is slightly larger than in windows (25) to - * stay on the safe side. */ -#define MAXMENUDEPTH 30 - /* (other menu->FocusedItem values give the position of the focused item) */ #define NO_SELECTED_ITEM 0xffff
@@ -127,8 +122,6 @@ static BOOL fEndMenu = FALSE;
DWORD WINAPI DrawMenuBarTemp(HWND hwnd, HDC hDC, LPRECT lprect, HMENU hMenu, HFONT hFont);
-static BOOL SetMenuItemInfo_common( MENUITEM *, const MENUITEMINFOW * ); - static BOOL is_win_menu_disallowed(HWND hwnd) { return (GetWindowLongW(hwnd, GWL_STYLE) & (WS_CHILD | WS_POPUP)) == WS_CHILD; @@ -623,15 +616,6 @@ static UINT MENU_FindSubMenu( HMENU *hmenu, HMENU hSubTarget ) return NO_SELECTED_ITEM; }
-/*********************************************************************** - * MENU_FreeItemData - */ -static void MENU_FreeItemData( MENUITEM* item ) -{ - /* delete text */ - HeapFree( GetProcessHeap(), 0, item->text ); -} - /*********************************************************************** * MENU_AdjustMenuItemRect * @@ -2078,62 +2062,6 @@ static void MENU_MoveSelection( HWND hwndOwner, HMENU hmenu, INT offset ) }
-/********************************************************************** - * insert_menu_item - * - * Insert (allocate) a new item into a menu. - */ -static POPUPMENU *insert_menu_item(HMENU hMenu, UINT id, UINT flags, UINT *ret_pos) -{ - MENUITEM *newItems; - POPUPMENU *menu; - UINT pos = id; - - /* Find where to insert new item */ - if (!(menu = find_menu_item(hMenu, id, flags, &pos))) - { - if (!(menu = grab_menu_ptr(hMenu))) - return NULL; - pos = menu->nItems; - } - - /* Make sure that MDI system buttons stay on the right side. - * Note: XP treats only bitmap handles 1 - 6 as "magic" ones - * regardless of their id. - */ - while (pos > 0 && (INT_PTR)menu->items[pos - 1].hbmpItem >= (INT_PTR)HBMMENU_SYSTEM && - (INT_PTR)menu->items[pos - 1].hbmpItem <= (INT_PTR)HBMMENU_MBAR_CLOSE_D) - pos--; - - TRACE("inserting at %u flags %x\n", pos, flags); - - /* Create new items array */ - - newItems = HeapAlloc( GetProcessHeap(), 0, sizeof(MENUITEM) * (menu->nItems+1) ); - if (!newItems) - { - release_menu_ptr(menu); - WARN("allocation failed\n" ); - return NULL; - } - if (menu->nItems > 0) - { - /* Copy the old array into the new one */ - if (pos > 0) memcpy( newItems, menu->items, pos * sizeof(MENUITEM) ); - if (pos < menu->nItems) memcpy( &newItems[pos+1], &menu->items[pos], - (menu->nItems-pos)*sizeof(MENUITEM) ); - HeapFree( GetProcessHeap(), 0, menu->items ); - } - menu->items = newItems; - menu->nItems++; - memset( &newItems[pos], 0, sizeof(*newItems) ); - menu->Height = 0; /* force size recalculate */ - - *ret_pos = pos; - return menu; -} - - /********************************************************************** * MENU_ParseResource * @@ -3616,9 +3544,9 @@ BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data, if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE); if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE, id, data ); - if (flags & MF_REMOVE) return RemoveMenu( hMenu, - flags & MF_BYPOSITION ? pos : id, - flags & ~MF_REMOVE ); + if (flags & MF_REMOVE) return NtUserRemoveMenu( hMenu, + flags & MF_BYPOSITION ? pos : id, + flags & ~MF_REMOVE ); /* Default: MF_INSERT */ return InsertMenuA( hMenu, pos, flags, id, data ); } @@ -3636,9 +3564,9 @@ BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data, if (flags & MF_DELETE) return DeleteMenu(hMenu, pos, flags & ~MF_DELETE); if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE, id, data ); - if (flags & MF_REMOVE) return RemoveMenu( hMenu, - flags & MF_BYPOSITION ? pos : id, - flags & ~MF_REMOVE ); + if (flags & MF_REMOVE) return NtUserRemoveMenu( hMenu, + flags & MF_BYPOSITION ? pos : id, + flags & ~MF_REMOVE ); /* Default: MF_INSERT */ return InsertMenuW( hMenu, pos, flags, id, data ); } @@ -3877,10 +3805,6 @@ BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags, UINT_PTR id, LPCWSTR str ) { MENUITEMINFOW mii; - POPUPMENU *menu; - MENUITEM *item; - UINT newpos; - BOOL ret;
if (IS_STRING_ITEM(flags) && str) TRACE("hMenu %p, pos %d, flags %08x, id %04lx, str %s\n", @@ -3888,19 +3812,9 @@ BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags, else TRACE("hMenu %p, pos %d, flags %08x, id %04lx, str %p (not a string)\n", hMenu, pos, flags, id, str );
- if (!(menu = insert_menu_item(hMenu, pos, flags, &newpos))) - return FALSE; - MENU_mnu2mnuii( flags, id, str, &mii); mii.fMask |= MIIM_CHECKMARKS; - - item = &menu->items[newpos]; - ret = SetMenuItemInfo_common( item, &mii ); - if (!ret) - RemoveMenu( hMenu, pos, flags ); - release_menu_ptr(menu); - - return ret; + return NtUserThunkedMenuItemInfo( hMenu, pos, flags, NtUserInsertMenuItem, &mii, NULL ); }
@@ -3948,46 +3862,6 @@ BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags, }
-/********************************************************************** - * RemoveMenu (USER32.@) - */ -BOOL WINAPI RemoveMenu( HMENU hMenu, UINT id, UINT flags ) -{ - POPUPMENU *menu; - UINT pos; - - TRACE("(menu=%p id=%#x flags=%04x)\n", hMenu, id, flags); - - if (!(menu = find_menu_item(hMenu, id, flags, &pos))) - return FALSE; - - /* Remove item */ - MENU_FreeItemData( &menu->items[pos] ); - - if (--menu->nItems == 0) - { - HeapFree( GetProcessHeap(), 0, menu->items ); - menu->items = NULL; - } - else - { - MENUITEM *new_items, *item = &menu->items[pos]; - - while (pos < menu->nItems) - { - *item = *(item+1); - item++; - pos++; - } - new_items = HeapReAlloc( GetProcessHeap(), 0, menu->items, menu->nItems * sizeof(MENUITEM) ); - if (new_items) menu->items = new_items; - } - release_menu_ptr(menu); - - return TRUE; -} - - /********************************************************************** * DeleteMenu (USER32.@) */ @@ -4002,7 +3876,7 @@ BOOL WINAPI DeleteMenu( HMENU hMenu, UINT id, UINT flags ) if (menu->items[pos].fType & MF_POPUP) NtUserDestroyMenu( menu->items[pos].hSubMenu );
- RemoveMenu(menu->obj.handle, pos, flags | MF_BYPOSITION); + NtUserRemoveMenu( menu->obj.handle, pos, flags | MF_BYPOSITION ); release_menu_ptr(menu); return TRUE; } @@ -4015,26 +3889,14 @@ BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags, UINT_PTR id, LPCWSTR str ) { MENUITEMINFOW mii; - POPUPMENU *menu; - UINT item_pos; - BOOL ret;
if (IS_STRING_ITEM(flags)) TRACE("%p %d %04x %04lx %s\n", hMenu, pos, flags, id, debugstr_w(str) ); else TRACE("%p %d %04x %04lx %p\n", hMenu, pos, flags, id, str );
- if (!(menu = find_menu_item(hMenu, pos, flags, &item_pos))) - { - /* workaround for Word 95: pretend that SC_TASKLIST item exists */ - if (pos == SC_TASKLIST && !(flags & MF_BYPOSITION)) return TRUE; - return FALSE; - } - menu->Height = 0; /* force size recalculate */ MENU_mnu2mnuii( flags, id, str, &mii); - ret = SetMenuItemInfo_common( &menu->items[item_pos], &mii ); - release_menu_ptr(menu); - return ret; + return NtUserThunkedMenuItemInfo( hMenu, pos, flags, NtUserSetMenuItemInfo, &mii, NULL ); }
@@ -4120,21 +3982,6 @@ HMENU WINAPI CreateMenu(void) }
-void free_menu_items( void *ptr ) -{ - POPUPMENU *menu = ptr; - MENUITEM *item = menu->items; - int i; - - for (i = menu->nItems; i > 0; i--, item++) - { - if (item->fType & MF_POPUP) NtUserDestroyMenu( item->hSubMenu ); - MENU_FreeItemData( item ); - } - HeapFree( GetProcessHeap(), 0, menu->items ); -} - - /********************************************************************** * GetSystemMenu (USER32.@) */ @@ -4654,108 +4501,6 @@ BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos, }
-/********************************************************************** - * MENU_depth - * - * detect if there are loops in the menu tree (or the depth is too large) - */ -static int MENU_depth( POPUPMENU *pmenu, int depth) -{ - UINT i; - MENUITEM *item; - int subdepth; - - depth++; - if( depth > MAXMENUDEPTH) return 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( bdepth > subdepth) subdepth = bdepth; - } - if( subdepth > MAXMENUDEPTH) - TRACE("<- hmenu %p\n", item->hSubMenu); - } - return subdepth; -} - - -/********************************************************************** - * SetMenuItemInfo_common - * - * Note: does not support the MIIM_TYPE flag. Use the MIIM_FTYPE, - * MIIM_BITMAP and MIIM_STRING flags instead. - */ - -static BOOL SetMenuItemInfo_common( MENUITEM *menu, const MENUITEMINFOW *lpmii ) -{ - if (!menu) return FALSE; - - debug_print_menuitem("SetMenuItemInfo_common from: ", menu, ""); - - if (lpmii->fMask & MIIM_FTYPE ) { - menu->fType &= ~MENUITEMINFO_TYPE_MASK; - menu->fType |= lpmii->fType & MENUITEMINFO_TYPE_MASK; - } - if (lpmii->fMask & MIIM_STRING ) { - const WCHAR *text = lpmii->dwTypeData; - /* free the string when used */ - HeapFree(GetProcessHeap(), 0, menu->text); - if (!text) - menu->text = NULL; - else if ((menu->text = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(text)+1) * sizeof(WCHAR) ))) - lstrcpyW( menu->text, text ); - } - - if (lpmii->fMask & MIIM_STATE) - /* Other menu items having MFS_DEFAULT are not converted - to normal items */ - menu->fState = lpmii->fState & MENUITEMINFO_STATE_MASK; - - if (lpmii->fMask & MIIM_ID) - menu->wID = lpmii->wID; - - if (lpmii->fMask & MIIM_SUBMENU) { - menu->hSubMenu = lpmii->hSubMenu; - if (menu->hSubMenu) { - POPUPMENU *subMenu = MENU_GetMenu(menu->hSubMenu); - if (subMenu) { - if( MENU_depth( subMenu, 0) > MAXMENUDEPTH) { - ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n"); - menu->hSubMenu = 0; - return FALSE; - } - subMenu->wFlags |= MF_POPUP; - menu->fType |= MF_POPUP; - } else { - SetLastError( ERROR_INVALID_PARAMETER); - return FALSE; - } - } - else - menu->fType &= ~MF_POPUP; - } - - if (lpmii->fMask & MIIM_CHECKMARKS) - { - menu->hCheckBit = lpmii->hbmpChecked; - menu->hUnCheckBit = lpmii->hbmpUnchecked; - } - if (lpmii->fMask & MIIM_DATA) - menu->dwItemData = lpmii->dwItemData; - - if (lpmii->fMask & MIIM_BITMAP) - menu->hbmpItem = lpmii->hbmpItem; - - if( !menu->text && !(menu->fType & MFT_OWNERDRAW) && !menu->hbmpItem) - menu->fType |= MFT_SEPARATOR; - - debug_print_menuitem("SetMenuItemInfo_common to : ", menu, ""); - return TRUE; -} - /********************************************************************** * MENU_NormalizeMenuItemInfoStruct * @@ -4808,8 +4553,6 @@ BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos, { WCHAR *strW = NULL; MENUITEMINFOW mii; - POPUPMENU *menu; - UINT pos; BOOL ret;
TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu, item, bypos, lpmii); @@ -4825,15 +4568,9 @@ BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos, mii.dwTypeData = strW; }
- if (!(menu = find_menu_item(hmenu, item, bypos ? MF_BYPOSITION : 0, &pos))) - { - /* workaround for Word 95: pretend that SC_TASKLIST item exists */ - HeapFree( GetProcessHeap(), 0, strW ); - if (item == SC_TASKLIST && !bypos) return TRUE; - return FALSE; - } - ret = SetMenuItemInfo_common( &menu->items[pos], &mii ); - release_menu_ptr(menu); + ret = NtUserThunkedMenuItemInfo( hmenu, item, bypos ? MF_BYPOSITION : 0, + NtUserSetMenuItemInfo, &mii, NULL ); + HeapFree( GetProcessHeap(), 0, strW ); return ret; } @@ -4845,24 +4582,13 @@ BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos, const MENUITEMINFOW *lpmii) { MENUITEMINFOW mii; - POPUPMENU *menu; - BOOL ret; - UINT pos;
TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu, item, bypos, lpmii);
if (!MENU_NormalizeMenuItemInfoStruct( lpmii, &mii )) return FALSE;
- if (!(menu = find_menu_item(hmenu, item, bypos ? MF_BYPOSITION : 0, &pos))) - { - /* workaround for Word 95: pretend that SC_TASKLIST item exists */ - if (item == SC_TASKLIST && !bypos) return TRUE; - return FALSE; - } - - ret = SetMenuItemInfo_common(&menu->items[pos], &mii); - release_menu_ptr(menu); - return ret; + return NtUserThunkedMenuItemInfo( hmenu, item, bypos ? MF_BYPOSITION : 0, + NtUserSetMenuItemInfo, &mii, NULL ); }
/********************************************************************** @@ -4915,8 +4641,6 @@ BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos, { WCHAR *strW = NULL; MENUITEMINFOW mii; - POPUPMENU *menu; - UINT pos; BOOL ret;
TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, bypos, lpmii); @@ -4932,14 +4656,9 @@ BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos, mii.dwTypeData = strW; }
- if (!(menu = insert_menu_item(hMenu, uItem, bypos ? MF_BYPOSITION : 0, &pos))) - { - HeapFree( GetProcessHeap(), 0, strW ); - return FALSE; - } + ret = NtUserThunkedMenuItemInfo( hMenu, uItem, bypos ? MF_BYPOSITION : 0, + NtUserInsertMenuItem, &mii, NULL );
- ret = SetMenuItemInfo_common( &menu->items[pos], &mii ); - release_menu_ptr(menu); HeapFree( GetProcessHeap(), 0, strW ); return ret; } @@ -4952,20 +4671,13 @@ BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos, const MENUITEMINFOW *lpmii) { MENUITEMINFOW mii; - POPUPMENU *menu; - UINT pos; - BOOL ret;
TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, bypos, lpmii);
if (!MENU_NormalizeMenuItemInfoStruct( lpmii, &mii )) return FALSE;
- if (!(menu = insert_menu_item(hMenu, uItem, bypos ? MF_BYPOSITION : 0, &pos))) - return FALSE; - - ret = SetMenuItemInfo_common( &menu->items[pos], &mii ); - release_menu_ptr(menu); - return ret; + return NtUserThunkedMenuItemInfo( hMenu, uItem, bypos ? MF_BYPOSITION : 0, + NtUserInsertMenuItem, &mii, NULL ); }
/********************************************************************** diff --git a/dlls/user32/user32.spec b/dlls/user32/user32.spec index da0b7c5a1ab..298a0fa3150 100644 --- a/dlls/user32/user32.spec +++ b/dlls/user32/user32.spec @@ -619,7 +619,7 @@ @ stdcall ReleaseCapture() @ stdcall ReleaseDC(long long) NtUserReleaseDC @ stdcall RemoveClipboardFormatListener(long) NtUserRemoveClipboardFormatListener -@ stdcall RemoveMenu(long long long) +@ stdcall RemoveMenu(long long long) NtUserRemoveMenu @ stdcall RemovePropA(long str) @ stdcall RemovePropW(long wstr) @ stdcall ReplyMessage(long) diff --git a/dlls/user32/user_main.c b/dlls/user32/user_main.c index 1400597eb5d..babd5f95e55 100644 --- a/dlls/user32/user_main.c +++ b/dlls/user32/user_main.c @@ -165,7 +165,6 @@ static const struct user_callbacks user_funcs = ImmProcessKey, ImmTranslateMessage, SetSystemMenu, - free_menu_items, free_win_ptr, MENU_IsMenuActive, notify_ime, diff --git a/dlls/win32u/menu.c b/dlls/win32u/menu.c index 5d1a5ec12d6..0d7127fb4c6 100644 --- a/dlls/win32u/menu.c +++ b/dlls/win32u/menu.c @@ -39,9 +39,26 @@ struct accelerator ACCEL table[1]; };
+/* maximum allowed depth of any branch in the menu tree. + * This value is slightly larger than in windows (25) to + * stay on the safe side. */ +#define MAXMENUDEPTH 30 + /* (other menu->FocusedItem values give the position of the focused item) */ #define NO_SELECTED_ITEM 0xffff
+/* macro to test that flags do not indicate bitmap, ownerdraw or separator */ +#define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING) +#define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1)) + +#define MENUITEMINFO_TYPE_MASK \ + (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \ + MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \ + MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ ) +#define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU) +#define STATE_MASK (~TYPE_MASK) +#define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT)) + /********************************************************************** * NtUserCopyAcceleratorTable (win32u.@) */ @@ -111,6 +128,73 @@ BOOL WINAPI NtUserDestroyAcceleratorTable( HACCEL handle ) return TRUE; }
+#define MENUFLAG(bit,text) \ + do { \ + if (flags & (bit)) { flags &= ~(bit); strcat(buf, (text)); } \ + } while (0) + +static const char *debugstr_menuitem( const MENUITEM *item ) +{ + static const char *const hbmmenus[] = { "HBMMENU_CALLBACK", "", "HBMMENU_SYSTEM", + "HBMMENU_MBAR_RESTORE", "HBMMENU_MBAR_MINIMIZE", "UNKNOWN BITMAP", "HBMMENU_MBAR_CLOSE", + "HBMMENU_MBAR_CLOSE_D", "HBMMENU_MBAR_MINIMIZE_D", "HBMMENU_POPUP_CLOSE", + "HBMMENU_POPUP_RESTORE", "HBMMENU_POPUP_MAXIMIZE", "HBMMENU_POPUP_MINIMIZE" }; + char buf[256]; + UINT flags; + + if (!item) return "NULL"; + + sprintf( buf, "{ ID=0x%lx", item->wID ); + if (item->hSubMenu) sprintf( buf + strlen(buf), ", Sub=%p", item->hSubMenu ); + + flags = item->fType; + if (flags) + { + strcat( buf, ", fType=" ); + MENUFLAG( MFT_SEPARATOR, "sep" ); + MENUFLAG( MFT_OWNERDRAW, "own" ); + MENUFLAG( MFT_BITMAP, "bit" ); + MENUFLAG( MF_POPUP, "pop" ); + MENUFLAG( MFT_MENUBARBREAK, "barbrk" ); + MENUFLAG( MFT_MENUBREAK, "brk"); + MENUFLAG( MFT_RADIOCHECK, "radio" ); + MENUFLAG( MFT_RIGHTORDER, "rorder" ); + MENUFLAG( MF_SYSMENU, "sys" ); + MENUFLAG( MFT_RIGHTJUSTIFY, "right" ); /* same as MF_HELP */ + if (flags) sprintf( buf + strlen(buf), "+0x%x", flags ); + } + + flags = item->fState; + if (flags) + { + strcat( buf, ", State=" ); + MENUFLAG( MFS_GRAYED, "grey" ); + MENUFLAG( MFS_DEFAULT, "default" ); + MENUFLAG( MFS_DISABLED, "dis" ); + MENUFLAG( MFS_CHECKED, "check" ); + MENUFLAG( MFS_HILITE, "hi" ); + MENUFLAG( MF_USECHECKBITMAPS, "usebit" ); + MENUFLAG( MF_MOUSESELECT, "mouse" ); + if (flags) sprintf( buf + strlen(buf), "+0x%x", flags ); + } + + if (item->hCheckBit) sprintf( buf + strlen(buf), ", Chk=%p", item->hCheckBit ); + if (item->hUnCheckBit) sprintf( buf + strlen(buf), ", Unc=%p", item->hUnCheckBit ); + if (item->text) sprintf( buf + strlen(buf), ", Text=%s", debugstr_w(item->text) ); + if (item->dwItemData) sprintf( buf + strlen(buf), ", ItemData=0x%08lx", item->dwItemData ); + + if (item->hbmpItem) + { + if (IS_MAGIC_BITMAP( item->hbmpItem )) + sprintf( buf + strlen(buf), ", hbitmap=%s", hbmmenus[(INT_PTR)item->hbmpItem + 1] ); + else + sprintf( buf + strlen(buf), ", hbitmap=%p", item->hbmpItem ); + } + return wine_dbg_sprintf( "%s }", buf ); +} + +#undef MENUFLAG + static POPUPMENU *grab_menu_ptr( HMENU handle ) { POPUPMENU *menu = get_user_handle_ptr( handle, NTUSER_OBJ_MENU ); @@ -210,6 +294,53 @@ static POPUPMENU *find_menu_item( HMENU handle, UINT id, UINT flags, UINT *pos ) return menu; }
+static POPUPMENU *insert_menu_item( HMENU handle, UINT id, UINT flags, UINT *ret_pos ) +{ + MENUITEM *new_items; + POPUPMENU *menu; + UINT pos = id; + + /* Find where to insert new item */ + if (!(menu = find_menu_item(handle, id, flags, &pos))) + { + if (!(menu = grab_menu_ptr(handle))) + return NULL; + pos = menu->nItems; + } + + /* Make sure that MDI system buttons stay on the right side. + * Note: XP treats only bitmap handles 1 - 6 as "magic" ones + * regardless of their id. + */ + while (pos > 0 && (INT_PTR)menu->items[pos - 1].hbmpItem >= (INT_PTR)HBMMENU_SYSTEM && + (INT_PTR)menu->items[pos - 1].hbmpItem <= (INT_PTR)HBMMENU_MBAR_CLOSE_D) + pos--; + + TRACE( "inserting at %u flags %x\n", pos, flags ); + + new_items = malloc( sizeof(MENUITEM) * (menu->nItems + 1) ); + if (!new_items) + { + release_menu_ptr( menu ); + return NULL; + } + if (menu->nItems > 0) + { + /* Copy the old array into the new one */ + if (pos > 0) memcpy( new_items, menu->items, pos * sizeof(MENUITEM) ); + if (pos < menu->nItems) memcpy( &new_items[pos + 1], &menu->items[pos], + (menu->nItems - pos) * sizeof(MENUITEM) ); + free( menu->items ); + } + menu->items = new_items; + menu->nItems++; + memset( &new_items[pos], 0, sizeof(*new_items) ); + menu->Height = 0; /* force size recalculate */ + + *ret_pos = pos; + return menu; +} + static BOOL is_win_menu_disallowed( HWND hwnd ) { return (get_window_long(hwnd, GWL_STYLE) & (WS_CHILD | WS_POPUP)) == WS_CHILD; @@ -257,8 +388,19 @@ BOOL WINAPI NtUserDestroyMenu( HMENU handle ) menu->hWnd = 0; }
- if (menu->items && user_callbacks) /* recursively destroy submenus */ - user_callbacks->free_menu_items( menu ); + /* recursively destroy submenus */ + if (menu->items) + { + MENUITEM *item = menu->items; + int i; + + for (i = menu->nItems; i > 0; i--, item++) + { + if (item->fType & MF_POPUP) NtUserDestroyMenu( item->hSubMenu ); + free( item->text ); + } + free( menu->items ); + }
free( menu ); return TRUE; @@ -527,6 +669,206 @@ BOOL get_menu_info( HMENU handle, MENUINFO *info ) return TRUE; }
+/********************************************************************** + * menu_depth + * + * detect if there are loops in the menu tree (or the depth is too large) + */ +static int menu_depth( POPUPMENU *pmenu, int depth) +{ + int i, subdepth; + MENUITEM *item; + + if (++depth > MAXMENUDEPTH) return depth; + item = pmenu->items; + subdepth = depth; + for (i = 0; i < pmenu->nItems && subdepth <= MAXMENUDEPTH; i++, item++) + { + POPUPMENU *submenu = item->hSubMenu ? grab_menu_ptr( item->hSubMenu ) : NULL; + if (submenu) + { + int bdepth = menu_depth( submenu, depth); + if (bdepth > subdepth) subdepth = bdepth; + release_menu_ptr( submenu ); + } + if (subdepth > MAXMENUDEPTH) + TRACE( "<- hmenu %p\n", item->hSubMenu ); + } + + return subdepth; +} + +static BOOL set_menu_item_info( MENUITEM *menu, const MENUITEMINFOW *info ) +{ + if (!menu) return FALSE; + + TRACE( "%s\n", debugstr_menuitem( menu )); + + if (info->fMask & MIIM_FTYPE ) + { + menu->fType &= ~MENUITEMINFO_TYPE_MASK; + menu->fType |= info->fType & MENUITEMINFO_TYPE_MASK; + } + if (info->fMask & MIIM_STRING ) + { + const WCHAR *text = info->dwTypeData; + /* free the string when used */ + free( menu->text ); + if (!text) + menu->text = NULL; + else if ((menu->text = malloc( (lstrlenW(text) + 1) * sizeof(WCHAR) ))) + lstrcpyW( menu->text, text ); + } + + if (info->fMask & MIIM_STATE) + /* Other menu items having MFS_DEFAULT are not converted + to normal items */ + menu->fState = info->fState & MENUITEMINFO_STATE_MASK; + + if (info->fMask & MIIM_ID) + menu->wID = info->wID; + + if (info->fMask & MIIM_SUBMENU) + { + menu->hSubMenu = info->hSubMenu; + if (menu->hSubMenu) + { + POPUPMENU *submenu = grab_menu_ptr( menu->hSubMenu ); + if (!submenu) + { + SetLastError( ERROR_INVALID_PARAMETER); + return FALSE; + } + if (menu_depth( submenu, 0 ) > MAXMENUDEPTH) + { + ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded\n" ); + menu->hSubMenu = 0; + release_menu_ptr( submenu ); + return FALSE; + } + submenu->wFlags |= MF_POPUP; + menu->fType |= MF_POPUP; + release_menu_ptr( submenu ); + } + else + menu->fType &= ~MF_POPUP; + } + + if (info->fMask & MIIM_CHECKMARKS) + { + menu->hCheckBit = info->hbmpChecked; + menu->hUnCheckBit = info->hbmpUnchecked; + } + if (info->fMask & MIIM_DATA) + menu->dwItemData = info->dwItemData; + + if (info->fMask & MIIM_BITMAP) + menu->hbmpItem = info->hbmpItem; + + if (!menu->text && !(menu->fType & MFT_OWNERDRAW) && !menu->hbmpItem) + menu->fType |= MFT_SEPARATOR; + + TRACE( "to: %s\n", debugstr_menuitem( menu )); + return TRUE; +} + +/********************************************************************** + * NtUserThunkedMenuItemInfo (win32u.@) + */ +UINT WINAPI NtUserThunkedMenuItemInfo( HMENU handle, UINT pos, UINT flags, UINT method, + MENUITEMINFOW *info, UNICODE_STRING *str ) +{ + POPUPMENU *menu; + UINT i; + BOOL ret; + + switch (method) + { + case NtUserInsertMenuItem: + if (!info || info->cbSize != sizeof(*info)) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + if (!(menu = insert_menu_item( handle, pos, flags, &i ))) + { + /* workaround for Word 95: pretend that SC_TASKLIST item exists */ + if (pos == SC_TASKLIST && !(flags & MF_BYPOSITION)) return TRUE; + return FALSE; + } + + ret = set_menu_item_info( &menu->items[i], info ); + if (!ret) NtUserRemoveMenu( handle, pos, flags ); + release_menu_ptr(menu); + break; + + case NtUserSetMenuItemInfo: + if (!info || info->cbSize != sizeof(*info)) + { + SetLastError( ERROR_INVALID_PARAMETER ); + return FALSE; + } + + if (!(menu = find_menu_item( handle, pos, flags, &i ))) + { + /* workaround for Word 95: pretend that SC_TASKLIST item exists */ + if (pos == SC_TASKLIST && !(flags & MF_BYPOSITION)) return TRUE; + return FALSE; + } + + ret = set_menu_item_info( &menu->items[i], info ); + if (ret) menu->Height = 0; /* force size recalculate */ + release_menu_ptr(menu); + break; + + default: + FIXME( "unsupported method %u\n", method ); + return FALSE; + } + + return ret; +} + +/********************************************************************** + * NtUserRemoveMenu (win32u.@) + */ +BOOL WINAPI NtUserRemoveMenu( HMENU handle, UINT id, UINT flags ) +{ + POPUPMENU *menu; + UINT pos; + + TRACE( "(menu=%p id=%#x flags=%04x)\n", handle, id, flags ); + + if (!(menu = find_menu_item( handle, id, flags, &pos ))) + return FALSE; + + /* Remove item */ + free( menu->items[pos].text ); + + if (--menu->nItems == 0) + { + free( menu->items ); + menu->items = NULL; + } + else + { + MENUITEM *new_items, *item = &menu->items[pos]; + + while (pos < menu->nItems) + { + *item = item[1]; + item++; + pos++; + } + new_items = realloc( menu->items, menu->nItems * sizeof(MENUITEM) ); + if (new_items) menu->items = new_items; + } + + release_menu_ptr(menu); + return TRUE; +} + /********************************************************************** * NtUserSetMenuContextHelpId (win32u.@) */ diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h index fe9d7e18bc9..29e6b4eaf3e 100644 --- a/dlls/win32u/ntuser_private.h +++ b/dlls/win32u/ntuser_private.h @@ -38,7 +38,6 @@ struct user_callbacks BOOL (WINAPI *pImmProcessKey)(HWND, HKL, UINT, LPARAM, DWORD); BOOL (WINAPI *pImmTranslateMessage)(HWND, UINT, WPARAM, LPARAM); BOOL (WINAPI *pSetSystemMenu)( HWND hwnd, HMENU menu ); - void (CDECL *free_menu_items)( void *ptr ); void (CDECL *free_win_ptr)( struct tagWND *win ); HWND (CDECL *is_menu_active)(void); void (CDECL *notify_ime)( HWND hwnd, UINT param ); diff --git a/dlls/win32u/syscall.c b/dlls/win32u/syscall.c index dc58cbe1944..f585e90bd4a 100644 --- a/dlls/win32u/syscall.c +++ b/dlls/win32u/syscall.c @@ -156,6 +156,7 @@ static void * const syscalls[] = NtUserOpenInputDesktop, NtUserOpenWindowStation, NtUserRemoveClipboardFormatListener, + NtUserRemoveMenu, NtUserRemoveProp, NtUserSetKeyboardState, NtUserSetMenuContextHelpId, @@ -170,6 +171,7 @@ static void * const syscalls[] = NtUserSetWinEventHook, NtUserSetWindowsHookEx, NtUserThunkedMenuInfo, + NtUserThunkedMenuItemInfo, NtUserUnhookWinEvent, NtUserUnhookWindowsHookEx, NtUserWindowFromDC, diff --git a/dlls/win32u/win32u.spec b/dlls/win32u/win32u.spec index 208b167229e..07da23f633a 100644 --- a/dlls/win32u/win32u.spec +++ b/dlls/win32u/win32u.spec @@ -1147,7 +1147,7 @@ @ stub NtUserRemoteStopScreenUpdates @ stdcall -syscall NtUserRemoveClipboardFormatListener(long) @ stub NtUserRemoveInjectionDevice -@ stub NtUserRemoveMenu +@ stdcall -syscall NtUserRemoveMenu(long long long) @ stdcall -syscall NtUserRemoveProp(long wstr) @ stub NtUserRemoveVisualIdentifier @ stub NtUserReportInertia @@ -1275,7 +1275,7 @@ @ stdcall NtUserSystemParametersInfoForDpi(long long ptr long long) @ stub NtUserTestForInteractiveUser @ stdcall -syscall NtUserThunkedMenuInfo(long ptr) -@ stub NtUserThunkedMenuItemInfo +@ stdcall -syscall NtUserThunkedMenuItemInfo(long long long long ptr ptr) @ stdcall NtUserToUnicodeEx(long long ptr ptr long long long) @ stdcall NtUserTrackMouseEvent(ptr) @ stub NtUserTrackPopupMenuEx diff --git a/dlls/wow64win/syscall.h b/dlls/wow64win/syscall.h index 1bfc210eab0..776a7e671f6 100644 --- a/dlls/wow64win/syscall.h +++ b/dlls/wow64win/syscall.h @@ -143,6 +143,7 @@ SYSCALL_ENTRY( NtUserOpenInputDesktop ) \ SYSCALL_ENTRY( NtUserOpenWindowStation ) \ SYSCALL_ENTRY( NtUserRemoveClipboardFormatListener ) \ + SYSCALL_ENTRY( NtUserRemoveMenu ) \ SYSCALL_ENTRY( NtUserRemoveProp ) \ SYSCALL_ENTRY( NtUserSetKeyboardState ) \ SYSCALL_ENTRY( NtUserSetMenuContextHelpId ) \ @@ -157,6 +158,7 @@ SYSCALL_ENTRY( NtUserSetWinEventHook ) \ SYSCALL_ENTRY( NtUserSetWindowsHookEx ) \ SYSCALL_ENTRY( NtUserThunkedMenuInfo ) \ + SYSCALL_ENTRY( NtUserThunkedMenuItemInfo ) \ SYSCALL_ENTRY( NtUserUnhookWinEvent ) \ SYSCALL_ENTRY( NtUserUnhookWindowsHookEx ) \ SYSCALL_ENTRY( NtUserWindowFromDC ) diff --git a/dlls/wow64win/user.c b/dlls/wow64win/user.c index 554a6634f0e..1f287c7631c 100644 --- a/dlls/wow64win/user.c +++ b/dlls/wow64win/user.c @@ -30,6 +30,22 @@
WINE_DEFAULT_DEBUG_CHANNEL(wow);
+typedef struct +{ + UINT cbSize; + UINT fMask; + UINT fType; + UINT fState; + UINT wID; + UINT32 hSubMenu; + UINT32 hbmpChecked; + UINT32 hbmpUnchecked; + UINT32 dwItemData; + UINT32 dwTypeData; + UINT cch; + UINT32 hbmpItem; +} MENUITEMINFOW32; + NTSTATUS WINAPI wow64_NtUserInitializeClientPfnArrays( UINT *args ) { FIXME( "\n" ); @@ -708,3 +724,50 @@ NTSTATUS WINAPI wow64_NtUserThunkedMenuInfo( UINT *args )
return NtUserThunkedMenuInfo( menu, info32 ? &info : NULL ); } + +NTSTATUS WINAPI wow64_NtUserThunkedMenuItemInfo( UINT *args ) +{ + HMENU handle = get_handle( &args ); + UINT pos = get_ulong( &args ); + UINT flags = get_ulong( &args ); + UINT method = get_ulong( &args ); + MENUITEMINFOW32 *info32 = get_ptr( &args ); + UNICODE_STRING32 *str32 = get_ptr( &args ); + MENUITEMINFOW info = { sizeof(info) }, *info_ptr; + UNICODE_STRING str; + + if (info32) + { + info.cbSize = sizeof(info); + info.fMask = info32->fMask; + switch (method) + { + case NtUserSetMenuItemInfo: + case NtUserInsertMenuItem: + info.fType = info32->fType; + info.fState = info32->fState; + info.wID = info32->wID; + info.hSubMenu = UlongToHandle( info32->hSubMenu ); + info.hbmpChecked = UlongToHandle( info32->hbmpUnchecked ); + info.dwItemData = info32->dwItemData; + info.dwTypeData = UlongToPtr( info32->dwTypeData ); + info.cch = info32->cch; + info.hbmpItem = UlongToHandle( info32->hbmpItem ); + break; + } + info_ptr = &info; + } + else info_ptr = NULL; + + return NtUserThunkedMenuItemInfo( handle, pos, flags, method, info_ptr, + unicode_str_32to64( &str, str32 )); +} + +NTSTATUS WINAPI wow64_NtUserRemoveMenu( UINT *args ) +{ + HMENU handle = get_handle( &args ); + UINT id = get_ulong( &args ); + UINT flags = get_ulong( &args ); + + return NtUserRemoveMenu( handle, id, flags ); +} diff --git a/include/ntuser.h b/include/ntuser.h index 58486fcfcb0..75b9ba7b73c 100644 --- a/include/ntuser.h +++ b/include/ntuser.h @@ -178,6 +178,13 @@ enum NtUserSpyExit = 0x0301, };
+/* NtUserThunkedMenuItemInfo codes */ +enum +{ + NtUserSetMenuItemInfo, + NtUserInsertMenuItem, +}; + struct send_message_timeout_params { UINT flags; @@ -581,6 +588,7 @@ ATOM WINAPI NtUserRegisterClassExWOW( const WNDCLASSEXW *wc, UNICODE_STRING * BOOL WINAPI NtUserRegisterHotKey( HWND hwnd, INT id, UINT modifiers, UINT vk ); INT WINAPI NtUserReleaseDC( HWND hwnd, HDC hdc ); BOOL WINAPI NtUserRemoveClipboardFormatListener( HWND hwnd ); +BOOL WINAPI NtUserRemoveMenu( HMENU menu, UINT id, UINT flags ); HANDLE WINAPI NtUserRemoveProp( HWND hwnd, const WCHAR *str ); BOOL WINAPI NtUserScrollDC( HDC hdc, INT dx, INT dy, const RECT *scroll, const RECT *clip, HRGN ret_update_rgn, RECT *update_rect ); @@ -629,6 +637,8 @@ BOOL WINAPI NtUserShowWindowAsync( HWND hwnd, INT cmd ); BOOL WINAPI NtUserSystemParametersInfo( UINT action, UINT val, void *ptr, UINT winini ); BOOL WINAPI NtUserSystemParametersInfoForDpi( UINT action, UINT val, PVOID ptr, UINT winini, UINT dpi ); BOOL WINAPI NtUserThunkedMenuInfo( HMENU menu, const MENUINFO *info ); +UINT WINAPI NtUserThunkedMenuItemInfo( HMENU menu, UINT pos, UINT flags, UINT method, + MENUITEMINFOW *info, UNICODE_STRING *str ); INT WINAPI NtUserToUnicodeEx( UINT virt, UINT scan, const BYTE *state, WCHAR *str, int size, UINT flags, HKL layout ); BOOL WINAPI NtUserTrackMouseEvent( TRACKMOUSEEVENT *info );