[PATCH 05/13] win32u: Move menu item info management from user32.
Jacek Caban
wine at gitlab.winehq.org
Mon May 2 05:44:38 CDT 2022
From: Jacek Caban <jacek at codeweavers.com>
Signed-off-by: Jacek Caban <jacek at 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 );
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/18
More information about the wine-devel
mailing list