user32: Add a test for CheckMenuRadioItem and make it pass under Wine

Dmitry Timoshkov dmitry at codeweavers.com
Mon May 14 09:46:32 CDT 2007


Hello,

as reported in the bug 8038 CheckMenuRadioItem doesn't behave as expected
in Wine. The test I'm adding for CheckMenuRadioItem passes under Win98 and XP.

Changelog:
    user32: Add a test for CheckMenuRadioItem and make it pass under Wine.

---
 dlls/user32/menu.c            |   61 +++++++++++++--------
 dlls/user32/tests/menu.c      |  119 ++++++++++++++++++++++++++++++++++++++++-
 dlls/user32/tests/resource.rc |   21 +++++++
 3 files changed, 177 insertions(+), 24 deletions(-)

diff --git a/dlls/user32/menu.c b/dlls/user32/menu.c
index 4aca343..789f769 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 0fb2ced..141d6c5 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 <stdlib.h>
+#define _WIN32_WINNT 0x0501
+
 #include <stdarg.h>
 #include <stdio.h>
 #include <string.h>
@@ -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 47328fc..c2d5c30 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
+    }
+}
-- 
1.5.1.3






More information about the wine-patches mailing list