user: Accept more flags in SetMenuItemInfo and ModifyMenu.

- Accept MFT_MENU{BAR}BREAK, MFT_RADIOCHECK, MFT_RIGHTJUSTIFY, and
  MFT_RIGHTORDER in SetMenuItemInfo.
- InsertMenu, AppendMenu, ModifiyMenu: Accept MF_HILITE flag (undocumented).
- SetMenuItemInfo: Only use the lower word of the bitmap handle as
  documented in MSDN (Word 95 depends on this).
- The type MFT_RADIOCHECK cannot be set if only the checkmarks are
  modified with SetMenuItemInfo.
- New tests.
This commit is contained in:
Michael Kaufmann 2006-08-08 23:22:50 +02:00 committed by Alexandre Julliard
parent c4dd6c68d0
commit 9f07bcd25f
2 changed files with 187 additions and 25 deletions

View File

@ -159,11 +159,13 @@ typedef struct
#define IS_SYSTEM_MENU(menu) \
(!((menu)->wFlags & MF_POPUP) && ((menu)->wFlags & MF_SYSMENU))
#define TYPE_MASK (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
#define MENUITEMINFO_TYPE_MASK \
(MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
MFT_RIGHTORDER | MFT_RIGHTJUSTIFY | \
MF_POPUP | MF_SYSMENU | MF_HELP)
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))
#define WIN_ALLOWED_MENU(style) ((style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
@ -2050,8 +2052,9 @@ static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT_PTR id,
flags |= MF_POPUP; /* keep popup */
item->fType = flags & TYPE_MASK;
item->fState = (flags & STATE_MASK) &
~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
/* MFS_DEFAULT is not accepted. MF_HILITE is not listed as a valid flag
for ModifyMenu, but Windows accepts it */
item->fState = flags & MENUITEMINFO_STATE_MASK & ~MFS_DEFAULT;
/* Don't call SetRectEmpty here! */
@ -2123,10 +2126,14 @@ static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
{
WORD flags, id = 0;
LPCSTR str;
BOOL end_flag;
do
{
flags = GET_WORD(res);
end_flag = flags & MF_END;
/* Remove MF_END because it has the same value as MF_HILITE */
flags &= ~MF_END;
res += sizeof(WORD);
if (!(flags & MF_POPUP))
{
@ -2151,7 +2158,7 @@ static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
else AppendMenuW( hMenu, flags, id,
*(LPCWSTR)str ? (LPCWSTR)str : NULL );
}
} while (!(flags & MF_END));
} while (!end_flag);
return res;
}
@ -4352,7 +4359,7 @@ BOOL WINAPI IsMenu(HMENU hmenu)
static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
LPMENUITEMINFOW lpmii, BOOL unicode)
{
MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos? MF_BYPOSITION : 0);
MENUITEM *menu = MENU_FindItem (&hmenu, &item, bypos ? MF_BYPOSITION : 0);
debug_print_menuitem("GetMenuItemInfo_common: ", menu, "");
@ -4366,7 +4373,7 @@ static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
SetLastError( ERROR_INVALID_PARAMETER);
return FALSE;
}
lpmii->fType = menu->fType & ~MF_POPUP;
lpmii->fType = menu->fType & MENUITEMINFO_TYPE_MASK;
if( menu->hbmpItem) lpmii->fType |= MFT_BITMAP;
lpmii->hbmpItem = menu->hbmpItem; /* not on Win9x/ME */
if( lpmii->fType & MFT_BITMAP) {
@ -4421,13 +4428,13 @@ static BOOL GetMenuItemInfo_common ( HMENU hmenu, UINT item, BOOL bypos,
}
if (lpmii->fMask & MIIM_FTYPE)
lpmii->fType = menu->fType & ~MF_POPUP;
lpmii->fType = menu->fType & MENUITEMINFO_TYPE_MASK;
if (lpmii->fMask & MIIM_BITMAP)
lpmii->hbmpItem = menu->hbmpItem;
if (lpmii->fMask & MIIM_STATE)
lpmii->fState = menu->fState;
lpmii->fState = menu->fState & MENUITEMINFO_STATE_MASK;
if (lpmii->fMask & MIIM_ID)
lpmii->wID = menu->wID;
@ -4524,7 +4531,7 @@ static BOOL SetMenuItemInfo_common(MENUITEM * menu,
{
if (!menu) return FALSE;
debug_print_menuitem("SetmenuItemInfo_common from: ", menu, "");
debug_print_menuitem("SetMenuItemInfo_common from: ", menu, "");
if (lpmii->fMask & MIIM_TYPE ) {
if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) {
@ -4533,15 +4540,16 @@ static BOOL SetMenuItemInfo_common(MENUITEM * menu,
SetLastError( ERROR_INVALID_PARAMETER);
return FALSE;
}
/* make only MENU_ITEM_TYPE bits in menu->fType equal lpmii->fType */
menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
/* Remove the old type bits and replace them with the new ones */
menu->fType &= ~MENUITEMINFO_TYPE_MASK;
menu->fType |= lpmii->fType & MENUITEMINFO_TYPE_MASK;
if (IS_STRING_ITEM(menu->fType)) {
HeapFree(GetProcessHeap(), 0, menu->text);
set_menu_item_text( menu, lpmii->dwTypeData, unicode );
} else if( (menu->fType) & MFT_BITMAP)
menu->hbmpItem = (HBITMAP)lpmii->dwTypeData;
menu->hbmpItem = HBITMAP_32(LOWORD(lpmii->dwTypeData));
}
if (lpmii->fMask & MIIM_FTYPE ) {
@ -4549,8 +4557,8 @@ static BOOL SetMenuItemInfo_common(MENUITEM * menu,
SetLastError( ERROR_INVALID_PARAMETER);
return FALSE;
}
menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
menu->fType &= ~MENUITEMINFO_TYPE_MASK;
menu->fType |= lpmii->fType & MENUITEMINFO_TYPE_MASK;
}
if (lpmii->fMask & MIIM_STRING ) {
/* free the string when used */
@ -4560,8 +4568,9 @@ static BOOL SetMenuItemInfo_common(MENUITEM * menu,
if (lpmii->fMask & MIIM_STATE)
{
/* FIXME: MFS_DEFAULT do we have to reset the other menu items? */
menu->fState = lpmii->fState;
/* Other menu items having MFS_DEFAULT are not converted
to normal items */
menu->fState = lpmii->fState & MENUITEMINFO_STATE_MASK;
}
if (lpmii->fMask & MIIM_ID)
@ -4586,9 +4595,6 @@ static BOOL SetMenuItemInfo_common(MENUITEM * menu,
if (lpmii->fMask & MIIM_CHECKMARKS)
{
if (lpmii->fType & MFT_RADIOCHECK)
menu->fType |= MFT_RADIOCHECK;
menu->hCheckBit = lpmii->hbmpChecked;
menu->hUnCheckBit = lpmii->hbmpUnchecked;
}

View File

@ -974,7 +974,7 @@ static void test_menu_iteminfo( void )
{, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
init, OK, ER )
TMII_DONE
/* Separator */
TMII_INSMI( {, S, MIIM_TYPE, MFT_SEPARATOR, 0, 0, 0, 0, 0, 0, txt, 0, 0, }, OK)
TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
{, S, MIIM_TYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
@ -1165,7 +1165,96 @@ static void test_menu_iteminfo( void )
{, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
init, OK, ER )
TMII_DONE
/* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
Only the low word of the dwTypeData is used.
Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK)
TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
{, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, },
empty, OK, OK )
TMII_DONE
/* Type flags */
TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
{, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
empty, OK, OK )
TMII_DONE
/* State flags */
TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
{, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, },
empty, OK, OK )
TMII_DONE
/* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK)
TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
{, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, },
empty, OK, OK )
TMII_DONE
/* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK)
TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
{, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
empty, OK, OK )
TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
{, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
empty, OK, OK )
TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
{, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
empty, OK, OK )
TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK)
TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
{, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
empty, OK, OK )
TMII_DONE
/* Bitmaps inserted with MIIM_TYPE and MFT_BITMAP:
Only the low word of the dwTypeData is used.
Use a magic bitmap here (Word 95 uses this to create its MDI menu buttons) */
TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -1, -1, -1, -1, -1, -1, MAKELONG(HBMMENU_MBAR_CLOSE, 0x1234), -1, -1, }, OK)
TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
{, S, MIIM_TYPE, MFT_BITMAP | MFT_RIGHTJUSTIFY, -9, -9, 0, -9, -9, -9, HBMMENU_MBAR_CLOSE, 0, HBMMENU_MBAR_CLOSE, },
empty, OK, OK )
TMII_DONE
/* Type flags */
TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
{, S, MIIM_TYPE, MFT_BITMAP | MFT_MENUBARBREAK | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_RIGHTORDER, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
empty, OK, OK )
TMII_DONE
/* State flags */
TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
TMII_SMII( {, S, MIIM_STATE, -1, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
TMII_GMII ( {, S, MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
{, S, MIIM_STATE, -9, MFS_CHECKED | MFS_DEFAULT | MFS_GRAYED | MFS_HILITE, -9, 0, -9, -9, -9, -9, -9, -9, },
empty, OK, OK )
TMII_DONE
/* The style MFT_RADIOCHECK cannot be set with MIIM_CHECKMARKS only */
TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
TMII_SMII( {, S, MIIM_CHECKMARKS, MFT_RADIOCHECK, -1, -1, -1, hbm, hbm, -1, -1, -1, -1, }, OK)
TMII_GMII ( {, S, MIIM_CHECKMARKS | MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
{, S, MIIM_CHECKMARKS | MIIM_TYPE, MFT_BITMAP, -9, -9, 0, hbm, hbm, -9, hbm, 0, hbm, },
empty, OK, OK )
TMII_DONE
/* MFT_BITMAP is added automatically by GetMenuItemInfo() for MIIM_TYPE */
TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, -1, -1, }, OK)
TMII_SMII( {, S, MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, 0x1234, -1, -1, }, OK)
TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
{, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
empty, OK, OK )
TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
{, S, MIIM_TYPE, MFT_BITMAP | MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
empty, OK, OK )
TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
{, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, -9, -9, -9, },
empty, OK, OK )
TMII_SMII( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, NULL, }, OK)
TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, -9, -9, -9, },
{, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, NULL, },
empty, OK, OK )
TMII_DONE
} while( !(ansi = !ansi) );
DeleteObject( hbm);
}
@ -1686,6 +1775,71 @@ static void test_menu_input(void) {
DestroyWindow(hWnd);
}
void test_menu_flags( void )
{
HMENU hMenu, hPopupMenu;
hMenu = CreateMenu();
hPopupMenu = CreatePopupMenu();
AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup");
AppendMenu(hPopupMenu, MF_STRING | MF_HILITE | MF_DEFAULT, 101, "Item 1");
InsertMenu(hPopupMenu, 1, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 102, "Item 2");
AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
ModifyMenu(hPopupMenu, 2, MF_BYPOSITION | MF_STRING | MF_HILITE | MF_DEFAULT, 103, "Item 3");
ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE,
"AppendMenu should accept MF_HILITE\n");
ok(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE,
"InsertMenu should accept MF_HILITE\n");
ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
"ModifyMenu should accept MF_HILITE\n");
ok(!(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_DEFAULT),
"AppendMenu must not accept MF_DEFAULT\n");
ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_DEFAULT),
"InsertMenu must not accept MF_DEFAULT\n");
ok(!(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_DEFAULT),
"ModifyMenu must not accept MF_DEFAULT\n");
DestroyMenu(hMenu);
}
void test_menu_hilitemenuitem( void )
{
HMENU hMenu, hPopupMenu;
hMenu = CreateMenu();
hPopupMenu = CreatePopupMenu();
AppendMenu(hMenu, MF_POPUP | MF_STRING, (UINT)hPopupMenu, "Popup");
AppendMenu(hPopupMenu, MF_STRING, 101, "Item 1");
AppendMenu(hPopupMenu, MF_STRING, 102, "Item 2");
AppendMenu(hPopupMenu, MF_STRING, 103, "Item 3");
HiliteMenuItem(NULL, hPopupMenu, 0, MF_HILITE);
HiliteMenuItem(NULL, hPopupMenu, 1, MF_HILITE);
HiliteMenuItem(NULL, hPopupMenu, 2, MF_HILITE);
HiliteMenuItem(NULL, hPopupMenu, 1, MF_UNHILITE);
todo_wine
{
ok(GetMenuState(hPopupMenu, 0, MF_BYPOSITION) & MF_HILITE,
"HiliteMenuItem: Item 1 is not hilited\n");
}
ok(!(GetMenuState(hPopupMenu, 1, MF_BYPOSITION) & MF_HILITE),
"HiliteMenuItem: Item 2 is hilited\n");
todo_wine
{
ok(GetMenuState(hPopupMenu, 2, MF_BYPOSITION) & MF_HILITE,
"HiliteMenuItem: Item 3 is not hilited\n");
}
DestroyMenu(hMenu);
}
START_TEST(menu)
{
pSetMenuInfo =
@ -1702,4 +1856,6 @@ START_TEST(menu)
test_menu_search_bycommand();
test_menu_bmp_and_string();
test_menu_input();
test_menu_flags();
test_menu_hilitemenuitem();
}