Separate menu bitmaps and strings.

Rein Klazes wijn at wanadoo.nl
Fri Dec 30 06:12:17 CST 2005


Hi,

As discussed on the developer list this fixes menu problems, at least
two filed in wine's bugzilla, with applications that expect ownerdraw
and bitmap menus to contain strings as well.

Changelog:

dlls/user		: menu.c
dlls/user/tests	: menu.c

Store bitmaps and bitmaps always in separate fields in the internal menu
structure.  Get rid of a lot of assumptions in the code that the menu
can have strings only when it is not some other type and that bitmaps
come in two flavors.
Add a lot of conformance tests, including some submitted by Jason
Edmeades.

Rein.
-------------- next part --------------
--- wine/dlls/user/menu.c	2005-11-30 18:21:27.000000000 +0100
+++ mywine/dlls/user/menu.c	2005-12-30 11:09:10.000000000 +0100
@@ -72,10 +72,10 @@ typedef struct {
     HMENU hSubMenu;		/* Pop-up menu.  */
     HBITMAP hCheckBit;		/* Bitmap when checked.  */
     HBITMAP hUnCheckBit;	/* Bitmap when unchecked.  */
-    LPWSTR text;			/* Item text or bitmap handle.  */
+    LPWSTR text;		/* Item text. */
     ULONG_PTR dwItemData;	/* Application defined.  */
     LPWSTR dwTypeData;		/* depends on fMask */
-    HBITMAP hbmpItem;		/* bitmap in win98 style menus */
+    HBITMAP hbmpItem;		/* bitmap */
     /* ----------- Wine stuff ----------- */
     RECT      rect;		/* Item area (relative to menu window) */
     UINT      xTab;		/* X position of text after Tab */
@@ -148,8 +148,7 @@ typedef struct
   ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
 
 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
-#define IS_BITMAP_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_BITMAP)
-#define IS_MAGIC_ITEM(id)     ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
+#define IS_MAGIC_BITMAP(id)     ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
 
 #define IS_SYSTEM_MENU(menu)  \
 	(!((menu)->wFlags & MF_POPUP) && ((menu)->wFlags & MF_SYSMENU))
@@ -612,8 +611,7 @@ UINT MENU_FindSubMenu( HMENU *hmenu, HME
 static void MENU_FreeItemData( MENUITEM* item )
 {
     /* delete text */
-    if (IS_STRING_ITEM(item->fType) && item->text)
-        HeapFree( GetProcessHeap(), 0, item->text );
+    HeapFree( GetProcessHeap(), 0, item->text );
 }
 
 /***********************************************************************
@@ -671,7 +669,7 @@ static UINT MENU_FindItemByKey( HWND hwn
 
 	     for (i = 0; i < menu->nItems; i++, item++)
 	     {
-		if (IS_STRING_ITEM(item->fType) && item->text)
+		if( item->text)
 		{
 		    WCHAR *p = item->text - 2;
 		    do
@@ -740,22 +738,22 @@ static void MENU_GetBitmapItemSize( HBIT
  *           MENU_DrawBitmapItem
  *
  * Draw a bitmap item.
- * drawhbmbitmap : True to draw the hbmbitmap(MIIM_BITMAP)/False to draw the MF_BITMAP
  */
-static void MENU_DrawBitmapItem( HDC hdc, MENUITEM *lpitem, const RECT *rect, BOOL menuBar, BOOL drawhbmbitmap )
+static void MENU_DrawBitmapItem( HDC hdc, MENUITEM *lpitem, const RECT *rect, BOOL menuBar)
 {
     BITMAP bm;
     DWORD rop;
     HDC hdcMem;
-    HBITMAP bmp = (HBITMAP)lpitem->text;
+    HBITMAP bmp;
     int w = rect->right - rect->left;
     int h = rect->bottom - rect->top;
     int bmp_xoffset = 0;
     int left, top;
-    HBITMAP hbmToDraw = (drawhbmbitmap)?lpitem->hbmpItem:(HBITMAP)lpitem->text;    
+    HBITMAP hbmToDraw = lpitem->hbmpItem;
+    bmp = hbmToDraw;
 
     /* Check if there is a magic menu item associated with this item */
-    if (IS_MAGIC_ITEM(hbmToDraw))
+    if (IS_MAGIC_BITMAP(hbmToDraw))
     {
         UINT flags = 0;
         RECT r;
@@ -820,8 +818,8 @@ static void MENU_DrawBitmapItem( HDC hdc
     /* handle fontsize > bitmap_height */
     top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top;
     left=rect->left;
-    rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_ITEM(hbmToDraw)) ? NOTSRCCOPY : SRCCOPY;
-    if ((lpitem->fState & MF_HILITE) && IS_BITMAP_ITEM(lpitem->fType))
+    rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmToDraw)) ? NOTSRCCOPY : SRCCOPY;
+    if ((lpitem->fState & MF_HILITE) && lpitem->hbmpItem)
         SetBkColor(hdc, GetSysColor(COLOR_HIGHLIGHT));
     BitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop );
     DeleteDC( hdcMem );
@@ -892,7 +890,6 @@ static void MENU_CalcItemSize( HDC hdc, 
 
     if (!menuBar)
     {
-	/* New style MIIM_BITMAP */
 	if (lpitem->hbmpItem) 
 	{
 	    if (lpitem->hbmpItem == HBMMENU_CALLBACK)
@@ -927,13 +924,11 @@ static void MENU_CalcItemSize( HDC hdc, 
 	    lpitem->rect.right += 2 * check_bitmap_width;
 	if (lpitem->fType & MF_POPUP)
 	    lpitem->rect.right += arrow_bitmap_width;
-    }
-
-    if (IS_BITMAP_ITEM(lpitem->fType))
+    } else if (lpitem->hbmpItem)
     {
         SIZE size;
 
-        MENU_GetBitmapItemSize( (HBITMAP) lpitem->text, lpitem->dwItemData, &size );
+        MENU_GetBitmapItemSize( (HBITMAP) lpitem->hbmpItem, lpitem->dwItemData, &size );
         lpitem->rect.right  += size.cx;
         lpitem->rect.bottom += size.cy;
         /* Leave space for the sunken border */
@@ -941,9 +936,8 @@ static void MENU_CalcItemSize( HDC hdc, 
         lpitem->rect.bottom += 2;
     }
 
-
     /* it must be a text item - unless it's the system menu */
-    if (!(lpitem->fType & MF_SYSMENU) && IS_STRING_ITEM( lpitem->fType ))
+    if (!(lpitem->fType & MF_SYSMENU) && lpitem->text)
     {   SIZE size;
 
 	GetTextExtentPoint32W(hdc, lpitem->text,  strlenW(lpitem->text), &size);
@@ -1303,7 +1297,6 @@ static void MENU_DrawMenuItem( HWND hwnd
         {
             RECT rc;
             rc = rect;
-            /* New style MIIM_BITMAP */
             if (lpitem->hbmpItem)
             {
                 POPUPMENU *menu = MENU_GetMenu(hmenu);
@@ -1342,7 +1335,6 @@ static void MENU_DrawMenuItem( HWND hwnd
                 DeleteDC( hdcMem );
                 DeleteObject( bm );
             }
-            /* New style MIIM_BITMAP */
             if (lpitem->hbmpItem)
             {
                 HBITMAP hbm = lpitem->hbmpItem;
@@ -1371,7 +1363,7 @@ static void MENU_DrawMenuItem( HWND hwnd
                     SetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
 
                 } else {
-                    MENU_DrawBitmapItem(hdc, lpitem, &rect, FALSE, TRUE);
+                    MENU_DrawBitmapItem(hdc, lpitem, &rect, FALSE);
                 }
             }
         }
@@ -1394,19 +1386,15 @@ static void MENU_DrawMenuItem( HWND hwnd
 	rect.left += check_bitmap_width;
 	rect.right -= arrow_bitmap_width;
     }
-
+    else if( lpitem->hbmpItem && !(lpitem->fType & MF_OWNERDRAW))
+    {   /* Draw the bitmap */
+	MENU_DrawBitmapItem( hdc, lpitem, &rect, menuBar);
+    }
     /* Done for owner-drawn */
     if (lpitem->fType & MF_OWNERDRAW)
         return;
-
-    /* Draw the item text or bitmap */
-    if (IS_BITMAP_ITEM(lpitem->fType))
-    {
-	MENU_DrawBitmapItem( hdc, lpitem, &rect, menuBar, FALSE);
-	return;
-    }
-    /* No bitmap - process text if present */
-    else if (IS_STRING_ITEM(lpitem->fType))
+    /* process text if present */
+    if (lpitem->text)
     {
 	register int i;
 	HFONT hfontOld = 0;
@@ -1745,13 +1733,12 @@ static void MENU_MoveSelection( HWND hwn
 static BOOL MENU_SetItemData( MENUITEM *item, UINT flags, UINT_PTR id,
                                 LPCWSTR str )
 {
-    LPWSTR prevText = IS_STRING_ITEM(item->fType) ? item->text : NULL;
-
     debug_print_menuitem("MENU_SetItemData from: ", item, "");
     TRACE("flags=%x str=%p\n", flags, str);
 
     if (IS_STRING_ITEM(flags))
     {
+        LPWSTR prevText = item->text;
         if (!str)
         {
             flags |= MF_SEPARATOR;
@@ -1771,10 +1758,15 @@ static BOOL MENU_SetItemData( MENUITEM *
             strcpyW( text, str );
             item->text = text;
         }
+        item->hbmpItem = NULL;
+        HeapFree( GetProcessHeap(), 0, prevText );
+    }
+    else if(( flags & MFT_BITMAP)) {
+        item->hbmpItem = HBITMAP_32(LOWORD(str));
+        /* setting bitmap clears text */
+        HeapFree( GetProcessHeap(), 0, item->text );
+        item->text = NULL;
     }
-    else if (IS_BITMAP_ITEM(flags))
-        item->text = (LPWSTR)HBITMAP_32(LOWORD(str));
-    else item->text = NULL;
 
     if (flags & MF_OWNERDRAW)
         item->dwItemData = (DWORD_PTR)str;
@@ -1808,12 +1800,8 @@ static BOOL MENU_SetItemData( MENUITEM *
     item->fState = (flags & STATE_MASK) &
         ~(MF_HILITE | MF_MOUSESELECT | MF_BYPOSITION);
 
-
     /* Don't call SetRectEmpty here! */
 
-
-    HeapFree( GetProcessHeap(), 0, prevText );
-
     debug_print_menuitem("MENU_SetItemData to  : ", item, "");
     return TRUE;
 }
@@ -3318,8 +3306,10 @@ INT WINAPI GetMenuStringA(
 
     TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags );
     if (str && nMaxSiz) str[0] = '\0';
-    if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
-    if (!IS_STRING_ITEM(item->fType)) return 0;
+    if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) {
+        SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
+        return 0;
+    }
     if (!str || !nMaxSiz) return strlenW(item->text);
     if (!WideCharToMultiByte( CP_ACP, 0, item->text, -1, str, nMaxSiz, NULL, NULL ))
         str[nMaxSiz-1] = 0;
@@ -3338,9 +3328,15 @@ INT WINAPI GetMenuStringW( HMENU hMenu, 
 
     TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, wItemID, str, nMaxSiz, wFlags );
     if (str && nMaxSiz) str[0] = '\0';
-    if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) return 0;
-    if (!IS_STRING_ITEM(item->fType)) return 0;
-    if (!str || !nMaxSiz) return strlenW(item->text);
+    if (!(item = MENU_FindItem( &hMenu, &wItemID, wFlags ))) {
+        SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
+        return 0;
+    }
+    if (!str || !nMaxSiz) return item->text ? strlenW(item->text) : 0;
+    if( !(item->text)) {
+        str[0] = 0;
+        return 0;
+    }
     lstrcpynW( str, item->text, nMaxSiz );
     return strlenW(str);
 }
@@ -4095,51 +4091,64 @@ static BOOL GetMenuItemInfo_common ( HME
 
     if (!menu)
 	return FALSE;
-
-    if (lpmii->fMask & MIIM_TYPE) {
-	lpmii->fType = menu->fType;
-	switch (MENU_ITEM_TYPE(menu->fType)) {
-	case MF_STRING:
-            break;  /* will be done below */
-	case MF_OWNERDRAW:
-	case MF_BITMAP:
-	    lpmii->dwTypeData = menu->text;
-	    /* fall through */
-	default:
+    
+    if( lpmii->fMask & MIIM_TYPE) {
+        if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) {
+            SetLastError( ERROR_INVALID_PARAMETER);
+            return FALSE;
+        }
+	lpmii->fType = menu->fType & ~MF_POPUP;
+        if( menu->hbmpItem) lpmii->fType |= MFT_BITMAP;
+	lpmii->hbmpItem = menu->hbmpItem;
+        if( lpmii->fType & MFT_BITMAP) {
+	    lpmii->dwTypeData = (LPWSTR) menu->hbmpItem;
 	    lpmii->cch = 0;
-	}
+        } else if( lpmii->fType & (MFT_OWNERDRAW | MFT_SEPARATOR)) {
+	    lpmii->dwTypeData = 0;
+	    lpmii->cch = 0;
+        }
     }
 
     /* copy the text string */
-    if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)) &&
-         (MENU_ITEM_TYPE(menu->fType) == MF_STRING) && menu->text)
-    {
-        int len;
-        if (unicode)
-        {
-            len = strlenW(menu->text);
-            if(lpmii->dwTypeData && lpmii->cch)
-                lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
-        }
-        else
-        {
-            len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL, 0, NULL, NULL );
+    if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING))) {
+         if( !menu->text ) {
+                if(lpmii->dwTypeData && lpmii->cch) {
+                    lpmii->cch = 0;
+                    if( unicode)
+                        *((WCHAR *)lpmii->dwTypeData) = 0;
+                    else
+                        *((CHAR *)lpmii->dwTypeData) = 0;
+                }
+         } else {
+            int len;
+            if (unicode)
+            {
+                len = strlenW(menu->text);
+                if(lpmii->dwTypeData && lpmii->cch)
+                    lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
+            }
+            else
+            {
+                len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL,
+                        0, NULL, NULL ) - 1;
+                if(lpmii->dwTypeData && lpmii->cch)
+                    if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
+                            (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
+                        ((LPSTR)lpmii->dwTypeData)[lpmii->cch - 1] = 0;
+            }
+            /* if we've copied a substring we return its length */
             if(lpmii->dwTypeData && lpmii->cch)
-                if (!WideCharToMultiByte( CP_ACP, 0, menu->text, -1,
-                                          (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
-                    ((LPSTR)lpmii->dwTypeData)[lpmii->cch-1] = 0;
-        }
-        /* if we've copied a substring we return its length */
-        if(lpmii->dwTypeData && lpmii->cch)
-        {
-            if (lpmii->cch <= len) lpmii->cch--;
+                if (lpmii->cch <= len + 1)
+                    lpmii->cch--;
+                else
+                    lpmii->cch = len;
+            else /* return length of string */
+                lpmii->cch = len;
         }
-        else /* return length of string */
-            lpmii->cch = len;
     }
 
     if (lpmii->fMask & MIIM_FTYPE)
-	lpmii->fType = menu->fType;
+	lpmii->fType = menu->fType & ~MF_POPUP;
 
     if (lpmii->fMask & MIIM_BITMAP)
 	lpmii->hbmpItem = menu->hbmpItem;
@@ -4152,6 +4161,8 @@ static BOOL GetMenuItemInfo_common ( HME
 
     if (lpmii->fMask & MIIM_SUBMENU)
 	lpmii->hSubMenu = menu->hSubMenu;
+    else
+        lpmii->hSubMenu = 0; /* hSubMenu is always cleared */
 
     if (lpmii->fMask & MIIM_CHECKMARKS) {
 	lpmii->hbmpChecked = menu->hCheckBit;
@@ -4169,8 +4180,20 @@ static BOOL GetMenuItemInfo_common ( HME
 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
                                   LPMENUITEMINFOA lpmii)
 {
-    return GetMenuItemInfo_common (hmenu, item, bypos,
-                                    (LPMENUITEMINFOW)lpmii, FALSE);
+    BOOL ret;
+    MENUITEMINFOA mii;
+    if( lpmii->cbSize != sizeof( mii) &&
+            lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
+        SetLastError( ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+    memcpy( &mii, lpmii, lpmii->cbSize);
+    mii.cbSize = sizeof( mii);
+    ret = GetMenuItemInfo_common (hmenu, item, bypos,
+                                    (LPMENUITEMINFOW)&mii, FALSE);
+    mii.cbSize = lpmii->cbSize;
+    memcpy( lpmii, &mii, mii.cbSize);
+    return ret;
 }
 
 /**********************************************************************
@@ -4179,8 +4202,19 @@ BOOL WINAPI GetMenuItemInfoA( HMENU hmen
 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
                                   LPMENUITEMINFOW lpmii)
 {
-    return GetMenuItemInfo_common (hmenu, item, bypos,
-                                     lpmii, TRUE);
+    BOOL ret;
+    MENUITEMINFOW mii;
+    if( lpmii->cbSize != sizeof( mii) &&
+            lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
+        SetLastError( ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+    memcpy( &mii, lpmii, lpmii->cbSize);
+    mii.cbSize = sizeof( mii);
+    ret = GetMenuItemInfo_common (hmenu, item, bypos, &mii, TRUE);
+    mii.cbSize = lpmii->cbSize;
+    memcpy( lpmii, &mii, mii.cbSize);
+    return ret;
 }
 
 
@@ -4188,10 +4222,7 @@ BOOL WINAPI GetMenuItemInfoW( HMENU hmen
 inline static void set_menu_item_text( MENUITEM *menu, LPCWSTR text, BOOL unicode )
 {
     if (!text)
-    {
         menu->text = NULL;
-        menu->fType |= MF_SEPARATOR;
-    }
     else if (unicode)
     {
         if ((menu->text = HeapAlloc( GetProcessHeap(), 0, (strlenW(text)+1) * sizeof(WCHAR) )))
@@ -4220,43 +4251,33 @@ static BOOL SetMenuItemInfo_common(MENUI
     debug_print_menuitem("MENU_SetItemInfo_common from: ", menu, "");
 
     if (lpmii->fMask & MIIM_TYPE ) {
-	/* Get rid of old string. */
-	if (IS_STRING_ITEM(menu->fType) && menu->text) {
-	    HeapFree(GetProcessHeap(), 0, menu->text);
-	    menu->text = NULL;
-	}
-
+        if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) {
+            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);
 
-        if (IS_STRING_ITEM(menu->fType))
+        if (IS_STRING_ITEM(menu->fType)) {
+	    HeapFree(GetProcessHeap(), 0, menu->text);
             set_menu_item_text( menu, lpmii->dwTypeData, unicode );
-        else
-            menu->text = lpmii->dwTypeData;
+        } else if( (menu->fType) & MFT_BITMAP)
+                menu->hbmpItem = (HBITMAP)lpmii->dwTypeData;
     }
 
     if (lpmii->fMask & MIIM_FTYPE ) {
-	/* free the string when the type is changing */
-	if ( (!IS_STRING_ITEM(lpmii->fType)) && IS_STRING_ITEM(menu->fType) && menu->text) {
-	    HeapFree(GetProcessHeap(), 0, menu->text);
-	    menu->text = NULL;
-	}
+        if(( lpmii->fType & MFT_BITMAP)) {
+            SetLastError( ERROR_INVALID_PARAMETER);
+            return FALSE;
+        }
 	menu->fType &= ~MENU_ITEM_TYPE(menu->fType);
 	menu->fType |= MENU_ITEM_TYPE(lpmii->fType);
-
-        if (IS_STRING_ITEM(menu->fType))
-            set_menu_item_text( menu, lpmii->dwTypeData, unicode );
-        else
-            menu->text = lpmii->dwTypeData;
     }
-
     if (lpmii->fMask & MIIM_STRING ) {
-	if (IS_STRING_ITEM(menu->fType)) {
-            /* free the string when used */
-            HeapFree(GetProcessHeap(), 0, menu->text);
-            set_menu_item_text( menu, lpmii->dwTypeData, unicode );
-	}
+        /* free the string when used */
+        HeapFree(GetProcessHeap(), 0, menu->text);
+        set_menu_item_text( menu, lpmii->dwTypeData, unicode );
     }
 
     if (lpmii->fMask & MIIM_STATE)
@@ -4276,9 +4297,10 @@ static BOOL SetMenuItemInfo_common(MENUI
 		subMenu->wFlags |= MF_POPUP;
 		menu->fType |= MF_POPUP;
 	    }
-	    else
-		/* FIXME: Return an error ? */
-		menu->fType &= ~MF_POPUP;
+	    else {
+                SetLastError( ERROR_INVALID_PARAMETER);
+                return FALSE;
+            }
 	}
 	else
 	    menu->fType &= ~MF_POPUP;
@@ -4298,6 +4320,9 @@ static BOOL SetMenuItemInfo_common(MENUI
     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;
 }
@@ -4308,8 +4333,19 @@ static BOOL SetMenuItemInfo_common(MENUI
 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
                                  const MENUITEMINFOA *lpmii)
 {
+    MENUITEMINFOA mii;
+    if( lpmii->cbSize != sizeof( mii) &&
+            lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
+        SetLastError( ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+    memcpy( &mii, lpmii, lpmii->cbSize);
+    if( lpmii->cbSize != sizeof( mii)) {
+        mii.cbSize = sizeof( mii);
+        mii.hbmpItem = NULL;
+    }
     return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
-				    (const MENUITEMINFOW *)lpmii, FALSE);
+				    (const MENUITEMINFOW *)&mii, FALSE);
 }
 
 /**********************************************************************
@@ -4318,8 +4354,19 @@ BOOL WINAPI SetMenuItemInfoA(HMENU hmenu
 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
                                  const MENUITEMINFOW *lpmii)
 {
-    return SetMenuItemInfo_common(MENU_FindItem(&hmenu, &item, bypos? MF_BYPOSITION : 0),
-				    lpmii, TRUE);
+    MENUITEMINFOW mii;
+    if( lpmii->cbSize != sizeof( mii) &&
+            lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
+        SetLastError( ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+    memcpy( &mii, lpmii, lpmii->cbSize);
+    if( lpmii->cbSize != sizeof( mii)) {
+        mii.cbSize = sizeof( mii);
+        mii.hbmpItem = NULL;
+    }
+    return SetMenuItemInfo_common(MENU_FindItem(&hmenu,
+                &item, bypos? MF_BYPOSITION : 0), &mii, TRUE);
 }
 
 /**********************************************************************
@@ -4420,7 +4467,18 @@ BOOL WINAPI InsertMenuItemA(HMENU hMenu,
                                 const MENUITEMINFOA *lpmii)
 {
     MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
-    return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)lpmii, FALSE);
+    MENUITEMINFOA mii;
+    if( lpmii->cbSize != sizeof( mii) &&
+            lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
+        SetLastError( ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+    memcpy( &mii, lpmii, lpmii->cbSize);
+    if( lpmii->cbSize != sizeof( mii)) {
+        mii.cbSize = sizeof( mii);
+        mii.hbmpItem = NULL;
+    }
+    return SetMenuItemInfo_common(item, (const MENUITEMINFOW *)&mii, FALSE);
 }
 
 
@@ -4431,7 +4489,18 @@ BOOL WINAPI InsertMenuItemW(HMENU hMenu,
                                 const MENUITEMINFOW *lpmii)
 {
     MENUITEM *item = MENU_InsertItem(hMenu, uItem, bypos ? MF_BYPOSITION : 0 );
-    return SetMenuItemInfo_common(item, lpmii, TRUE);
+    MENUITEMINFOW mii;
+    if( lpmii->cbSize != sizeof( mii) &&
+            lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
+        SetLastError( ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+    memcpy( &mii, lpmii, lpmii->cbSize);
+    if( lpmii->cbSize != sizeof( mii)) {
+        mii.cbSize = sizeof( mii);
+        mii.hbmpItem = NULL;
+    }
+    return SetMenuItemInfo_common(item, &mii, TRUE);
 }
 
 /**********************************************************************
--- wine/dlls/user/tests/menu.c	2005-11-30 18:21:29.000000000 +0100
+++ mywine/dlls/user/tests/menu.c	2005-12-29 16:44:33.000000000 +0100
@@ -29,6 +29,7 @@
 #include "winbase.h"
 #include "wingdi.h"
 #include "winuser.h"
+#include "wchar.h"
 
 #include "wine/test.h"
 
@@ -253,9 +254,17 @@ static void test_menu_ownerdraw(void)
 
 static void test_menu_add_string( void )
 {
+    HMENU hmenu;
     MENUITEMINFO info;
+    BOOL rc;
+    
     char string[0x80];
-    HMENU hmenu;
+    char string2[0x80];
+
+    char strback[0x80];
+    WCHAR strbackW[0x80];
+    static const WCHAR expectedString[] = {'D', 'u', 'm', 'm', 'y', ' ', 
+                         's', 't', 'r', 'i', 'n', 'g', 0};
 
     hmenu = CreateMenu();
 
@@ -279,9 +288,591 @@ static void test_menu_add_string( void )
 
     ok( !strcmp( string, "blah" ), "menu item name differed\n");
 
+    /* Test combination of ownerdraw and strings with GetMenuItemString(A/W) */
+    strcpy(string, "Dummy string");
+    memset(&info, 0x00, sizeof(info));
+    info.cbSize= sizeof(MENUITEMINFO); 
+    info.fMask= MIIM_FTYPE | MIIM_STRING; /* Set OwnerDraw + typeData */
+    info.fType= MFT_OWNERDRAW;
+    info.dwTypeData= string; 
+    rc = InsertMenuItem( hmenu, 0, TRUE, &info );
+    ok (rc, "InsertMenuItem failed\n");
+
+    strcpy(string,"Garbage");
+    ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
+    ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
+
+    ok (GetMenuStringW( hmenu, 0, (WCHAR *)strbackW, 99, MF_BYPOSITION), "GetMenuStringW on ownerdraw entry failed\n");
+    ok (!lstrcmpW( strbackW, expectedString ), "Menu text from Unicode version incorrect\n");
+
+    /* Just change ftype to string and see what text is stored */
+    memset(&info, 0x00, sizeof(info));
+    info.cbSize= sizeof(MENUITEMINFO); 
+    info.fMask= MIIM_FTYPE; /* Set string type */
+    info.fType= MFT_STRING;
+    info.dwTypeData= (char *)0xdeadbeef; 
+    rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
+    ok (rc, "SetMenuItemInfo failed\n");
+
+    /* Did we keep the old dwTypeData? */
+    ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
+    ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
+
+    /* Ensure change to bitmap type fails */
+    memset(&info, 0x00, sizeof(info));
+    info.cbSize= sizeof(MENUITEMINFO); 
+    info.fMask= MIIM_FTYPE; /* Set as bitmap type */
+    info.fType= MFT_BITMAP;
+    info.dwTypeData= (char *)0xdeadbee2; 
+    rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
+    ok (!rc, "SetMenuItemInfo unexpectedly worked\n");
+
+    /* Just change ftype back and ensure data hasnt been freed */
+    info.fType= MFT_OWNERDRAW; /* Set as ownerdraw type */
+    info.dwTypeData= (char *)0xdeadbee3; 
+    rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
+    ok (rc, "SetMenuItemInfo failed\n");
+    
+    /* Did we keep the old dwTypeData? */
+    ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
+    ok (!strcmp( strback, "Dummy string" ), "Menu text from Ansi version incorrect\n");
+
+    /* Just change string value (not type) */
+    memset(&info, 0x00, sizeof(info));
+    info.cbSize= sizeof(MENUITEMINFO); 
+    info.fMask= MIIM_STRING; /* Set typeData */
+    strcpy(string2, "string2");
+    info.dwTypeData= string2; 
+    rc = SetMenuItemInfo( hmenu, 0, TRUE, &info );
+    ok (rc, "SetMenuItemInfo failed\n");
+
+    ok (GetMenuString( hmenu, 0, strback, 99, MF_BYPOSITION), "GetMenuString on ownerdraw entry failed\n");
+    ok (!strcmp( strback, "string2" ), "Menu text from Ansi version incorrect\n");
+
     DestroyMenu( hmenu );
 }
 
+/* define building blocks for the menu item info tests */
+static int strncmpW( const WCHAR *str1, const WCHAR *str2, int n )
+{
+    if (n <= 0) return 0;
+    while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
+    return *str1 - *str2;
+}
+
+static  WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
+{
+    WCHAR *p = dst;
+    while ((*p++ = *src++));
+    return dst;
+}
+
+
+#define DMIINFF( i, e, field)\
+    ok((int)((i)->field)==(int)((e)->field) || (int)((i)->field)==(0xffff & (int)((e)->field)), \
+    "%s got 0x%x expected 0x%x\n", #field, (int)((i)->field), (int)((e)->field));
+
+#define DUMPMIINF(s,i,e)\
+{\
+    DMIINFF( i, e, fMask)\
+    DMIINFF( i, e, fType)\
+    DMIINFF( i, e, fState)\
+    DMIINFF( i, e, wID)\
+    DMIINFF( i, e, hSubMenu)\
+    DMIINFF( i, e, hbmpChecked)\
+    DMIINFF( i, e, hbmpUnchecked)\
+    DMIINFF( i, e, dwItemData)\
+    DMIINFF( i, e, dwTypeData)\
+    DMIINFF( i, e, cch)\
+    if( s==sizeof(MENUITEMINFOA)) DMIINFF( i, e, hbmpItem)\
+}    
+
+/* insert menu item */
+#define TMII_INSMI( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
+    eret1)\
+{\
+    MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
+    HMENU hmenu = CreateMenu();\
+    BOOL ret, stop = FALSE;\
+    SetLastError( 0xdeadbeef);\
+    if(ansi)strcpy( string, init);\
+    else strcpyW( (WCHAR*)string, (WCHAR*)init);\
+    if( ansi) ret = InsertMenuItemA(hmenu, 0, TRUE, &info1 );\
+    else ret = InsertMenuItemW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
+    if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
+        stop = TRUE;\
+    } else ok( (eret1)==ret,"InsertMenuItem failed, err %ld\n",GetLastError());\
+
+
+/* GetMenuItemInfo + GetMenuString  */
+#define TMII_GMII( a2,b2,c2,d2,e2,f2,g2,h2,i2,j2,k2,l2,m2,n2,\
+    a3,b3,c3,d3,e3,f3,g3,h3,i3,j3,k3,l3,m3,n3,\
+    expname, eret2, eret3)\
+{\
+  MENUITEMINFOA info2A=a2 b2,c2,d2,e2,f2,(void*)g2,(void*)h2,(void*)i2,j2,(void*)k2,l2,(void*)m2 n2;\
+  MENUITEMINFOA einfoA=a3 b3,c3,d3,e3,f3,(void*)g3,(void*)h3,(void*)i3,j3,(void*)k3,l3,(void*)m3 n3;\
+  MENUITEMINFOA *info2 = &info2A;\
+  MENUITEMINFOA *einfo = &einfoA;\
+  MENUITEMINFOW *info2W = (MENUITEMINFOW *)&info2A;\
+  if( !stop) {\
+    ret = ansi ? GetMenuItemInfoA( hmenu, 0, TRUE, info2 ) :\
+        GetMenuItemInfoW( hmenu, 0, TRUE, info2W );\
+    if( !(eret2)) ok( (eret2)==ret,"GetMenuItemInfo should have failed.\n");\
+    else { \
+      ok( (eret2)==ret,"GetMenuItemInfo failed, err %ld\n",GetLastError());\
+      ret = memcmp( info2, einfo, sizeof einfoA);\
+    /*  ok( ret==0, "Got wrong menu item info data\n");*/\
+      if( ret) DUMPMIINF(info2A.cbSize, &info2A, &einfoA)\
+      if( einfo->dwTypeData == string) {\
+        if(ansi) ok( !strncmp( expname, info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
+            einfo->dwTypeData ? einfo->dwTypeData: "");\
+        else ok( !strncmpW( (WCHAR*)expname, (WCHAR*)info2->dwTypeData, einfo->cch ), "menu item name differed \"%s\"\n",\
+            einfo->dwTypeData ? einfo->dwTypeData: "");\
+        ret = ansi ? GetMenuStringA( hmenu, 0, string, 80, MF_BYPOSITION) :\
+            GetMenuStringW( hmenu, 0, string, 80, MF_BYPOSITION);\
+        if( (eret3)){\
+            ok( ret, "GetMenuString failed, err %ld\n",GetLastError());\
+        }else\
+            ok( !ret, "GetMenuString should have failed\n");\
+      }\
+    }\
+  }\
+}
+
+#define TMII_DONE \
+    RemoveMenu(hmenu, 0, TRUE );\
+    DestroyMenu( hmenu );\
+    DestroyMenu( submenu );\
+submenu = CreateMenu();\
+}
+/* modify menu */
+#define TMII_MODM( flags, id, data, eret  )\
+if( !stop) {\
+    if(ansi)ret = ModifyMenuA( hmenu, 0, flags, (UINT_PTR)id, (char*)data);\
+    else ret = ModifyMenuW( hmenu, 0, flags, (UINT_PTR)id, (WCHAR*)data);\
+    if( !(eret)) ok( (eret)==ret,"ModifyMenuA should have failed.\n");\
+    else  ok( (eret)==ret,"ModifyMenuA failed, err %ld\n",GetLastError());\
+}
+
+/* SetMenuItemInfo */
+#define TMII_SMII( a1,b1,c1,d1,e1,f1,g1,h1,i1,j1,k1,l1,m1,n1,\
+    eret1)\
+if( !stop) {\
+    MENUITEMINFOA info1=a1 b1,c1,d1,e1,f1,(void*)g1,(void*)h1,(void*)i1,j1,(void*)k1,l1,(void*)m1 n1;\
+    SetLastError( 0xdeadbeef);\
+    if(ansi)strcpy( string, init);\
+    else strcpyW( (WCHAR*)string, (WCHAR*)init);\
+    if( ansi) ret = SetMenuItemInfoA(hmenu, 0, TRUE, &info1 );\
+    else ret = SetMenuItemInfoW(hmenu, 0, TRUE, (MENUITEMINFOW*)&info1 );\
+    if( !(eret1)) { ok( (eret1)==ret,"InsertMenuItem should have failed.\n");\
+        stop = TRUE;\
+    } else ok( (eret1)==ret,"InsertMenuItem failed, err %ld\n",GetLastError());\
+}
+
+
+
+#define OK 1
+#define ER 0
+
+
+static void test_menu_iteminfo(  )
+{
+  int S=sizeof( MENUITEMINFOA);
+  int ansi = TRUE;
+  char txtA[]="wine";
+  char initA[]="XYZ";
+  char emptyA[]="";
+  WCHAR txtW[]={'W','i','n','e',0};
+  WCHAR initW[]={'X','Y','Z',0};
+  WCHAR emptyW[]={0};
+  void *txt, *init, *empty, *string;
+  HBITMAP hbm = CreateBitmap(1,1,1,1,NULL);
+  char stringA[0x80];
+  HMENU submenu=CreateMenu();
+
+  do {
+    if( ansi) {txt=txtA;init=initA;empty=emptyA;string=stringA;}
+    else {txt=txtW;init=initW;empty=emptyW;string=stringA;}
+    trace( "%s string %p hbm %p txt %p\n", ansi ?  "ANSI tests:   " : "Unicode tests:", string, hbm, txt);
+    /* test all combinations of MFT_STRING, MFT_OWNERDRAW and MFT_BITMAP */
+    /* (since MFT_STRING is zero, there are four of them) */
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, 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_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
+        txt, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
+        empty, OK, ER )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
+        empty, OK, ER )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
+        empty, OK, ER )
+    TMII_DONE
+    /* not enough space for name*/
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
+        {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, NULL, 4, 0, },
+        empty, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 5, -9, },
+        {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
+        txt, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 4, -9, },
+        {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 3, 0, },
+        txt, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, NULL, 0, -9, },
+        {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 0, 0, },
+        empty, OK, ER )
+    TMII_DONE
+    /* can not combine MIIM_TYPE with some other flags */
+    TMII_INSMI( {, S, MIIM_TYPE|MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
+    TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
+        {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
+        empty, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE|MIIM_STRING, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
+        empty, ER, OK )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, ER)
+    TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
+        {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
+        empty, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
+        empty, ER, OK )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE|MIIM_BITMAP, MFT_BITMAP, -1, -1, -1, -1, -1, -1, hbm, 6, hbm, }, ER)
+    TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
+        {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
+        empty, OK, OK )
+    TMII_DONE
+        /* but succeeds with some others */
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE|MIIM_SUBMENU, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
+        txt, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE|MIIM_STATE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE|MIIM_STATE, MFT_STRING, 0, -9, 0, -9, -9, -9, string, 4, 0, },
+        txt, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -1, 888, -1, -1, -1, -1, txt, 6, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE|MIIM_ID, MFT_STRING, -9, 888, 0, -9, -9, -9, string, 4, 0, },
+        txt, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -1, -1, -1, -1, -1, 999, txt, 6, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING, -9, -9, 0, -9, -9, 999, string, 4, 0, },
+        txt, OK, OK )
+    TMII_DONE
+    /* to be continued */
+    /* set text with MIIM_TYPE and retrieve with MIIM_STRING */ 
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, -9, },
+        txt, OK, OK )
+    TMII_DONE
+    /* set text with MIIM_TYPE and retrieve with MIIM_STRING; MFT_OWNERDRAW causes an empty string */ 
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
+        empty, OK, ER )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
+        empty, OK, ER )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, -9, },
+        init, OK, ER )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
+    TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, 0, -9, -9, -9, 0, -9, -9, -9, string, 80, -9, },
+        init, OK, OK )
+    TMII_DONE
+    /* contrary to MIIM_TYPE,you can set the text for an owner draw menu */ 
+    TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
+        txt, OK, OK )
+    TMII_DONE
+    /* same but retrieve with MIIM_TYPE */ 
+    TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
+        txt, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 0, -9, },
+        empty, OK, ER )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING, -1, -1, -1, -1, -1, -1, NULL, 0, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_STRING|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
+        empty, OK, ER )
+    TMII_DONE
+
+    /* How is that with bitmaps? */ 
+    TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
+        empty, OK, ER )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
+    TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_BITMAP|MIIM_FTYPE, 0, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
+        init, OK, ER )
+    TMII_DONE
+        /* MIIM_BITMAP does not like MFT_BITMAP */
+    TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, ER)
+    TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
+        {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
+        init, OK, OK )
+    TMII_DONE
+        /* no problem with OWNERDRAWN */
+    TMII_INSMI( {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
+    TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 80, hbm, },
+        init, OK, ER )
+    TMII_DONE
+        /* setting MFT_BITMAP with MFT_FTYPE fails anyway */
+    TMII_INSMI( {, S, MIIM_FTYPE, MFT_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, ER)
+    TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
+        {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
+        empty, OK, OK )
+    TMII_DONE
+
+    /* menu with submenu */
+    TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
+        init, OK, ER )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, empty, 0, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_SUBMENU, -9, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
+        init, OK, ER )
+    TMII_DONE
+    /* menu with submenu, without MIIM_SUBMENU the submenufield is cleared */
+    TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, submenu, -1, -1, -1, txt, 0, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_STRING|MIIM_FTYPE, MFT_STRING|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 0, -9, },
+        empty, OK, ER )
+    TMII_GMII ( {, S, MIIM_SUBMENU|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, submenu, -9, -9, -9, string, 80, -9, },
+        empty, OK, ER )
+    TMII_DONE
+    /* menu with invalid submenu */
+    TMII_INSMI( {, S, MIIM_SUBMENU|MIIM_FTYPE, MFT_STRING, -1, -1, 999, -1, -1, -1, txt, 0, -1, }, ER)
+    TMII_GMII ( {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
+        {, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, },
+        init, OK, ER )
+    TMII_DONE
+ 
+    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, },
+        empty, OK, ER )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, hbm, 6, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_BITMAP|MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, hbm, 0, hbm, },
+        empty, OK, ER )
+    TMII_DONE
+     /* SEPARATOR and STRING go well together */
+    /* BITMAP and STRING go well together */
+    TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
+    TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
+        txt, OK, OK )
+    TMII_DONE
+     /* BITMAP, SEPARATOR and STRING go well together */
+    TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
+    TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 4, hbm, },
+        txt, OK, OK )
+    TMII_DONE
+     /* last two tests, but use MIIM_TYPE to retrieve info */
+    TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, 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, NULL, 4, NULL, },
+        txt, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
+        txt, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
+        txt, OK, OK )
+    TMII_DONE
+     /* same three with MFT_OWNERDRAW */
+    TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
+        txt, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
+        txt, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_BITMAP|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, hbm, 4, hbm, },
+        txt, OK, OK )
+    TMII_DONE
+
+    TMII_INSMI( {, S, MIIM_STRING|MIIM_FTYPE|MIIM_ID, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
+        txt,  OK, OK )
+    TMII_DONE
+    /* test with modifymenu: string is preserved after seting OWNERDRAW */
+    TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
+    TMII_MODM( MFT_OWNERDRAW, -1, 787, OK)
+    TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_FTYPE|MIIM_STRING|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 787, string, 4, -9, },
+        txt,  OK, OK )
+    TMII_DONE
+    /* same with bitmap: now the text is cleared */
+    TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
+    TMII_MODM( MFT_BITMAP, 545, hbm, OK)
+    TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_BITMAP, -9, 545, 0, -9, -9, -9, string, 0, hbm, },
+        empty,  OK, ER )
+    TMII_DONE
+    /* start with bitmap: now setting text clears it (though he flag is raised) */
+    TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
+    TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 0, 0, -9, -9, -9, string, 0, hbm, },
+        empty,  OK, ER )
+    TMII_MODM( MFT_STRING, 545, txt, OK)
+    TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 4, 0, },
+        txt,  OK, OK )
+    TMII_DONE
+    /*repeat with text NULL */
+    TMII_INSMI( {, S, MIIM_BITMAP, MFT_STRING, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
+    TMII_MODM( MFT_STRING, 545, NULL, OK)
+    TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_SEPARATOR, -9, 545, 0, -9, -9, -9, string, 0, 0, },
+        empty,  OK, ER )
+    TMII_DONE
+    /* repeat with text "" */
+    TMII_INSMI( {, S, MIIM_BITMAP, -1 , -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
+    TMII_MODM( MFT_STRING, 545, empty, OK)
+    TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_ID, MFT_STRING, -9, 545, 0, -9, -9, -9, string, 0, 0, },
+        empty,  OK, ER )
+    TMII_DONE
+    /* start with bitmap: set ownerdraw */
+    TMII_INSMI( {, S, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
+    TMII_MODM( MFT_OWNERDRAW, -1, 232, OK)
+    TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP|MIIM_DATA, MFT_OWNERDRAW, -9, -9, 0, -9, -9, 232, string, 0, hbm, },
+        empty,  OK, ER )
+    TMII_DONE
+    /* ask nothing */
+    TMII_INSMI( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
+    TMII_GMII ( {, S, 0, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+                {, S, 0, -9, -9, -9,  0, -9, -9, -9, string, 80, -9, },
+        init, OK, OK )
+    TMII_DONE
+    /* some tests with small cbSize: the hbmpItem is to be ignored */ 
+    TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, 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, NULL, 0, NULL, },
+        empty, OK, ER )
+    TMII_DONE
+    TMII_INSMI( {, S - 4, MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, -1, -1, hbm, }, OK)
+    TMII_GMII ( {, S, MIIM_BITMAP|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_BITMAP|MIIM_FTYPE, MFT_SEPARATOR, -9, -9, 0, -9, -9, -9, string, 80, NULL, },
+        init, OK, ER )
+    TMII_DONE
+    TMII_INSMI( {, S - 4, MIIM_STRING|MIIM_BITMAP, -1, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, NULL, },
+        txt, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, 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, NULL, 4, NULL, },
+        txt, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
+        txt, OK, OK )
+    TMII_DONE
+    TMII_INSMI( {, S - 4, MIIM_FTYPE|MIIM_STRING|MIIM_BITMAP, MFT_SEPARATOR|MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, txt, 6, hbm, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_SEPARATOR|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, NULL, 4, NULL, },
+        txt, OK, OK )
+    TMII_DONE
+    /* MIIM_TYPE by itself does not get/set the dwItemData for OwnerDrawn menus  */
+    TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 343, 0, 0, 0, },
+        empty, OK, ER )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, 0, 0, 0, },
+        empty, OK, ER )
+    TMII_DONE
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING|MFT_OWNERDRAW, -1, -1, -1, -1, -1, 343, txt, 0, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_TYPE|MIIM_DATA, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE|MIIM_DATA, MFT_STRING|MFT_OWNERDRAW, -9, -9, 0, -9, -9, 0, 0, 0, 0, },
+        empty, OK, ER )
+    TMII_DONE
+    /* set a string menu to ownerdraw with MIIM_TYPE */
+    TMII_INSMI( {, S, MIIM_TYPE, MFT_STRING, -2, -2, -2, -2, -2, -2, txt, -2, -2, }, OK)
+    TMII_SMII( {, S, MIIM_TYPE, MFT_OWNERDRAW, -1, -1, -1, -1, -1, -1, -1, -1, -1, }, OK)
+    TMII_GMII ( {, S, MIIM_STRING|MIIM_FTYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_STRING|MIIM_FTYPE, MFT_OWNERDRAW, -9, -9, 0, -9, -9, -9, string, 4, -9, },
+        txt, OK, OK )
+    TMII_DONE
+    /* test with modifymenu add submenu */
+    TMII_INSMI( {, S, MIIM_STRING, MFT_STRING, -1, -1, -1, -1, -1, -1, txt, 0, -1, }, OK)
+    TMII_MODM( MF_POPUP, submenu, txt, OK)
+    TMII_GMII ( {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_FTYPE|MIIM_STRING|MIIM_SUBMENU, MFT_STRING, -9, -9, submenu, -9, -9, -9, string, 4, -9, },
+        txt,  OK, OK )
+    TMII_GMII ( {, S, MIIM_TYPE, -9, -9, -9, -9, -9, -9, -9, string, 80, -9, },
+        {, S, MIIM_TYPE, MFT_STRING, -9, -9, 0, -9, -9, -9, string, 4, 0, },
+        txt,  OK, OK )
+    TMII_DONE
+
+    ansi = !ansi;
+  } while( !ansi);
+  DeleteObject( hbm);
+}
 
 START_TEST(menu)
 {
@@ -290,4 +881,5 @@ START_TEST(menu)
     test_menu_locked_by_window();
     test_menu_ownerdraw();
     test_menu_add_string();
+    test_menu_iteminfo();
 }


More information about the wine-patches mailing list