Implement NtUserGetMenuBarInfo. Tested with MPlayerC with OBJID_MENU only, the rest...
[reactos.git] / reactos / subsys / win32k / ntuser / menu.c
index 8c21329..c4b4f3c 100644 (file)
@@ -115,7 +115,15 @@ CleanupMenuImpl(VOID)
 
 PMENU_OBJECT FASTCALL UserGetMenuObject(HMENU hMenu)
 {
-   PMENU_OBJECT Menu = (PMENU_OBJECT)UserGetObject(&gHandleTable, hMenu, otMenu);
+   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);
@@ -314,7 +322,7 @@ IntCreateMenu(PHANDLE Handle, BOOL IsMenuBar)
    Menu->MenuInfo.dwStyle = 0; /* FIXME */
    Menu->MenuInfo.cyMax = 0; /* default */
    Menu->MenuInfo.hbrBack =
-      NtGdiCreateSolidBrush(RGB(192, 192, 192)); /* FIXME: default background color */
+      NtGdiCreateSolidBrush(RGB(192, 192, 192), 0); /* FIXME: default background color */
    Menu->MenuInfo.dwContextHelpID = 0; /* default */
    Menu->MenuInfo.dwMenuData = 0; /* default */
    Menu->MenuInfo.Self = *Handle;
@@ -899,7 +907,9 @@ IntInsertMenuItem(PMENU_OBJECT MenuObject, UINT uItem, BOOL fByPosition,
 
    pos = IntInsertMenuItemToList(MenuObject, MenuItem, pos);
 
-   return pos >= 0;
+   DPRINT("IntInsertMenuItemToList = %i\n", pos);
+
+   return (pos >= 0);
 }
 
 UINT FASTCALL
@@ -1544,22 +1554,37 @@ NtUserInsertMenuItem(
 
    if(!(Menu = UserGetMenuObject(hMenu)))
    {
-      RETURN(0);
+      RETURN( FALSE);
    }
 
+   /* Try to copy the whole MENUITEMINFOW structure */
    Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, sizeof(MENUITEMINFOW));
-   if (NT_SUCCESS(Status))
+   if (NT_SUCCESS(Status))
    {
-      SetLastNtError(Status);
-      RETURN( FALSE);
+      if (sizeof(MENUITEMINFOW) != ItemInfo.cbSize
+         && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize)
+      {
+         SetLastWin32Error(ERROR_INVALID_PARAMETER);
+         RETURN( FALSE);
+      }
+      RETURN( IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo));
    }
-   if (ItemInfo.cbSize != sizeof(MENUITEMINFOW))
+
+   /* Try to copy without last field (not present in older versions) */
+   Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, FIELD_OFFSET(MENUITEMINFOW, hbmpItem));
+   if (NT_SUCCESS(Status))
    {
-      SetLastWin32Error(ERROR_INVALID_PARAMETER);
-      RETURN( FALSE);
+      if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize)
+      {
+         SetLastWin32Error(ERROR_INVALID_PARAMETER);
+         RETURN( FALSE);
+      }
+      ItemInfo.hbmpItem = (HBITMAP)0;
+      RETURN( IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo));
    }
 
-   RETURN( IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo));
+   SetLastNtError(Status);
+   RETURN( FALSE);
 
 CLEANUP:
    DPRINT("Leave NtUserInsertMenuItem, ret=%i\n",_ret_);
@@ -1611,7 +1636,7 @@ CLEANUP:
 
 
 /*
- * @unimplemented
+ * @implemented
  */
 BOOL STDCALL
 NtUserGetMenuBarInfo(
@@ -1620,9 +1645,209 @@ NtUserGetMenuBarInfo(
    LONG idItem,
    PMENUBARINFO pmbi)
 {
-   UNIMPLEMENTED
+   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);
 
-   return 0;
+CLEANUP:
+   DPRINT("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;  
 }
 
 
@@ -1651,16 +1876,11 @@ NtUserGetMenuItemRect(
    LPRECT lprcItem)
 {
    ROSMENUINFO mi;
-   ROSMENUITEMINFO mii;
    HWND referenceHwnd;
-   LPPOINT lpPoints;
-   LPRECT lpRect = NULL;
-   POINT FromOffset;
-   LONG XMove, YMove;
-   ULONG i;
+   RECT Rect;
    NTSTATUS Status;
    PMENU_OBJECT Menu;
-   PWINDOW_OBJECT ReferenceWnd;
+   PMENU_ITEM MenuItem;
    DECLARE_RETURN(BOOL);
 
    DPRINT("Enter NtUserGetMenuItemRect\n");
@@ -1671,41 +1891,26 @@ NtUserGetMenuItemRect(
       RETURN(FALSE);
    }
 
-   if(!UserMenuItemInfo(Menu, uItem, MF_BYPOSITION, &mii, FALSE))
-      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;
+      referenceHwnd = mi.Wnd; /* Okay we found it, so now what do we do? */
    }
 
    if (lprcItem == NULL)
       RETURN( FALSE);
-   *lpRect = mii.Rect;
-   lpPoints = (LPPOINT)lpRect;
-
-   ReferenceWnd = UserGetWindowObject(referenceHwnd);
-   if (!ReferenceWnd || !UserGetClientOrigin(ReferenceWnd, &FromOffset))
-   {
-      RETURN( FALSE);
-   }
-
-   XMove = FromOffset.x;
-   YMove = FromOffset.y;
-
-   for (i = 0; i < 2; i++)
-   {
-      lpPoints[i].x += XMove;
-      lpPoints[i].y += YMove;
-   }
 
-   Status = MmCopyToCaller(lprcItem, lpPoints, sizeof(POINT));
+   Status = MmCopyToCaller(lprcItem, &Rect, sizeof(RECT));
    if (! NT_SUCCESS(Status))
    {
       SetLastNtError(Status);
@@ -1923,7 +2128,7 @@ UserMenuItemInfo(
       return( FALSE);
    }
    if (sizeof(MENUITEMINFOW) != Size
-         && sizeof(MENUITEMINFOW) - sizeof(HBITMAP) != Size
+         && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != Size
          && sizeof(ROSMENUITEMINFO) != Size)
    {
       SetLastWin32Error(ERROR_INVALID_PARAMETER);
@@ -1937,7 +2142,7 @@ UserMenuItemInfo(
    }
    /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
       set/get hbmpItem */
-   if (sizeof(MENUITEMINFOW) - sizeof(HBITMAP) == Size
+   if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) == Size
          && 0 != (ItemInfo.fMask & MIIM_BITMAP))
    {
       SetLastWin32Error(ERROR_INVALID_PARAMETER);