user: Accept more flags in SetMenuItemInfo and ModifyMenu

Michael Kaufmann hallo at michael-kaufmann.ch
Tue Aug 8 16:22:50 CDT 2006


This makes the MDI buttons appear in Word 95.
An older version of this patch is at http://www.winehq.org/pipermail/wine-patches/2006-April/025919.html

Changelog:
  - 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

-------------- next part --------------
Index: dlls/user/menu.c
===================================================================
RCS file: /home/wine/wine/dlls/user/menu.c,v
retrieving revision 1.65
diff -u -r1.65 menu.c
--- dlls/user/menu.c	12 Jun 2006 12:12:23 -0000	1.65
+++ dlls/user/menu.c	8 Aug 2006 21:02:40 -0000
@@ -159,11 +159,13 @@
 #define IS_SYSTEM_MENU(menu)  \
 	(!((menu)->wFlags & MF_POPUP) && ((menu)->wFlags & MF_SYSMENU))
 
-#define 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)
+#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))
 
 #define WIN_ALLOWED_MENU(style) ((style & (WS_CHILD | WS_POPUP)) != WS_CHILD)
 
@@ -2050,8 +2052,9 @@
       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 @@
 {
     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 @@
             else AppendMenuW( hMenu, flags, id,
                                 *(LPCWSTR)str ? (LPCWSTR)str : NULL );
         }
-    } while (!(flags & MF_END));
+    } while (!end_flag);
     return res;
 }
 
@@ -4352,7 +4359,7 @@
 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 @@
             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 @@
     }
 
     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 @@
 {
     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 @@
             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 @@
             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 @@
 
     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 @@
 
     if (lpmii->fMask & MIIM_CHECKMARKS)
     {
-        if (lpmii->fType & MFT_RADIOCHECK)
-            menu->fType |= MFT_RADIOCHECK;
-
 	menu->hCheckBit = lpmii->hbmpChecked;
 	menu->hUnCheckBit = lpmii->hbmpUnchecked;
     }
Index: dlls/user/tests/menu.c
===================================================================
RCS file: /home/wine/wine/dlls/user/tests/menu.c,v
retrieving revision 1.26
diff -u -r1.26 menu.c
--- dlls/user/tests/menu.c	27 Jul 2006 10:43:29 -0000	1.26
+++ dlls/user/tests/menu.c	8 Aug 2006 21:02:52 -0000
@@ -974,7 +974,7 @@
         {, -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 @@
         {, 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 @@
     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 @@
     test_menu_search_bycommand();
     test_menu_bmp_and_string();
     test_menu_input();
+    test_menu_flags();
+    test_menu_hilitemenuitem();
 }


More information about the wine-patches mailing list