Fix the USER32 DLL initialization and cleanup routines to prevent memory/resource...
[reactos.git] / reactos / lib / user32 / windows / menu.c
index b8c5f8a..65d1749 100644 (file)
@@ -21,7 +21,7 @@
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-/* $Id: menu.c,v 1.54 2004/03/10 20:36:19 silverblade Exp $
+/* $Id$
  *
  * PROJECT:         ReactOS user32.dll
  * FILE:            lib/user32/windows/menu.c
 
 /* INCLUDES ******************************************************************/
 
-#define __NTAPP__
-
-#include <windows.h>
 #include <user32.h>
-#include <string.h>
-#include <draw.h>
-#include <window.h>
-#include <strpool.h>
-#include <ntos/rtl.h>
-
-#include <user32/callback.h>
-#include "user32/regcontrol.h"
-#include "../controls/controls.h"
-
 #define NDEBUG
 #include <debug.h>
 
@@ -73,7 +60,9 @@
 
 #define IS_SYSTEM_POPUP(MenuInfo) \
        (0 != ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
-  
+
+#define IS_MAGIC_ITEM(Bmp)   ((int) Bmp <12)
+
 #define MENU_BAR_ITEMS_SPACE (12)
 #define SEPARATOR_HEIGHT (5)
 #define MENU_TAB_SPACE (8)
@@ -117,19 +106,19 @@ static LRESULT WINAPI PopupMenuWndProcW(HWND hwnd, UINT message, WPARAM wParam,
 const struct builtin_class_descr POPUPMENU_builtin_class =
 {
     POPUPMENU_CLASS_ATOMW,                     /* name */
-    CS_GLOBALCLASS | CS_SAVEBITS | CS_DBLCLKS, /* style  */
+    CS_SAVEBITS | CS_DBLCLKS,                  /* style  */
     (WNDPROC) PopupMenuWndProcW,               /* FIXME - procW */
     (WNDPROC) NULL,                            /* FIXME - procA */
     sizeof(MENUINFO *),                        /* extra */
-    (LPCWSTR) IDC_ARROW,                        /* cursor */
-    (HBRUSH)(COLOR_MENU + 1)                    /* brush */
+    (LPCWSTR) IDC_ARROW,                       /* cursor */
+    (HBRUSH)(COLOR_MENU + 1)                   /* brush */
 };
 
 
 /* INTERNAL FUNCTIONS ********************************************************/
 
-/* Rip the fun and easy to use and fun WINE unicode string manipulation routines. 
- * Of course I didnt copy the ASM code because we want this to be portable 
+/* Rip the fun and easy to use and fun WINE unicode string manipulation routines.
+ * Of course I didnt copy the ASM code because we want this to be portable
  * and it needs to go away.
  */
 
@@ -151,8 +140,10 @@ static BOOL fEndMenu = FALSE;
 static HWND TopPopup;
 
 /* Dimension of the menu bitmaps */
-static WORD ArrowBitmapWidth = 0/*, ArrowBitmapHeight = 0*/;
+static WORD ArrowBitmapWidth = 0, ArrowBitmapHeight = 0;
 
+static HBITMAP StdMnArrow = NULL;
+static HBITMAP BmpSysMenu = NULL;
 
 /***********************************************************************
  *           MenuGetRosMenuInfo
@@ -164,7 +155,7 @@ MenuGetRosMenuInfo(PROSMENUINFO MenuInfo, HMENU Menu)
 {
   MenuInfo->cbSize = sizeof(ROSMENUINFO);
   MenuInfo->fMask = MIM_BACKGROUND | MIM_HELPID | MIM_MAXHEIGHT | MIM_MENUDATA | MIM_STYLE;
-  
+
   return NtUserMenuInfo(Menu, MenuInfo, FALSE);
 }
 
@@ -178,7 +169,7 @@ MenuSetRosMenuInfo(PROSMENUINFO MenuInfo)
 {
   MenuInfo->cbSize = sizeof(ROSMENUINFO);
   MenuInfo->fMask = MIM_BACKGROUND | MIM_HELPID | MIM_MAXHEIGHT | MIM_MENUDATA | MIM_STYLE;
-  
+
   return NtUserMenuInfo(MenuInfo->Self, MenuInfo, TRUE);
 }
 
@@ -199,87 +190,38 @@ MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
  *
  * Get full information about a menu item
  */
-#define INITIAL_STRING_SIZE 32 /* in WCHARs */
 static BOOL FASTCALL
 MenuGetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo)
 {
-  UNICODE_STRING Text;
-
-  if (MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType) && NULL != ItemInfo->dwTypeData)
+  if (ItemInfo->dwTypeData != NULL)
     {
-      /* There's already a buffer allocated */
-      Text.Buffer = ItemInfo->dwTypeData;
-      Text.Length = ItemInfo->cch * sizeof(WCHAR);
-      Text.MaximumLength = (ItemInfo->cch < INITIAL_STRING_SIZE ? INITIAL_STRING_SIZE
-                            : ItemInfo->cch + 1) * sizeof(WCHAR);
-    }
-  else
-    {
-      Text.Buffer = HeapAlloc(GetProcessHeap(), 0, INITIAL_STRING_SIZE * sizeof(WCHAR));
-      if (NULL == Text.Buffer)
-        {
-          return FALSE;
-        }
-      Text.Length = 0;
-      Text.MaximumLength = INITIAL_STRING_SIZE * sizeof(WCHAR);
-      ItemInfo->cch = INITIAL_STRING_SIZE - 1;
+      HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData);
     }
-  ItemInfo->dwTypeData = (LPWSTR) &Text;
 
   ItemInfo->fMask = MIIM_BITMAP | MIIM_CHECKMARKS | MIIM_DATA | MIIM_FTYPE
                     | MIIM_ID | MIIM_STATE | MIIM_STRING | MIIM_SUBMENU | MIIM_TYPE;
+  ItemInfo->dwTypeData = NULL;
 
   if (! NtUserMenuItemInfo(Menu, Index, TRUE, ItemInfo, FALSE))
     {
-      if (NULL != Text.Buffer)
-        {
-          HeapFree(GetProcessHeap(), 0, Text.Buffer);
-          ItemInfo->dwTypeData = NULL;
-          ItemInfo->cch = 0;
-        }
       ItemInfo->fType = 0;
       return FALSE;
     }
 
-  if (MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType))
+  if (MENU_ITEM_TYPE(ItemInfo->fType) == MF_STRING)
     {
-      /* We have a string... */
-      if (Text.MaximumLength < (ItemInfo->cch + 1) * sizeof(WCHAR))
+      ItemInfo->cch++;
+      ItemInfo->dwTypeData = HeapAlloc(GetProcessHeap(), 0,
+                                       ItemInfo->cch * sizeof(WCHAR));
+      if (NULL == ItemInfo->dwTypeData)
         {
-          /* ...but we didn't allocate enough memory. Let's try again */
-          HeapFree(GetProcessHeap(), 0, Text.Buffer);
-          Text.Buffer = HeapAlloc(GetProcessHeap(), 0, (ItemInfo->cch + 1) * sizeof(WCHAR));
-          if (NULL == Text.Buffer)
-            {
-              ItemInfo->dwTypeData = NULL;
-              ItemInfo->cch = 0;
-              return FALSE;
-            }
-          Text.Length = (ItemInfo->cch + 1) * sizeof(WCHAR);
-          Text.MaximumLength = (ItemInfo->cch + 1) * sizeof(WCHAR);
-          ItemInfo->cch++;
-          if (! NtUserMenuItemInfo(Menu, Index, TRUE, ItemInfo, FALSE))
-            {
-              HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData);
-              ItemInfo->dwTypeData = NULL;
-              ItemInfo->cch = 0;
-              ItemInfo->fType = 0;
-            }
+          return FALSE;
         }
-    }
 
-  if (MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType))
-    {
-      ItemInfo->dwTypeData = Text.Buffer;
-      ItemInfo->cch = Text.Length / sizeof(WCHAR);
-      Text.Buffer[ItemInfo->cch] = L'\0';
-    }
-  else
-    {
-      /* Not a string, clean up the buffer */
-      if (NULL != Text.Buffer)
+      if (! NtUserMenuItemInfo(Menu, Index, TRUE, ItemInfo, FALSE))
         {
-          HeapFree(GetProcessHeap(), 0, Text.Buffer);
+          ItemInfo->fType = 0;
+          return FALSE;
         }
     }
 
@@ -294,27 +236,18 @@ MenuGetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo)
 static BOOL FASTCALL
 MenuSetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo)
 {
-  UNICODE_STRING Text;
-  BOOL StringVal;
   BOOL Ret;
 
-  StringVal = (MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType) && NULL != ItemInfo->dwTypeData);
-  if (StringVal)
-    {
-      Text.Buffer = ItemInfo->dwTypeData;
-      Text.Length = wcslen(Text.Buffer) * sizeof(WCHAR);
-      Text.MaximumLength = Text.Length + sizeof(WCHAR);
-      ItemInfo->dwTypeData = (LPWSTR) &Text;
-    }
+  if (MENU_ITEM_TYPE(ItemInfo->fType) == MF_STRING &&
+      ItemInfo->dwTypeData != NULL)
+  {
+    ItemInfo->cch = wcslen(ItemInfo->dwTypeData);
+  }
   ItemInfo->fMask = MIIM_BITMAP | MIIM_CHECKMARKS | MIIM_DATA | MIIM_FTYPE
                     | MIIM_ID | MIIM_STATE | MIIM_STRING | MIIM_SUBMENU | MIIM_TYPE;
-  
-  Ret = NtUserMenuItemInfo(Menu, Index, TRUE, ItemInfo, TRUE);
 
-  if (StringVal)
-    {
-      ItemInfo->dwTypeData = Text.Buffer;
-    }
+
+  Ret = NtUserMenuItemInfo(Menu, Index, TRUE, ItemInfo, TRUE);
 
   return Ret;
 }
@@ -327,11 +260,9 @@ MenuSetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo)
 static VOID FASTCALL
 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
 {
-  if (MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType) && NULL != ItemInfo->dwTypeData)
+  if (ItemInfo->dwTypeData != NULL)
     {
       HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData);
-      ItemInfo->dwTypeData = NULL;
-      ItemInfo->cch = 0;
     }
 }
 
@@ -370,6 +301,192 @@ MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo)
   HeapFree(GetProcessHeap(), 0, ItemInfo);
 }
 
+
+/***********************************************************************
+ *           MenuLoadBitmaps
+ *
+ * Load the arrow bitmap. We can't do this from MenuInit since user32
+ * can also be used (and thus initialized) from text-mode.
+ */
+static void FASTCALL
+MenuLoadBitmaps(VOID)
+{
+  /* Load menu bitmaps */
+  if (NULL == StdMnArrow)
+    {
+      StdMnArrow = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW));
+
+      if (NULL != StdMnArrow)
+        {
+          BITMAP bm;
+          GetObjectW(StdMnArrow, sizeof(BITMAP), &bm);
+          ArrowBitmapWidth = bm.bmWidth;
+          ArrowBitmapHeight = bm.bmHeight;
+        }
+    }
+
+  /* Load system buttons bitmaps */
+  if (NULL == BmpSysMenu)
+    {
+      BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
+    }
+}
+
+/***********************************************************************
+ *           MenuGetBitmapItemSize
+ *
+ * Get the size of a bitmap item.
+ */
+static void FASTCALL
+MenuGetBitmapItemSize(UINT Id, DWORD Data, SIZE *Size)
+{
+  BITMAP Bm;
+  HBITMAP Bmp = (HBITMAP) Id;
+
+  Size->cx = Size->cy = 0;
+
+  /* check if there is a magic menu item associated with this item */
+  if (0 != Id && IS_MAGIC_ITEM(Id))
+    {
+      switch((INT_PTR) LOWORD(Id))
+        {
+          case (INT_PTR) HBMMENU_SYSTEM:
+            if (0 != Data)
+              {
+                Bmp = (HBITMAP) Data;
+                break;
+              }
+            /* fall through */
+          case (INT_PTR) HBMMENU_MBAR_RESTORE:
+          case (INT_PTR) HBMMENU_MBAR_MINIMIZE:
+          case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D:
+          case (INT_PTR) HBMMENU_MBAR_CLOSE:
+          case (INT_PTR) HBMMENU_MBAR_CLOSE_D:
+            /* FIXME: Why we need to subtract these magic values? */
+            Size->cx = GetSystemMetrics(SM_CXSIZE) - 2;
+            Size->cy = GetSystemMetrics(SM_CYSIZE) - 4;
+            return;
+          case (INT_PTR) HBMMENU_CALLBACK:
+          case (INT_PTR) HBMMENU_POPUP_CLOSE:
+          case (INT_PTR) HBMMENU_POPUP_RESTORE:
+          case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
+          case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
+          default:
+            DPRINT("Magic menu bitmap not implemented\n");
+            return;
+        }
+    }
+
+  if (GetObjectW(Bmp, sizeof(BITMAP), &Bm))
+    {
+      Size->cx = Bm.bmWidth;
+      Size->cy = Bm.bmHeight;
+    }
+}
+
+/***********************************************************************
+ *           MenuDrawBitmapItem
+ *
+ * Draw a bitmap item.
+ */
+static void FASTCALL
+MenuDrawBitmapItem(HDC Dc, PROSMENUITEMINFO Item, const RECT *Rect, BOOL MenuBar)
+{
+  BITMAP Bm;
+  DWORD Rop;
+  HDC DcMem;
+  HBITMAP Bmp = (HBITMAP) Item->hbmpItem;
+  int w = Rect->right - Rect->left;
+  int h = Rect->bottom - Rect->top;
+  int BmpXoffset = 0;
+  int Left, Top;
+
+  /* Check if there is a magic menu item associated with this item */
+  if (IS_MAGIC_ITEM(Item->hbmpItem))
+    {
+      UINT Flags = 0;
+      RECT r;
+
+      r = *Rect;
+      switch ((int) Item->hbmpItem)
+        {
+          case (INT_PTR) HBMMENU_SYSTEM:
+            if (NULL != Item->hbmpItem)
+              {
+                Bmp = Item->hbmpItem;
+                if (! GetObjectW(Bmp, sizeof(BITMAP), &Bm))
+                  {
+                    return;
+                  }
+              }
+            else
+              {
+                Bmp = BmpSysMenu;
+                if (! GetObjectW(Bmp, sizeof(BITMAP), &Bm))
+                  {
+                    return;
+                  }
+                /* only use right half of the bitmap */
+                BmpXoffset = Bm.bmWidth / 2;
+                Bm.bmWidth -= BmpXoffset;
+              }
+            goto got_bitmap;
+          case (INT_PTR) HBMMENU_MBAR_RESTORE:
+            Flags = DFCS_CAPTIONRESTORE;
+            break;
+          case (INT_PTR) HBMMENU_MBAR_MINIMIZE:
+            r.right += 1;
+            Flags = DFCS_CAPTIONMIN;
+            break;
+          case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D:
+            r.right += 1;
+            Flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
+            break;
+          case (INT_PTR) HBMMENU_MBAR_CLOSE:
+            Flags = DFCS_CAPTIONCLOSE;
+            break;
+          case (INT_PTR) HBMMENU_MBAR_CLOSE_D:
+            Flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
+            break;
+          case (INT_PTR) HBMMENU_CALLBACK:
+          case (INT_PTR) HBMMENU_POPUP_CLOSE:
+          case (INT_PTR) HBMMENU_POPUP_RESTORE:
+          case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
+          case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
+          default:
+            DPRINT("Magic menu bitmap not implemented\n");
+            return;
+        }
+      InflateRect(&r, -1, -1);
+      if (0 != (Item->fState & MF_HILITE))
+        {
+          Flags |= DFCS_PUSHED;
+        }
+      DrawFrameControl(Dc, &r, DFC_CAPTION, Flags);
+      return;
+    }
+
+  if (NULL == Bmp || ! GetObjectW(Bmp, sizeof(BITMAP), &Bm))
+    {
+      return;
+    }
+
+got_bitmap:
+  DcMem = CreateCompatibleDC(Dc);
+  SelectObject(DcMem, Bmp);
+
+  /* handle fontsize > bitmap_height */
+  Top = (Bm.bmHeight < h) ? Rect->top + (h - Bm.bmHeight) / 2 : Rect->top;
+  Left = Rect->left;
+  Rop = (0 != (Item->fState & MF_HILITE) && ! IS_MAGIC_ITEM(Item->hbmpItem)) ? NOTSRCCOPY : SRCCOPY;
+  if (0 != (Item->fState & MF_HILITE) && IS_BITMAP_ITEM(Item->fType))
+    {
+      SetBkColor(Dc, GetSysColor(COLOR_HIGHLIGHT));
+    }
+  BitBlt(Dc, Left, Top, w, h, DcMem, BmpXoffset, 0, Rop);
+  DeleteDC(DcMem);
+}
+
 /***********************************************************************
  *           MenuDrawMenuItem
  *
@@ -384,22 +501,51 @@ MenuDrawMenuItem(HWND Wnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC Dc,
 
   if (0 != (Item->fType & MF_SYSMENU))
     {
-#if 0 /* FIXME */
-       if( !IsIconic(hwnd) ) {
-           if (TWEAK_WineLook > WIN31_LOOK)
-               NC_DrawSysButton95( hwnd, hdc,
-                                   lpitem->fState &
-                                   (MF_HILITE | MF_MOUSESELECT) );
-           else
-               NC_DrawSysButton( hwnd, hdc,
-                                 lpitem->fState &
-                                 (MF_HILITE | MF_MOUSESELECT) );
+      if (! IsIconic(Wnd))
+        {
+          UserGetInsideRectNC(Wnd, &Rect);
+          UserDrawSysMenuButton(Wnd, Dc, &Rect,
+                                Item->fState & (MF_HILITE | MF_MOUSESELECT));
        }
-#endif
 
       return;
     }
 
+  /* Setup colors */
+
+  if (0 != (Item->fState & MF_HILITE))
+    {
+      if (MenuBar)
+        {
+          SetTextColor(Dc, GetSysColor(COLOR_MENUTEXT));
+          SetBkColor(Dc, GetSysColor(COLOR_MENU));
+        }
+      else
+        {
+          if (0 != (Item->fState & MF_GRAYED))
+            {
+              SetTextColor(Dc, GetSysColor(COLOR_GRAYTEXT));
+            }
+          else
+            {
+              SetTextColor(Dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
+            }
+          SetBkColor(Dc, GetSysColor(COLOR_HIGHLIGHT));
+        }
+    }
+  else
+    {
+      if (0 != (Item->fState & MF_GRAYED))
+        {
+          SetTextColor(Dc, GetSysColor(COLOR_GRAYTEXT));
+        }
+      else
+        {
+          SetTextColor(Dc, GetSysColor(COLOR_MENUTEXT));
+        }
+      SetBkColor(Dc, GetSysColor(COLOR_MENU));
+    }
+
   if (0 != (Item->fType & MF_OWNERDRAW))
     {
       /*
@@ -435,7 +581,7 @@ MenuDrawMenuItem(HWND Wnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC Dc,
       dis.hDC        = Dc;
       dis.rcItem     = Item->Rect;
       DPRINT("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
-             "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hwndOwner,
+             "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", Wnd,
              dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
              dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
              dis.rcItem.bottom);
@@ -443,8 +589,8 @@ MenuDrawMenuItem(HWND Wnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC Dc,
       /* Fall through to draw popup-menu arrow */
     }
 
-  DPRINT("rect={%ld,%ld,%ld,%ld}\n", Item->rect.left, Item->rect.top,
-                                     Item->rect.right, Item->rect.bottom);
+  DPRINT("rect={%ld,%ld,%ld,%ld}\n", Item->Rect.left, Item->Rect.top,
+                                     Item->Rect.right, Item->Rect.bottom);
 
   if (MenuBar && 0 != (Item->fType & MF_SEPARATOR))
     {
@@ -498,41 +644,6 @@ MenuDrawMenuItem(HWND Wnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC Dc,
         }
     }
 
-  /* Setup colors */
-
-  if (0 != (Item->fState & MF_HILITE))
-    {
-      if (MenuBar)
-        {
-          SetTextColor(Dc, GetSysColor(COLOR_MENUTEXT));
-          SetBkColor(Dc, GetSysColor(COLOR_MENU));
-        }
-      else
-        {
-          if (0 != (Item->fState & MF_GRAYED))
-            {
-              SetTextColor(Dc, GetSysColor(COLOR_GRAYTEXT));
-            }
-          else
-            {
-              SetTextColor(Dc, GetSysColor(COLOR_HIGHLIGHTTEXT));
-            }
-          SetBkColor(Dc, GetSysColor(COLOR_HIGHLIGHT));
-        }
-    }
-  else
-    {
-      if (0 != (Item->fState & MF_GRAYED))
-        {
-          SetTextColor(Dc, GetSysColor(COLOR_GRAYTEXT));
-        }
-      else
-        {
-          SetTextColor(Dc, GetSysColor(COLOR_MENUTEXT));
-        }
-      SetBkColor(Dc, GetSysColor(COLOR_MENU));
-    }
-
 #if 0
   /* helper lines for debugging */
   FrameRect(Dc, &Rect, GetStockObject(BLACK_BRUSH));
@@ -554,8 +665,7 @@ MenuDrawMenuItem(HWND Wnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC Dc,
            * FIXME:
            * Custom checkmark bitmaps are monochrome but not always 1bpp.
            */
-#if 0 /* FIXME */
-          HBITMAP bm = 0 != (Item->fState & MF_CHECKED) ? Item->hCheckBit : Item->hUnCheckBit;
+          HBITMAP bm = 0 != (Item->fState & MF_CHECKED) ? Item->hbmpChecked : Item->hbmpUnchecked;
           if (NULL != bm)  /* we have a custom bitmap */
             {
               HDC DcMem = CreateCompatibleDC(Dc);
@@ -566,9 +676,6 @@ MenuDrawMenuItem(HWND Wnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC Dc,
               DeleteDC(DcMem);
             }
           else if (0 != (Item->fState & MF_CHECKED))  /* standard bitmaps */
-#else
-          if (0 != (Item->fState & MF_CHECKED))  /* standard bitmaps */
-#endif
             {
               RECT r;
               HBITMAP bm = CreateBitmap(CheckBitmapWidth, CheckBitmapHeight, 1, 1, NULL);
@@ -585,22 +692,20 @@ MenuDrawMenuItem(HWND Wnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC Dc,
             }
         }
 
-#if 0 /* FIXME */
-         /* Draw the popup-menu arrow */
-       if (lpitem->fType & MF_POPUP)
-       {
-           HDC hdcMem = CreateCompatibleDC( hdc );
-           HBITMAP hOrigBitmap;
-
-           hOrigBitmap = SelectObject( hdcMem, hStdMnArrow );
-           BitBlt( hdc, rect.right - arrow_bitmap_width - 1,
-                     (y - arrow_bitmap_height) / 2,
-                     arrow_bitmap_width, arrow_bitmap_height,
-                     hdcMem, 0, 0, SRCCOPY );
-            SelectObject( hdcMem, hOrigBitmap );
-           DeleteDC( hdcMem );
-       }
-#endif
+      /* Draw the popup-menu arrow */
+      if (0 != (Item->fType & MF_POPUP))
+        {
+          HDC DcMem = CreateCompatibleDC(Dc);
+          HBITMAP OrigBitmap;
+
+          OrigBitmap = SelectObject(DcMem, StdMnArrow);
+          BitBlt(Dc, Rect.right - ArrowBitmapWidth - 1,
+                 (y - ArrowBitmapHeight) / 2,
+                 ArrowBitmapWidth, ArrowBitmapHeight,
+                 DcMem, 0, 0, SRCCOPY);
+          SelectObject(DcMem, OrigBitmap);
+          DeleteDC(DcMem);
+        }
 
       Rect.left += CheckBitmapWidth;
       Rect.right -= ArrowBitmapWidth;
@@ -615,9 +720,7 @@ MenuDrawMenuItem(HWND Wnd, PROSMENUINFO MenuInfo, HWND WndOwner, HDC Dc,
   /* Draw the item text or bitmap */
   if (IS_BITMAP_ITEM(Item->fType))
     {
-#if 0 /* FIXME */
-      MENU_DrawBitmapItem( hdc, lpitem, &rect, menuBar );
-#endif
+      MenuDrawBitmapItem(Dc, Item, &Rect, MenuBar);
       return;
     }
   /* No bitmap - process text if present */
@@ -740,6 +843,8 @@ MenuDrawPopupMenu(HWND Wnd, HDC Dc, HMENU Menu)
                                       MenuInfo.Height, FALSE, ODA_DRAWENTIRE);
                     }
                 }
+
+             MenuCleanupRosMenuItemInfo(&ItemInfo);
            }
        }
       else
@@ -949,7 +1054,7 @@ BOOL
 MenuInit(VOID)
 {
   NONCLIENTMETRICSW ncm;
-  
+
   /* get the menu font */
   if(!hMenuFont || !hMenuFontBold)
   {
@@ -959,19 +1064,21 @@ MenuInit(VOID)
       DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
       return FALSE;
     }
-    
+
     hMenuFont = CreateFontIndirectW(&ncm.lfMenuFont);
     if(hMenuFont == NULL)
     {
       DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
       return FALSE;
     }
-    
+
     ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
     hMenuFontBold = CreateFontIndirectW(&ncm.lfMenuFont);
     if(hMenuFontBold == NULL)
     {
       DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
+      DeleteObject(hMenuFont);
+      hMenuFont = NULL;
       return FALSE;
     }
   }
@@ -980,6 +1087,24 @@ MenuInit(VOID)
 }
 
 
+VOID
+MenuCleanup(VOID)
+{
+  if (hMenuFont)
+  {
+    DeleteObject(hMenuFont);
+    hMenuFont = NULL;
+  }
+
+  if (hMenuFontBold)
+  {
+    DeleteObject(hMenuFontBold);
+    hMenuFontBold = NULL;
+  }
+}
+
+
+
 /***********************************************************************
  *           MenuCalcItemSize
  *
@@ -1055,17 +1180,20 @@ MenuCalcItemSize(HDC Dc, PROSMENUITEMINFO ItemInfo, HWND WndOwner,
 
   if (IS_BITMAP_ITEM(ItemInfo->fType))
     {
-#if 0 /* FIXME */
-      SIZE size;
+      SIZE Size;
 
-      MENU_GetBitmapItemSize( (int)lpitem->text, lpitem->dwItemData, &size );
-      lpitem->rect.right  += size.cx;
-      lpitem->rect.bottom += size.cy;
+      MenuGetBitmapItemSize((int) ItemInfo->hbmpItem, (DWORD) ItemInfo->hbmpItem, &Size);
+      ItemInfo->Rect.right  += Size.cx;
+      ItemInfo->Rect.bottom += Size.cy;
 
       /* Leave space for the sunken border */
-      lpitem->rect.right  += 2;
-      lpitem->rect.bottom += 2;
-#endif
+      ItemInfo->Rect.right  += 2;
+      ItemInfo->Rect.bottom += 2;
+
+      /* Special case: Minimize button doesn't have a space behind it. */
+      if (ItemInfo->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE ||
+          ItemInfo->hbmpItem == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D)
+        ItemInfo->Rect.right -= 1;
     }
 
   /* it must be a text item - unless it's the system menu */
@@ -1230,7 +1358,7 @@ MenuMenuBarCalcSize(HDC Dc, LPRECT Rect, PROSMENUINFO MenuInfo, HWND WndOwner)
     }
 
   DPRINT("left=%ld top=%ld right=%ld bottom=%ld\n",
-         Rrect->left, Rect->top, Rect->right, Rect->bottom);
+         Rect->left, Rect->top, Rect->right, Rect->bottom);
   MenuInfo->Width = Rect->right - Rect->left;
   MenuInfo->Height = 0;
   MaxY = Rect->top + 1;
@@ -1291,6 +1419,8 @@ MenuMenuBarCalcSize(HDC Dc, LPRECT Rect, PROSMENUINFO MenuInfo, HWND WndOwner)
             }
        }
 
+/* FIXME: Is this really needed? */
+#if 0
       /* Finish the line (set all items to the largest height found) */
       while (Start < i)
         {
@@ -1301,6 +1431,9 @@ MenuMenuBarCalcSize(HDC Dc, LPRECT Rect, PROSMENUINFO MenuInfo, HWND WndOwner)
             }
           Start++;
         }
+#else
+     Start = i;
+#endif
     }
 
   Rect->bottom = MaxY;
@@ -1443,10 +1576,7 @@ UINT MenuDrawMenuBar(HDC DC, LPRECT Rect, HWND Wnd, BOOL SuppressDraw)
     {
       FontOld = SelectObject(DC, hMenuFont);
 
-      if (0 == MenuInfo.Height)
-        {
-          MenuMenuBarCalcSize(DC, Rect, &MenuInfo, Wnd);
-        }
+      MenuMenuBarCalcSize(DC, Rect, &MenuInfo, Wnd);
 
       Rect->bottom = Rect->top + MenuInfo.Height;
 
@@ -1592,7 +1722,7 @@ MenuShowPopup(HWND WndOwner, HMENU Menu, UINT Id,
     }
 
   /* Display the window */
-  SetWindowPos(MenuInfo.Wnd, HWND_TOP, 0, 0, 0, 0,
+  SetWindowPos(MenuInfo.Wnd, HWND_TOPMOST, 0, 0, 0, 0,
                SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE);
   UpdateWindow(MenuInfo.Wnd);
 
@@ -1765,46 +1895,56 @@ MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset)
 {
   INT i;
   ROSMENUITEMINFO ItemInfo;
+  INT OrigPos;
+
+  DPRINT("hwnd=%x menu=%x off=0x%04x\n", WndOwner, MenuInfo, Offset);
 
-  DPRINT("hwnd=%x menu=%x off=0x%04x\n", WndOwner, MenuInfo, offset);
+  /* Prevent looping */
+  if (0 == MenuInfo->MenuItemCount || 0 == Offset)
+    return;
+  else if (Offset < -1)
+    Offset = -1;
+  else if (Offset > 1)
+    Offset = 1;
 
   MenuInitRosMenuItemInfo(&ItemInfo);
-  if (NO_SELECTED_ITEM != MenuInfo->FocusedItem)
+
+  OrigPos = MenuInfo->FocusedItem;
+  if (OrigPos == NO_SELECTED_ITEM) /* NO_SELECTED_ITEM is not -1 ! */
+    {
+       OrigPos = 0;
+       i = -1;
+    }
+  else
+    {
+      i = MenuInfo->FocusedItem;
+    }
+
+  do
     {
-      if (1 == MenuInfo->MenuItemCount)
+      /* Step */
+      i += Offset;
+      /* Clip and wrap around */
+      if (i < 0)
         {
-          MenuCleanupRosMenuItemInfo(&ItemInfo);
-          return;
+          i = MenuInfo->MenuItemCount - 1;
         }
-      else
+      else if (i >= MenuInfo->MenuItemCount)
         {
-          for (i = MenuInfo->FocusedItem + Offset;
-               0 <= i && i < MenuInfo->MenuItemCount;
-               i += Offset)
-            {
-              if (MenuGetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo) &&
-                  0 == (ItemInfo.fType & MF_SEPARATOR))
-                {
-                  MenuSelectItem(WndOwner, MenuInfo, i, TRUE, NULL);
-                  MenuCleanupRosMenuItemInfo(&ItemInfo);
-                  return;
-                }
-            }
+          i = 0;
         }
-    }
-
-  for (i = (0 < Offset) ? 0 : MenuInfo->MenuItemCount - 1;
-       0 <= i && i < MenuInfo->MenuItemCount; i += Offset)
-    {
+      /* If this is a good candidate; */
       if (MenuGetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo) &&
-          0 == (ItemInfo.fType & MF_SEPARATOR))
+          0 == (ItemInfo.fType & MF_SEPARATOR) &&
+          0 == (ItemInfo.fState & (MFS_DISABLED | MFS_GRAYED)) )
         {
           MenuSelectItem(WndOwner, MenuInfo, i, TRUE, NULL);
           MenuCleanupRosMenuItemInfo(&ItemInfo);
           return;
         }
-    }
+    } while (i != OrigPos);
 
+  /* Not found */
   MenuCleanupRosMenuItemInfo(&ItemInfo);
 }
 
@@ -1813,10 +1953,14 @@ MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset)
  *
  * Grey the appropriate items in System menu.
  */
-static void FASTCALL
-MenuInitSysMenuPopup(HMENU Menu, DWORD Style, DWORD ClsStyle )
+void FASTCALL
+MenuInitSysMenuPopup(HMENU Menu, DWORD Style, DWORD ClsStyle, LONG HitTest )
 {
   BOOL Gray;
+  UINT DefItem;
+  #if 0
+  MENUITEMINFOW mii;
+  #endif
 
   Gray = 0 == (Style & WS_THICKFRAME) || 0 != (Style & (WS_MAXIMIZE | WS_MINIMIZE));
   EnableMenuItem(Menu, SC_SIZE, (Gray ? MF_GRAYED : MF_ENABLED));
@@ -1835,6 +1979,33 @@ MenuInitSysMenuPopup(HMENU Menu, DWORD Style, DWORD ClsStyle )
     {
       EnableMenuItem(Menu, SC_CLOSE, MF_GRAYED);
     }
+
+  /* Set default menu item */
+  if(Style & WS_MINIMIZE)
+  {
+    DefItem = SC_RESTORE;
+  }
+  else
+  {
+    if(HitTest == HTCAPTION)
+    {
+      DefItem = ((Style & (WS_MAXIMIZE | WS_MINIMIZE)) ? SC_RESTORE : SC_MAXIMIZE);
+    }
+    else
+    {
+      DefItem = SC_CLOSE;
+    }
+  }
+  #if 0
+  mii.cbSize = sizeof(MENUITEMINFOW);
+  mii.fMask = MIIM_STATE;
+  if((DefItem != SC_CLOSE) && GetMenuItemInfoW(Menu, DefItem, FALSE, &mii) &&
+     (mii.fState & (MFS_GRAYED | MFS_DISABLED)))
+  {
+    DefItem = SC_CLOSE;
+  }
+  #endif
+  SetMenuDefaultItem(Menu, DefItem, MF_BYCOMMAND);
 }
 
 /***********************************************************************
@@ -1922,9 +2093,8 @@ MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Fl
 
   if (IS_SYSTEM_MENU(MenuInfo))
     {
-      MenuInitSysMenuPopup(ItemInfo.hSubMenu,
-                           GetWindowLongW(MenuInfo->Wnd, GWL_STYLE ),
-                           GetClassLongW(MenuInfo->Wnd, GCL_STYLE));
+      MenuInitSysMenuPopup(ItemInfo.hSubMenu, GetWindowLongW(MenuInfo->Wnd, GWL_STYLE),
+                           GetClassLongW(MenuInfo->Wnd, GCL_STYLE), HTSYSMENU);
 
       NcGetSysPopupPos(MenuInfo->Wnd, &Rect);
       Rect.top = Rect.bottom;
@@ -2127,15 +2297,19 @@ MenuButtonDown(MTRACKER* Mt, HMENU PtMenu, UINT Flags)
           return FALSE;
         }
 
-      if (MenuInfo.FocusedItem != Index)
-        {
-          MenuSwitchTracking(Mt, &MenuInfo, Index);
-        }
+      if (!(Item.fType & MF_SEPARATOR) &&
+          !(Item.fState & (MFS_DISABLED | MFS_GRAYED)) )
+       {
+          if (MenuInfo.FocusedItem != Index)
+            {
+              MenuSwitchTracking(Mt, &MenuInfo, Index);
+            }
 
-      /* If the popup menu is not already "popped" */
-      if (0 == (Item.fState & MF_MOUSESELECT))
-        {
-          Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
+          /* If the popup menu is not already "popped" */
+          if (0 == (Item.fState & MF_MOUSESELECT))
+            {
+              Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
+            }
         }
 
       MenuCleanupRosMenuItemInfo(&Item);
@@ -2273,6 +2447,7 @@ MenuMouseMove(MTRACKER *Mt, HMENU PtMenu, UINT Flags)
 {
   UINT Index;
   ROSMENUINFO MenuInfo;
+  ROSMENUITEMINFO ItemInfo;
 
   if (NULL != PtMenu)
     {
@@ -2305,9 +2480,16 @@ MenuMouseMove(MTRACKER *Mt, HMENU PtMenu, UINT Flags)
     }
   else if (MenuInfo.FocusedItem != Index)
     {
-      MenuSwitchTracking(Mt, &MenuInfo, Index);
-      Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
-    }
+       MenuInitRosMenuItemInfo(&ItemInfo);
+       if (MenuGetRosMenuItemInfo(MenuInfo.Self, Index, &ItemInfo) &&
+           !(ItemInfo.fType & MF_SEPARATOR) &&
+           !(ItemInfo.fState & (MFS_DISABLED | MFS_GRAYED)) )
+       {
+           MenuSwitchTracking(Mt, &MenuInfo, Index);
+           Mt->CurrentMenu = MenuShowSubPopup(Mt->OwnerWnd, &MenuInfo, FALSE, Flags);
+       }
+       MenuCleanupRosMenuItemInfo(&ItemInfo);
+    }
 
   return TRUE;
 }
@@ -2534,6 +2716,7 @@ MenuDoNextMenu(MTRACKER* Mt, UINT Vk)
         {
           Mt->OwnerWnd = NewWnd;
           SetCapture(Mt->OwnerWnd);
+          NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, Mt->OwnerWnd);
         }
 
       Mt->TopMenu = Mt->CurrentMenu = NewMenu; /* all subpopups are hidden */
@@ -2896,6 +3079,7 @@ MenuTrackMenu(HMENU Menu, UINT Flags, INT x, INT y,
     }
 
   SetCapture(Mt.OwnerWnd);
+  NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, Mt.OwnerWnd);
 
   while (! fEndMenu)
     {
@@ -3111,9 +3295,13 @@ MenuTrackMenu(HMENU Menu, UINT Flags, INT x, INT y,
               case WM_SYSKEYDOWN:
                 switch (Msg.wParam)
                   {
+                    DbgPrint("Menu.c WM_SYSKEYDOWN wPram %d\n",Msg.wParam);
                     case VK_MENU:
                       fEndMenu = TRUE;
                       break;
+                    case VK_LMENU:
+                      fEndMenu = TRUE;
+                      break;
                   }
                 break;  /* WM_SYSKEYDOWN */
 
@@ -3181,6 +3369,7 @@ MenuTrackMenu(HMENU Menu, UINT Flags, INT x, INT y,
         }
     }
 
+  NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER, NULL);
   SetCapture(NULL);  /* release the capture */
 
   /* If dropdown is still painted and the close box is clicked on
@@ -3224,7 +3413,7 @@ MenuTrackMenu(HMENU Menu, UINT Flags, INT x, INT y,
 static BOOL FASTCALL
 MenuExitTracking(HWND Wnd)
 {
-  DPRINT("hwnd=%p\n", hWnd);
+  DPRINT("hwnd=%p\n", Wnd);
 
   SendMessageW(Wnd, WM_EXITMENULOOP, 0, 0);
   ShowCaret(0);
@@ -3238,7 +3427,7 @@ MenuTrackMouseMenuBar(HWND Wnd, ULONG Ht, POINT Pt)
   HMENU Menu = (HTSYSMENU == Ht) ? NtUserGetSystemMenu(Wnd, FALSE) : GetMenu(Wnd);
   UINT Flags = TPM_ENTERIDLEEX | TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON;
 
-  DPRINT("wnd=%p ht=0x%04x (%ld,%ld)\n", Wnd, Ht, pt.x, pt.y);
+  DPRINT("wnd=%p ht=0x%04x (%ld,%ld)\n", Wnd, Ht, Pt.x, Pt.y);
 
   if (IsMenu(Menu))
     {
@@ -3279,7 +3468,7 @@ AppendMenuA(HMENU hMenu,
            UINT_PTR uIDNewItem,
            LPCSTR lpNewItem)
 {
-  return(InsertMenuA(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem, 
+  return(InsertMenuA(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem,
                     lpNewItem));
 }
 
@@ -3293,7 +3482,7 @@ AppendMenuW(HMENU hMenu,
            UINT_PTR uIDNewItem,
            LPCWSTR lpNewItem)
 {
-  return(InsertMenuW(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem, 
+  return(InsertMenuW(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem,
                     lpNewItem));
 }
 
@@ -3311,7 +3500,7 @@ CheckMenuItem(HMENU hmenu,
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL STDCALL
 CheckMenuRadioItem(HMENU hmenu,
@@ -3320,8 +3509,43 @@ CheckMenuRadioItem(HMENU hmenu,
                   UINT idCheck,
                   UINT uFlags)
 {
+  ROSMENUINFO mi;
+  PROSMENUITEMINFO Items;
+  int i;
+  BOOL ret = FALSE;
+
+  mi.cbSize = sizeof(MENUINFO);
+
   UNIMPLEMENTED;
-  return FALSE;
+
+  if(idFirst > idLast) return ret;
+
+  if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
+
+  if(MenuGetAllRosMenuItemInfo(mi.Self, &Items) <= 0) return ret;
+
+  for (i = 0 ; i < mi.MenuItemCount; i++)
+    {
+      if (0 != (Items[i].fType & MF_MENUBARBREAK)) break;
+      if ( i >= idFirst && i <= idLast )
+      {
+         if ( i == idCheck)
+         {
+             Items[i].fType |= MFT_RADIOCHECK;
+             Items[i].fState |= MFS_CHECKED;
+         }
+         else
+         {
+             Items[i].fType &= ~MFT_RADIOCHECK;
+             Items[i].fState &= ~MFS_CHECKED;
+         }
+         if(!MenuSetRosMenuItemInfo(mi.Self, i ,&Items[i]))
+             break;
+      }
+   if ( i == mi.MenuItemCount) ret = TRUE;
+    }
+  MenuCleanupRosMenuItemInfo(Items);
+  return ret;
 }
 
 
@@ -3331,6 +3555,7 @@ CheckMenuRadioItem(HMENU hmenu,
 HMENU STDCALL
 CreateMenu(VOID)
 {
+  MenuLoadBitmaps();
   return NtUserCreateMenu(FALSE);
 }
 
@@ -3341,6 +3566,7 @@ CreateMenu(VOID)
 HMENU STDCALL
 CreatePopupMenu(VOID)
 {
+  MenuLoadBitmaps();
   return NtUserCreateMenu(TRUE);
 }
 
@@ -3368,21 +3594,19 @@ DestroyMenu(HMENU hMenu)
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL STDCALL
 DrawMenuBar(HWND hWnd)
 {
-  UNIMPLEMENTED
-  /* FIXME - return NtUserCallHwndLock(hWnd, 0x55); */
-  return FALSE;
+  return (BOOL)NtUserCallHwndLock(hWnd, HWNDLOCK_ROUTINE_DRAWMENUBAR);
 }
 
 
 /*
  * @implemented
  */
-UINT STDCALL
+BOOL STDCALL
 EnableMenuItem(HMENU hMenu,
               UINT uIDEnableItem,
               UINT uEnable)
@@ -3435,7 +3659,7 @@ GetMenuBarInfo(HWND hwnd,
 LONG STDCALL
 GetMenuCheckMarkDimensions(VOID)
 {
-  return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK), 
+  return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK),
                  GetSystemMetrics(SM_CYMENUCHECK)));
 }
 
@@ -3461,16 +3685,16 @@ GetMenuInfo(HMENU hmenu,
 {
   ROSMENUINFO mi;
   BOOL res = FALSE;
-  
+
   if(!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO)))
     return FALSE;
-  
+
   RtlZeroMemory(&mi, sizeof(MENUINFO));
   mi.cbSize = sizeof(MENUINFO);
   mi.fMask = lpcmi->fMask;
-  
+
   res = NtUserMenuInfo(hmenu, &mi, FALSE);
-  
+
   memcpy(lpcmi, &mi, sizeof(MENUINFO));
   return res;
 }
@@ -3496,15 +3720,15 @@ GetMenuItemID(HMENU hMenu,
              int nPos)
 {
   ROSMENUITEMINFO mii;
-  
+
   mii.cbSize = sizeof(MENUITEMINFOW);
   mii.fMask = MIIM_ID | MIIM_SUBMENU;
-  
+
   if (! NtUserMenuItemInfo(hMenu, nPos, MF_BYPOSITION, &mii, FALSE))
     {
       return -1;
     }
-  
+
   if (NULL != mii.hSubMenu)
     {
       return -1;
@@ -3513,44 +3737,90 @@ GetMenuItemID(HMENU hMenu,
     {
       return -1;
     }
-  
+
   return mii.wID;
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL STDCALL
 GetMenuItemInfoA(
-  HMENU hMenu,
-  UINT uItem,
-  BOOL fByPosition,
-  LPMENUITEMINFOA lpmii)
+   HMENU Menu,
+   UINT Item,
+   BOOL ByPosition,
+   LPMENUITEMINFOA mii)
 {
-  UNIMPLEMENTED;
-  return FALSE;
+   LPSTR AnsiBuffer;
+   MENUITEMINFOW miiW;
+
+   if (mii->cbSize != sizeof(MENUITEMINFOA) &&
+       mii->cbSize != sizeof(MENUITEMINFOA) - sizeof(HBITMAP))
+   {
+      SetLastError(ERROR_INVALID_PARAMETER);
+      return FALSE;
+   }
+
+   if ((mii->fMask & (MIIM_STRING | MIIM_TYPE)) == 0)
+   {
+      /* No text requested, just pass on */
+      return NtUserMenuItemInfo(Menu, Item, ByPosition, (PROSMENUITEMINFO) mii, FALSE);
+   }
+
+   RtlCopyMemory(&miiW, mii, mii->cbSize);
+   AnsiBuffer = mii->dwTypeData;
+
+   if (AnsiBuffer != NULL)
+   {
+      miiW.dwTypeData = RtlAllocateHeap(GetProcessHeap(), 0,
+                                        miiW.cch * sizeof(WCHAR));
+      if (miiW.dwTypeData == NULL)
+         return FALSE;
+   }
+
+   if (!NtUserMenuItemInfo(Menu, Item, ByPosition, (PROSMENUITEMINFO)&miiW, FALSE))
+   {
+      HeapFree(GetProcessHeap(), 0, miiW.dwTypeData);
+      return FALSE;
+   }
+
+   if (AnsiBuffer != NULL)
+   {
+      if (IS_STRING_ITEM(miiW.fType))
+      {
+         WideCharToMultiByte(CP_ACP, 0, miiW.dwTypeData, miiW.cch, AnsiBuffer,
+                             mii->cch, NULL, NULL);
+      }
+      RtlFreeHeap(GetProcessHeap(), 0, miiW.dwTypeData);
+   }
+
+   RtlCopyMemory(mii, &miiW, miiW.cbSize);
+   if (AnsiBuffer)
+   {
+        mii->dwTypeData = AnsiBuffer;
+        mii->cch = strlen(AnsiBuffer);
+   }
+   return TRUE;
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
-BOOL
-STDCALL
+BOOL STDCALL
 GetMenuItemInfoW(
-  HMENU hMenu,
-  UINT uItem,
-  BOOL fByPosition,
-  LPMENUITEMINFOW lpmii)
+   HMENU Menu,
+   UINT Item,
+   BOOL ByPosition,
+   LPMENUITEMINFOW mii)
 {
-  UNIMPLEMENTED;
-  return FALSE;
+   return NtUserMenuItemInfo(Menu, Item, ByPosition, (PROSMENUITEMINFO) mii, FALSE);
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL STDCALL
 GetMenuItemRect(HWND hWnd,
@@ -3558,8 +3828,7 @@ GetMenuItemRect(HWND hWnd,
                UINT uItem,
                LPRECT lprcItem)
 {
-  UNIMPLEMENTED;
-  return(FALSE);
+  return NtUserGetMenuItemRect( hWnd, hMenu, uItem, lprcItem);
 }
 
 
@@ -3578,7 +3847,8 @@ GetMenuState(
 
   mii.cbSize = sizeof(MENUITEMINFOW);
   mii.fMask = MIIM_STATE | MIIM_TYPE | MIIM_SUBMENU;
-  
+  mii.dwTypeData = NULL;
+
   SetLastError(0);
   if(NtUserMenuItemInfo(hMenu, uId, uFlags, &mii, FALSE))
     {
@@ -3590,24 +3860,24 @@ GetMenuState(
               return (UINT) -1;
             }
           nSubItems = MenuInfo.MenuItemCount;
-      
+
           /* FIXME - ported from wine, does that work (0xff)? */
           if(GetLastError() != ERROR_INVALID_MENU_HANDLE)
             return (nSubItems << 8) | ((mii.fState | mii.fType) & 0xff);
 
           return (UINT)-1; /* Invalid submenu */
         }
-    
+
       /* FIXME - ported from wine, does that work? */
       return (mii.fType | mii.fState);
     }
-  
+
   return (UINT)-1;
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 int
 STDCALL
@@ -3618,13 +3888,22 @@ GetMenuStringA(
   int nMaxCount,
   UINT uFlag)
 {
-  UNIMPLEMENTED;
-  return 0;
+  MENUITEMINFOA mii;
+  mii.dwTypeData = lpString;
+  mii.fMask = MIIM_STRING;
+  mii.fType = MF_STRING;
+  mii.cbSize = sizeof(MENUITEMINFOA);
+  mii.cch = nMaxCount;
+
+  if(!(GetMenuItemInfoA( hMenu, uIDItem, (BOOL)(MF_BYPOSITION & uFlag),&mii)))
+     return 0;
+  else
+     return mii.cch;
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 int
 STDCALL
@@ -3635,8 +3914,16 @@ GetMenuStringW(
   int nMaxCount,
   UINT uFlag)
 {
-  UNIMPLEMENTED;
-  return 0;
+  MENUITEMINFOW miiW;
+  miiW.dwTypeData = lpString;
+  miiW.fMask = MIIM_STRING;
+  miiW.cbSize = sizeof(MENUITEMINFOW);
+  miiW.cch = nMaxCount;
+
+  if(!(GetMenuItemInfoW( hMenu, uIDItem, (BOOL)(MF_BYPOSITION & uFlag),&miiW)))
+     return 0;
+  else
+     return miiW.cch;
 }
 
 
@@ -3711,16 +3998,26 @@ InsertMenuA(
   mii.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE;
   mii.fType = 0;
   mii.fState = MFS_ENABLED;
-  
+
   if(uFlags & MF_BITMAP)
   {
     mii.fType |= MFT_BITMAP;
+    mii.fMask |= MIIM_BITMAP;
+    mii.hbmpItem = (HBITMAP) lpNewItem;
   }
   else if(uFlags & MF_OWNERDRAW)
   {
     mii.fType |= MFT_OWNERDRAW;
+    mii.fMask |= MIIM_DATA;
+    mii.dwItemData = (DWORD) lpNewItem;
+  }
+  else
+  {
+    mii.fMask |= MIIM_TYPE;
+    mii.dwTypeData = (LPSTR)lpNewItem;
+    mii.cch = (NULL == lpNewItem ? 0 : strlen(lpNewItem));
   }
-  
+
   if(uFlags & MF_RIGHTJUSTIFY)
   {
     mii.fType |= MFT_RIGHTJUSTIFY;
@@ -3741,10 +4038,10 @@ InsertMenuA(
   {
     mii.fState |= MFS_GRAYED;
   }
-  
-  mii.dwTypeData = (LPSTR)lpNewItem;
+
   if(uFlags & MF_POPUP)
   {
+    mii.fType |= MF_POPUP;
     mii.fMask |= MIIM_SUBMENU;
     mii.hSubMenu = (HMENU)uIDNewItem;
   }
@@ -3753,7 +4050,7 @@ InsertMenuA(
     mii.fMask |= MIIM_ID;
     mii.wID = (UINT)uIDNewItem;
   }
-  return InsertMenuItemA(hMenu, uPosition, (BOOL)!(MF_BYPOSITION & uFlags), &mii);
+  return InsertMenuItemA(hMenu, uPosition, (BOOL)((MF_BYPOSITION & uFlags) > 0), &mii);
 }
 
 
@@ -3774,29 +4071,29 @@ InsertMenuItemA(
   BOOL CleanHeap = FALSE;
   NTSTATUS Status;
 
-  if((lpmii->cbSize == sizeof(MENUITEMINFOA)) || 
+  if((lpmii->cbSize == sizeof(MENUITEMINFOA)) ||
      (lpmii->cbSize == sizeof(MENUITEMINFOA) - sizeof(HBITMAP)))
   {
     RtlMoveMemory ( &mi, lpmii, lpmii->cbSize );
 
     /* copy the text string */
-    if((mi.fMask & (MIIM_TYPE | MIIM_STRING)) && 
+    if((mi.fMask & (MIIM_TYPE | MIIM_STRING)) &&
       (MENU_ITEM_TYPE(mi.fType) == MF_STRING) && mi.dwTypeData)
     {
-      Status = HEAP_strdupAtoW ( &mi.dwTypeData, (LPCSTR)mi.dwTypeData, &mi.cch );
+      Status = RtlCreateUnicodeStringFromAsciiz(&MenuText, (LPSTR)mi.dwTypeData);
       if (!NT_SUCCESS (Status))
       {
         SetLastError (RtlNtStatusToDosError(Status));
         return FALSE;
       }
-      RtlInitUnicodeString(&MenuText, (PWSTR)mi.dwTypeData);
-      mi.dwTypeData = (LPWSTR)&MenuText;
+      mi.dwTypeData = MenuText.Buffer;
+      mi.cch = MenuText.Length / sizeof(WCHAR);
       CleanHeap = TRUE;
     }
 
     res = NtUserInsertMenuItem(hMenu, uItem, fByPosition, &mi);
 
-    if ( CleanHeap ) HEAP_free ( mi.dwTypeData );
+    if ( CleanHeap ) RtlFreeUnicodeString ( &MenuText );
   }
   return res;
 }
@@ -3816,39 +4113,28 @@ InsertMenuItemW(
   MENUITEMINFOW mi;
   UNICODE_STRING MenuText;
   BOOL res = FALSE;
-  BOOL CleanHeap = FALSE;
-  HANDLE hHeap = RtlGetProcessHeap();
   mi.hbmpItem = (HBITMAP)0;
 
-  // while we could just pass 'lpmii' to win32k, we make a copy so that
-  // if a bad user passes bad data, we crash his process instead of the
-  // entire kernel
+  /* while we could just pass 'lpmii' to win32k, we make a copy so that
+     if a bad user passes bad data, we crash his process instead of the
+     entire kernel */
 
-  if((lpmii->cbSize == sizeof(MENUITEMINFOW)) || 
+  if((lpmii->cbSize == sizeof(MENUITEMINFOW)) ||
      (lpmii->cbSize == sizeof(MENUITEMINFOW) - sizeof(HBITMAP)))
   {
     memcpy(&mi, lpmii, lpmii->cbSize);
-    
+
     /* copy the text string */
-    if((mi.fMask & (MIIM_TYPE | MIIM_STRING)) && 
-      (MENU_ITEM_TYPE(mi.fType) == MF_STRING) && mi.dwTypeData)
+    if((mi.fMask & (MIIM_TYPE | MIIM_STRING)) &&
+      (MENU_ITEM_TYPE(mi.fType) == MF_STRING) &&
+      mi.dwTypeData != NULL)
     {
-      if(lpmii->cch > 0)
-      {
-        if(!RtlCreateUnicodeString(&MenuText, (PWSTR)lpmii->dwTypeData))
-        {
-          SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY));
-          return FALSE;
-        }
-        mi.dwTypeData = (LPWSTR)&MenuText;
-        mi.cch = MenuText.Length / sizeof(WCHAR);
-        CleanHeap = TRUE;
-      }
+      RtlInitUnicodeString(&MenuText, (PWSTR)lpmii->dwTypeData);
+      mi.dwTypeData = MenuText.Buffer;
+      mi.cch = MenuText.Length / sizeof(WCHAR);
     };
-    
+
     res = NtUserInsertMenuItem(hMenu, uItem, fByPosition, &mi);
-    
-    if(CleanHeap) RtlFreeHeap (hHeap, 0, mi.dwTypeData);
   }
   return res;
 }
@@ -3875,12 +4161,22 @@ InsertMenuW(
   if(uFlags & MF_BITMAP)
   {
     mii.fType |= MFT_BITMAP;
+    mii.fMask |= MIIM_BITMAP;
+    mii.hbmpItem = (HBITMAP) lpNewItem;
   }
   else if(uFlags & MF_OWNERDRAW)
   {
     mii.fType |= MFT_OWNERDRAW;
+    mii.fMask |= MIIM_DATA;
+    mii.dwItemData = (DWORD) lpNewItem;
   }
-  
+  else
+  {
+    mii.fMask |= MIIM_TYPE;
+    mii.dwTypeData = (LPWSTR)lpNewItem;
+    mii.cch = (NULL == lpNewItem ? 0 : wcslen(lpNewItem));
+  }
+
   if(uFlags & MF_RIGHTJUSTIFY)
   {
     mii.fType |= MFT_RIGHTJUSTIFY;
@@ -3901,9 +4197,7 @@ InsertMenuW(
   {
     mii.fState |= MFS_GRAYED;
   }
-  
-  mii.dwTypeData = (LPWSTR)lpNewItem;
-  mii.cch = (NULL == lpNewItem ? 0 : wcslen(lpNewItem));
+
   if(uFlags & MF_POPUP)
   {
     mii.fType |= MF_POPUP;
@@ -3915,7 +4209,7 @@ InsertMenuW(
     mii.fMask |= MIIM_ID;
     mii.wID = (UINT)uIDNewItem;
   }
-  return InsertMenuItemW(hMenu, uPosition, (BOOL)!(MF_BYPOSITION & uFlags), &mii);
+  return InsertMenuItemW(hMenu, uPosition, (BOOL)((MF_BYPOSITION & uFlags) > 0), &mii);
 }
 
 
@@ -4032,7 +4326,7 @@ MenuItemFromPoint(
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL
 STDCALL
@@ -4043,13 +4337,94 @@ ModifyMenuA(
   UINT_PTR uIDNewItem,
   LPCSTR lpNewItem)
 {
+  MENUITEMINFOA mii;
+  memset( &mii, 0, sizeof(mii) );
+  mii.cbSize = sizeof(MENUITEMINFOA);
+  mii.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE;
+  mii.fType = 0;
+  mii.fState = MFS_ENABLED;
+
   UNIMPLEMENTED;
-  return FALSE;
+
+  if(!GetMenuItemInfoA( hMnu,
+                        uPosition,
+                       (BOOL)(MF_BYPOSITION & uFlags),
+                        &mii)) return FALSE;
+
+  if(uFlags & MF_BITMAP)
+  {
+    mii.fType |= MFT_BITMAP;
+    mii.fMask |= MIIM_BITMAP;
+    mii.hbmpItem = (HBITMAP) lpNewItem;
+  }
+  else if(uFlags & MF_OWNERDRAW)
+  {
+    mii.fType |= MFT_OWNERDRAW;
+    mii.fMask |= MIIM_DATA;
+    mii.dwItemData = (DWORD) lpNewItem;
+  }
+  else /* Default action MF_STRING. */
+  {
+    if(mii.dwTypeData != NULL)
+    {
+      HeapFree(GetProcessHeap(),0, mii.dwTypeData);
+    }
+    /* Item beginning with a backspace is a help item */
+    if (*lpNewItem == '\b')
+    {
+       mii.fType |= MF_HELP;
+       lpNewItem++;
+    }
+    mii.fMask |= MIIM_TYPE;
+    mii.dwTypeData = (LPSTR)lpNewItem;
+    mii.cch = (NULL == lpNewItem ? 0 : strlen(lpNewItem));
+  }
+
+  if(uFlags & MF_RIGHTJUSTIFY)
+  {
+    mii.fType |= MFT_RIGHTJUSTIFY;
+  }
+  if(uFlags & MF_MENUBREAK)
+  {
+    mii.fType |= MFT_MENUBREAK;
+  }
+  if(uFlags & MF_MENUBARBREAK)
+  {
+    mii.fType |= MFT_MENUBARBREAK;
+  }
+  if(uFlags & MF_DISABLED)
+  {
+    mii.fState |= MFS_DISABLED;
+  }
+  if(uFlags & MF_GRAYED)
+  {
+    mii.fState |= MFS_GRAYED;
+  }
+
+  if ((mii.fType & MF_POPUP) && (uFlags & MF_POPUP) && (mii.hSubMenu != (HMENU)uIDNewItem))
+    NtUserDestroyMenu( mii.hSubMenu );   /* ModifyMenu() spec */
+
+  if(uFlags & MF_POPUP)
+  {
+    mii.fType |= MF_POPUP;
+    mii.fMask |= MIIM_SUBMENU;
+    mii.hSubMenu = (HMENU)uIDNewItem;
+  }
+  else
+  {
+    mii.fMask |= MIIM_ID;
+    mii.wID = (UINT)uIDNewItem;
+  }
+
+  return SetMenuItemInfoA( hMnu,
+                           uPosition,
+                          (BOOL)(MF_BYPOSITION & uFlags),
+                           &mii);
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL
 STDCALL
@@ -4060,8 +4435,88 @@ ModifyMenuW(
   UINT_PTR uIDNewItem,
   LPCWSTR lpNewItem)
 {
+  MENUITEMINFOW mii;
+  memset ( &mii, 0, sizeof(mii) );
+  mii.cbSize = sizeof(MENUITEMINFOW);
+  mii.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE;
+  mii.fState = MFS_ENABLED;
+
   UNIMPLEMENTED;
-  return FALSE;
+
+  if(!NtUserMenuItemInfo( hMnu,
+                          uPosition,
+                         (BOOL)(MF_BYPOSITION & uFlags),
+                         (PROSMENUITEMINFO) &mii,
+                          FALSE)) return FALSE;
+
+  if(uFlags & MF_BITMAP)
+  {
+    mii.fType |= MFT_BITMAP;
+    mii.fMask |= MIIM_BITMAP;
+    mii.hbmpItem = (HBITMAP) lpNewItem;
+  }
+  else if(uFlags & MF_OWNERDRAW)
+  {
+    mii.fType |= MFT_OWNERDRAW;
+    mii.fMask |= MIIM_DATA;
+    mii.dwItemData = (DWORD) lpNewItem;
+  }
+  else
+  {
+    /*if(mii.dwTypeData != NULL)
+    {
+      HeapFree(GetProcessHeap(),0, mii.dwTypeData);
+    }*/
+    if (*lpNewItem == '\b')
+    {
+       mii.fType |= MF_HELP;
+       lpNewItem++;
+    }
+    mii.fMask |= MIIM_TYPE;
+    mii.dwTypeData = (LPWSTR)lpNewItem;
+    mii.cch = (NULL == lpNewItem ? 0 : wcslen(lpNewItem));
+  }
+
+  if(uFlags & MF_RIGHTJUSTIFY)
+  {
+    mii.fType |= MFT_RIGHTJUSTIFY;
+  }
+  if(uFlags & MF_MENUBREAK)
+  {
+    mii.fType |= MFT_MENUBREAK;
+  }
+  if(uFlags & MF_MENUBARBREAK)
+  {
+    mii.fType |= MFT_MENUBARBREAK;
+  }
+  if(uFlags & MF_DISABLED)
+  {
+    mii.fState |= MFS_DISABLED;
+  }
+  if(uFlags & MF_GRAYED)
+  {
+    mii.fState |= MFS_GRAYED;
+  }
+
+  if ((mii.fType & MF_POPUP) && (uFlags & MF_POPUP) && (mii.hSubMenu != (HMENU)uIDNewItem))
+    NtUserDestroyMenu( mii.hSubMenu );
+
+  if(uFlags & MF_POPUP)
+  {
+    mii.fType |= MF_POPUP;
+    mii.fMask |= MIIM_SUBMENU;
+    mii.hSubMenu = (HMENU)uIDNewItem;
+  }
+  else
+  {
+    mii.fMask |= MIIM_ID;
+    mii.wID = (UINT)uIDNewItem;
+  }
+
+  return SetMenuItemInfoW( hMnu,
+                           uPosition,
+                           (BOOL)(MF_BYPOSITION & uFlags),
+                           &mii);
 }
 
 
@@ -4117,14 +4572,14 @@ SetMenuInfo(
   BOOL res = FALSE;
   if(lpcmi->cbSize != sizeof(MENUINFO))
     return res;
-    
+
   memcpy(&mi, lpcmi, sizeof(MENUINFO));
   return NtUserMenuInfo(hmenu, &mi, TRUE);
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL
 STDCALL
@@ -4135,13 +4590,28 @@ SetMenuItemBitmaps(
   HBITMAP hBitmapUnchecked,
   HBITMAP hBitmapChecked)
 {
-  UNIMPLEMENTED;
-  return FALSE;
+  ROSMENUITEMINFO uItem;
+
+  if(!(NtUserMenuItemInfo(hMenu, uPosition, 
+                 (BOOL)(MF_BYPOSITION & uFlags), &uItem, FALSE))) return FALSE;
+
+  if (!hBitmapChecked && !hBitmapUnchecked)
+  {
+    uItem.fState &= ~MF_USECHECKBITMAPS;
+  }
+  else  /* Install new bitmaps */
+  {
+    uItem.hbmpChecked = hBitmapChecked;
+    uItem.hbmpUnchecked = hBitmapUnchecked;
+    uItem.fState |= MF_USECHECKBITMAPS;
+  }
+ return NtUserMenuItemInfo(hMenu, uPosition,
+                                 (BOOL)(MF_BYPOSITION & uFlags), &uItem, TRUE);
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL
 STDCALL
@@ -4149,15 +4619,42 @@ SetMenuItemInfoA(
   HMENU hMenu,
   UINT uItem,
   BOOL fByPosition,
-  LPMENUITEMINFOA lpmii)
+  LPCMENUITEMINFOA lpmii)
 {
-  UNIMPLEMENTED;
-  return FALSE;
+  MENUITEMINFOW MenuItemInfoW;
+  UNICODE_STRING UnicodeString;
+  ULONG Result;
+
+  RtlCopyMemory(&MenuItemInfoW, lpmii, min(lpmii->cbSize, sizeof(MENUITEMINFOW)));
+
+  if ((MenuItemInfoW.fMask & (MIIM_TYPE | MIIM_STRING)) &&
+      (MENU_ITEM_TYPE(MenuItemInfoW.fType) == MF_STRING) &&
+      MenuItemInfoW.dwTypeData != NULL)
+  {
+    RtlCreateUnicodeStringFromAsciiz(&UnicodeString,
+                                     (LPSTR)MenuItemInfoW.dwTypeData);
+    MenuItemInfoW.dwTypeData = UnicodeString.Buffer;
+    MenuItemInfoW.cch = UnicodeString.Length / sizeof(WCHAR);
+  }
+  else
+  {
+    UnicodeString.Buffer = NULL;
+  }
+
+  Result = NtUserMenuItemInfo(hMenu, uItem, fByPosition,
+                              (PROSMENUITEMINFO)&MenuItemInfoW, TRUE);
+
+  if (UnicodeString.Buffer != NULL)
+  {
+    RtlFreeUnicodeString(&UnicodeString);
+  }
+
+  return Result;
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL
 STDCALL
@@ -4165,10 +4662,18 @@ SetMenuItemInfoW(
   HMENU hMenu,
   UINT uItem,
   BOOL fByPosition,
-  LPMENUITEMINFOW lpmii)
+  LPCMENUITEMINFOW lpmii)
 {
-  UNIMPLEMENTED;
-  return FALSE;
+  MENUITEMINFOW MenuItemInfoW;
+
+  RtlCopyMemory(&MenuItemInfoW, lpmii, min(lpmii->cbSize, sizeof(MENUITEMINFOW)));
+  if (0 != (MenuItemInfoW.fMask & MIIM_STRING))
+  {
+    MenuItemInfoW.cch = wcslen(MenuItemInfoW.dwTypeData);
+  }
+
+  return NtUserMenuItemInfo(hMenu, uItem, fByPosition,
+                            (PROSMENUITEMINFO)&MenuItemInfoW, TRUE);
 }
 
 /*
@@ -4177,7 +4682,7 @@ SetMenuItemInfoW(
 BOOL
 STDCALL
 SetSystemMenu (
-  HWND hwnd, 
+  HWND hwnd,
   HMENU hMenu)
 {
   if(!hwnd)
@@ -4200,41 +4705,50 @@ SetSystemMenu (
 BOOL
 STDCALL
 TrackPopupMenu(
-  HMENU hMenu,
-  UINT uFlags,
+  HMENU Menu,
+  UINT Flags,
   int x,
   int y,
-  int nReserved,
-  HWND hWnd,
-  CONST RECT *prcRect)
+  int Reserved,
+  HWND Wnd,
+  CONST RECT *Rect)
 {
-  TPMPARAMS tpm;
-  
-  if(prcRect)
-  {
-    tpm.cbSize = sizeof(TPMPARAMS);
-    tpm.rcExclude = *prcRect;
-  }
-  
-  return (BOOL)NtUserTrackPopupMenuEx(hMenu, uFlags, x, y, hWnd, 
-                                         (prcRect ? &tpm : NULL));
+  BOOL ret = FALSE;
+
+  MenuInitTracking(Wnd, Menu, TRUE, Flags);
+
+  /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
+  if (0 == (Flags & TPM_NONOTIFY))
+    {
+      SendMessageW(Wnd, WM_INITMENUPOPUP, (WPARAM) Menu, 0);
+    }
+
+  if (MenuShowPopup(Wnd, Menu, 0, x, y, 0, 0 ))
+    {
+      ret = MenuTrackMenu(Menu, Flags | TPM_POPUPMENU, 0, 0, Wnd, Rect);
+    }
+  MenuExitTracking(Wnd);
+
+  return ret;
 }
 
 
 /*
- * @implemented
+ * @unimplemented
  */
 BOOL
 STDCALL
 TrackPopupMenuEx(
-  HMENU hmenu,
-  UINT fuFlags,
+  HMENU Menu,
+  UINT Flags,
   int x,
   int y,
-  HWND hwnd,
-  LPTPMPARAMS lptpm)
+  HWND Wnd,
+  LPTPMPARAMS Tpm)
 {
-  return (BOOL)NtUserTrackPopupMenuEx(hmenu, fuFlags, x, y, hwnd, lptpm);
+  /* Not fully implemented */
+  return TrackPopupMenu(Menu, Flags, x, y, 0, Wnd,
+                        NULL != Tpm ? &Tpm->rcExclude : NULL);
 }
 
 
@@ -4260,7 +4774,7 @@ GetMenuContextHelpId(HMENU hmenu)
   ROSMENUINFO mi;
   mi.cbSize = sizeof(ROSMENUINFO);
   mi.fMask = MIM_HELPID;
-  
+
   if(NtUserMenuInfo(hmenu, &mi, FALSE))
   {
     return mi.dwContextHelpID;
@@ -4322,7 +4836,7 @@ ChangeMenuW(
     {
         case MF_APPEND :
             return AppendMenuW(hMenu, flags &~ MF_APPEND, cmdInsert, lpszNewItem);
-        
+
         case MF_DELETE :
             return DeleteMenu(hMenu, cmd, flags &~ MF_DELETE);
 
@@ -4360,7 +4874,7 @@ ChangeMenuA(
     {
         case MF_APPEND :
             return AppendMenuA(hMenu, flags &~ MF_APPEND, cmdInsert, lpszNewItem);
-        
+
         case MF_DELETE :
             return DeleteMenu(hMenu, cmd, flags &~ MF_DELETE);