diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c index 4aca343dc7a..789f769baaa 100644 --- a/dlls/user32/menu.c +++ b/dlls/user32/menu.c @@ -4817,34 +4817,49 @@ BOOL WINAPI CheckMenuRadioItem(HMENU hMenu, UINT first, UINT last, UINT check, UINT bypos) { - MENUITEM *mifirst, *milast, *micheck; - HMENU mfirst = hMenu, mlast = hMenu, mcheck = hMenu; + BOOL done = FALSE; + UINT i; + MENUITEM *mi_first = NULL, *mi_check; + HMENU m_first, m_check; - TRACE("%p: %d-%d, check %d, bypos=%d\n", hMenu, first, last, check, bypos); + TRACE("%p: %u-%u, check %u, flags %04x\n", hMenu, first, last, check, bypos); - mifirst = MENU_FindItem (&mfirst, &first, bypos); - milast = MENU_FindItem (&mlast, &last, bypos); - micheck = MENU_FindItem (&mcheck, &check, bypos); + for (i = first; i <= last; i++) + { + UINT pos = i; - if (mifirst == NULL || milast == NULL || micheck == NULL || - mifirst > milast || mfirst != mlast || mfirst != mcheck || - micheck > milast || micheck < mifirst) - return FALSE; + if (!mi_first) + { + m_first = hMenu; + mi_first = MENU_FindItem(&m_first, &pos, bypos); + if (!mi_first) continue; + mi_check = mi_first; + m_check = m_first; + } + else + { + m_check = hMenu; + mi_check = MENU_FindItem(&m_check, &pos, bypos); + if (!mi_check) continue; + } - while (mifirst <= milast) - { - if (mifirst == micheck) - { - mifirst->fType |= MFT_RADIOCHECK; - mifirst->fState |= MFS_CHECKED; - } else { - mifirst->fType &= ~MFT_RADIOCHECK; - mifirst->fState &= ~MFS_CHECKED; - } - mifirst++; - } + if (m_first != m_check) continue; + if (mi_check->fType == MFT_SEPARATOR) continue; - return TRUE; + if (i == check) + { + mi_check->fType |= MFT_RADIOCHECK; + mi_check->fState |= MFS_CHECKED; + done = TRUE; + } + else + { + /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */ + mi_check->fState &= ~MFS_CHECKED; + } + } + + return done; } diff --git a/dlls/user32/tests/menu.c b/dlls/user32/tests/menu.c index 0fb2ced5cd8..141d6c5181c 100644 --- a/dlls/user32/tests/menu.c +++ b/dlls/user32/tests/menu.c @@ -2,6 +2,7 @@ * Unit tests for menus * * Copyright 2005 Robert Shearman + * Copyright 2007 Dmitry Timoshkov * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,7 +19,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include +#define _WIN32_WINNT 0x0501 + #include #include #include @@ -1872,6 +1874,120 @@ static void test_menu_hilitemenuitem( void ) DestroyMenu(hMenu); } +static void check_menu_items(HMENU hmenu, UINT checked_cmd, UINT checked_type, + UINT checked_state) +{ + UINT i, count; + + count = GetMenuItemCount(hmenu); + + for (i = 0; i < count; i++) + { + BOOL ret; + MENUITEMINFO mii; + + memset(&mii, 0, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_FTYPE | MIIM_STATE | MIIM_ID | MIIM_SUBMENU; + ret = GetMenuItemInfo(hmenu, i, TRUE, &mii); + ok(ret, "GetMenuItemInfo(%u) failed\n", i); +#if 0 + trace("item #%u: fType %04x, fState %04x, wID %u, hSubMenu %p\n", + i, mii.fType, mii.fState, mii.wID, mii.hSubMenu); +#endif + if (mii.hSubMenu) + { + ok((HMENU)mii.wID == mii.hSubMenu, "id %u: wID should be equal to hSubMenu\n", checked_cmd); + check_menu_items(mii.hSubMenu, checked_cmd, checked_type, checked_state); + } + else + { + if (mii.wID == checked_cmd) + { + ok(mii.fType == checked_type, "id %u: expected fType %04x, got %04x\n", checked_cmd, checked_type, mii.fType); + ok(mii.fState == checked_state, "id %u: expected fState %04x, got %04x\n", checked_cmd, checked_state, mii.fState); + ok(mii.wID != 0, "id %u: not expected wID 0\n", checked_cmd); + } + else + { + ok(mii.fType != MFT_RADIOCHECK, "id %u: not expected fType MFT_RADIOCHECK on cmd %u\n", checked_cmd, mii.wID); + + if (mii.fType == MFT_SEPARATOR) + { +todo_wine { + ok(mii.fState == MFS_GRAYED, "id %u: expected fState MFS_GRAYED, got %04x\n", checked_cmd, mii.fState); +} + ok(mii.wID == 0, "id %u: expected wID 0, got %u\n", checked_cmd, mii.wID); + } + else + { + ok(mii.fState == 0, "id %u: expected fState 0, got %04x\n", checked_cmd, mii.fState); + ok(mii.wID != 0, "id %u: not expected wID 0\n", checked_cmd); + } + } + } + } +} + +static void clear_ftype_and_state(HMENU hmenu, UINT id, UINT flags) +{ + BOOL ret; + MENUITEMINFO mii; + + memset(&mii, 0, sizeof(mii)); + mii.cbSize = sizeof(mii); + mii.fMask = MIIM_FTYPE | MIIM_STATE; + ret = SetMenuItemInfo(hmenu, id, (flags & MF_BYPOSITION) != 0, &mii); + ok(ret, "SetMenuItemInfo(%u) failed\n", id); +} + +static void test_CheckMenuRadioItem(void) +{ + BOOL ret; + HMENU hmenu; + + hmenu = LoadMenu(GetModuleHandle(0), MAKEINTRESOURCE(1)); + assert(hmenu != 0); + + check_menu_items(hmenu, -1, 0, 0); + + ret = CheckMenuRadioItem(hmenu, 100, 100, 100, MF_BYCOMMAND); + ok(ret, "CheckMenuRadioItem failed\n"); + check_menu_items(hmenu, 100, MFT_RADIOCHECK, MFS_CHECKED); + + /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */ + ret = CheckMenuRadioItem(hmenu, 100, 100, -1, MF_BYCOMMAND); + ok(!ret, "CheckMenuRadioItem should return FALSE\n"); + check_menu_items(hmenu, 100, MFT_RADIOCHECK, 0); + + /* clear check */ + clear_ftype_and_state(hmenu, 100, MF_BYCOMMAND); + check_menu_items(hmenu, -1, 0, 0); + + /* first and checked items are on different menus */ + ret = CheckMenuRadioItem(hmenu, 0, 300, 202, MF_BYCOMMAND); + ok(!ret, "CheckMenuRadioItem should return FALSE\n"); + check_menu_items(hmenu, -1, 0, 0); + + ret = CheckMenuRadioItem(hmenu, 200, 300, 202, MF_BYCOMMAND); + ok(ret, "CheckMenuRadioItem failed\n"); + check_menu_items(hmenu, 202, MFT_RADIOCHECK, MFS_CHECKED); + + /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */ + ret = CheckMenuRadioItem(hmenu, 202, 202, -1, MF_BYCOMMAND); + ok(!ret, "CheckMenuRadioItem should return FALSE\n"); + check_menu_items(hmenu, 202, MFT_RADIOCHECK, 0); + + /* clear check */ + clear_ftype_and_state(hmenu, 202, MF_BYCOMMAND); + check_menu_items(hmenu, -1, 0, 0); + + /* just for fun, try to check separator */ + ret = CheckMenuRadioItem(hmenu, 0, 300, 0, MF_BYCOMMAND); + ok(!ret, "CheckMenuRadioItem should return FALSE\n"); + check_menu_items(hmenu, -1, 0, 0); +} + START_TEST(menu) { pSetMenuInfo = @@ -1890,4 +2006,5 @@ START_TEST(menu) test_menu_input(); test_menu_flags(); test_menu_hilitemenuitem(); + test_CheckMenuRadioItem(); } diff --git a/dlls/user32/tests/resource.rc b/dlls/user32/tests/resource.rc index 47328fc7d4f..c2d5c3090e1 100644 --- a/dlls/user32/tests/resource.rc +++ b/dlls/user32/tests/resource.rc @@ -106,3 +106,24 @@ END '00 00 00 00 00 00 00 00 00 00 FF FF FF 00 40 00' '00 00' } */ + +1 MENU +{ + POPUP "&File" + { + MENUITEM "&New", 100 + MENUITEM "&Open", 101 + MENUITEM "&Save", 102 + MENUITEM SEPARATOR + MENUITEM "E&xit", 103 + } + POPUP "Edit" + { + MENUITEM "&Undo", 200 + MENUITEM SEPARATOR + MENUITEM "Cu&t", 201 + MENUITEM "&Copy", 202 + MENUITEM "&Paste", 203 + MENUITEM "&Delete", 204 + } +}