[WIN32SS] For application menu's, only exclude the menu item,
[reactos.git] / win32ss / user / ntuser / menu.c
index 8432f3a..ecf6776 100644 (file)
@@ -71,7 +71,7 @@ BOOL fInEndMenu = FALSE;
 #define MENU_COL_SPACE 4
 
 /*  top and bottom margins for popup menus */
-#define MENU_TOP_MARGIN 2 //3
+#define MENU_TOP_MARGIN 3
 #define MENU_BOTTOM_MARGIN 2
 
 #define MENU_ITEM_HBMP_SPACE (5)
@@ -274,6 +274,7 @@ BOOL IntDestroyMenu( PMENU pMenu, BOOL bRecurse)
 {
     PMENU SubMenu;
 
+    ASSERT(UserIsEnteredExclusive());
     if (pMenu->rgItems) /* recursively destroy submenus */
     {
        int i;
@@ -319,6 +320,7 @@ UserDestroyMenuObject(PVOID Object)
 BOOL FASTCALL
 IntDestroyMenuObject(PMENU Menu, BOOL bRecurse)
 {
+   ASSERT(UserIsEnteredExclusive());
    if (Menu)
    {
       PWND Window;
@@ -378,7 +380,7 @@ MenuInit(VOID)
       ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
       return FALSE;
     }
-    ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
+    ncm.lfMenuFont.lfWeight = min(ncm.lfMenuFont.lfWeight + (FW_BOLD - FW_NORMAL), FW_HEAVY);
     ghMenuFontBold = GreCreateFontIndirectW(&ncm.lfMenuFont);
     if (ghMenuFontBold == NULL)
     {
@@ -598,6 +600,7 @@ BOOL FASTCALL
 IntRemoveMenuItem( PMENU pMenu, UINT nPos, UINT wFlags, BOOL bRecurse )
 {
     PITEM item;
+    PITEM newItems;
 
     TRACE("(menu=%p pos=%04x flags=%04x)\n",pMenu, nPos, wFlags);
     if (!(item = MENU_FindItem( &pMenu, &nPos, wFlags ))) return FALSE;
@@ -617,13 +620,17 @@ IntRemoveMenuItem( PMENU pMenu, UINT nPos, UINT wFlags, BOOL bRecurse )
     }
     else
     {
-       while(nPos < pMenu->cItems)
-       {
-           *item = *(item+1);
-           item++;
-           nPos++;
-       }
-       pMenu->rgItems = DesktopHeapReAlloc(pMenu->head.rpdesk, pMenu->rgItems, pMenu->cItems * sizeof(ITEM));
+        while (nPos < pMenu->cItems)
+        {
+            *item = *(item+1);
+            item++;
+            nPos++;
+        }
+        newItems = DesktopHeapReAlloc(pMenu->head.rpdesk, pMenu->rgItems, pMenu->cItems * sizeof(ITEM));
+        if (newItems)
+        {
+            pMenu->rgItems = newItems;
+        }
     }
     return TRUE;
 }
@@ -773,10 +780,10 @@ IntCloneMenuItems(PMENU Destination, PMENU Source)
    if(!Source->cItems)
       return FALSE;
 
-   NewMenuItem = DesktopHeapAlloc(Destination->head.rpdesk, (Source->cItems+1) * sizeof(ITEM));
+   NewMenuItem = DesktopHeapAlloc(Destination->head.rpdesk, Source->cItems * sizeof(ITEM));
    if(!NewMenuItem) return FALSE;
 
-   RtlZeroMemory(NewMenuItem, (Source->cItems+1) * sizeof(ITEM));
+   RtlZeroMemory(NewMenuItem, Source->cItems * sizeof(ITEM));
 
    Destination->rgItems = NewMenuItem;
 
@@ -810,6 +817,7 @@ IntCloneMenuItems(PMENU Destination, PMENU Source)
          NewMenuItem->Xlpstr = NewMenuItem->lpstr.Buffer;
       }
       NewMenuItem->hbmp = MenuItem->hbmp;
+      Destination->cItems = i + 1;
    }
    return TRUE;
 }
@@ -842,7 +850,7 @@ IntCloneMenu(PMENU Source)
    Menu->spwndNotify = NULL;
    Menu->cyMenu = 0;
    Menu->cxMenu = 0;
-   Menu->cItems = Source->cItems;
+   Menu->cItems = 0;
    Menu->iTop = 0;
    Menu->iMaxTop = 0;
    Menu->cxTextAlign = 0;
@@ -1164,7 +1172,12 @@ IntSetMenuItemInfo(PMENU MenuObject, PITEM MenuItem, PROSMENUITEMINFO lpmii, PUN
       {
          UNICODE_STRING Source;
 
-         Source.Length = Source.MaximumLength = lpmii->cch * sizeof(WCHAR);
+         if (!NT_VERIFY(lpmii->cch <= UNICODE_STRING_MAX_CHARS))
+         {
+             return FALSE;
+         }
+
+         Source.Length = Source.MaximumLength = (USHORT)(lpmii->cch * sizeof(WCHAR));
          Source.Buffer = lpmii->dwTypeData;
 
          MenuItem->lpstr.Buffer = DesktopHeapAlloc( MenuObject->head.rpdesk, Source.Length + sizeof(WCHAR));
@@ -1646,9 +1659,12 @@ static void FASTCALL MENU_DrawBitmapItem(HDC hdc, PITEM lpitem, const RECT *rect
     int h = rect->bottom - rect->top;
     int bmp_xoffset = 0;
     int left, top;
+    BOOL flat_menu;
     HBITMAP hbmToDraw = lpitem->hbmp;
     bmp = hbmToDraw;
 
+    UserSystemParametersInfo(SPI_GETFLATMENU, 0, &flat_menu, 0);
+
     /* Check if there is a magic menu item associated with this item */
     if (IS_MAGIC_BITMAP(hbmToDraw))
     {
@@ -1736,7 +1752,7 @@ static void FASTCALL MENU_DrawBitmapItem(HDC hdc, PITEM lpitem, const RECT *rect
                 drawItem.itemData = lpitem->dwItemData;
                 /* some applications make this assumption on the DC's origin */
                 GreSetViewportOrgEx( hdc, lpitem->xItem, lpitem->yItem, &origorg);
-                RECTL_vOffsetRect( &drawItem.rcItem, - lpitem->xItem, - lpitem->yItem);
+                RECTL_vOffsetRect(&drawItem.rcItem, -(LONG)lpitem->xItem, -(LONG)lpitem->yItem);
                 co_IntSendMessage( UserHMGetHandle(WndOwner), WM_DRAWITEM, 0, (LPARAM)&drawItem);
                 GreSetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
                 return;
@@ -1767,6 +1783,13 @@ static void FASTCALL MENU_DrawBitmapItem(HDC hdc, PITEM lpitem, const RECT *rect
     rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmToDraw)) ? NOTSRCCOPY : SRCCOPY;
     if ((lpitem->fState & MF_HILITE) && lpitem->hbmp)
         IntGdiSetBkColor(hdc, IntGetSysColor(COLOR_HIGHLIGHT));
+    if (MenuBar &&
+        !flat_menu &&
+        (lpitem->fState & (MF_HILITE | MF_GRAYED)) == MF_HILITE)
+    {
+        ++left;
+        ++top;
+    }
     NtGdiBitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop , 0, 0);
     IntGdiDeleteDC( hdcMem, FALSE );
 }
@@ -2088,7 +2111,7 @@ static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, PMENU lppop, PWND pwnd
     //TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
     lppop->cxMenu  = lprect->right - lprect->left;
     lppop->cyMenu = 0;
-    maxY = lprect->top+1;
+    maxY = lprect->top;
     start = 0;
     helpPos = ~0U;
     lppop->cxTextAlign = 0;
@@ -2129,7 +2152,7 @@ static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, PMENU lppop, PWND pwnd
        start = i; /* This works! */
     }
 
-    lprect->bottom = maxY;
+    lprect->bottom = maxY + 1;
     lppop->cyMenu = lprect->bottom - lprect->top;
 
     /* Flush right all items between the MF_RIGHTJUSTIFY and */
@@ -2154,11 +2177,10 @@ static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, PMENU lppop, PWND pwnd
  */
 static void MENU_DrawScrollArrows(PMENU lppop, HDC hdc)
 {
-    UINT arrow_bitmap_width, arrow_bitmap_height;
-    RECT rect, dfcrc;
+    UINT arrow_bitmap_height;
+    RECT rect;
     UINT Flags = 0;
 
-    arrow_bitmap_width  = gpsi->oembmi[OBI_DNARROW].cx;
     arrow_bitmap_height = gpsi->oembmi[OBI_DNARROW].cy;
 
     rect.left = 0;
@@ -2166,22 +2188,14 @@ static void MENU_DrawScrollArrows(PMENU lppop, HDC hdc)
     rect.right = lppop->cxMenu;
     rect.bottom = arrow_bitmap_height;
     FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENU));
-    dfcrc.left = (lppop->cxMenu - arrow_bitmap_width) / 2;
-    dfcrc.top = 0;
-    dfcrc.right = arrow_bitmap_width;
-    dfcrc.bottom = arrow_bitmap_height;
-    DrawFrameControl(hdc, &dfcrc, DFC_MENU, (lppop->iTop ? 0 : DFCS_INACTIVE)|DFCS_MENUARROWUP);
+    DrawFrameControl(hdc, &rect, DFC_MENU, (lppop->iTop ? 0 : DFCS_INACTIVE)|DFCS_MENUARROWUP);
 
     rect.top = lppop->cyMenu - arrow_bitmap_height;
     rect.bottom = lppop->cyMenu;
     FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENU));
     if (!(lppop->iTop < lppop->iMaxTop - (MENU_GetMaxPopupHeight(lppop) - 2 * arrow_bitmap_height)))
        Flags = DFCS_INACTIVE;
-    dfcrc.left = (lppop->cxMenu - arrow_bitmap_width) / 2;
-    dfcrc.top = lppop->cyMenu - arrow_bitmap_height;
-    dfcrc.right = arrow_bitmap_width;
-    dfcrc.bottom = lppop->cyMenu;
-    DrawFrameControl(hdc, &dfcrc, DFC_MENU, Flags|DFCS_MENUARROWDOWN);
+    DrawFrameControl(hdc, &rect, DFC_MENU, Flags|DFCS_MENUARROWDOWN);
 }
 
 /***********************************************************************
@@ -2314,10 +2328,15 @@ static void FASTCALL MENU_DrawMenuItem(PWND Wnd, PMENU Menu, PWND WndOwner, HDC
         }
         else
         {
-            if(menuBar)
+            if (menuBar)
+            {
+                FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENU));
                 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
+            }
             else
+            {
                 FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_HIGHLIGHT));
+            }
         }
     }
     else
@@ -2354,7 +2373,7 @@ static void FASTCALL MENU_DrawMenuItem(PWND Wnd, PMENU Menu, PWND WndOwner, HDC
 
         rc.left++;
         rc.right--;
-        rc.top = ( rc.top + rc.bottom) / 2;
+        rc.top = (rc.top + rc.bottom) / 2 - 1;
         if (flat_menu)
         {
             oldPen = NtGdiSelectPen( hdc, NtGdiGetStockObject(DC_PEN) );
@@ -2506,6 +2525,16 @@ static void FASTCALL MENU_DrawMenuItem(PWND Wnd, PMENU Menu, PWND WndOwner, HDC
                     break;
         }
 
+        if (menuBar &&
+            !flat_menu &&
+            (lpitem->fState & (MF_HILITE | MF_GRAYED)) == MF_HILITE)
+        {
+            RECTL_vOffsetRect(&rect, +1, +1);
+        }
+
+        if (!menuBar)
+            --rect.bottom;
+
         if(lpitem->fState & MF_GRAYED)
         {
             if (!(lpitem->fState & MF_HILITE) )
@@ -2547,6 +2576,16 @@ static void FASTCALL MENU_DrawMenuItem(PWND Wnd, PMENU Menu, PWND WndOwner, HDC
             DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat );
         }
 
+        if (!menuBar)
+            ++rect.bottom;
+
+        if (menuBar &&
+            !flat_menu &&
+            (lpitem->fState & (MF_HILITE | MF_GRAYED)) == MF_HILITE)
+        {
+            RECTL_vOffsetRect(&rect, -1, -1);
+        }
+
         if (hfontOld)
         {
            NtGdiSelectFont (hdc, hfontOld);
@@ -2812,22 +2851,110 @@ static BOOL MENU_InitPopup( PWND pWndOwner, PMENU menu, UINT flags )
     return TRUE;
 }
 
+
+#define SHOW_DEBUGRECT      0
+
+#if SHOW_DEBUGRECT
+static void DebugRect(const RECT* rectl, COLORREF color)
+{
+    HBRUSH brush;
+    RECT rr;
+    HDC hdc;
+
+    if (!rectl)
+        return;
+
+    hdc = UserGetDCEx(NULL, 0, DCX_USESTYLE);
+
+    brush = IntGdiCreateSolidBrush(color);
+
+    rr = *rectl;
+    RECTL_vInflateRect(&rr, 1, 1);
+    FrameRect(hdc, rectl, brush);
+    FrameRect(hdc, &rr, brush);
+
+    NtGdiDeleteObjectApp(brush);
+    UserReleaseDC(NULL, hdc, TRUE);
+}
+
+static void DebugPoint(INT x, INT y, COLORREF color)
+{
+    RECT rr = {x, y, x, y};
+    DebugRect(&rr, color);
+}
+#endif
+
+static BOOL RECTL_Intersect(const RECT* pRect, INT x, INT y, UINT width, UINT height)
+{
+    RECT other = {x, y, x + width, y + height};
+    RECT dum;
+
+    return RECTL_bIntersectRect(&dum, pRect, &other);
+}
+
+static BOOL MENU_MoveRect(UINT flags, INT* x, INT* y, INT width, INT height, const RECT* pExclude, PMONITOR monitor)
+{
+    /* Figure out if we should move vertical or horizontal */
+    if (flags & TPM_VERTICAL)
+    {
+        /* Move in the vertical direction: TPM_BOTTOMALIGN means drop it above, otherways drop it below */
+        if (flags & TPM_BOTTOMALIGN)
+        {
+            if (pExclude->top - height >= monitor->rcMonitor.top)
+            {
+                *y = pExclude->top - height;
+                return TRUE;
+            }
+        }
+        else
+        {
+            if (pExclude->bottom + height < monitor->rcMonitor.bottom)
+            {
+                *y = pExclude->bottom;
+                return TRUE;
+            }
+        }
+    }
+    else
+    {
+        /* Move in the horizontal direction: TPM_RIGHTALIGN means drop it to the left, otherways go right */
+        if (flags & TPM_RIGHTALIGN)
+        {
+            if (pExclude->left - width >= monitor->rcMonitor.left)
+            {
+                *x = pExclude->left - width;
+                return TRUE;
+            }
+        }
+        else
+        {
+            if (pExclude->right + width < monitor->rcMonitor.right)
+            {
+                *x = pExclude->right;
+                return TRUE;
+            }
+        }
+    }
+    return FALSE;
+}
+
 /***********************************************************************
  *           MenuShowPopup
  *
  * Display a popup menu.
  */
 static BOOL FASTCALL MENU_ShowPopup(PWND pwndOwner, PMENU menu, UINT id, UINT flags,
-                              INT x, INT y, INT xanchor, INT yanchor )
+                              INT x, INT y, const RECT* pExclude)
 {
     UINT width, height;
-    POINT pt;
+    POINT ptx;
     PMONITOR monitor;
     PWND pWnd;
     USER_REFERENCE_ENTRY Ref;
+    BOOL bIsPopup = (flags & TPM_POPUPMENU) != 0;
 
-    TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
-          pwndOwner, menu, id, x, y, xanchor, yanchor);
+    TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x\n",
+          pwndOwner, menu, id, x, y);
 
     if (menu->iItem != NO_SELECTED_ITEM)
     {
@@ -2835,6 +2962,11 @@ static BOOL FASTCALL MENU_ShowPopup(PWND pwndOwner, PMENU menu, UINT id, UINT fl
         menu->iItem = NO_SELECTED_ITEM;
     }
 
+#if SHOW_DEBUGRECT
+    if (pExclude)
+        DebugRect(pExclude, RGB(255, 0, 0));
+#endif
+
     menu->dwArrowsOn = 0;
     MENU_PopupMenuCalcSize(menu, pwndOwner);
 
@@ -2843,39 +2975,102 @@ static BOOL FASTCALL MENU_ShowPopup(PWND pwndOwner, PMENU menu, UINT id, UINT fl
     width = menu->cxMenu + UserGetSystemMetrics(SM_CXBORDER);
     height = menu->cyMenu + UserGetSystemMetrics(SM_CYBORDER);
 
-    /* FIXME: should use item rect */
-    pt.x = x;
-    pt.y = y;
-    monitor = UserMonitorFromPoint( pt, MONITOR_DEFAULTTONEAREST );
-
-    if (flags & TPM_LAYOUTRTL) 
+    if (flags & TPM_LAYOUTRTL)
         flags ^= TPM_RIGHTALIGN;
 
-    if( flags & TPM_RIGHTALIGN ) x -= width;
-    if( flags & TPM_CENTERALIGN ) x -= width / 2;
+    if (flags & TPM_RIGHTALIGN)
+        x -= width;
+    if (flags & TPM_CENTERALIGN)
+        x -= width / 2;
 
-    if( flags & TPM_BOTTOMALIGN ) y -= height;
-    if( flags & TPM_VCENTERALIGN ) y -= height / 2;
+    if (flags & TPM_BOTTOMALIGN)
+        y -= height;
+    if (flags & TPM_VCENTERALIGN)
+        y -= height / 2;
 
-    if( x + width > monitor->rcMonitor.right)
-    {
-        if( xanchor && x >= width - xanchor )
-            x -= width - xanchor;
+    /* FIXME: should use item rect */
+    ptx.x = x;
+    ptx.y = y;
+#if SHOW_DEBUGRECT
+    DebugPoint(x, y, RGB(0, 0, 255));
+#endif
+    monitor = UserMonitorFromPoint( ptx, MONITOR_DEFAULTTONEAREST );
 
-        if( x + width > monitor->rcMonitor.right)
+    /* We are off the right side of the screen */
+    if (x + width > monitor->rcMonitor.right)
+    {
+        if ((x - width) < monitor->rcMonitor.left || x >= monitor->rcMonitor.right)
             x = monitor->rcMonitor.right - width;
+        else
+            x -= width;
+    }
+
+    /* We are off the left side of the screen */
+    if (x < monitor->rcMonitor.left)
+    {
+        /* Re-orient the menu around the x-axis */
+        x += width;
+
+        if (x < monitor->rcMonitor.left || x >= monitor->rcMonitor.right || bIsPopup)
+            x = monitor->rcMonitor.left;
     }
-    if( x < monitor->rcMonitor.left ) x = monitor->rcMonitor.left;
 
-    if( y + height > monitor->rcMonitor.bottom)
+    /* Same here, but then the top */
+    if (y < monitor->rcMonitor.top)
     {
-        if( yanchor && y >= height + yanchor )
-            y -= height + yanchor;
+        y += height;
 
-        if( y + height > monitor->rcMonitor.bottom)
+        if (y < monitor->rcMonitor.top || y >= monitor->rcMonitor.bottom || bIsPopup)
+            y = monitor->rcMonitor.top;
+    }
+
+    /* And the bottom */
+    if (y + height > monitor->rcMonitor.bottom)
+    {
+        if ((y - height) < monitor->rcMonitor.top || y >= monitor->rcMonitor.bottom || bIsPopup)
             y = monitor->rcMonitor.bottom - height;
+        else
+            y -= height;
+    }
+
+    if (pExclude)
+    {
+        RECT Cleaned;
+
+        if (RECTL_bIntersectRect(&Cleaned, pExclude, &monitor->rcMonitor) &&
+            RECTL_Intersect(&Cleaned, x, y, width, height))
+        {
+            UINT flag_mods[] = {
+                0,                                                  /* First try the 'normal' way */
+                TPM_BOTTOMALIGN | TPM_RIGHTALIGN,                   /* Then try the opposite side */
+                TPM_VERTICAL,                                       /* Then swap horizontal / vertical */
+                TPM_BOTTOMALIGN | TPM_RIGHTALIGN | TPM_VERTICAL,    /* Then the other side again (still swapped hor/ver) */
+            };
+            UINT n;
+            for (n = 0; n < RTL_NUMBER_OF(flag_mods); ++n)
+            {
+                INT tx = x;
+                INT ty = y;
+
+                /* Try to move a bit around */
+                if (MENU_MoveRect(flags ^ flag_mods[n], &tx, &ty, width, height, &Cleaned, monitor) &&
+                    !RECTL_Intersect(&Cleaned, tx, ty, width, height))
+                {
+                    x = tx;
+                    y = ty;
+                    break;
+                }
+            }
+            /* If none worked, we go with the original x/y */
+        }
     }
-    if( y < monitor->rcMonitor.top ) y = monitor->rcMonitor.top;
+
+#if SHOW_DEBUGRECT
+    {
+        RECT rr = {x, y, x + width, y + height};
+        DebugRect(&rr, RGB(0, 255, 0));
+    }
+#endif
 
     pWnd = ValidateHwndNoErr( menu->hWnd );
 
@@ -3123,7 +3318,7 @@ static void FASTCALL MENU_HideSubPopups(PWND pWndOwner, PMENU Menu,
  */
 static PMENU FASTCALL MENU_ShowSubPopup(PWND WndOwner, PMENU Menu, BOOL SelectFirst, UINT Flags)
 {
-  RECT Rect;
+  RECT Rect, ParentRect;
   ITEM *Item;
   HDC Dc;
   PWND pWnd;
@@ -3158,6 +3353,23 @@ static PMENU FASTCALL MENU_ShowSubPopup(PWND WndOwner, PMENU Menu, BOOL SelectFi
 
   pWnd = ValidateHwndNoErr(Menu->hWnd);
 
+  /* Grab the rect of our (entire) parent menu, so we can try to not overlap it */
+  if (Menu->fFlags & MNF_POPUP)
+  {
+    if (!IntGetWindowRect(pWnd, &ParentRect))
+    {
+        ERR("No pWnd\n");
+        ParentRect = Rect;
+    }
+  }
+  else
+  {
+    /* Inside the menu bar, we do not want to grab the entire window... */
+    ParentRect = Rect;
+    if (pWnd)
+        RECTL_vOffsetRect(&ParentRect, pWnd->rcWindow.left, pWnd->rcWindow.top);
+  }
+
   /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
   if (!(Item->fState & MF_HILITE))
   {
@@ -3234,7 +3446,7 @@ static PMENU FASTCALL MENU_ShowSubPopup(PWND WndOwner, PMENU Menu, BOOL SelectFi
   MENU_InitPopup( WndOwner, Item->spSubMenu, Flags );
 
   MENU_ShowPopup( WndOwner, Item->spSubMenu, Menu->iItem, Flags,
-                Rect.left, Rect.top, Rect.right, Rect.bottom );
+                Rect.left, Rect.top, &ParentRect);
   if (SelectFirst)
   {
       MENU_MoveSelection(WndOwner, Item->spSubMenu, ITEM_NEXT);
@@ -3834,7 +4046,7 @@ static void FASTCALL MENU_KeyRight(MTRACKER *pmt, UINT Flags, UINT msg)
  * Menu tracking code.
  */
 static INT FASTCALL MENU_TrackMenu(PMENU pmenu, UINT wFlags, INT x, INT y,
-                            PWND pwnd, const RECT *lprect )
+                            PWND pwnd)
 {
     MSG msg;
     BOOL fRemove;
@@ -3857,9 +4069,8 @@ static INT FASTCALL MENU_TrackMenu(PMENU pmenu, UINT wFlags, INT x, INT y,
     mt.Pt.x = x;
     mt.Pt.y = y;
 
-    TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x (%ld,%ld)-(%ld,%ld)\n",
-         UserHMGetHandle(pmenu), wFlags, x, y, UserHMGetHandle(pwnd), lprect ? lprect->left : 0, lprect ? lprect->top : 0,
-         lprect ? lprect->right : 0, lprect ? lprect->bottom : 0);
+    TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x\n",
+         UserHMGetHandle(pmenu), wFlags, x, y, UserHMGetHandle(pwnd));
 
     pti->MessageQueue->QF_flags &= ~QF_ACTIVATIONCHANGE;
 
@@ -4270,7 +4481,7 @@ VOID MENU_TrackMouseMenuBar( PWND pWnd, ULONG ht, POINT pt)
         MENU_InitTracking(pWnd, pMenu, FALSE, wFlags);
         /* fetch the window menu again, it may have changed */
         pMenu = (ht == HTSYSMENU) ? get_win_sys_menu( UserHMGetHandle(pWnd) ) : IntGetMenu( UserHMGetHandle(pWnd) );
-        MENU_TrackMenu(pMenu, wFlags, pt.x, pt.y, pWnd, NULL);
+        MENU_TrackMenu(pMenu, wFlags, pt.x, pt.y, pWnd);
         MENU_ExitTracking(pWnd, FALSE, wFlags);
     }
 }
@@ -4334,7 +4545,7 @@ VOID MENU_TrackKbdMenuBar(PWND pwnd, UINT wParam, WCHAR wChar)
     }
 
 track_menu:
-    MENU_TrackMenu( TrackMenu, wFlags, 0, 0, pwnd, NULL );
+    MENU_TrackMenu( TrackMenu, wFlags, 0, 0, pwnd );
     MENU_ExitTracking( pwnd, FALSE, wFlags);
 }
 
@@ -4376,9 +4587,8 @@ BOOL WINAPI IntTrackPopupMenuEx( PMENU menu, UINT wFlags, int x, int y,
        if (menu->fFlags & MNF_SYSMENU)
           MENU_InitSysMenuPopup( menu, pWnd->style, pWnd->pcls->style, HTSYSMENU);
 
-       if (MENU_ShowPopup(pWnd, menu, 0, wFlags, x, y, 0, 0 ))
-          ret = MENU_TrackMenu( menu, wFlags | TPM_POPUPMENU, 0, 0, pWnd,
-                                lpTpm ? &lpTpm->rcExclude : NULL);
+       if (MENU_ShowPopup(pWnd, menu, 0, wFlags | TPM_POPUPMENU, x, y, lpTpm ? &lpTpm->rcExclude : NULL))
+          ret = MENU_TrackMenu( menu, wFlags | TPM_POPUPMENU, 0, 0, pWnd);
        else
        {
           MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);
@@ -4464,6 +4674,10 @@ PopupMenuWndProc(
       {
         CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
         pPopupMenu->spmenu = UserGetMenuObject(cs->lpCreateParams);
+        if (pPopupMenu->spmenu)
+        {
+           UserReferenceObject(pPopupMenu->spmenu);
+        }
         break;
       }
 
@@ -4508,6 +4722,10 @@ PopupMenuWndProc(
 
     case WM_NCDESTROY:
       {
+         if (pPopupMenu->spmenu)
+         {
+            IntReleaseMenuObject(pPopupMenu->spmenu);
+         }
          DesktopHeapFree(Wnd->head.rpdesk, pPopupMenu );
          ((PMENUWND)Wnd)->ppopupmenu = 0;
          Wnd->fnid = FNID_DESTROY;
@@ -4523,6 +4741,11 @@ PopupMenuWndProc(
            ERR("Bad Menu Handle\n");
            break;
         }
+        UserReferenceObject(pmenu);
+        if (pPopupMenu->spmenu)
+        {
+           IntReleaseMenuObject(pPopupMenu->spmenu);
+        }
         pPopupMenu->spmenu = pmenu;
         break;
       }
@@ -5086,15 +5309,13 @@ PMENU FASTCALL MENU_GetSystemMenu(PWND Window, PMENU Popup)
       if (!hNewMenu)
       {
          ERR("No Menu!!\n");
-         IntReleaseMenuObject(SysMenu);
-         UserDestroyMenu(hSysMenu);
+         IntDestroyMenuObject(SysMenu, FALSE);
          return NULL;
       }
       Menu = UserGetMenuObject(hNewMenu);
       if (!Menu)
       {
-         IntReleaseMenuObject(SysMenu);
-         UserDestroyMenu(hSysMenu);
+         IntDestroyMenuObject(SysMenu, FALSE);
          return NULL;
       }
 
@@ -5114,6 +5335,12 @@ PMENU FASTCALL MENU_GetSystemMenu(PWND Window, PMENU Popup)
       IntMenuItemInfo(Menu, SC_MINIMIZE, FALSE, &ItemInfoSet, TRUE, NULL);
 
       NewMenu = IntCloneMenu(Menu);
+      if (NewMenu == NULL)
+      {
+         IntDestroyMenuObject(Menu, FALSE);
+         IntDestroyMenuObject(SysMenu, FALSE);
+         return NULL;
+      }
 
       IntReleaseMenuObject(NewMenu);
       UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE);
@@ -5166,7 +5393,7 @@ IntGetSystemMenu(PWND Window, BOOL bRevert)
    else
    {
       Menu = Window->SystemMenu ? UserGetMenuObject(Window->SystemMenu) : NULL;
-      if ((!Window->SystemMenu || Menu->fFlags & MNF_SYSDESKMN) && Window->style & WS_SYSMENU)
+      if ((!Menu || Menu->fFlags & MNF_SYSDESKMN) && Window->style & WS_SYSMENU)
       {
          Menu = MENU_GetSystemMenu(Window, NULL);
          Window->SystemMenu = Menu ? UserHMGetHandle(Menu) : NULL;
@@ -5278,7 +5505,7 @@ IntSetMenu(
 
    }
 
-   Wnd->IDMenu = (UINT) Menu;
+   Wnd->IDMenu = (UINT_PTR) Menu;
    if (NULL != NewMenu)
    {
       NewMenu->hWnd = UserHMGetHandle(Wnd);
@@ -5435,7 +5662,7 @@ NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
    DECLARE_RETURN(HMENU);
 
    TRACE("Enter NtUserGetSystemMenu\n");
-   UserEnterShared();
+   UserEnterExclusive();
 
    if (!(Window = UserGetWindowObject(hWnd)))
    {