Implement NtUserGetMenuBarInfo. Tested with MPlayerC with OBJID_MENU only, the rest...
[reactos.git] / reactos / subsys / win32k / ntuser / menu.c
index 7d122f0..c4b4f3c 100644 (file)
@@ -16,7 +16,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.11 2003/08/06 13:17:44 weiden Exp $
+/* $Id$
  *
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  */
 /* INCLUDES ******************************************************************/
 
-#include <ddk/ntddk.h>
-#include <win32k/win32k.h>
-#include <napi/win32.h>
-#include <include/menu.h>
-#include <include/error.h>
-#include <include/winsta.h>
-#include <include/object.h>
-#include <include/guicheck.h>
-#include <include/window.h>
-#include <include/color.h>
+#include <w32k.h>
 
 #define NDEBUG
 #include <debug.h>
 
+
+/* STATIC FUNCTION ***********************************************************/
+
+static
+BOOL FASTCALL
+UserMenuItemInfo(
+   PMENU_OBJECT Menu,
+   UINT Item,
+   BOOL ByPosition,
+   PROSMENUITEMINFO UnsafeItemInfo,
+   BOOL SetOrGet);
+
+static
+BOOL FASTCALL
+UserMenuInfo(
+   PMENU_OBJECT Menu,
+   PROSMENUINFO UnsafeMenuInfo,
+   BOOL SetOrGet);
+
 /* INTERNAL ******************************************************************/
 
 /* maximum number of menu items a menu can contain */
 #define MAX_MENU_ITEMS (0x4000)
+#define MAX_GOINTOSUBMENU (0x10)
 
-#ifndef MIIM_STRING
-#define MIIM_STRING      (0x00000040)
-#endif
-#ifndef MIIM_BITMAP
-#define MIIM_BITMAP      (0x00000080)
-#endif
-#ifndef MIIM_FTYPE
-#define MIIM_FTYPE       (0x00000100)
-#endif
-
-/* TODO - Optimize */
 #define UpdateMenuItemState(state, change) \
 {\
   if((change) & MFS_DISABLED) { \
-    if(!((state) & MFS_DISABLED)) (state) |= MFS_DISABLED; \
+    (state) |= MFS_DISABLED; \
   } else { \
-    if((state) & MFS_DISABLED) (state) ^= MFS_DISABLED; \
+    (state) &= ~MFS_DISABLED; \
   } \
   if((change) & MFS_CHECKED) { \
-    if(!((state) & MFS_CHECKED)) (state) |= MFS_CHECKED; \
+    (state) |= MFS_CHECKED; \
   } else { \
-    if((state) & MFS_CHECKED) (state) ^= MFS_CHECKED; \
+    (state) &= ~MFS_CHECKED; \
   } \
   if((change) & MFS_HILITE) { \
-    if(!((state) & MFS_HILITE)) (state) |= MFS_HILITE; \
+    (state) |= MFS_HILITE; \
+  } else { \
+    (state) &= ~MFS_HILITE; \
+  } \
+  if((change) & MFS_DEFAULT) { \
+    (state) |= MFS_DEFAULT; \
   } else { \
-    if((state) & MFS_HILITE) (state) ^= MFS_HILITE; \
+    (state) &= ~MFS_DEFAULT; \
+  } \
+  if((change) & MF_MOUSESELECT) { \
+    (state) |= MF_MOUSESELECT; \
+  } else { \
+    (state) &= ~MF_MOUSESELECT; \
   } \
 }
 
 #define FreeMenuText(MenuItem) \
 { \
-  if(((MenuItem).fMask & (MIIM_TYPE | MIIM_STRING)) && \
-           (MENU_ITEM_TYPE((MenuItem).fType) == MF_STRING) && \
-           (MenuItem).dwTypeData) { \
-    ExFreePool((MenuItem).dwTypeData); \
-    (MenuItem).dwTypeData = 0; \
-    (MenuItem).cch = 0; \
-    DbgPrint("FreeMenuText(): Deleted menu text\n"); \
+  if((MENU_ITEM_TYPE((MenuItem)->fType) == MF_STRING) && \
+           (MenuItem)->Text.Length) { \
+    RtlFreeUnicodeString(&(MenuItem)->Text); \
   } \
 }
 
+#define InRect(r, x, y) \
+      ( ( ((r).right >=  x)) && \
+        ( ((r).left <= x)) && \
+        ( ((r).bottom >=  y)) && \
+        ( ((r).top <= y)) )
+
 NTSTATUS FASTCALL
 InitMenuImpl(VOID)
 {
-  return(STATUS_SUCCESS);
+   return(STATUS_SUCCESS);
 }
 
 NTSTATUS FASTCALL
 CleanupMenuImpl(VOID)
 {
-  return(STATUS_SUCCESS);
+   return(STATUS_SUCCESS);
+}
+
+PMENU_OBJECT FASTCALL UserGetMenuObject(HMENU hMenu)
+{
+   PMENU_OBJECT Menu;
+   
+   if (!hMenu)
+   {
+      SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
+      return NULL;
+   }
+   
+   Menu = (PMENU_OBJECT)UserGetObject(&gHandleTable, hMenu, otMenu);
+   if (!Menu)
+   {
+      SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
+      return NULL;
+   }
+
+   ASSERT(USER_BODY_TO_HEADER(Menu)->RefCount >= 0);
+   return Menu;
 }
 
-#if 1
+
+#if 0
 void FASTCALL
 DumpMenuItemList(PMENU_ITEM MenuItem)
 {
-  UINT cnt = 0;
-  while(MenuItem)
-  {
-    if(MenuItem->MenuItem.dwTypeData)
-      DbgPrint(" %d. %ws\n", ++cnt, (LPWSTR)MenuItem->MenuItem.dwTypeData);
-    else
-      DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt, MenuItem->MenuItem.dwTypeData);
-    DbgPrint("   fType=");
-    if(MFT_BITMAP & MenuItem->MenuItem.fType) DbgPrint("MFT_BITMAP ");
-    if(MFT_MENUBARBREAK & MenuItem->MenuItem.fType) DbgPrint("MFT_MENUBARBREAK ");
-    if(MFT_MENUBREAK & MenuItem->MenuItem.fType) DbgPrint("MFT_MENUBREAK ");
-    if(MFT_OWNERDRAW & MenuItem->MenuItem.fType) DbgPrint("MFT_OWNERDRAW ");
-    if(MFT_RADIOCHECK & MenuItem->MenuItem.fType) DbgPrint("MFT_RADIOCHECK ");
-    if(MFT_RIGHTJUSTIFY & MenuItem->MenuItem.fType) DbgPrint("MFT_RIGHTJUSTIFY ");
-    if(MFT_SEPARATOR & MenuItem->MenuItem.fType) DbgPrint("MFT_SEPARATOR ");
-    if(MFT_STRING & MenuItem->MenuItem.fType) DbgPrint("MFT_STRING ");
-    DbgPrint("\n   fState=");
-    if(MFS_DISABLED & MenuItem->MenuItem.fState) DbgPrint("MFS_DISABLED ");
-    else DbgPrint("MFS_ENABLED ");
-    if(MFS_CHECKED & MenuItem->MenuItem.fState) DbgPrint("MFS_CHECKED ");
-    else DbgPrint("MFS_UNCHECKED ");
-    if(MFS_HILITE & MenuItem->MenuItem.fState) DbgPrint("MFS_HILITE ");
-    else DbgPrint("MFS_UNHILITE ");
-    if(MFS_DEFAULT & MenuItem->MenuItem.fState) DbgPrint("MFS_DEFAULT ");
-    if(MFS_GRAYED & MenuItem->MenuItem.fState) DbgPrint("MFS_GRAYED ");
-    DbgPrint("\n   wId=%d\n", MenuItem->MenuItem.wID);
-    MenuItem = MenuItem->Next;
-  }
-  DbgPrint("Entries: %d\n", cnt);
-  return;
+   UINT cnt = 0;
+   while(MenuItem)
+   {
+      if(MenuItem->Text.Length)
+         DbgPrint(" %d. %wZ\n", ++cnt, &MenuItem->Text);
+      else
+         DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt, (DWORD)MenuItem->Text.Buffer);
+      DbgPrint("   fType=");
+      if(MFT_BITMAP & MenuItem->fType)
+         DbgPrint("MFT_BITMAP ");
+      if(MFT_MENUBARBREAK & MenuItem->fType)
+         DbgPrint("MFT_MENUBARBREAK ");
+      if(MFT_MENUBREAK & MenuItem->fType)
+         DbgPrint("MFT_MENUBREAK ");
+      if(MFT_OWNERDRAW & MenuItem->fType)
+         DbgPrint("MFT_OWNERDRAW ");
+      if(MFT_RADIOCHECK & MenuItem->fType)
+         DbgPrint("MFT_RADIOCHECK ");
+      if(MFT_RIGHTJUSTIFY & MenuItem->fType)
+         DbgPrint("MFT_RIGHTJUSTIFY ");
+      if(MFT_SEPARATOR & MenuItem->fType)
+         DbgPrint("MFT_SEPARATOR ");
+      if(MFT_STRING & MenuItem->fType)
+         DbgPrint("MFT_STRING ");
+      DbgPrint("\n   fState=");
+      if(MFS_DISABLED & MenuItem->fState)
+         DbgPrint("MFS_DISABLED ");
+      else
+         DbgPrint("MFS_ENABLED ");
+      if(MFS_CHECKED & MenuItem->fState)
+         DbgPrint("MFS_CHECKED ");
+      else
+         DbgPrint("MFS_UNCHECKED ");
+      if(MFS_HILITE & MenuItem->fState)
+         DbgPrint("MFS_HILITE ");
+      else
+         DbgPrint("MFS_UNHILITE ");
+      if(MFS_DEFAULT & MenuItem->fState)
+         DbgPrint("MFS_DEFAULT ");
+      if(MFS_GRAYED & MenuItem->fState)
+         DbgPrint("MFS_GRAYED ");
+      DbgPrint("\n   wId=%d\n", MenuItem->wID);
+      MenuItem = MenuItem->Next;
+   }
+   DbgPrint("Entries: %d\n", cnt);
+   return;
 }
 #endif
 
 PMENU_OBJECT FASTCALL
-W32kGetMenuObject(HMENU hMenu)
+IntGetMenuObject(HMENU hMenu)
 {
-  PMENU_OBJECT MenuObject;
-  NTSTATUS Status = ObmReferenceObjectByHandle(PsGetWin32Process()->
-                      WindowStation->HandleTable, hMenu, otMenu, 
-                      (PVOID*)&MenuObject);
-  if (!NT_SUCCESS(Status))
-  {
-    return NULL;
-  }
-  return MenuObject;
+   PMENU_OBJECT Menu = UserGetMenuObject(hMenu);
+   if (Menu)
+   {
+      ASSERT(USER_BODY_TO_HEADER(Menu)->RefCount >= 0);
+
+      USER_BODY_TO_HEADER(Menu)->RefCount++;
+   }
+   return Menu;
 }
 
-VOID FASTCALL
-W32kReleaseMenuObject(PMENU_OBJECT MenuObject)
+BOOL FASTCALL
+IntFreeMenuItem(PMENU_OBJECT Menu, PMENU_ITEM MenuItem,
+                BOOL RemoveFromList, BOOL bRecurse)
 {
-  ObmDereferenceObject(MenuObject);
+   FreeMenuText(MenuItem);
+   if(RemoveFromList)
+   {
+      /* FIXME - Remove from List */
+      Menu->MenuInfo.MenuItemCount--;
+   }
+   if(bRecurse && MenuItem->hSubMenu)
+   {
+      PMENU_OBJECT SubMenu;
+      SubMenu = UserGetMenuObject(MenuItem->hSubMenu );
+      if(SubMenu)
+      {
+         IntDestroyMenuObject(SubMenu, bRecurse, TRUE);
+      }
+   }
+
+   /* Free memory */
+   ExFreePool(MenuItem);
+
+   return TRUE;
 }
 
 BOOL FASTCALL
-W32kFreeMenuItem(PMENU_OBJECT MenuObject, PMENU_ITEM MenuItem,
-    BOOL RemoveFromList, BOOL bRecurse)
+IntRemoveMenuItem(PMENU_OBJECT Menu, UINT uPosition, UINT uFlags,
+                  BOOL bRecurse)
 {
-  if(MenuItem)
-  {
-    FreeMenuText(MenuItem->MenuItem);
-    if(RemoveFromList)
-    {
-      /* FIXME - Remove from List */
-      MenuObject->MenuItemCount--;
-    }
-  }
-  return FALSE;
+   PMENU_ITEM PrevMenuItem, MenuItem;
+   if(IntGetMenuItemByFlag(Menu, uPosition, uFlags, &MenuItem,
+                           &PrevMenuItem) > -1)
+   {
+      if(MenuItem)
+      {
+         if(PrevMenuItem)
+            PrevMenuItem->Next = MenuItem->Next;
+         else
+         {
+            Menu->MenuItemList = MenuItem->Next;
+         }
+         return IntFreeMenuItem(Menu, MenuItem, TRUE, bRecurse);
+      }
+   }
+   return FALSE;
 }
 
 UINT FASTCALL
-W32kDeleteMenuItems(PMENU_OBJECT MenuObject, BOOL bRecurse)
+IntDeleteMenuItems(PMENU_OBJECT Menu, BOOL bRecurse)
 {
-  UINT res = 0;
-  PMENU_ITEM NextItem;
-  PMENU_ITEM CurItem = MenuObject->MenuItemList;
-  while(CurItem)
-  {
-    NextItem = CurItem->Next;
-    W32kFreeMenuItem(MenuObject, CurItem, FALSE, bRecurse);
-    CurItem = NextItem;
-    res++;
-  }
-  MenuObject->MenuItemCount = 0;
-  MenuObject->MenuItemList = NULL;
-  return res;
+   UINT res = 0;
+   PMENU_ITEM NextItem;
+   PMENU_ITEM CurItem = Menu->MenuItemList;
+   while(CurItem)
+   {
+      NextItem = CurItem->Next;
+      IntFreeMenuItem(Menu, CurItem, FALSE, bRecurse);
+      CurItem = NextItem;
+      res++;
+   }
+   Menu->MenuInfo.MenuItemCount = 0;
+   Menu->MenuItemList = NULL;
+   return res;
 }
 
 BOOL FASTCALL
-W32kDestroyMenuObject(PMENU_OBJECT MenuObject)
+IntDestroyMenuObject(PMENU_OBJECT Menu,
+                     BOOL bRecurse, BOOL RemoveFromProcess)
 {
-  if(MenuObject)
-  {  
-    /* remove all menu items */
-    ExAcquireFastMutexUnsafe (&MenuObject->MenuItemsLock);
-    W32kDeleteMenuItems(MenuObject, FALSE); /* do not destroy submenus */
-    ExReleaseFastMutexUnsafe (&MenuObject->MenuItemsLock);
-    
-    W32kReleaseMenuObject(MenuObject);
-    
-    ObmCloseHandle(PsGetWin32Process()->WindowStation->HandleTable, MenuObject->Self);
-  
-    return TRUE;
-  }
-  return FALSE;
+   if(Menu)
+   {
+      PWINSTATION_OBJECT WindowStation;
+      NTSTATUS Status;
+
+      /* remove all menu items */
+      IntDeleteMenuItems(Menu, bRecurse); /* do not destroy submenus */
+
+      if(RemoveFromProcess)
+      {
+         RemoveEntryList(&Menu->ListEntry);
+      }
+
+      Status = ObReferenceObjectByHandle(Menu->Process->Win32WindowStation,
+                                         0,
+                                         ExWindowStationObjectType,
+                                         KernelMode,
+                                         (PVOID*)&WindowStation,
+                                         NULL);
+      if(NT_SUCCESS(Status))
+      {
+         ObmDeleteObject(Menu->MenuInfo.Self, otMenu);
+         ObDereferenceObject(WindowStation);
+         return TRUE;
+      }
+   }
+   return FALSE;
 }
 
 PMENU_OBJECT FASTCALL
-W32kCreateMenu(PHANDLE Handle)
+IntCreateMenu(PHANDLE Handle, BOOL IsMenuBar)
 {
-  PMENU_OBJECT MenuObject = (PMENU_OBJECT)ObmCreateObject(
-      PsGetWin32Process()->WindowStation->HandleTable, Handle, 
-      otMenu, sizeof(MENU_OBJECT));
-  
-  if(!MenuObject)
-  {
-    *Handle = 0;
-    return NULL;
-  }
-
-  MenuObject->Self = *Handle;
-  MenuObject->RtoL = FALSE; /* default */
-  MenuObject->MenuInfo.cbSize = sizeof(MENUINFO); /* not used */
-  MenuObject->MenuInfo.fMask = 0; /* not used */
-  MenuObject->MenuInfo.dwStyle = 0; /* FIXME */
-  MenuObject->MenuInfo.cyMax = 0; /* default */
-  MenuObject->MenuInfo.hbrBack = W32kGetSysColorBrush(COLOR_MENU); /*default background color */
-  MenuObject->MenuInfo.dwContextHelpID = 0; /* default */  
-  MenuObject->MenuInfo.dwMenuData = 0; /* default */
-  
-  MenuObject->MenuItemCount = 0;
-  MenuObject->MenuItemList = NULL;
-  ExInitializeFastMutex(&MenuObject->MenuItemsLock);
-  
-  return MenuObject;
+   PMENU_OBJECT Menu;
+
+   Menu = (PMENU_OBJECT)ObmCreateObject(
+             &gHandleTable, Handle,
+             otMenu, sizeof(MENU_OBJECT));
+
+   if(!Menu)
+   {
+      *Handle = 0;
+      return NULL;
+   }
+
+   Menu->Process = PsGetCurrentProcess();
+   Menu->RtoL = FALSE; /* default */
+   Menu->MenuInfo.cbSize = sizeof(MENUINFO); /* not used */
+   Menu->MenuInfo.fMask = 0; /* not used */
+   Menu->MenuInfo.dwStyle = 0; /* FIXME */
+   Menu->MenuInfo.cyMax = 0; /* default */
+   Menu->MenuInfo.hbrBack =
+      NtGdiCreateSolidBrush(RGB(192, 192, 192), 0); /* FIXME: default background color */
+   Menu->MenuInfo.dwContextHelpID = 0; /* default */
+   Menu->MenuInfo.dwMenuData = 0; /* default */
+   Menu->MenuInfo.Self = *Handle;
+   Menu->MenuInfo.FocusedItem = NO_SELECTED_ITEM;
+   Menu->MenuInfo.Flags = (IsMenuBar ? 0 : MF_POPUP);
+   Menu->MenuInfo.Wnd = NULL;
+   Menu->MenuInfo.WndOwner = NULL;
+   Menu->MenuInfo.Height = 0;
+   Menu->MenuInfo.Width = 0;
+   Menu->MenuInfo.TimeToHide = FALSE;
+
+   Menu->MenuInfo.MenuItemCount = 0;
+   Menu->MenuItemList = NULL;
+
+   /* Insert menu item into process menu handle list */
+   InsertTailList(&PsGetWin32Process()->MenuListHead, &Menu->ListEntry);
+
+   return Menu;
 }
 
 BOOL FASTCALL
-W32kSetMenuFlagRtoL(PMENU_OBJECT MenuObject)
+IntCloneMenuItems(PMENU_OBJECT Destination, PMENU_OBJECT Source)
 {
-  if(MenuObject)
-  {
-    MenuObject->RtoL = TRUE;
-    return TRUE;
-  }
-  return FALSE;
+   PMENU_ITEM MenuItem, NewMenuItem = NULL;
+   PMENU_ITEM Old = NULL;
+
+   if(!Source->MenuInfo.MenuItemCount)
+      return FALSE;
+
+   MenuItem = Source->MenuItemList;
+   while(MenuItem)
+   {
+      Old = NewMenuItem;
+      if(NewMenuItem)
+         NewMenuItem->Next = MenuItem;
+      NewMenuItem = ExAllocatePoolWithTag(PagedPool, sizeof(MENU_ITEM), TAG_MENUITEM);
+      if(!NewMenuItem)
+         break;
+      NewMenuItem->fType = MenuItem->fType;
+      NewMenuItem->fState = MenuItem->fState;
+      NewMenuItem->wID = MenuItem->wID;
+      NewMenuItem->hSubMenu = MenuItem->hSubMenu;
+      NewMenuItem->hbmpChecked = MenuItem->hbmpChecked;
+      NewMenuItem->hbmpUnchecked = MenuItem->hbmpUnchecked;
+      NewMenuItem->dwItemData = MenuItem->dwItemData;
+      if((MENU_ITEM_TYPE(NewMenuItem->fType) == MF_STRING))
+      {
+         if(MenuItem->Text.Length)
+         {
+            NewMenuItem->Text.Length = 0;
+            NewMenuItem->Text.MaximumLength = MenuItem->Text.MaximumLength;
+            NewMenuItem->Text.Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, MenuItem->Text.MaximumLength, TAG_STRING);
+            if(!NewMenuItem->Text.Buffer)
+            {
+               ExFreePool(NewMenuItem);
+               break;
+            }
+            RtlCopyUnicodeString(&NewMenuItem->Text, &MenuItem->Text);
+         }
+         else
+         {
+            NewMenuItem->Text.Buffer = MenuItem->Text.Buffer;
+         }
+      }
+      else
+      {
+         NewMenuItem->Text.Buffer = MenuItem->Text.Buffer;
+      }
+      NewMenuItem->hbmpItem = MenuItem->hbmpItem;
+
+      NewMenuItem->Next = NULL;
+      if(Old)
+         Old->Next = NewMenuItem;
+      else
+         Destination->MenuItemList = NewMenuItem;
+      Destination->MenuInfo.MenuItemCount++;
+      MenuItem = MenuItem->Next;
+   }
+
+   return TRUE;
+}
+
+PMENU_OBJECT FASTCALL
+IntCloneMenu(PMENU_OBJECT Source)
+{
+   HANDLE hMenu;
+   PMENU_OBJECT Menu;
+
+   if(!Source)
+      return NULL;
+
+   Menu = (PMENU_OBJECT)ObmCreateObject(
+             &gHandleTable, &hMenu,
+             otMenu, sizeof(MENU_OBJECT));
+
+   if(!Menu)
+      return NULL;
+
+   Menu->Process = PsGetCurrentProcess();
+   Menu->RtoL = Source->RtoL;
+   Menu->MenuInfo.cbSize = sizeof(MENUINFO); /* not used */
+   Menu->MenuInfo.fMask = Source->MenuInfo.fMask;
+   Menu->MenuInfo.dwStyle = Source->MenuInfo.dwStyle;
+   Menu->MenuInfo.cyMax = Source->MenuInfo.cyMax;
+   Menu->MenuInfo.hbrBack = Source->MenuInfo.hbrBack;
+   Menu->MenuInfo.dwContextHelpID = Source->MenuInfo.dwContextHelpID;
+   Menu->MenuInfo.dwMenuData = Source->MenuInfo.dwMenuData;
+   Menu->MenuInfo.Self = hMenu;
+   Menu->MenuInfo.FocusedItem = NO_SELECTED_ITEM;
+   Menu->MenuInfo.Wnd = NULL;
+   Menu->MenuInfo.WndOwner = NULL;
+   Menu->MenuInfo.Height = 0;
+   Menu->MenuInfo.Width = 0;
+   Menu->MenuInfo.TimeToHide = FALSE;
+
+   Menu->MenuInfo.MenuItemCount = 0;
+   Menu->MenuItemList = NULL;
+
+   /* Insert menu item into process menu handle list */
+   InsertTailList(&PsGetWin32Process()->MenuListHead, &Menu->ListEntry);
+
+   IntCloneMenuItems(Menu, Source);
+
+   return Menu;
+}
+
+BOOL FASTCALL
+IntSetMenuFlagRtoL(PMENU_OBJECT Menu)
+{
+   Menu->RtoL = TRUE;
+   return TRUE;
+}
+
+BOOL FASTCALL
+IntSetMenuContextHelpId(PMENU_OBJECT Menu, DWORD dwContextHelpId)
+{
+   Menu->MenuInfo.dwContextHelpID = dwContextHelpId;
+   return TRUE;
 }
 
 BOOL FASTCALL
-W32kSetMenuContextHelpId(PMENU_OBJECT MenuObject, DWORD dwContextHelpId)
+IntGetMenuInfo(PMENU_OBJECT Menu, PROSMENUINFO lpmi)
 {
-  if(MenuObject)
-  {
-    MenuObject->MenuInfo.dwContextHelpID = dwContextHelpId;
-    return TRUE;
-  }
-  return FALSE;
+   if(lpmi->fMask & MIM_BACKGROUND)
+      lpmi->hbrBack = Menu->MenuInfo.hbrBack;
+   if(lpmi->fMask & MIM_HELPID)
+      lpmi->dwContextHelpID = Menu->MenuInfo.dwContextHelpID;
+   if(lpmi->fMask & MIM_MAXHEIGHT)
+      lpmi->cyMax = Menu->MenuInfo.cyMax;
+   if(lpmi->fMask & MIM_MENUDATA)
+      lpmi->dwMenuData = Menu->MenuInfo.dwMenuData;
+   if(lpmi->fMask & MIM_STYLE)
+      lpmi->dwStyle = Menu->MenuInfo.dwStyle;
+   if (sizeof(MENUINFO) < lpmi->cbSize)
+   {
+      RtlCopyMemory((char *) lpmi + sizeof(MENUINFO),
+                    (char *) &Menu->MenuInfo + sizeof(MENUINFO),
+                    lpmi->cbSize - sizeof(MENUINFO));
+   }
+
+   return TRUE;
 }
 
+
 BOOL FASTCALL
-W32kGetMenuInfo(PMENU_OBJECT MenuObject, LPMENUINFO lpmi)
+IntIsMenu(HMENU hMenu)
 {
-  if(MenuObject)
-  {
-    if(lpmi->fMask & MIM_BACKGROUND)
-      lpmi->hbrBack = MenuObject->MenuInfo.hbrBack;
-    if(lpmi->fMask & MIM_HELPID)
-      lpmi->dwContextHelpID = MenuObject->MenuInfo.dwContextHelpID;
-    if(lpmi->fMask & MIM_MAXHEIGHT)
-      lpmi->cyMax = MenuObject->MenuInfo.cyMax;
-    if(lpmi->fMask & MIM_MENUDATA)
-      lpmi->dwMenuData = MenuObject->MenuInfo.dwMenuData;
-    if(lpmi->fMask & MIM_STYLE)
-      lpmi->dwStyle = MenuObject->MenuInfo.dwStyle;
-    return TRUE;
-  }
-  return FALSE;
+   PMENU_OBJECT Menu;
+
+   if((Menu = UserGetMenuObject(hMenu)))
+   {
+      return TRUE;
+   }
+   return FALSE;
 }
 
+
 BOOL FASTCALL
-W32kSetMenuInfo(PMENU_OBJECT MenuObject, LPMENUINFO lpmi)
+IntSetMenuInfo(PMENU_OBJECT Menu, PROSMENUINFO lpmi)
 {
-  if(MenuObject)
-  {
-    if(lpmi->fMask & MIM_BACKGROUND)
-      MenuObject->MenuInfo.hbrBack = lpmi->hbrBack;
-    if(lpmi->fMask & MIM_HELPID)
-      MenuObject->MenuInfo.dwContextHelpID = lpmi->dwContextHelpID;
-    if(lpmi->fMask & MIM_MAXHEIGHT)
-      MenuObject->MenuInfo.cyMax = lpmi->cyMax;
-    if(lpmi->fMask & MIM_MENUDATA)
-      MenuObject->MenuInfo.dwMenuData = lpmi->dwMenuData;
-    if(lpmi->fMask & MIM_STYLE)
-      MenuObject->MenuInfo.dwStyle = lpmi->dwStyle;
-    if(lpmi->fMask & MIM_APPLYTOSUBMENUS)
-    {
+   if(lpmi->fMask & MIM_BACKGROUND)
+      Menu->MenuInfo.hbrBack = lpmi->hbrBack;
+   if(lpmi->fMask & MIM_HELPID)
+      Menu->MenuInfo.dwContextHelpID = lpmi->dwContextHelpID;
+   if(lpmi->fMask & MIM_MAXHEIGHT)
+      Menu->MenuInfo.cyMax = lpmi->cyMax;
+   if(lpmi->fMask & MIM_MENUDATA)
+      Menu->MenuInfo.dwMenuData = lpmi->dwMenuData;
+   if(lpmi->fMask & MIM_STYLE)
+      Menu->MenuInfo.dwStyle = lpmi->dwStyle;
+   if(lpmi->fMask & MIM_APPLYTOSUBMENUS)
+   {
       /* FIXME */
-    }
-    return TRUE;
-  }
-  return FALSE;
+   }
+   if (sizeof(MENUINFO) < lpmi->cbSize)
+   {
+      Menu->MenuInfo.FocusedItem = lpmi->FocusedItem;
+      Menu->MenuInfo.Height = lpmi->Height;
+      Menu->MenuInfo.Width = lpmi->Width;
+      Menu->MenuInfo.Wnd = lpmi->Wnd;
+      Menu->MenuInfo.WndOwner = lpmi->WndOwner;
+      Menu->MenuInfo.TimeToHide = lpmi->TimeToHide;
+   }
+
+   return TRUE;
 }
 
 
 int FASTCALL
-W32kGetMenuItemByFlag(PMENU_OBJECT MenuObject, UINT uSearchBy, UINT fFlag, PMENU_ITEM *MenuItem)
+IntGetMenuItemByFlag(PMENU_OBJECT Menu, UINT uSearchBy, UINT fFlag,
+                     PMENU_ITEM *MenuItem, PMENU_ITEM *PrevMenuItem)
 {
-  PMENU_ITEM CurItem = MenuObject->MenuItemList;
-  int p;
-  if(MF_BYPOSITION & fFlag)
-  {
-    PMENU_ITEM PrevItem = NULL;
-    p = uSearchBy;
-    while(CurItem && (p > 0))
-    {
-      PrevItem = CurItem;
-      CurItem = CurItem->Next;
-      p--;
-    }
-    if(MenuItem)
-    {
+   PMENU_ITEM PrevItem = NULL;
+   PMENU_ITEM CurItem = Menu->MenuItemList;
+   int p;
+   int ret;
+
+   if(MF_BYPOSITION & fFlag)
+   {
+      p = uSearchBy;
+      while(CurItem && (p > 0))
+      {
+         PrevItem = CurItem;
+         CurItem = CurItem->Next;
+         p--;
+      }
       if(CurItem)
-        *MenuItem = CurItem;
+      {
+         if(MenuItem)
+            *MenuItem = CurItem;
+         if(PrevMenuItem)
+            *PrevMenuItem = PrevItem;
+      }
       else
       {
-        *MenuItem = NULL;
-        return -1;
+         if(MenuItem)
+            *MenuItem = NULL;
+         if(PrevMenuItem)
+            *PrevMenuItem = NULL; /* ? */
+         return -1;
       }
-    }
-
-    return uSearchBy - p;
-  }
-  else
-  {
-    p = 0;
-    while(CurItem)
-    {
-      if(CurItem->MenuItem.wID == uSearchBy)
+
+      return uSearchBy - p;
+   }
+   else
+   {
+      p = 0;
+      while(CurItem)
       {
-        if(MenuItem) *MenuItem = CurItem;
-        return p;
+         if(CurItem->wID == uSearchBy)
+         {
+            if(MenuItem)
+               *MenuItem = CurItem;
+            if(PrevMenuItem)
+               *PrevMenuItem = PrevItem;
+            return p;
+         }
+         else if (0 != (CurItem->fType & MF_POPUP))
+         {
+            Menu = UserGetMenuObject(CurItem->hSubMenu);
+            if (NULL != Menu)
+            {
+               ret = IntGetMenuItemByFlag(Menu, uSearchBy, fFlag,
+                                          MenuItem, PrevMenuItem);
+               if (-1 != ret)
+               {
+                  return ret;
+               }
+            }
+         }
+         PrevItem = CurItem;
+         CurItem = CurItem->Next;
+         p++;
       }
-      CurItem = CurItem->Next;
-      p++;
-    }
-  }
-  return -1;
+   }
+   return -1;
 }
 
 
 int FASTCALL
-W32kInsertMenuItemToList(PMENU_OBJECT MenuObject, PMENU_ITEM MenuItem, int pos)
+IntInsertMenuItemToList(PMENU_OBJECT Menu, PMENU_ITEM MenuItem, int pos)
 {
-  PMENU_ITEM CurItem;
-  PMENU_ITEM LastItem = NULL;
-  UINT npos = 0;
-  
-  CurItem = MenuObject->MenuItemList;
-  if(pos <= -1)
-  {
-    while(CurItem)
-    {
-      LastItem = CurItem;
-      CurItem = CurItem->Next;
-      npos++;
-    }
-  }
-  else
-  {
-    while(CurItem && (pos > 0))
-    {
-      LastItem = CurItem;
-      CurItem = CurItem->Next;
-      pos--;
-      npos++;
-    }
-  }
-
-  if(CurItem)
-  {
-    if(LastItem)
-    {
-      /* insert the item before CurItem */
-      MenuItem->Next = LastItem->Next;
-      LastItem->Next = MenuItem;
-    }
-    else
-    {
-      /* insert at the beginning */
-      MenuObject->MenuItemList = MenuItem;
-      MenuItem->Next = CurItem;
-    }
-  }
-  else
-  {
-    if(LastItem)
-    {
-      /* insert at the end */
-      LastItem->Next = MenuItem;
-      MenuItem->Next = NULL;
-    }
-    else
-    {
-      /* insert first item */
-      MenuObject->MenuItemList = MenuItem;
-      MenuItem->Next = NULL;
-    }
-  }
-  MenuObject->MenuItemCount++;
-  
-  return npos;
+   PMENU_ITEM CurItem;
+   PMENU_ITEM LastItem = NULL;
+   UINT npos = 0;
+
+   CurItem = Menu->MenuItemList;
+   if(pos <= -1)
+   {
+      while(CurItem)
+      {
+         LastItem = CurItem;
+         CurItem = CurItem->Next;
+         npos++;
+      }
+   }
+   else
+   {
+      while(CurItem && (pos > 0))
+      {
+         LastItem = CurItem;
+         CurItem = CurItem->Next;
+         pos--;
+         npos++;
+      }
+   }
+
+   if(CurItem)
+   {
+      if(LastItem)
+      {
+         /* insert the item before CurItem */
+         MenuItem->Next = LastItem->Next;
+         LastItem->Next = MenuItem;
+      }
+      else
+      {
+         /* insert at the beginning */
+         Menu->MenuItemList = MenuItem;
+         MenuItem->Next = CurItem;
+      }
+   }
+   else
+   {
+      if(LastItem)
+      {
+         /* append item */
+         LastItem->Next = MenuItem;
+         MenuItem->Next = NULL;
+      }
+      else
+      {
+         /* insert first item */
+         Menu->MenuItemList = MenuItem;
+         MenuItem->Next = NULL;
+      }
+   }
+   Menu->MenuInfo.MenuItemCount++;
+
+   return npos;
 }
 
 BOOL FASTCALL
-W32kSetMenuItemInfo(PMENU_OBJECT MenuObject, PMENU_ITEM MenuItem, LPCMENUITEMINFOW lpmii)
+IntGetMenuItemInfo(PMENU_OBJECT Menu, /* UNUSED PARAM!! */
+                   PMENU_ITEM MenuItem, PROSMENUITEMINFO lpmii)
 {
-  if(!MenuItem || !MenuObject || !lpmii)
-  {
-    return FALSE;
-  }
-
-  if((MenuItem->MenuItem.fMask & (MIIM_TYPE | MIIM_STRING)) && 
-           (MENU_ITEM_TYPE(MenuItem->MenuItem.fType) == MF_STRING) && 
-           MenuItem->MenuItem.dwTypeData)
-  {
-    /* delete old string */
-    ExFreePool(MenuItem->MenuItem.dwTypeData);
-    MenuItem->MenuItem.dwTypeData = 0;
-    MenuItem->MenuItem.cch = 0;
-  }
-  
-  MenuItem->MenuItem.fType = lpmii->fType;
-  MenuItem->MenuItem.cch = lpmii->cch;
-  
-  if(lpmii->fMask & MIIM_BITMAP)
-  {
-    MenuItem->MenuItem.hbmpItem = lpmii->hbmpItem;
-  }
-  if(lpmii->fMask & MIIM_CHECKMARKS)
-  {
-    MenuItem->MenuItem.hbmpChecked = lpmii->hbmpChecked;
-    MenuItem->MenuItem.hbmpUnchecked = lpmii->hbmpUnchecked;
-  }
-  if(lpmii->fMask & MIIM_DATA)
-  {
-    MenuItem->MenuItem.dwItemData = lpmii->dwItemData;
-  }
-  if(lpmii->fMask & (MIIM_FTYPE | MIIM_TYPE))
-  {
-    MenuItem->MenuItem.fType = lpmii->fType;
-  }
-  if(lpmii->fMask & MIIM_ID)
-  {
-    MenuItem->MenuItem.wID = lpmii->wID;
-  }
-  if(lpmii->fMask & MIIM_STATE)
-  {
-    UpdateMenuItemState(MenuItem->MenuItem.fState, lpmii->fState);
-    /* FIXME - only one item can have MFS_DEFAULT */
-  }
-  
-  if(lpmii->fMask & MIIM_SUBMENU)
-  {
-    MenuItem->MenuItem.hSubMenu = lpmii->hSubMenu;
-  }
-  if((lpmii->fMask & (MIIM_TYPE | MIIM_STRING)) && 
-           (MENU_ITEM_TYPE(lpmii->fType) == MF_STRING) && lpmii->dwTypeData)
-  {
-    FreeMenuText(MenuItem->MenuItem);
-    MenuItem->MenuItem.dwTypeData = (LPWSTR)ExAllocatePool(PagedPool, (lpmii->cch + 1) * sizeof(WCHAR));
-    if(!MenuItem->MenuItem.dwTypeData)
-    {
-      MenuItem->MenuItem.cch = 0;
-      /* FIXME Set last error code? */
-      SetLastWin32Error(STATUS_NO_MEMORY);
+   NTSTATUS Status;
+
+   if(lpmii->fMask & MIIM_BITMAP)
+   {
+      lpmii->hbmpItem = MenuItem->hbmpItem;
+   }
+   if(lpmii->fMask & MIIM_CHECKMARKS)
+   {
+      lpmii->hbmpChecked = MenuItem->hbmpChecked;
+      lpmii->hbmpUnchecked = MenuItem->hbmpUnchecked;
+   }
+   if(lpmii->fMask & MIIM_DATA)
+   {
+      lpmii->dwItemData = MenuItem->dwItemData;
+   }
+   if(lpmii->fMask & (MIIM_FTYPE | MIIM_TYPE))
+   {
+      lpmii->fType = MenuItem->fType;
+   }
+   if(lpmii->fMask & MIIM_ID)
+   {
+      lpmii->wID = MenuItem->wID;
+   }
+   if(lpmii->fMask & MIIM_STATE)
+   {
+      lpmii->fState = MenuItem->fState;
+   }
+   if(lpmii->fMask & MIIM_SUBMENU)
+   {
+      lpmii->hSubMenu = MenuItem->hSubMenu;
+   }
+   if (lpmii->fMask & (MIIM_STRING | MIIM_TYPE))
+   {
+      if (lpmii->dwTypeData == NULL)
+      {
+         lpmii->cch = MenuItem->Text.Length / sizeof(WCHAR);
+      }
+      else
+      {
+         Status = MmCopyToCaller(lpmii->dwTypeData, MenuItem->Text.Buffer,
+                                 min(lpmii->cch * sizeof(WCHAR),
+                                     MenuItem->Text.MaximumLength));
+         if (! NT_SUCCESS(Status))
+         {
+            SetLastNtError(Status);
+            return FALSE;
+         }
+      }
+   }
+
+   if (sizeof(ROSMENUITEMINFO) == lpmii->cbSize)
+   {
+      lpmii->Rect = MenuItem->Rect;
+      lpmii->XTab = MenuItem->XTab;
+   }
+
+   return TRUE;
+}
+
+BOOL FASTCALL
+IntSetMenuItemInfo(PMENU_OBJECT MenuObject, PMENU_ITEM MenuItem, PROSMENUITEMINFO lpmii)
+{
+   PMENU_OBJECT SubMenuObject;
+
+   if(!MenuItem || !MenuObject || !lpmii)
+   {
       return FALSE;
-    }
-    MenuItem->MenuItem.cch = lpmii->cch;
-    memcpy(MenuItem->MenuItem.dwTypeData, lpmii->dwTypeData, (lpmii->cch + 1) * sizeof(WCHAR));
-  }
-  
-  return TRUE;
+   }
+
+   MenuItem->fType = lpmii->fType;
+
+   if(lpmii->fMask & MIIM_BITMAP)
+   {
+      MenuItem->hbmpItem = lpmii->hbmpItem;
+   }
+   if(lpmii->fMask & MIIM_CHECKMARKS)
+   {
+      MenuItem->hbmpChecked = lpmii->hbmpChecked;
+      MenuItem->hbmpUnchecked = lpmii->hbmpUnchecked;
+   }
+   if(lpmii->fMask & MIIM_DATA)
+   {
+      MenuItem->dwItemData = lpmii->dwItemData;
+   }
+   if(lpmii->fMask & (MIIM_FTYPE | MIIM_TYPE))
+   {
+      /*
+       * Delete the menu item type when changing type from
+       * MF_STRING.
+       */
+      if (MenuItem->fType != lpmii->fType &&
+            MENU_ITEM_TYPE(MenuItem->fType) == MF_STRING)
+      {
+         FreeMenuText(MenuItem);
+         RtlInitUnicodeString(&MenuItem->Text, NULL);
+      }
+      MenuItem->fType = lpmii->fType;
+   }
+   if(lpmii->fMask & MIIM_ID)
+   {
+      MenuItem->wID = lpmii->wID;
+   }
+   if(lpmii->fMask & MIIM_STATE)
+   {
+      /* remove MFS_DEFAULT flag from all other menu items if this item
+         has the MFS_DEFAULT state */
+      if(lpmii->fState & MFS_DEFAULT)
+         UserSetMenuDefaultItem(MenuObject, -1, 0);
+      /* update the menu item state flags */
+      UpdateMenuItemState(MenuItem->fState, lpmii->fState);
+   }
+
+   if(lpmii->fMask & MIIM_SUBMENU)
+   {
+      MenuItem->hSubMenu = lpmii->hSubMenu;
+      /* Make sure the submenu is marked as a popup menu */
+      if (MenuItem->hSubMenu)
+      {
+         SubMenuObject = UserGetMenuObject(MenuItem->hSubMenu);
+         if (SubMenuObject != NULL)
+         {
+            SubMenuObject->MenuInfo.Flags |= MF_POPUP;
+            MenuItem->fType |= MF_POPUP;
+         }
+         else
+         {
+            MenuItem->fType &= ~MF_POPUP;
+         }
+      }
+      else
+      {
+         MenuItem->fType &= ~MF_POPUP;
+      }
+   }
+   if ((lpmii->fMask & (MIIM_TYPE | MIIM_STRING)) &&
+         (MENU_ITEM_TYPE(lpmii->fType) == MF_STRING))
+   {
+      FreeMenuText(MenuItem);
+
+      if(lpmii->dwTypeData && lpmii->cch)
+      {
+         UNICODE_STRING Source;
+
+         Source.Length =
+            Source.MaximumLength = lpmii->cch * sizeof(WCHAR);
+         Source.Buffer = lpmii->dwTypeData;
+
+         MenuItem->Text.Buffer = (PWSTR)ExAllocatePoolWithTag(
+                                    PagedPool, Source.Length + sizeof(WCHAR), TAG_STRING);
+         if(MenuItem->Text.Buffer != NULL)
+         {
+            MenuItem->Text.Length = 0;
+            MenuItem->Text.MaximumLength = Source.Length + sizeof(WCHAR);
+            RtlCopyUnicodeString(&MenuItem->Text, &Source);
+            MenuItem->Text.Buffer[MenuItem->Text.Length / sizeof(WCHAR)] = 0;
+         }
+         else
+         {
+            RtlInitUnicodeString(&MenuItem->Text, NULL);
+         }
+      }
+      else
+      {
+         if (0 == (MenuObject->MenuInfo.Flags & MF_SYSMENU))
+         {
+            MenuItem->fType |= MF_SEPARATOR;
+         }
+         RtlInitUnicodeString(&MenuItem->Text, NULL);
+      }
+   }
+
+   if (sizeof(ROSMENUITEMINFO) == lpmii->cbSize)
+   {
+      MenuItem->Rect = lpmii->Rect;
+      MenuItem->XTab = lpmii->XTab;
+   }
+
+   return TRUE;
 }
 
 BOOL FASTCALL
-W32kInsertMenuItem(PMENU_OBJECT MenuObject, UINT uItem, WINBOOL fByPosition,
-                   LPCMENUITEMINFOW lpmii)
+IntInsertMenuItem(PMENU_OBJECT MenuObject, UINT uItem, BOOL fByPosition,
+                  PROSMENUITEMINFO ItemInfo)
 {
-  int pos = (int)uItem;
-  PMENU_ITEM MenuItem;
-  
-  if(MenuObject->MenuItemCount >= MAX_MENU_ITEMS)
-  {
-    /* FIXME Set last error code? */
-    SetLastWin32Error(STATUS_NO_MEMORY);
-    return FALSE;
-  }
-  
-  if(fByPosition)
-  {
-    /* calculate position */
-    if(pos > MenuObject->MenuItemCount)
-      pos = MenuObject->MenuItemCount;
-  }
-  else
-  {
-    pos = W32kGetMenuItemByFlag(MenuObject, uItem, MF_BYCOMMAND, NULL);
-  }
-  if(pos < -1) pos = -1;
-  
-  MenuItem = ExAllocatePool(PagedPool, sizeof(MENU_ITEM));
-  if(!MenuItem)
-  {
-    /* FIXME Set last error code? */
-    SetLastWin32Error(STATUS_NO_MEMORY);
-    return FALSE;
-  }
-  
-  RtlZeroMemory(&MenuItem->MenuItem, sizeof(MENUITEMINFOW));
-  MenuItem->MenuItem.cbSize = sizeof(MENUITEMINFOW);
-  
-  if(!W32kSetMenuItemInfo(MenuObject, MenuItem, lpmii))
-  {
-    ExFreePool(MenuObject);
-    return FALSE;
-  }
-  
-  pos = W32kInsertMenuItemToList(MenuObject, MenuItem, pos);
-  DumpMenuItemList(MenuObject->MenuItemList);
-  return pos >= 0;
+   int pos = (int)uItem;
+   PMENU_ITEM MenuItem;
+
+   if (MAX_MENU_ITEMS <= MenuObject->MenuInfo.MenuItemCount)
+   {
+      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+      return FALSE;
+   }
+
+   if (fByPosition)
+   {
+      /* calculate position */
+      if(MenuObject->MenuInfo.MenuItemCount < pos)
+      {
+         pos = MenuObject->MenuInfo.MenuItemCount;
+      }
+   }
+   else
+   {
+      pos = IntGetMenuItemByFlag(MenuObject, uItem, MF_BYCOMMAND, NULL, NULL);
+   }
+   if (pos < -1)
+   {
+      pos = -1;
+   }
+
+   MenuItem = ExAllocatePoolWithTag(PagedPool, sizeof(MENU_ITEM), TAG_MENUITEM);
+   if (NULL == MenuItem)
+   {
+      SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
+      return FALSE;
+   }
+
+   MenuItem->fType = MFT_STRING;
+   MenuItem->fState = MFS_ENABLED | MFS_UNCHECKED;
+   MenuItem->wID = 0;
+   MenuItem->hSubMenu = (HMENU)0;
+   MenuItem->hbmpChecked = (HBITMAP)0;
+   MenuItem->hbmpUnchecked = (HBITMAP)0;
+   MenuItem->dwItemData = 0;
+   RtlInitUnicodeString(&MenuItem->Text, NULL);
+   MenuItem->hbmpItem = (HBITMAP)0;
+
+   if (! IntSetMenuItemInfo(MenuObject, MenuItem, ItemInfo))
+   {
+      ExFreePool(MenuItem);
+      return FALSE;
+   }
+
+   /* Force size recalculation! */
+   MenuObject->MenuInfo.Height = 0;
+
+   pos = IntInsertMenuItemToList(MenuObject, MenuItem, pos);
+
+   DPRINT("IntInsertMenuItemToList = %i\n", pos);
+
+   return (pos >= 0);
 }
 
 UINT FASTCALL
-W32kEnableMenuItem(PMENU_OBJECT MenuObject, UINT uIDEnableItem, UINT uEnable)
+IntEnableMenuItem(PMENU_OBJECT MenuObject, UINT uIDEnableItem, UINT uEnable)
 {
-  PMENU_ITEM MenuItem;
-  UINT res = W32kGetMenuItemByFlag(MenuObject, uIDEnableItem, uEnable, &MenuItem);
-  if(!MenuItem || (res == (UINT)-1))
-  {
-    return (UINT)-1;
-  }
-  
-  res = MenuItem->MenuItem.fState & (MF_GRAYED | MF_DISABLED);
-  
-  if(uEnable & MF_DISABLED)
-  {
-    if(!(MenuItem->MenuItem.fState & MF_DISABLED))
-        MenuItem->MenuItem.fState |= MF_DISABLED;
-    if(uEnable & MF_GRAYED)
-    {
-      if(!(MenuItem->MenuItem.fState & MF_GRAYED))
-          MenuItem->MenuItem.fState |= MF_GRAYED;
-    }
-  }
-  else
-  {
-    if(uEnable & MF_GRAYED)
-    {
-      if(!(MenuItem->MenuItem.fState & MF_GRAYED))
-          MenuItem->MenuItem.fState |= MF_GRAYED;
-      if(!(MenuItem->MenuItem.fState & MF_DISABLED))
-          MenuItem->MenuItem.fState |= MF_DISABLED;
-    }
-    else
-    {
-      if(MenuItem->MenuItem.fState & MF_DISABLED)
-          MenuItem->MenuItem.fState ^= MF_DISABLED;
-      if(MenuItem->MenuItem.fState & MF_GRAYED)
-          MenuItem->MenuItem.fState ^= MF_GRAYED;
-    }
-  }
-  
-  return res;
+   PMENU_ITEM MenuItem;
+   UINT res = IntGetMenuItemByFlag(MenuObject, uIDEnableItem, uEnable, &MenuItem, NULL);
+   if(!MenuItem || (res == (UINT)-1))
+   {
+      return (UINT)-1;
+   }
+
+   res = MenuItem->fState & (MF_GRAYED | MF_DISABLED);
+
+   if(uEnable & MF_DISABLED)
+   {
+      if(!(MenuItem->fState & MF_DISABLED))
+         MenuItem->fState |= MF_DISABLED;
+      if(uEnable & MF_GRAYED)
+      {
+         if(!(MenuItem->fState & MF_GRAYED))
+            MenuItem->fState |= MF_GRAYED;
+      }
+   }
+   else
+   {
+      if(uEnable & MF_GRAYED)
+      {
+         if(!(MenuItem->fState & MF_GRAYED))
+            MenuItem->fState |= MF_GRAYED;
+         if(!(MenuItem->fState & MF_DISABLED))
+            MenuItem->fState |= MF_DISABLED;
+      }
+      else
+      {
+         if(MenuItem->fState & MF_DISABLED)
+            MenuItem->fState ^= MF_DISABLED;
+         if(MenuItem->fState & MF_GRAYED)
+            MenuItem->fState ^= MF_GRAYED;
+      }
+   }
+
+   return res;
 }
 
-/*
+
 DWORD FASTCALL
-W32kBuildMenuItemList(PMENU_OBJECT MenuObject, MENUITEMINFOW *lpmiil, ULONG nMax)
+IntBuildMenuItemList(PMENU_OBJECT MenuObject, PVOID Buffer, ULONG nMax)
 {
-  DWORD Index = 0;
-  PMENU_ITEM CurItem = MenuObject->MenuItemList;
-  while(CurItem && (nMax > 0))
-  {
-    memcpy(&lpmiil[Index], &CurItem->MenuItem, sizeof(MENUITEMINFOW));
-    CurItem = CurItem->Next;
-    Index++;
-    nMax--;
-  }
-  return Index;
+   DWORD res = 0;
+   UINT sz;
+   ROSMENUITEMINFO mii;
+   PVOID Buf;
+   PMENU_ITEM CurItem = MenuObject->MenuItemList;
+   PWCHAR StrOut;
+   NTSTATUS Status;
+   WCHAR NulByte;
+
+   if (0 != nMax)
+   {
+      if (nMax < MenuObject->MenuInfo.MenuItemCount * sizeof(ROSMENUITEMINFO))
+      {
+         return 0;
+      }
+      StrOut = (PWCHAR)((char *) Buffer + MenuObject->MenuInfo.MenuItemCount
+                        * sizeof(ROSMENUITEMINFO));
+      nMax -= MenuObject->MenuInfo.MenuItemCount * sizeof(ROSMENUITEMINFO);
+      sz = sizeof(ROSMENUITEMINFO);
+      Buf = Buffer;
+      mii.cbSize = sizeof(ROSMENUITEMINFO);
+      mii.fMask = 0;
+      NulByte = L'\0';
+
+      while (NULL != CurItem)
+      {
+         mii.cch = CurItem->Text.Length / sizeof(WCHAR);
+         mii.dwItemData = CurItem->dwItemData;
+         if (0 != CurItem->Text.Length)
+         {
+            mii.dwTypeData = StrOut;
+         }
+         else
+         {
+            mii.dwTypeData = NULL;
+         }
+         mii.fState = CurItem->fState;
+         mii.fType = CurItem->fType;
+         mii.hbmpChecked = CurItem->hbmpChecked;
+         mii.hbmpItem = CurItem->hbmpItem;
+         mii.hbmpUnchecked = CurItem->hbmpUnchecked;
+         mii.hSubMenu = CurItem->hSubMenu;
+         mii.Rect = CurItem->Rect;
+         mii.XTab = CurItem->XTab;
+
+         Status = MmCopyToCaller(Buf, &mii, sizeof(ROSMENUITEMINFO));
+         if (! NT_SUCCESS(Status))
+         {
+            SetLastNtError(Status);
+            return 0;
+         }
+         Buf = (PVOID)((ULONG_PTR)Buf + sizeof(ROSMENUITEMINFO));
+
+         if (0 != CurItem->Text.Length
+               && (nMax >= CurItem->Text.Length + sizeof(WCHAR)))
+         {
+            /* copy string */
+            Status = MmCopyToCaller(StrOut, CurItem->Text.Buffer,
+                                    CurItem->Text.Length);
+            if (! NT_SUCCESS(Status))
+            {
+               SetLastNtError(Status);
+               return 0;
+            }
+            StrOut += CurItem->Text.Length / sizeof(WCHAR);
+            Status = MmCopyToCaller(StrOut, &NulByte, sizeof(WCHAR));
+            if (! NT_SUCCESS(Status))
+            {
+               SetLastNtError(Status);
+               return 0;
+            }
+            StrOut++;
+            nMax -= CurItem->Text.Length + sizeof(WCHAR);
+         }
+         else if (0 != CurItem->Text.Length)
+         {
+            break;
+         }
+
+         CurItem = CurItem->Next;
+         res++;
+      }
+   }
+   else
+   {
+      while (NULL != CurItem)
+      {
+         res += sizeof(ROSMENUITEMINFO) + CurItem->Text.Length + sizeof(WCHAR);
+         CurItem = CurItem->Next;
+      }
+   }
+
+   return res;
 }
-*/
+
 
 DWORD FASTCALL
-W32kCheckMenuItem(PMENU_OBJECT MenuObject, UINT uIDCheckItem, UINT uCheck)
+IntCheckMenuItem(PMENU_OBJECT MenuObject, UINT uIDCheckItem, UINT uCheck)
 {
-  PMENU_ITEM MenuItem;
-  int res = -1;
-
-  if((W32kGetMenuItemByFlag(MenuObject, uIDCheckItem, uCheck, &MenuItem) < 0) || !MenuItem)
-  {
-    return -1;
-  }
-
-  res = (DWORD)(MenuItem->MenuItem.fState & MF_CHECKED);
-  if(uCheck & MF_CHECKED)
-  {
-    if(!(MenuItem->MenuItem.fState & MF_CHECKED))
-        MenuItem->MenuItem.fState |= MF_CHECKED;
-  }
-  else
-  {
-    if(MenuItem->MenuItem.fState & MF_CHECKED)
-        MenuItem->MenuItem.fState ^= MF_CHECKED;
-  }
-
-  return (DWORD)res;
+   PMENU_ITEM MenuItem;
+   int res = -1;
+
+   if((IntGetMenuItemByFlag(MenuObject, uIDCheckItem, uCheck, &MenuItem, NULL) < 0) || !MenuItem)
+   {
+      return -1;
+   }
+
+   res = (DWORD)(MenuItem->fState & MF_CHECKED);
+   if(uCheck & MF_CHECKED)
+   {
+      if(!(MenuItem->fState & MF_CHECKED))
+         MenuItem->fState |= MF_CHECKED;
+   }
+   else
+   {
+      if(MenuItem->fState & MF_CHECKED)
+         MenuItem->fState ^= MF_CHECKED;
+   }
+
+   return (DWORD)res;
 }
 
 BOOL FASTCALL
-W32kHiliteMenuItem(PWINDOW_OBJECT WindowObject, PMENU_OBJECT MenuObject,
-  UINT uItemHilite, UINT uHilite)
+IntHiliteMenuItem(PWINDOW_OBJECT WindowObject, PMENU_OBJECT MenuObject,
+                  UINT uItemHilite, UINT uHilite)
 {
-  PMENU_ITEM MenuItem;
-  BOOL res = W32kGetMenuItemByFlag(MenuObject, uItemHilite, uHilite, &MenuItem);
-  if(!MenuItem || !res)
-  {
-    return FALSE;
-  }
-  
-  if(uHilite & MF_HILITE)
-  {
-    if(!(MenuItem->MenuItem.fState & MF_HILITE))
-        MenuItem->MenuItem.fState |= MF_HILITE;
-  }
-  else
-  {
-    if(MenuItem->MenuItem.fState & MF_HILITE)
-        MenuItem->MenuItem.fState ^= MF_HILITE;
-  }
-  
-  /* FIXME - update the window's menu */
-  
-  return TRUE;
+   PMENU_ITEM MenuItem;
+   BOOL res = IntGetMenuItemByFlag(MenuObject, uItemHilite, uHilite, &MenuItem, NULL);
+   if(!MenuItem || !res)
+   {
+      return FALSE;
+   }
+
+   if(uHilite & MF_HILITE)
+   {
+      if(!(MenuItem->fState & MF_HILITE))
+         MenuItem->fState |= MF_HILITE;
+   }
+   else
+   {
+      if(MenuItem->fState & MF_HILITE)
+         MenuItem->fState ^= MF_HILITE;
+   }
+
+   /* FIXME - update the window's menu */
+
+   return TRUE;
 }
 
 BOOL FASTCALL
-W32kSetMenuDefaultItem(PMENU_OBJECT MenuObject, UINT uItem, UINT fByPos)
+UserSetMenuDefaultItem(PMENU_OBJECT MenuObject, UINT uItem, UINT fByPos)
 {
-  BOOL ret = FALSE;
-  PMENU_ITEM MenuItem = MenuObject->MenuItemList;  
-  if(fByPos)
-  {
-    UINT pos = 0;
-    while(MenuItem)
-    {
-      if(pos == uItem)
+   BOOL ret = FALSE;
+   PMENU_ITEM MenuItem = MenuObject->MenuItemList;
+
+   if(uItem == (UINT)-1)
+   {
+      while(MenuItem)
       {
-        if(!(MenuItem->MenuItem.fState & MFS_DEFAULT))
-          MenuItem->MenuItem.fState |= MFS_DEFAULT;
-        ret = TRUE;
+         if(MenuItem->fState & MFS_DEFAULT)
+            MenuItem->fState ^= MFS_DEFAULT;
+         MenuItem = MenuItem->Next;
       }
-      else
+      return TRUE;
+   }
+
+   if(fByPos)
+   {
+      UINT pos = 0;
+      while(MenuItem)
       {
-        if(MenuItem->MenuItem.fState & MFS_DEFAULT)
-          MenuItem->MenuItem.fState ^= MFS_DEFAULT;
+         if(pos == uItem)
+         {
+            if(!(MenuItem->fState & MFS_DEFAULT))
+               MenuItem->fState |= MFS_DEFAULT;
+            ret = TRUE;
+         }
+         else
+         {
+            if(MenuItem->fState & MFS_DEFAULT)
+               MenuItem->fState ^= MFS_DEFAULT;
+         }
+         pos++;
+         MenuItem = MenuItem->Next;
       }
-      pos++;
-      MenuItem = MenuItem->Next;
-    }
-  }
-  else
-  {
-    while(MenuItem)
-    {
-      if(!ret && (MenuItem->MenuItem.wID == uItem))
+   }
+   else
+   {
+      while(MenuItem)
       {
-        if(!(MenuItem->MenuItem.fState & MFS_DEFAULT))
-          MenuItem->MenuItem.fState |= MFS_DEFAULT;
-        ret = TRUE;
+         if(!ret && (MenuItem->wID == uItem))
+         {
+            if(!(MenuItem->fState & MFS_DEFAULT))
+               MenuItem->fState |= MFS_DEFAULT;
+            ret = TRUE;
+         }
+         else
+         {
+            if(MenuItem->fState & MFS_DEFAULT)
+               MenuItem->fState ^= MFS_DEFAULT;
+         }
+         MenuItem = MenuItem->Next;
       }
-      else
+   }
+   return ret;
+}
+
+
+UINT FASTCALL
+IntGetMenuDefaultItem(PMENU_OBJECT MenuObject, UINT fByPos, UINT gmdiFlags,
+                      DWORD *gismc)
+{
+   UINT x = 0;
+   UINT res = -1;
+   UINT sres;
+   PMENU_OBJECT SubMenuObject;
+   PMENU_ITEM MenuItem = MenuObject->MenuItemList;
+
+   while(MenuItem)
+   {
+      if(MenuItem->fState & MFS_DEFAULT)
       {
-        if(MenuItem->MenuItem.fState & MFS_DEFAULT)
-          MenuItem->MenuItem.fState ^= MFS_DEFAULT;
+
+         if(!(gmdiFlags & GMDI_USEDISABLED) && (MenuItem->fState & MFS_DISABLED))
+            break;
+
+         if(fByPos & MF_BYPOSITION)
+            res = x;
+         else
+            res = MenuItem->wID;
+
+         if((*gismc < MAX_GOINTOSUBMENU) && (gmdiFlags & GMDI_GOINTOPOPUPS) &&
+               MenuItem->hSubMenu)
+         {
+
+            SubMenuObject = UserGetMenuObject(MenuItem->hSubMenu);
+            if(!SubMenuObject || (SubMenuObject == MenuObject))
+               break;
+
+            (*gismc)++;
+            sres = IntGetMenuDefaultItem(SubMenuObject, fByPos, gmdiFlags, gismc);
+            (*gismc)--;
+
+            if(sres > (UINT)-1)
+               res = sres;
+         }
+
+         break;
       }
+
       MenuItem = MenuItem->Next;
-    }
-  }
-  return ret;
+      x++;
+   }
+
+   return res;
+}
+
+VOID FASTCALL
+co_IntInitTracking(PWINDOW_OBJECT Window, PMENU_OBJECT Menu, BOOL Popup,
+                   UINT Flags)
+{
+   /* FIXME - hide caret */
+
+   if(!(Flags & TPM_NONOTIFY))
+      co_IntSendMessage(Window->hSelf, WM_SETCURSOR, (WPARAM)Window->hSelf, HTCAPTION);
+
+   /* FIXME - send WM_SETCURSOR message */
+
+   if(!(Flags & TPM_NONOTIFY))
+      co_IntSendMessage(Window->hSelf, WM_INITMENU, (WPARAM)Menu->MenuInfo.Self, 0);
+}
+
+VOID FASTCALL
+co_IntExitTracking(PWINDOW_OBJECT Window, PMENU_OBJECT Menu, BOOL Popup,
+                   UINT Flags)
+{
+   if(!(Flags & TPM_NONOTIFY))
+      co_IntSendMessage(Window->hSelf, WM_EXITMENULOOP, 0 /* FIXME */, 0);
+
+   /* FIXME - Show caret again */
+}
+
+INT FASTCALL
+IntTrackMenu(PMENU_OBJECT Menu, PWINDOW_OBJECT Window, INT x, INT y,
+             RECT lprect)
+{
+   return 0;
+}
+
+BOOL FASTCALL
+co_IntTrackPopupMenu(PMENU_OBJECT Menu, PWINDOW_OBJECT Window,
+                     UINT Flags, POINT *Pos, UINT MenuPos, RECT *ExcludeRect)
+{
+   co_IntInitTracking(Window, Menu, TRUE, Flags);
+
+   co_IntExitTracking(Window, Menu, TRUE, Flags);
+   return FALSE;
+}
+
+BOOL FASTCALL
+IntSetMenuItemRect(PMENU_OBJECT Menu, UINT Item, BOOL fByPos, RECT *rcRect)
+{
+   PMENU_ITEM mi;
+   if(IntGetMenuItemByFlag(Menu, Item, (fByPos ? MF_BYPOSITION : MF_BYCOMMAND),
+                           &mi, NULL) > -1)
+   {
+      mi->Rect = *rcRect;
+      return TRUE;
+   }
+   return FALSE;
+}
+
+
+/*!
+ * Internal function. Called when the process is destroyed to free the remaining menu handles.
+*/
+BOOL FASTCALL
+IntCleanupMenus(struct _EPROCESS *Process, PW32PROCESS Win32Process)
+{
+   PEPROCESS CurrentProcess;
+   PLIST_ENTRY LastHead = NULL;
+   PMENU_OBJECT MenuObject;
+
+   CurrentProcess = PsGetCurrentProcess();
+   if (CurrentProcess != Process)
+   {
+      KeAttachProcess(&Process->Pcb);
+   }
+
+   while (Win32Process->MenuListHead.Flink != &(Win32Process->MenuListHead) &&
+          Win32Process->MenuListHead.Flink != LastHead)
+   {
+      LastHead = Win32Process->MenuListHead.Flink;
+      MenuObject = CONTAINING_RECORD(Win32Process->MenuListHead.Flink, MENU_OBJECT, ListEntry);
+
+      IntDestroyMenuObject(MenuObject, FALSE, TRUE);
+   }
+
+   if (CurrentProcess != Process)
+   {
+      KeDetachProcess();
+   }
+   return TRUE;
 }
 
 /* FUNCTIONS *****************************************************************/
@@ -704,36 +1313,38 @@ W32kSetMenuDefaultItem(PMENU_OBJECT MenuObject, UINT uItem, UINT fByPos)
 DWORD
 STDCALL
 NtUserBuildMenuItemList(
- HMENU hMenu,
LPCMENUITEMINFOW* lpmiil,
- ULONG nBufSize,
- DWORD Reserved)
  HMENU hMenu,
  VOID* Buffer,
  ULONG nBufSize,
  DWORD Reserved)
 {
-  DWORD res = -1;
-  PMENU_OBJECT MenuObject = W32kGetMenuObject(hMenu);
-  if(!MenuObject)
-  {
-    SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
-    return -1;
-  }
-  
-  if(lpmiil)
-  {
-    /* FIXME need to pass the menu strings to user32 somehow....
-    
-    ExAcquireFastMutexUnsafe(&MenuObject->MenuItemsLock);
-    res = W32kBuildMenuItemList(MenuObject, lpmiil, nBufSize / sizeof(LPCMENUITEMINFO));
-    ExReleaseFastMutexUnsafe(&MenuObject->MenuItemsLock);
-    */
-  }
-  else
-  {
-    res = MenuObject->MenuItemCount;
-  }
-  
-  W32kReleaseMenuObject(MenuObject);
-
-  return res;
+   DWORD res = -1;
+   PMENU_OBJECT Menu;
+   DECLARE_RETURN(DWORD);
+
+   DPRINT("Enter NtUserBuildMenuItemList\n");
+   UserEnterExclusive();
+
+   if(!(Menu = UserGetMenuObject(hMenu)))
+   {
+      RETURN( (DWORD)-1);
+   }
+
+   if(Buffer)
+   {
+      res = IntBuildMenuItemList(Menu, Buffer, nBufSize);
+   }
+   else
+   {
+      res = Menu->MenuInfo.MenuItemCount;
+   }
+
+   RETURN( res);
+
+CLEANUP:
+   DPRINT("Leave NtUserBuildMenuItemList, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 
@@ -742,86 +1353,155 @@ NtUserBuildMenuItemList(
  */
 DWORD STDCALL
 NtUserCheckMenuItem(
-  HMENU hmenu,
-  UINT uIDCheckItem,
-  UINT uCheck)
+   HMENU hMenu,
+   UINT uIDCheckItem,
+   UINT uCheck)
 {
-  DWORD res = 0;
-  PMENU_OBJECT MenuObject = W32kGetMenuObject(hmenu);
-  if(!MenuObject)
-  {
-    SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
-    return (DWORD)-1;
-  }
-  ExAcquireFastMutexUnsafe(&MenuObject->MenuItemsLock);
-  res = W32kCheckMenuItem(MenuObject, uIDCheckItem, uCheck);
-  ExReleaseFastMutexUnsafe(&MenuObject->MenuItemsLock);
-  W32kReleaseMenuObject(MenuObject);
-  return res;
+   PMENU_OBJECT Menu;
+   DECLARE_RETURN(DWORD);
+
+   DPRINT("Enter NtUserCheckMenuItem\n");
+   UserEnterExclusive();
+
+   if(!(Menu = UserGetMenuObject(hMenu)))
+   {
+      RETURN( (DWORD)-1);
+   }
+
+   RETURN( IntCheckMenuItem(Menu, uIDCheckItem, uCheck));
+
+CLEANUP:
+   DPRINT("Leave NtUserCheckMenuItem, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 
-/*
- * @implemented
- */
+HMENU FASTCALL UserCreateMenu(BOOL PopupMenu)
+{
+   PWINSTATION_OBJECT WinStaObject;
+   HANDLE Handle;
+
+   NTSTATUS Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
+                     KernelMode,
+                     0,
+                     &WinStaObject);
+
+   if (!NT_SUCCESS(Status))
+   {
+      DPRINT("Validation of window station handle (0x%X) failed\n",
+             PsGetCurrentProcess()->Win32WindowStation);
+      SetLastNtError(Status);
+      return (HMENU)0;
+   }
+
+   IntCreateMenu(&Handle, !PopupMenu);
+
+   ObDereferenceObject(WinStaObject);
+   return (HMENU)Handle;
+}
+
+
+
 HMENU STDCALL
-NtUserCreateMenu(VOID)
+NtUserCreateMenu(BOOL PopupMenu)
 {
-  PWINSTATION_OBJECT WinStaObject;
-  HANDLE Handle;
-  
-  NTSTATUS Status = ValidateWindowStationHandle(PROCESS_WINDOW_STATION(),
-                                      KernelMode,
-                                      0,
-                                      &WinStaObject);
-                                      
-  if (!NT_SUCCESS(Status))
-  {
-    DPRINT("Validation of window station handle (0x%X) failed\n",
-      PROCESS_WINDOW_STATION());
-    SetLastWin32Error(Status);
-    return (HMENU)0;
-  }
-
-  W32kCreateMenu(&Handle);
-  ObDereferenceObject(WinStaObject);
-  return (HMENU)Handle;
+   DECLARE_RETURN(HMENU);
+
+   DPRINT("Enter NtUserCreateMenu\n");
+   UserEnterExclusive();
+
+   RETURN(UserCreateMenu(PopupMenu));
+
+CLEANUP:
+   DPRINT("Leave NtUserCreateMenu, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 
+
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL STDCALL
 NtUserDeleteMenu(
-  HMENU hMenu,
-  UINT uPosition,
-  UINT uFlags)
+   HMENU hMenu,
+   UINT uPosition,
+   UINT uFlags)
 {
+   PMENU_OBJECT Menu;
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserDeleteMenu\n");
+   UserEnterExclusive();
 
-  UNIMPLEMENTED
+   if(!(Menu = UserGetMenuObject(hMenu)))
+   {
+      RETURN( FALSE);
+   }
 
-  return 0;
+   RETURN( IntRemoveMenuItem(Menu, uPosition, uFlags, TRUE));
+
+CLEANUP:
+   DPRINT("Leave NtUserDeleteMenu, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 
+
+/*
+ * @implemented
+ */
+BOOL FASTCALL UserDestroyMenu(HMENU hMenu)
+{
+   PMENU_OBJECT Menu;
+   
+   if(!(Menu = UserGetMenuObject(hMenu)))
+   {
+      return FALSE;
+   }
+   
+   if(Menu->Process != PsGetCurrentProcess())
+   {
+      SetLastWin32Error(ERROR_ACCESS_DENIED);
+      return FALSE;
+   }
+
+   return IntDestroyMenuObject(Menu, FALSE, TRUE);
+}
+
 /*
  * @implemented
  */
 BOOL STDCALL
 NtUserDestroyMenu(
-  HMENU hMenu)
+   HMENU hMenu)
 {
-  /* FIXME, check if menu belongs to the process */
-  
-  PMENU_OBJECT MenuObject = W32kGetMenuObject(hMenu);
-  if(!MenuObject)
-  {
-    SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
-    return FALSE;
-  }
-
-  return W32kDestroyMenuObject(MenuObject);
+   PMENU_OBJECT Menu;
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserDestroyMenu\n");
+   UserEnterExclusive();
+
+   if(!(Menu = UserGetMenuObject(hMenu)))
+   {
+      RETURN( FALSE);
+   }
+   
+   if(Menu->Process != PsGetCurrentProcess())
+   {
+      SetLastWin32Error(ERROR_ACCESS_DENIED);
+      RETURN( FALSE);
+   }
+
+   RETURN( IntDestroyMenuObject(Menu, FALSE, TRUE));
+
+CLEANUP:
+   DPRINT("Leave NtUserDestroyMenu, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 
@@ -830,24 +1510,27 @@ NtUserDestroyMenu(
  */
 UINT STDCALL
 NtUserEnableMenuItem(
-  HMENU hMenu,
-  UINT uIDEnableItem,
-  UINT uEnable)
+   HMENU hMenu,
+   UINT uIDEnableItem,
+   UINT uEnable)
 {
-  UINT res = (UINT)-1;
-  PMENU_OBJECT MenuObject;
-  MenuObject = W32kGetMenuObject(hMenu);
-  if(!MenuObject)
-  {
-    SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
-    return res;
-  }
-  ExAcquireFastMutexUnsafe(&MenuObject->MenuItemsLock);
-  res = W32kEnableMenuItem(MenuObject, uIDEnableItem, uEnable);
-  ExReleaseFastMutexUnsafe(&MenuObject->MenuItemsLock);
-  W32kReleaseMenuObject(MenuObject);
-
-  return res;
+   PMENU_OBJECT Menu;
+   DECLARE_RETURN(UINT);
+
+   DPRINT("Enter NtUserEnableMenuItem\n");
+   UserEnterExclusive();
+
+   if(!(Menu = UserGetMenuObject(hMenu)))
+   {
+      RETURN(-1);
+   }
+
+   RETURN( IntEnableMenuItem(Menu, uIDEnableItem, uEnable));
+
+CLEANUP:
+   DPRINT("Leave NtUserEnableMenuItem, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 
@@ -856,24 +1539,57 @@ NtUserEnableMenuItem(
  */
 DWORD STDCALL
 NtUserInsertMenuItem(
-  HMENU hMenu,
-  UINT uItem,
-  WINBOOL fByPosition,
-  LPCMENUITEMINFOW lpmii)
+   HMENU hMenu,
+   UINT uItem,
+   BOOL fByPosition,
+   LPCMENUITEMINFOW UnsafeItemInfo)
 {
-  DWORD res = 0;
-  PMENU_OBJECT MenuObject;
-  MenuObject = W32kGetMenuObject(hMenu);
-  if(!MenuObject)
-  {
-    SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
-    return 0;
-  }
-  ExAcquireFastMutexUnsafe(&MenuObject->MenuItemsLock);
-  res = W32kInsertMenuItem(MenuObject, uItem, fByPosition, lpmii);
-  ExReleaseFastMutexUnsafe(&MenuObject->MenuItemsLock);
-  W32kReleaseMenuObject(MenuObject);
-  return res;
+   PMENU_OBJECT Menu;
+   NTSTATUS Status;
+   ROSMENUITEMINFO ItemInfo;
+   DECLARE_RETURN(DWORD);
+
+   DPRINT("Enter NtUserInsertMenuItem\n");
+   UserEnterExclusive();
+
+   if(!(Menu = UserGetMenuObject(hMenu)))
+   {
+      RETURN( FALSE);
+   }
+
+   /* Try to copy the whole MENUITEMINFOW structure */
+   Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, sizeof(MENUITEMINFOW));
+   if (NT_SUCCESS(Status))
+   {
+      if (sizeof(MENUITEMINFOW) != ItemInfo.cbSize
+         && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize)
+      {
+         SetLastWin32Error(ERROR_INVALID_PARAMETER);
+         RETURN( FALSE);
+      }
+      RETURN( IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo));
+   }
+
+   /* Try to copy without last field (not present in older versions) */
+   Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, FIELD_OFFSET(MENUITEMINFOW, hbmpItem));
+   if (NT_SUCCESS(Status))
+   {
+      if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize)
+      {
+         SetLastWin32Error(ERROR_INVALID_PARAMETER);
+         RETURN( FALSE);
+      }
+      ItemInfo.hbmpItem = (HBITMAP)0;
+      RETURN( IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo));
+   }
+
+   SetLastNtError(Status);
+   RETURN( FALSE);
+
+CLEANUP:
+   DPRINT("Leave NtUserInsertMenuItem, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 
@@ -883,55 +1599,329 @@ NtUserInsertMenuItem(
 BOOL STDCALL
 NtUserEndMenu(VOID)
 {
-  UNIMPLEMENTED
-  
-  return 0;
+   UNIMPLEMENTED
+
+   return 0;
 }
 
 
 /*
- * @unimplemented
+ * @implemented
+ */
+UINT STDCALL
+NtUserGetMenuDefaultItem(
+   HMENU hMenu,
+   UINT fByPos,
+   UINT gmdiFlags)
+{
+   PMENU_OBJECT Menu;
+   DWORD gismc = 0;
+   DECLARE_RETURN(UINT);
+
+   DPRINT("Enter NtUserGetMenuDefaultItem\n");
+   UserEnterExclusive();
+
+   if(!(Menu = UserGetMenuObject(hMenu)))
+   {
+      RETURN(-1);
+   }
+
+   RETURN( IntGetMenuDefaultItem(Menu, fByPos, gmdiFlags, &gismc));
+
+CLEANUP:
+   DPRINT("Leave NtUserGetMenuDefaultItem, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
+}
+
+
+/*
+ * @implemented
  */
 BOOL STDCALL
 NtUserGetMenuBarInfo(
-  HWND hwnd,
-  LONG idObject,
-  LONG idItem,
-  PMENUBARINFO pmbi)
+   HWND hwnd,
+   LONG idObject,
+   LONG idItem,
+   PMENUBARINFO pmbi)
 {
-  UNIMPLEMENTED
-
-  return 0;
+   BOOL Res = TRUE;
+   PMENU_OBJECT MenuObject;
+   PMENU_ITEM mi;
+   PWINDOW_OBJECT WindowObject;
+   HMENU hMenu;
+   POINT Offset;
+   RECT Rect;
+   MENUBARINFO kmbi;
+   DECLARE_RETURN(BOOL);
+  
+   DPRINT("Enter NtUserGetMenuBarInfo\n");
+   UserEnterShared();
+  
+   if (!(WindowObject = UserGetWindowObject(hwnd)))
+     {
+        SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
+        RETURN(FALSE);
+     }
+
+   hMenu = (HMENU)WindowObject->IDMenu;
+
+   if (!(MenuObject = UserGetMenuObject(hMenu)))
+     {
+       SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
+       RETURN(FALSE);
+     }
+
+   if (pmbi->cbSize != sizeof(MENUBARINFO))
+     {
+       SetLastWin32Error(ERROR_INVALID_PARAMETER);
+       RETURN(FALSE);
+     }
+
+   kmbi.cbSize = sizeof(MENUBARINFO);
+   kmbi.fBarFocused = FALSE;
+   kmbi.fFocused = FALSE;
+   kmbi.hwndMenu = NULL;
+   
+   switch (idObject)
+   {
+      case OBJID_MENU:
+      {
+         PMENU_OBJECT SubMenuObject;
+         kmbi.hMenu = hMenu;
+         if (idItem) /* Non-Zero-Based. */
+           {
+              if (IntGetMenuItemByFlag(MenuObject, idItem-1, MF_BYPOSITION, &mi, NULL) > -1)
+                   kmbi.rcBar = mi->Rect;
+              else
+                {
+                   Res = FALSE;
+                   break;
+                }
+           }
+         else
+           {  
+              /* If items is zero we assume info for the menu itself. */
+              if (!(IntGetClientOrigin(WindowObject, &Offset)))
+                {
+                   Res = FALSE;
+                   break;
+                }
+              Rect.left = Offset.x;
+              Rect.right = Offset.x + MenuObject->MenuInfo.Width;
+              Rect.top = Offset.y;
+              Rect.bottom = Offset.y + MenuObject->MenuInfo.Height;
+              kmbi.rcBar = Rect;
+              DPRINT("Rect top = %d bottom = %d left = %d right = %d \n",
+                       Rect.top, Rect.bottom, Rect.left, Rect.right);
+           }
+         if (idItem)
+           {
+              if (idItem-1 == MenuObject->MenuInfo.FocusedItem)
+                    kmbi.fFocused = TRUE;
+           }
+         if (MenuObject->MenuInfo.FocusedItem != NO_SELECTED_ITEM)
+               kmbi.fBarFocused = TRUE;
+         SubMenuObject = UserGetMenuObject(MenuObject->MenuItemList->hSubMenu);
+         if(SubMenuObject) kmbi.hwndMenu = SubMenuObject->MenuInfo.Wnd;
+         DPRINT("OBJID_MENU, idItem = %d\n",idItem);
+         break;
+      }
+      case OBJID_CLIENT:
+      {
+         PMENU_OBJECT SubMenuObject, XSubMenuObject;
+         SubMenuObject = UserGetMenuObject(MenuObject->MenuItemList->hSubMenu);
+         if(SubMenuObject) kmbi.hMenu = SubMenuObject->MenuInfo.Self;
+         else
+           {
+              Res = FALSE;
+              DPRINT1("OBJID_CLIENT, No SubMenu!\n");
+              break;
+           }
+         if (idItem)
+           {
+              if (IntGetMenuItemByFlag(SubMenuObject, idItem-1, MF_BYPOSITION, &mi, NULL) > -1)
+                   kmbi.rcBar = mi->Rect;
+              else
+                {
+                   Res = FALSE;
+                   break;
+                }
+           }
+         else
+           {
+              PWINDOW_OBJECT SubWinObj;
+              if (!(SubWinObj = UserGetWindowObject(SubMenuObject->MenuInfo.Wnd)))
+                {
+                   Res = FALSE;
+                   break;
+                }
+              if (!(IntGetClientOrigin(SubWinObj, &Offset)))
+                {
+                   Res = FALSE;
+                   break;
+                }
+              Rect.left = Offset.x;
+              Rect.right = Offset.x + SubMenuObject->MenuInfo.Width;
+              Rect.top = Offset.y;
+              Rect.bottom = Offset.y + SubMenuObject->MenuInfo.Height;
+              kmbi.rcBar = Rect;
+           }
+         if (idItem)
+           {
+              if (idItem-1 == SubMenuObject->MenuInfo.FocusedItem)
+                   kmbi.fFocused = TRUE;
+           }
+         if (SubMenuObject->MenuInfo.FocusedItem != NO_SELECTED_ITEM)
+               kmbi.fBarFocused = TRUE;
+         XSubMenuObject = UserGetMenuObject(SubMenuObject->MenuItemList->hSubMenu);
+         if (XSubMenuObject) kmbi.hwndMenu = XSubMenuObject->MenuInfo.Wnd;
+         DPRINT("OBJID_CLIENT, idItem = %d\n",idItem);
+         break;
+      }
+      case OBJID_SYSMENU:
+      {
+         PMENU_OBJECT SysMenuObject, SubMenuObject;
+         if(!(SysMenuObject = IntGetSystemMenu(WindowObject, FALSE, FALSE)))
+         {
+           Res = FALSE;
+           break;
+         }
+         kmbi.hMenu = SysMenuObject->MenuInfo.Self;
+         if (idItem)
+           {
+              if (IntGetMenuItemByFlag(SysMenuObject, idItem-1, MF_BYPOSITION, &mi, NULL) > -1)
+                   kmbi.rcBar = mi->Rect;
+              else
+                {
+                   Res = FALSE;
+                   break;
+                }
+           }
+         else
+           {
+              PWINDOW_OBJECT SysWinObj;
+              if (!(SysWinObj = UserGetWindowObject(SysMenuObject->MenuInfo.Wnd)))
+                {
+                   Res = FALSE;
+                   break;
+                }
+              if (!(IntGetClientOrigin(SysWinObj, &Offset)))
+                {
+                   Res = FALSE;
+                   break;
+                }
+              Rect.left = Offset.x;
+              Rect.right = Offset.x + SysMenuObject->MenuInfo.Width;
+              Rect.top = Offset.y;
+              Rect.bottom = Offset.y + SysMenuObject->MenuInfo.Height;
+              kmbi.rcBar = Rect;
+           }
+         if (idItem)
+           {
+              if (idItem-1 == SysMenuObject->MenuInfo.FocusedItem)
+                    kmbi.fFocused = TRUE;
+           }
+         if (SysMenuObject->MenuInfo.FocusedItem != NO_SELECTED_ITEM)
+               kmbi.fBarFocused = TRUE;
+         SubMenuObject = UserGetMenuObject(SysMenuObject->MenuItemList->hSubMenu);
+         if(SubMenuObject) kmbi.hwndMenu = SubMenuObject->MenuInfo.Wnd;
+         DPRINT("OBJID_SYSMENU, idItem = %d\n",idItem);
+         break;
+      }
+      default:
+         Res = FALSE;
+         DPRINT1("Unknown idObject = %d, idItem = %d\n",idObject,idItem);
+   }
+   if (Res)
+     {
+        NTSTATUS Status = MmCopyToCaller(pmbi, &kmbi, sizeof(MENUBARINFO));
+        if (! NT_SUCCESS(Status))
+          {
+            SetLastNtError(Status);
+            RETURN(FALSE);
+          }
+     }
+   RETURN(Res);
+
+CLEANUP:
+   DPRINT("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;  
 }
 
 
 /*
  * @unimplemented
  */
-DWORD STDCALL
+UINT STDCALL
 NtUserGetMenuIndex(
-  DWORD Unknown0,
-  DWORD Unknown1)
+   HMENU hMenu,
+   UINT wID)
 {
-  UNIMPLEMENTED
+   UNIMPLEMENTED
 
-  return 0;
+   return 0;
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL STDCALL
 NtUserGetMenuItemRect(
-  HWND hWnd,
-  HMENU hMenu,
-  UINT uItem,
-  LPRECT lprcItem)
+   HWND hWnd,
+   HMENU hMenu,
+   UINT uItem,
+   LPRECT lprcItem)
 {
-  UNIMPLEMENTED
-
-  return 0;
+   ROSMENUINFO mi;
+   HWND referenceHwnd;
+   RECT Rect;
+   NTSTATUS Status;
+   PMENU_OBJECT Menu;
+   PMENU_ITEM MenuItem;
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserGetMenuItemRect\n");
+   UserEnterShared();
+
+   if (!(Menu = UserGetMenuObject(hMenu)))
+   {
+      RETURN(FALSE);
+   }
+
+   if (IntGetMenuItemByFlag(Menu, uItem, MF_BYPOSITION, &MenuItem, NULL) > -1)
+        Rect = MenuItem->Rect;
+   else
+      RETURN(FALSE);
+   
+   referenceHwnd = hWnd;
+   
+   if(!hWnd)
+   {
+      if(!UserMenuInfo(Menu, &mi, FALSE))
+         RETURN( FALSE);
+      if(mi.Wnd == 0)
+         RETURN( FALSE);
+      referenceHwnd = mi.Wnd; /* Okay we found it, so now what do we do? */
+   }
+
+   if (lprcItem == NULL)
+      RETURN( FALSE);
+
+   Status = MmCopyToCaller(lprcItem, &Rect, sizeof(RECT));
+   if (! NT_SUCCESS(Status))
+   {
+      SetLastNtError(Status);
+      RETURN( FALSE);
+   }
+   RETURN( TRUE);
+
+CLEANUP:
+   DPRINT("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 
@@ -940,123 +1930,316 @@ NtUserGetMenuItemRect(
  */
 BOOL STDCALL
 NtUserHiliteMenuItem(
-  HWND hwnd,
-  HMENU hmenu,
-  UINT uItemHilite,
-  UINT uHilite)
+   HWND hWnd,
+   HMENU hMenu,
+   UINT uItemHilite,
+   UINT uHilite)
+{
+   PMENU_OBJECT Menu;
+   PWINDOW_OBJECT Window;
+   DECLARE_RETURN(BOOLEAN);
+
+   DPRINT("Enter NtUserHiliteMenuItem\n");
+   UserEnterExclusive();
+
+   if(!(Window = UserGetWindowObject(hWnd)))
+   {
+      RETURN(FALSE);
+   }
+   
+   if(!(Menu = UserGetMenuObject(hMenu)))
+   {
+      RETURN(FALSE);
+   }
+   
+   if(Window->IDMenu == (UINT)hMenu)
+   {
+      RETURN( IntHiliteMenuItem(Window, Menu, uItemHilite, uHilite));
+   }
+
+   RETURN(FALSE);
+
+CLEANUP:
+   DPRINT("Leave NtUserHiliteMenuItem, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
+}
+
+
+static
+BOOL FASTCALL
+UserMenuInfo(
+   PMENU_OBJECT Menu,
+   PROSMENUINFO UnsafeMenuInfo,
+   BOOL SetOrGet)
 {
-  BOOL res = FALSE;
-  PMENU_OBJECT MenuObject;
-  PWINDOW_OBJECT WindowObject = W32kGetWindowObject(hwnd);
-  if(!WindowObject)
-  {
-    SetLastWin32Error(ERROR_INVALID_HANDLE);
-    return res;
-  }
-  MenuObject = W32kGetMenuObject(hmenu);
-  if(!MenuObject)
-  {
-    W32kReleaseWindowObject(WindowObject);
-    SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
-    return res;
-  }
-  if(WindowObject->Menu == hmenu)
-  {
-    ExAcquireFastMutexUnsafe(&MenuObject->MenuItemsLock);
-    res = W32kHiliteMenuItem(WindowObject, MenuObject, uItemHilite, uHilite);
-    ExReleaseFastMutexUnsafe(&MenuObject->MenuItemsLock);
-  }
-  W32kReleaseMenuObject(MenuObject);
-  W32kReleaseWindowObject(WindowObject);
-  return res;
+   BOOL Res;
+   DWORD Size;
+   NTSTATUS Status;
+   ROSMENUINFO MenuInfo;
+
+   Status = MmCopyFromCaller(&Size, &UnsafeMenuInfo->cbSize, sizeof(DWORD));
+   if (! NT_SUCCESS(Status))
+   {
+      SetLastNtError(Status);
+      return( FALSE);
+   }
+   if(Size < sizeof(MENUINFO) || sizeof(ROSMENUINFO) < Size)
+   {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      return( FALSE);
+   }
+   Status = MmCopyFromCaller(&MenuInfo, UnsafeMenuInfo, Size);
+   if (! NT_SUCCESS(Status))
+   {
+      SetLastNtError(Status);
+      return( FALSE);
+   }
+
+   if(SetOrGet)
+   {
+      /* Set MenuInfo */
+      Res = IntSetMenuInfo(Menu, &MenuInfo);
+   }
+   else
+   {
+      /* Get MenuInfo */
+      Res = IntGetMenuInfo(Menu, &MenuInfo);
+      if (Res)
+      {
+         Status = MmCopyToCaller(UnsafeMenuInfo, &MenuInfo, Size);
+         if (! NT_SUCCESS(Status))
+         {
+            SetLastNtError(Status);
+            return( FALSE);
+         }
+      }
+   }
+
+   return( Res);
 }
 
 
+
+
+
 /*
  * @implemented
  */
 BOOL
 STDCALL
 NtUserMenuInfo(
HMENU hmenu,
LPMENUINFO lpmi,
BOOL fsog)
  HMENU hMenu,
  PROSMENUINFO UnsafeMenuInfo,
  BOOL SetOrGet)
 {
-  BOOL res = FALSE;
-  PMENU_OBJECT MenuObject;
-  
-  if(lpmi->cbSize != sizeof(MENUINFO))
-  {
-    /* FIXME - Set Last Error */
-    return FALSE;
-  }
-  MenuObject = W32kGetMenuObject(hmenu);
-  if(!MenuObject)
-  {
-    SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
-    return FALSE;
-  }  
-  if(fsog)
-  {
-    /* Set MenuInfo */
-    res = W32kSetMenuInfo(MenuObject, lpmi);  
-  }
-  else
-  {
-    /* Get MenuInfo */
-    res = W32kGetMenuInfo(MenuObject, lpmi);
-  }  
-  W32kReleaseMenuObject(MenuObject);
-  return res;
+   PMENU_OBJECT Menu;
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserMenuInfo\n");
+   UserEnterShared();
+
+   if (!(Menu = UserGetMenuObject(hMenu)))
+   {
+      RETURN(FALSE);
+   }
+
+   RETURN(UserMenuInfo(Menu, UnsafeMenuInfo, SetOrGet));
+
+CLEANUP:
+   DPRINT("Leave NtUserMenuInfo, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 
+
 /*
- * @unimplemented
+ * @implemented
  */
 int STDCALL
 NtUserMenuItemFromPoint(
-  HWND hWnd,
-  HMENU hMenu,
-  DWORD X,
-  DWORD Y)
+   HWND hWnd,
+   HMENU hMenu,
+   DWORD X,
+   DWORD Y)
+{
+   PMENU_OBJECT Menu;
+   PWINDOW_OBJECT Window = NULL;
+   PMENU_ITEM mi;
+   int i;
+   DECLARE_RETURN(int);
+
+   DPRINT("Enter NtUserMenuItemFromPoint\n");
+   UserEnterExclusive();
+
+   if (!(Menu = UserGetMenuObject(hMenu)))
+   {
+      RETURN( -1);
+   }
+
+   if (!(Window = UserGetWindowObject(Menu->MenuInfo.Wnd)))
+   {
+      RETURN( -1);
+   }
+
+   X -= Window->WindowRect.left;
+   Y -= Window->WindowRect.top;
+
+   mi = Menu->MenuItemList;
+   for (i = 0; NULL != mi; i++)
+   {
+      if (InRect(mi->Rect, X, Y))
+      {
+         break;
+      }
+      mi = mi->Next;
+   }
+
+   RETURN( (mi ? i : NO_SELECTED_ITEM));
+
+CLEANUP:
+   DPRINT("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
+}
+
+
+
+static
+BOOL FASTCALL
+UserMenuItemInfo(
+   PMENU_OBJECT Menu,
+   UINT Item,
+   BOOL ByPosition,
+   PROSMENUITEMINFO UnsafeItemInfo,
+   BOOL SetOrGet)
 {
-  UNIMPLEMENTED
+   PMENU_ITEM MenuItem;
+   ROSMENUITEMINFO ItemInfo;
+   NTSTATUS Status;
+   UINT Size;
+   BOOL Ret;
+
+   Status = MmCopyFromCaller(&Size, &UnsafeItemInfo->cbSize, sizeof(UINT));
+   if (! NT_SUCCESS(Status))
+   {
+      SetLastNtError(Status);
+      return( FALSE);
+   }
+   if (sizeof(MENUITEMINFOW) != Size
+         && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != Size
+         && sizeof(ROSMENUITEMINFO) != Size)
+   {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      return( FALSE);
+   }
+   Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, Size);
+   if (! NT_SUCCESS(Status))
+   {
+      SetLastNtError(Status);
+      return( FALSE);
+   }
+   /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
+      set/get hbmpItem */
+   if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) == Size
+         && 0 != (ItemInfo.fMask & MIIM_BITMAP))
+   {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      return( FALSE);
+   }
+
+   if (IntGetMenuItemByFlag(Menu, Item,
+                            (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND),
+                            &MenuItem, NULL) < 0)
+   {
+      SetLastWin32Error(ERROR_INVALID_PARAMETER);
+      return( FALSE);
+   }
+
+   if (SetOrGet)
+   {
+      Ret = IntSetMenuItemInfo(Menu, MenuItem, &ItemInfo);
+   }
+   else
+   {
+      Ret = IntGetMenuItemInfo(Menu, MenuItem, &ItemInfo);
+      if (Ret)
+      {
+         Status = MmCopyToCaller(UnsafeItemInfo, &ItemInfo, Size);
+         if (! NT_SUCCESS(Status))
+         {
+            SetLastNtError(Status);
+            return( FALSE);
+         }
+      }
+   }
 
-  return 0;
+   return( Ret);
 }
 
 
+
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL
 STDCALL
 NtUserMenuItemInfo(
- HMENU hMenu,
UINT uItem,
BOOL fByPosition,
LPMENUITEMINFOW lpmii,
BOOL fsog)
  HMENU hMenu,
  UINT Item,
  BOOL ByPosition,
  PROSMENUITEMINFO UnsafeItemInfo,
  BOOL SetOrGet)
 {
-  UNIMPLEMENTED
+   PMENU_OBJECT Menu;
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserMenuItemInfo\n");
+   UserEnterExclusive();
+
+   if (!(Menu = UserGetMenuObject(hMenu)))
+   {
+      RETURN(FALSE);
+   }
+
+   RETURN( UserMenuItemInfo(Menu, Item, ByPosition, UnsafeItemInfo, SetOrGet));
+
+CLEANUP:
+   DPRINT("Leave NtUserMenuItemInfo, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 
-  return 0;
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL STDCALL
 NtUserRemoveMenu(
-  HMENU hMenu,
-  UINT uPosition,
-  UINT uFlags)
+   HMENU hMenu,
+   UINT uPosition,
+   UINT uFlags)
 {
-  UNIMPLEMENTED
+   PMENU_OBJECT Menu;
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserRemoveMenu\n");
+   UserEnterExclusive();
+
+   if(!(Menu = UserGetMenuObject(hMenu)))
+   {
+      RETURN( FALSE);
+   }
+
+   RETURN(IntRemoveMenuItem(Menu, uPosition, uFlags, FALSE));
+
+CLEANUP:
+   DPRINT("Leave NtUserRemoveMenu, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 
-  return 0;
 }
 
 
@@ -1065,46 +2248,56 @@ NtUserRemoveMenu(
  */
 BOOL STDCALL
 NtUserSetMenuContextHelpId(
-  HMENU hmenu,
-  DWORD dwContextHelpId)
+   HMENU hMenu,
+   DWORD dwContextHelpId)
 {
-  BOOL res;
-  PMENU_OBJECT MenuObject = W32kGetMenuObject(hmenu);
-  if(!MenuObject)
-  {
-    SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
-    return FALSE;
-  }
-
-  res = W32kSetMenuContextHelpId(MenuObject, dwContextHelpId);
-  W32kReleaseMenuObject(MenuObject);
-  return res;
+   PMENU_OBJECT Menu;
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserSetMenuContextHelpId\n");
+   UserEnterExclusive();
+
+   if(!(Menu = UserGetMenuObject(hMenu)))
+   {
+      RETURN( FALSE);
+   }
+
+   RETURN(IntSetMenuContextHelpId(Menu, dwContextHelpId));
+
+CLEANUP:
+   DPRINT("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 
+
 /*
  * @implemented
  */
 BOOL STDCALL
 NtUserSetMenuDefaultItem(
-  HMENU hMenu,
-  UINT uItem,
-  UINT fByPos)
+   HMENU hMenu,
+   UINT uItem,
+   UINT fByPos)
 {
-  BOOL res = FALSE;
-  PMENU_OBJECT MenuObject;
-  MenuObject = W32kGetMenuObject(hMenu);
-  if(!MenuObject)
-  {
-    SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
-    return FALSE;
-  }
-  ExAcquireFastMutexUnsafe(&MenuObject->MenuItemsLock);
-  res = W32kSetMenuDefaultItem(MenuObject, uItem, fByPos);
-  ExReleaseFastMutexUnsafe(&MenuObject->MenuItemsLock);
-  W32kReleaseMenuObject(MenuObject);
-
-  return res;
+   PMENU_OBJECT Menu;
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserSetMenuDefaultItem\n");
+   UserEnterExclusive();
+
+   if(!(Menu = UserGetMenuObject(hMenu)))
+   {
+      RETURN( FALSE);
+   }
+
+   RETURN( UserSetMenuDefaultItem(Menu, uItem, fByPos));
+
+CLEANUP:
+   DPRINT("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 
@@ -1113,19 +2306,25 @@ NtUserSetMenuDefaultItem(
  */
 BOOL STDCALL
 NtUserSetMenuFlagRtoL(
-  HMENU hMenu)
+   HMENU hMenu)
 {
-  BOOL res;
-  PMENU_OBJECT MenuObject = W32kGetMenuObject(hMenu);
-  if(!MenuObject)
-  {
-    SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
-    return FALSE;
-  }
-
-  res = W32kSetMenuFlagRtoL(MenuObject);
-  W32kReleaseMenuObject(MenuObject);
-  return res;
+   PMENU_OBJECT Menu;
+   DECLARE_RETURN(BOOL);
+
+   DPRINT("Enter NtUserSetMenuFlagRtoL\n");
+   UserEnterExclusive();
+
+   if(!(Menu = UserGetMenuObject(hMenu)))
+   {
+      RETURN( FALSE);
+   }
+
+   RETURN(IntSetMenuFlagRtoL(Menu));
+
+CLEANUP:
+   DPRINT("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
 }
 
 
@@ -1134,12 +2333,12 @@ NtUserSetMenuFlagRtoL(
  */
 DWORD STDCALL
 NtUserThunkedMenuInfo(
-  HMENU hMenu,
-  LPCMENUINFO lpcmi)
+   HMENU hMenu,
+   LPCMENUINFO lpcmi)
 {
-  UNIMPLEMENTED
-  /* This function seems just to call SetMenuInfo() */
-  return 0;
+   UNIMPLEMENTED
+   /* This function seems just to call SetMenuInfo() */
+   return 0;
 }
 
 
@@ -1148,36 +2347,37 @@ NtUserThunkedMenuInfo(
  */
 DWORD STDCALL
 NtUserThunkedMenuItemInfo(
-  HMENU hMenu,
-  UINT uItem,
-  BOOL fByPosition,
-  BOOL bInsert,
-  LPMENUITEMINFOW lpmii,
-  PUNICODE_STRING lpszCaption)
+   HMENU hMenu,
+   UINT uItem,
+   BOOL fByPosition,
+   BOOL bInsert,
+   LPMENUITEMINFOW lpmii,
+   PUNICODE_STRING lpszCaption)
 {
-  UNIMPLEMENTED
-  /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
-     if bInsert == TRUE call NtUserInsertMenuItem() else NtUserSetMenuItemInfo()
-  */
-  return 0;
+   UNIMPLEMENTED
+   /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
+      if bInsert == TRUE call NtUserInsertMenuItem() else NtUserSetMenuItemInfo()
+   */
+   return 0;
 }
 
 
 /*
- * @unimplemented
+ * @implemented
  */
+/* NOTE: unused function */
 BOOL STDCALL
 NtUserTrackPopupMenuEx(
-  HMENU hmenu,
-  UINT fuFlags,
-  int x,
-  int y,
-  HWND hwnd,
-  LPTPMPARAMS lptpm)
+   HMENU hMenu,
+   UINT fuFlags,
+   int x,
+   int y,
+   HWND hWnd,
+   LPTPMPARAMS lptpm)
 {
-  UNIMPLEMENTED
+   UNIMPLEMENTED
 
-  return 0;
+   return FALSE;
 }