win32u: Move menu item info management from user32.

Signed-off-by: Jacek Caban <jacek@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Jacek Caban 2022-04-14 00:51:26 +02:00 committed by Alexandre Julliard
parent 75c297f2b8
commit 77ab51019f
12 changed files with 444 additions and 316 deletions

View File

@ -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;

View File

@ -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) &&

View File

@ -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 );
}
/**********************************************************************

View File

@ -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)

View File

@ -165,7 +165,6 @@ static const struct user_callbacks user_funcs =
ImmProcessKey,
ImmTranslateMessage,
SetSystemMenu,
free_menu_items,
free_win_ptr,
MENU_IsMenuActive,
notify_ime,

View File

@ -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.@)
*/

View File

@ -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 );

View File

@ -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,

View File

@ -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

View File

@ -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 )

View File

@ -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 );
}

View File

@ -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 );