user32: Separate menu bitmaps and strings.
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.
diff --git a/dlls/user/menu.c b/dlls/user/menu.c
index e470c19..a6e5742 100644
--- a/dlls/user/menu.c
+++ b/dlls/user/menu.c
@@ -72,10 +72,10 @@
     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 @@
   ((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 @@
 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 @@
 
 	     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 @@
  *           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 @@
     /* 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 @@
 
     if (!menuBar)
     {
-	/* New style MIIM_BITMAP */
 	if (lpitem->hbmpItem) 
 	{
 	    if (lpitem->hbmpItem == HBMMENU_CALLBACK)
@@ -927,13 +924,11 @@
 	    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 @@
         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 @@
         {
             RECT rc;
             rc = rect;
-            /* New style MIIM_BITMAP */
             if (lpitem->hbmpItem)
             {
                 POPUPMENU *menu = MENU_GetMenu(hmenu);
@@ -1342,7 +1335,6 @@
                 DeleteDC( hdcMem );
                 DeleteObject( bm );
             }
-            /* New style MIIM_BITMAP */
             if (lpitem->hbmpItem)
             {
                 HBITMAP hbm = lpitem->hbmpItem;
@@ -1371,7 +1363,7 @@
                     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 @@
 	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 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 @@
             strcpyW( text, str );
             item->text = text;
         }
+        item->hbmpItem = NULL;
+        HeapFree( GetProcessHeap(), 0, prevText );
     }
-    else if (IS_BITMAP_ITEM(flags))
-        item->text = (LPWSTR)HBITMAP_32(LOWORD(str));
-    else item->text = NULL;
+    else if(( flags & MFT_BITMAP)) {
+        item->hbmpItem = HBITMAP_32(LOWORD(str));
+        /* setting bitmap clears text */
+        HeapFree( GetProcessHeap(), 0, item->text );
+        item->text = NULL;
+    }
 
     if (flags & MF_OWNERDRAW)
         item->dwItemData = (DWORD_PTR)str;
@@ -1808,12 +1800,8 @@
     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 @@
 
     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 @@
 
     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 @@
 
     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->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)
-                lstrcpynW(lpmii->dwTypeData, menu->text, lpmii->cch);
+                if (lpmii->cch <= len + 1)
+                    lpmii->cch--;
+                else
+                    lpmii->cch = len;
+            else /* return length of string */
+                lpmii->cch = len;
         }
-        else
-        {
-            len = WideCharToMultiByte( CP_ACP, 0, menu->text, -1, NULL, 0, NULL, NULL );
-            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--;
-        }
-        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 @@
 
     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 @@
 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 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 @@
 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 @@
     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 @@
 		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 @@
     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 @@
 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 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 @@
                                 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 @@
                                 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);
 }
 
 /**********************************************************************
diff --git a/dlls/user/tests/menu.c b/dlls/user/tests/menu.c
index 9c6b17c..b4e9830 100644
--- a/dlls/user/tests/menu.c
+++ b/dlls/user/tests/menu.c
@@ -253,9 +253,17 @@
 
 static void test_menu_add_string( void )
 {
-    MENUITEMINFO info;
-    char string[0x80];
     HMENU hmenu;
+    MENUITEMINFO info;
+    BOOL rc;
+    
+    char string[0x80];
+    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 +287,591 @@
 
     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 +880,5 @@
     test_menu_locked_by_window();
     test_menu_ownerdraw();
     test_menu_add_string();
+    test_menu_iteminfo();
 }