[EXPLORER-NEW]
[reactos.git] / win32ss / user / ntuser / menu.c
index f46ea91..bb93bfa 100644 (file)
@@ -150,7 +150,6 @@ PMENU FASTCALL VerifyMenu(PMENU pMenu)
    UINT i;
    if (!pMenu) return NULL;
 
-   ERR("VerifyMenu 1!\n");
    _SEH2_TRY
    {
       hMenu = UserHMGetHandle(pMenu);
@@ -167,24 +166,19 @@ PMENU FASTCALL VerifyMenu(PMENU pMenu)
       _SEH2_YIELD(return NULL);
    }
    _SEH2_END
-   ERR("VerifyMenu 2!\n");
+
    if ( UserObjectInDestroy(hMenu))
+   {
+      ERR("Menu is marked for destruction!\n");
       return NULL;
-   ERR("VerifyMenu 3!\n");
+   }
+
    return pMenu;
 }
 
-BOOL IntDestroyMenu( PMENU pMenu, BOOL bRecurse, BOOL RemoveFromProcess)
+BOOL IntDestroyMenu( PMENU pMenu, BOOL bRecurse)
 {
-    /* DestroyMenu should not destroy system menu popup owner */
-    if ((pMenu->fFlags & (MNF_POPUP | MNF_SYSSUBMENU)) == MNF_POPUP && pMenu->hWnd)
-    {
-       //PWND pWnd = ValidateHwndNoErr(pMenu->hWnd);
-       ERR("FIXME Pop up menu window thing'ie\n");
-       
-       //co_UserDestroyWindow( pWnd );
-       //pMenu->hWnd = 0;
-    }
+    PMENU SubMenu;
 
     if (pMenu->rgItems) /* recursively destroy submenus */
     {
@@ -192,36 +186,51 @@ BOOL IntDestroyMenu( PMENU pMenu, BOOL bRecurse, BOOL RemoveFromProcess)
        ITEM *item = pMenu->rgItems;
        for (i = pMenu->cItems; i > 0; i--, item++)
        {
-           pMenu->cItems--; //// I hate recursion logic! (jt) 4/2014. See r63028 comment for IntDeleteMenuItems.
+           SubMenu = item->spSubMenu;
+           item->spSubMenu = NULL;
+
+           /* Remove Item Text */
            FreeMenuText(pMenu,item);
-           if (bRecurse && item->spSubMenu)//VerifyMenu(item->spSubMenu))
+
+           /* Remove Item Bitmap and set it for this process */
+           if (item->hbmp && !(item->fState & MFS_HBMMENUBMP))
+           {
+              GreSetObjectOwner(item->hbmp, GDI_OBJ_HMGR_POWNED);
+              item->hbmp = NULL;
+           }
+
+           /* Remove Item submenu */
+           if (bRecurse && SubMenu)//VerifyMenu(SubMenu))
            {
-              IntDestroyMenu(item->spSubMenu, bRecurse, RemoveFromProcess);
-              item->spSubMenu = NULL;
+              /* Release submenu since it was referenced when inserted */
+              IntReleaseMenuObject(SubMenu);
+              IntDestroyMenuObject(SubMenu, bRecurse);
            }
        }
+       /* Free the Item */
        DesktopHeapFree(pMenu->head.rpdesk, pMenu->rgItems );
        pMenu->rgItems = NULL; 
-       pMenu->cItems = 0; //// What ever~!
+       pMenu->cItems = 0;
     }
     return TRUE;
 }
 
+/* Callback for the object manager */
+BOOLEAN
+UserDestroyMenuObject(PVOID Object)
+{
+    return IntDestroyMenuObject(Object, TRUE);
+}
+
 BOOL FASTCALL
-IntDestroyMenuObject(PMENU Menu,
-                     BOOL bRecurse, BOOL RemoveFromProcess)
+IntDestroyMenuObject(PMENU Menu, BOOL bRecurse)
 {
    if(Menu)
    {
       PWND Window;
-      
-      /* Remove all menu items */
-      IntDestroyMenu( Menu, bRecurse, RemoveFromProcess);
 
-      if(RemoveFromProcess)
-      {
-         RemoveEntryList(&Menu->ListEntry);
-      }
+      /* Remove all menu items */
+      IntDestroyMenu( Menu, bRecurse);
 
       if (PsGetCurrentProcessSessionId() == Menu->head.rpdesk->rpwinstaParent->dwSessionId)
       {
@@ -232,9 +241,17 @@ IntDestroyMenuObject(PMENU Menu,
             if (Window)
             {
                Window->IDMenu = 0;
+
+               /* DestroyMenu should not destroy system menu popup owner */
+               if ((Menu->fFlags & (MNF_POPUP | MNF_SYSSUBMENU)) == MNF_POPUP)
+               {
+                  // Should we check it to see if it has Class?
+                  ERR("FIXME Pop up menu window thing'ie\n");
+                  //co_UserDestroyWindow( Window );
+                  //Menu->hWnd = 0;
+               }
             }
          }
-         //UserDereferenceObject(Menu);
          ret = UserDeleteObject(Menu->head.h, TYPE_MENU);
          if (!ret)
          {  // Make sure it is really dead or just marked for deletion.
@@ -336,7 +353,7 @@ PITEM FASTCALL MENU_FindItem( PMENU *pmenu, UINT *nPos, UINT wFlags )
 BOOL FASTCALL
 IntRemoveMenuItem( PMENU pMenu, UINT nPos, UINT wFlags, BOOL bRecurse )
 {
-    PITEM item, NewItems;
+    PITEM item;
 
     TRACE("(menu=%p pos=%04x flags=%04x)\n",pMenu, nPos, wFlags);
     if (!(item = MENU_FindItem( &pMenu, &nPos, wFlags ))) return FALSE;
@@ -346,7 +363,7 @@ IntRemoveMenuItem( PMENU pMenu, UINT nPos, UINT wFlags, BOOL bRecurse )
     FreeMenuText(pMenu,item);
     if (bRecurse && item->spSubMenu)
     {
-       IntDestroyMenuObject(item->spSubMenu, bRecurse, TRUE);
+       IntDestroyMenuObject(item->spSubMenu, bRecurse);
     }
     ////// Use cAlloced with inc's of 8's....
     if (--pMenu->cItems == 0)
@@ -362,10 +379,7 @@ IntRemoveMenuItem( PMENU pMenu, UINT nPos, UINT wFlags, BOOL bRecurse )
            item++;
            nPos++;
        }
-        NewItems = DesktopHeapAlloc(pMenu->head.rpdesk, pMenu->cItems * sizeof(ITEM));
-        RtlCopyMemory(NewItems, pMenu->rgItems, pMenu->cItems * sizeof(ITEM));
-        DesktopHeapFree(pMenu->head.rpdesk, pMenu->rgItems);
-        pMenu->rgItems = NewItems;
+       pMenu->rgItems = DesktopHeapReAlloc(pMenu->head.rpdesk, pMenu->rgItems, pMenu->cItems * sizeof(ITEM));
     }
     return TRUE;
 }
@@ -465,14 +479,17 @@ IntInsertMenuItem(
 }
 
 PMENU FASTCALL
-IntCreateMenu(PHANDLE Handle, BOOL IsMenuBar)
+IntCreateMenu(
+    _Out_ PHANDLE Handle,
+    _In_ BOOL IsMenuBar,
+    _In_ PDESKTOP Desktop,
+    _In_ PPROCESSINFO ppi)
 {
    PMENU Menu;
-   PPROCESSINFO CurrentWin32Process;
 
    Menu = (PMENU)UserCreateObject( gHandleTable,
-                                          NULL,
-                                          NULL,
+                                          Desktop,
+                                          ppi->ptiList,
                                           Handle,
                                           TYPE_MENU,
                                           sizeof(MENU));
@@ -500,10 +517,6 @@ IntCreateMenu(PHANDLE Handle, BOOL IsMenuBar)
    Menu->hWnd = NULL;
    Menu->TimeToHide = FALSE;
 
-   /* Insert menu item into process menu handle list */
-   CurrentWin32Process = PsGetCurrentProcessWin32Process();
-   InsertTailList(&CurrentWin32Process->MenuListHead, &Menu->ListEntry);
-
    return Menu;
 }
 
@@ -533,28 +546,24 @@ IntCloneMenuItems(PMENU Destination, PMENU Source)
       NewMenuItem->hbmpChecked = MenuItem->hbmpChecked;
       NewMenuItem->hbmpUnchecked = MenuItem->hbmpUnchecked;
       NewMenuItem->dwItemData = MenuItem->dwItemData;
-      if((MENU_ITEM_TYPE(NewMenuItem->fType) == MF_STRING))
+      if (MenuItem->lpstr.Length)
       {
-         if(MenuItem->lpstr.Length)
-         {
-            NewMenuItem->lpstr.Length = 0;
-            NewMenuItem->lpstr.MaximumLength = MenuItem->lpstr.MaximumLength;
-            NewMenuItem->lpstr.Buffer = DesktopHeapAlloc(Destination->head.rpdesk, MenuItem->lpstr.MaximumLength);
-            if(!NewMenuItem->lpstr.Buffer)
-            {
-               DesktopHeapFree(Destination->head.rpdesk, NewMenuItem);
-               break;
-            }
-            RtlCopyUnicodeString(&NewMenuItem->lpstr, &MenuItem->lpstr);
-         }
-         else
+         NewMenuItem->lpstr.Length = 0;
+         NewMenuItem->lpstr.MaximumLength = MenuItem->lpstr.MaximumLength;
+         NewMenuItem->lpstr.Buffer = DesktopHeapAlloc(Destination->head.rpdesk, MenuItem->lpstr.MaximumLength);
+         if (!NewMenuItem->lpstr.Buffer)
          {
-            NewMenuItem->lpstr.Buffer = MenuItem->lpstr.Buffer;
+             DesktopHeapFree(Destination->head.rpdesk, NewMenuItem);
+             break;
          }
+         RtlCopyUnicodeString(&NewMenuItem->lpstr, &MenuItem->lpstr);
+         NewMenuItem->lpstr.Buffer[MenuItem->lpstr.Length / sizeof(WCHAR)] = 0;
+         NewMenuItem->Xlpstr = NewMenuItem->lpstr.Buffer;
       }
       else
       {
          NewMenuItem->lpstr.Buffer = MenuItem->lpstr.Buffer;
+         NewMenuItem->Xlpstr = NewMenuItem->lpstr.Buffer;
       }
       NewMenuItem->hbmp = MenuItem->hbmp;
    }
@@ -564,19 +573,19 @@ IntCloneMenuItems(PMENU Destination, PMENU Source)
 PMENU FASTCALL
 IntCloneMenu(PMENU Source)
 {
-   PPROCESSINFO CurrentWin32Process;
    HANDLE hMenu;
    PMENU Menu;
 
    if(!Source)
       return NULL;
 
+   /* A menu is valid process wide. We can pass to the object manager any thread ptr */
    Menu = (PMENU)UserCreateObject( gHandleTable,
-                                          NULL,
-                                          NULL,
-                                          &hMenu,
-                                          TYPE_MENU,
-                                          sizeof(MENU));
+                                   Source->head.rpdesk,
+                                   ((PPROCESSINFO)Source->head.hTaskWow)->ptiList,
+                                   &hMenu,
+                                   TYPE_MENU,
+                                   sizeof(MENU));
    if(!Menu)
       return NULL;
 
@@ -598,10 +607,6 @@ IntCloneMenu(PMENU Source)
    Menu->hWnd = NULL;
    Menu->TimeToHide = FALSE;
 
-   /* Insert menu item into process menu handle list */
-   CurrentWin32Process = PsGetCurrentProcessWin32Process();
-   InsertTailList(&CurrentWin32Process->MenuListHead, &Menu->ListEntry);
-
    IntCloneMenuItems(Menu, Source);
 
    return Menu;
@@ -773,6 +778,7 @@ BOOL FASTCALL
 IntSetMenuItemInfo(PMENU MenuObject, PITEM MenuItem, PROSMENUITEMINFO lpmii, PUNICODE_STRING lpstr)
 {
    PMENU SubMenuObject;
+   BOOL circref = FALSE;
 
    if(!MenuItem || !MenuObject || !lpmii)
    {
@@ -820,6 +826,10 @@ IntSetMenuItemInfo(PMENU MenuObject, PITEM MenuItem, PROSMENUITEMINFO lpmii, PUN
    if(lpmii->fMask & MIIM_BITMAP)
    {
       MenuItem->hbmp = lpmii->hbmpItem;
+      if (MenuItem->hbmp <= HBMMENU_POPUP_MINIMIZE && MenuItem->hbmp >= HBMMENU_CALLBACK)
+         MenuItem->fState |= MFS_HBMMENUBMP;
+      else
+         MenuItem->fState &= ~MFS_HBMMENUBMP; 
    }
    if(lpmii->fMask & MIIM_CHECKMARKS)
    {
@@ -846,17 +856,32 @@ IntSetMenuItemInfo(PMENU MenuObject, PITEM MenuItem, PROSMENUITEMINFO lpmii, PUN
 
    if(lpmii->fMask & MIIM_SUBMENU)
    {
-      /* Make sure the submenu is marked as a popup menu */
       if (lpmii->hSubMenu)
       {
          SubMenuObject = UserGetMenuObject(lpmii->hSubMenu);
-         if (SubMenuObject != NULL)
+         if ( SubMenuObject && !(UserObjectInDestroy(lpmii->hSubMenu)) )
          {
-            if ( MENU_depth( SubMenuObject, 0) > MAXMENUDEPTH)
+            //// wine Bug 12171 : Adding Popup Menu to itself! Could create endless loops.
+            //// CORE-7967.
+            if (MenuObject == SubMenuObject)
+            {
+               HANDLE hMenu;
+               ERR("Pop Up Menu Double Trouble!\n");
+               SubMenuObject = IntCreateMenu(&hMenu,
+                   FALSE,
+                   MenuObject->head.rpdesk,
+                   (PPROCESSINFO)MenuObject->head.hTaskWow); // It will be marked.
+               if (!SubMenuObject) return FALSE;
+               IntReleaseMenuObject(SubMenuObject); // This will be referenced again after insertion.
+               circref = TRUE;
+            }
+            if ( MENU_depth( SubMenuObject, 0) > MAXMENUDEPTH )
             {
                ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n");
+               if (circref) IntDestroyMenuObject(SubMenuObject, FALSE);
                return FALSE;
             }
+            /* Make sure the submenu is marked as a popup menu */
             SubMenuObject->fFlags |= MNF_POPUP;
             // Now fix the test_subpopup_locked_by_menu tests....
             if (MenuItem->spSubMenu) IntReleaseMenuObject(MenuItem->spSubMenu);
@@ -905,7 +930,7 @@ IntSetMenuItemInfo(PMENU MenuObject, PITEM MenuItem, PROSMENUITEMINFO lpmii, PUN
       }
    }
 
-   if( !(MenuObject->fFlags & MNF_SYSDESKMN) &&
+   if( !(MenuObject->fFlags & MNF_SYSMENU) &&
        !MenuItem->Xlpstr &&
        !lpmii->dwTypeData &&
        !(MenuItem->fType & MFT_OWNERDRAW) &&
@@ -1110,39 +1135,6 @@ co_IntTrackPopupMenu(PMENU Menu, PWND Window,
    return FALSE;
 }
 
-
-/*!
- * Internal function. Called when the process is destroyed to free the remaining menu handles.
-*/
-BOOL FASTCALL
-IntCleanupMenus(struct _EPROCESS *Process, PPROCESSINFO Win32Process)
-{
-   PEPROCESS CurrentProcess;
-   PLIST_ENTRY LastHead = NULL;
-   PMENU 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, ListEntry);
-      TRACE("Menus are stuck on the process list!\n");
-      IntDestroyMenuObject(MenuObject, FALSE, TRUE);
-   }
-
-   if (CurrentProcess != Process)
-   {
-      KeDetachProcess();
-   }
-   return TRUE;
-}
-
 BOOLEAN APIENTRY
 intGetTitleBarInfo(PWND pWindowObject, PTITLEBARINFO bti)
 {
@@ -1393,7 +1385,7 @@ UINT FASTCALL IntFindSubMenu(HMENU *hMenu, HMENU hSubTarget )
 }
 
 
-HMENU FASTCALL UserCreateMenu(BOOL PopupMenu)
+HMENU FASTCALL UserCreateMenu(PDESKTOP Desktop, BOOL PopupMenu)
 {
    PWINSTATION_OBJECT WinStaObject;
    HANDLE Handle;
@@ -1419,8 +1411,8 @@ HMENU FASTCALL UserCreateMenu(BOOL PopupMenu)
           SetLastNtError(Status);
           return (HMENU)0;
        }
-       Menu = IntCreateMenu(&Handle, !PopupMenu);
-       if (Menu->head.rpdesk->rpwinstaParent != WinStaObject)
+       Menu = IntCreateMenu(&Handle, !PopupMenu, Desktop, GetW32ProcessInfo());
+       if (Menu && Menu->head.rpdesk->rpwinstaParent != WinStaObject)
        {
           ERR("Desktop Window Station does not match Process one!\n");
        }
@@ -1428,13 +1420,41 @@ HMENU FASTCALL UserCreateMenu(BOOL PopupMenu)
    }
    else
    {
-       Menu = IntCreateMenu(&Handle, !PopupMenu);
+       Menu = IntCreateMenu(&Handle, !PopupMenu, GetW32ThreadInfo()->rpdesk, GetW32ProcessInfo());
    }
 
    if (Menu) UserDereferenceObject(Menu);
    return (HMENU)Handle;
 }
 
+BOOL FASTCALL
+IntMenuItemInfo(
+   PMENU Menu,
+   UINT Item,
+   BOOL ByPosition,
+   PROSMENUITEMINFO ItemInfo,
+   BOOL SetOrGet,
+   PUNICODE_STRING lpstr)
+{
+   PITEM MenuItem;
+   BOOL Ret;
+
+   if (!(MenuItem = MENU_FindItem( &Menu, &Item, (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND) )))
+   {
+      EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND);
+      return( FALSE);
+   }
+   if (SetOrGet)
+   {
+      Ret = IntSetMenuItemInfo(Menu, MenuItem, ItemInfo, lpstr);
+   }
+   else
+   {
+      Ret = IntGetMenuItemInfo(Menu, MenuItem, ItemInfo);
+   }
+   return( Ret);
+}
+
 BOOL FASTCALL
 UserMenuItemInfo(
    PMENU Menu,
@@ -1620,6 +1640,183 @@ IntGetMenuItemRect(
    return TRUE;
 }
 
+PMENU FASTCALL MENU_GetSystemMenu(PWND Window, PMENU Popup)
+{
+   PMENU Menu, NewMenu = NULL, SysMenu = NULL;
+   HMENU hSysMenu, hNewMenu = NULL;
+   ROSMENUITEMINFO ItemInfoSet = {0};
+   ROSMENUITEMINFO ItemInfo = {0};
+   UNICODE_STRING MenuName;
+
+   hSysMenu = UserCreateMenu(Window->head.rpdesk, FALSE);
+   if (NULL == hSysMenu)
+   {
+      return NULL;
+   }
+   SysMenu = UserGetMenuObject(hSysMenu);
+   if (NULL == SysMenu)
+   {
+       UserDestroyMenu(hSysMenu);
+       return NULL;
+   }
+   
+   SysMenu->fFlags |= MNF_SYSMENU;
+   SysMenu->hWnd = Window->head.h;
+
+   if (!Popup)
+   {
+      //hNewMenu = co_IntLoadSysMenuTemplate();
+      if ( Window->ExStyle & WS_EX_MDICHILD )
+      {
+         RtlInitUnicodeString( &MenuName, L"SYSMENUMDI");
+         hNewMenu = co_IntCallLoadMenu( hModClient, &MenuName);
+      }
+      else
+      {
+         RtlInitUnicodeString( &MenuName, L"SYSMENU");
+         hNewMenu = co_IntCallLoadMenu( hModClient, &MenuName);
+         //ERR("%wZ\n",&MenuName);
+      }
+      if (!hNewMenu)
+      {
+         ERR("No Menu!!\n");
+         IntReleaseMenuObject(SysMenu);
+         UserDestroyMenu(hSysMenu);
+         return NULL;
+      }
+      Menu = UserGetMenuObject(hNewMenu);
+      if (!Menu)
+      {
+         IntReleaseMenuObject(SysMenu);
+         UserDestroyMenu(hSysMenu);
+         return NULL;
+      }
+
+      // Do the rest in here.
+
+      Menu->fFlags |= MNS_CHECKORBMP | MNF_SYSMENU  | MNF_POPUP;
+
+      ItemInfoSet.cbSize = sizeof( MENUITEMINFOW);
+      ItemInfoSet.fMask = MIIM_BITMAP;
+      ItemInfoSet.hbmpItem = HBMMENU_POPUP_CLOSE;
+      IntMenuItemInfo(Menu, SC_CLOSE, FALSE, &ItemInfoSet, TRUE, NULL);
+      ItemInfoSet.hbmpItem = HBMMENU_POPUP_RESTORE;
+      IntMenuItemInfo(Menu, SC_RESTORE, FALSE, &ItemInfoSet, TRUE, NULL);
+      ItemInfoSet.hbmpItem = HBMMENU_POPUP_MAXIMIZE;
+      IntMenuItemInfo(Menu, SC_MAXIMIZE, FALSE, &ItemInfoSet, TRUE, NULL);
+      ItemInfoSet.hbmpItem = HBMMENU_POPUP_MINIMIZE;
+      IntMenuItemInfo(Menu, SC_MINIMIZE, FALSE, &ItemInfoSet, TRUE, NULL);
+
+      NewMenu = IntCloneMenu(Menu);
+
+      IntReleaseMenuObject(NewMenu);
+      UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE);
+
+      IntDestroyMenuObject(Menu, FALSE);
+   }
+   else
+   {
+      NewMenu = Popup;
+   }
+   if (NewMenu)
+   {
+      NewMenu->fFlags |= MNF_SYSMENU | MNF_POPUP;
+
+      if (Window->pcls->style & CS_NOCLOSE)
+         IntRemoveMenuItem(NewMenu, SC_CLOSE, MF_BYCOMMAND, TRUE);
+
+      ItemInfo.cbSize = sizeof(MENUITEMINFOW);
+      ItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU;
+      ItemInfo.fType = 0;
+      ItemInfo.fState = MFS_ENABLED;
+      ItemInfo.dwTypeData = NULL;
+      ItemInfo.cch = 0;
+      ItemInfo.hSubMenu = UserHMGetHandle(NewMenu);
+      IntInsertMenuItem(SysMenu, (UINT) -1, TRUE, &ItemInfo, NULL);
+
+      return SysMenu;
+   }
+   ERR("failed to load system menu!\n");
+   return NULL;
+}
+
+PMENU FASTCALL
+IntGetSystemMenu(PWND Window, BOOL bRevert)
+{
+   PMENU Menu;
+
+   if (bRevert)
+   {
+      if (Window->SystemMenu)
+      {
+         Menu = UserGetMenuObject(Window->SystemMenu);
+         if (Menu && !(Menu->fFlags & MNF_SYSDESKMN))
+         {
+            IntDestroyMenuObject(Menu, TRUE);
+            Window->SystemMenu = NULL;
+         }
+      }
+   }
+   else
+   {
+      Menu = Window->SystemMenu ? UserGetMenuObject(Window->SystemMenu) : NULL;
+      if ((!Window->SystemMenu || Menu->fFlags & MNF_SYSDESKMN) && Window->style & WS_SYSMENU)
+      {
+         Menu = MENU_GetSystemMenu(Window, NULL);
+         Window->SystemMenu = Menu ? UserHMGetHandle(Menu) : NULL;
+      }
+   }
+
+   if (Window->SystemMenu)
+   {
+      HMENU hMenu = IntGetSubMenu( Window->SystemMenu, 0);
+      /* Store the dummy sysmenu handle to facilitate the refresh */
+      /* of the close button if the SC_CLOSE item change */
+      Menu = UserGetMenuObject(hMenu);
+      if (Menu)
+      {
+         Menu->spwndNotify = Window;
+         Menu->fFlags |= MNF_SYSSUBMENU;
+      }
+      return Menu;
+   }
+   return NULL;
+}
+
+BOOL FASTCALL
+IntSetSystemMenu(PWND Window, PMENU Menu)
+{
+   PMENU OldMenu;
+
+   if (!(Window->style & WS_SYSMENU)) return FALSE;
+
+   if (Window->SystemMenu)
+   {
+      OldMenu = UserGetMenuObject(Window->SystemMenu);
+      if (OldMenu)
+      {
+          OldMenu->fFlags &= ~MNF_SYSMENU;
+         IntDestroyMenuObject(OldMenu, TRUE);
+      }
+   }
+
+   OldMenu = MENU_GetSystemMenu(Window, Menu);
+   if (OldMenu)
+   {  // Use spmenuSys too!
+      Window->SystemMenu = UserHMGetHandle(OldMenu);
+   }
+   else
+      Window->SystemMenu = NULL;
+
+   if (Menu && Window != Menu->spwndNotify)
+   {
+      Menu->spwndNotify = Window;
+   } 
+
+   return TRUE;
+}
+
+
 /* FUNCTIONS *****************************************************************/
 
 /*
@@ -1678,6 +1875,107 @@ CLEANUP:
    END_CLEANUP;
 }
 
+/*
+ * NtUserGetSystemMenu
+ *
+ * The NtUserGetSystemMenu function allows the application to access the
+ * window menu (also known as the system menu or the control menu) for
+ * copying and modifying.
+ *
+ * Parameters
+ *    hWnd
+ *       Handle to the window that will own a copy of the window menu.
+ *    bRevert
+ *       Specifies the action to be taken. If this parameter is FALSE,
+ *       NtUserGetSystemMenu returns a handle to the copy of the window menu
+ *       currently in use. The copy is initially identical to the window menu
+ *       but it can be modified.
+ *       If this parameter is TRUE, GetSystemMenu resets the window menu back
+ *       to the default state. The previous window menu, if any, is destroyed.
+ *
+ * Return Value
+ *    If the bRevert parameter is FALSE, the return value is a handle to a
+ *    copy of the window menu. If the bRevert parameter is TRUE, the return
+ *    value is NULL.
+ *
+ * Status
+ *    @implemented
+ */
+
+HMENU APIENTRY
+NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
+{
+   PWND Window;
+   PMENU Menu;
+   DECLARE_RETURN(HMENU);
+
+   TRACE("Enter NtUserGetSystemMenu\n");
+   UserEnterShared();
+
+   if (!(Window = UserGetWindowObject(hWnd)))
+   {
+      RETURN(NULL);
+   }
+
+   if (!(Menu = IntGetSystemMenu(Window, bRevert)))
+   {
+      RETURN(NULL);
+   }
+
+   RETURN(Menu->head.h);
+
+CLEANUP:
+   TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_);
+   UserLeave();
+   END_CLEANUP;
+}
+
+/*
+ * NtUserSetSystemMenu
+ *
+ * Status
+ *    @implemented
+ */
+
+BOOL APIENTRY
+NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
+{
+   BOOL Result = FALSE;
+   PWND Window;
+   PMENU Menu;
+   DECLARE_RETURN(BOOL);
+
+   TRACE("Enter NtUserSetSystemMenu\n");
+   UserEnterExclusive();
+
+   if (!(Window = UserGetWindowObject(hWnd)))
+   {
+      RETURN( FALSE);
+   }
+
+   if (hMenu)
+   {
+      /*
+       * Assign new menu handle and Up the Lock Count.
+       */
+      if (!(Menu = IntGetMenuObject(hMenu)))
+      {
+         RETURN( FALSE);
+      }
+
+      Result = IntSetSystemMenu(Window, Menu);
+   }
+   else
+      EngSetLastError(ERROR_INVALID_MENU_HANDLE);
+
+   RETURN( Result);
+
+CLEANUP:
+   TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_);
+   UserLeave();
+   END_CLEANUP;
+}
+
 /*
  * @implemented
  */
@@ -1763,7 +2061,7 @@ BOOL FASTCALL UserDestroyMenu(HMENU hMenu)
       EngSetLastError(ERROR_ACCESS_DENIED);
       return FALSE;
    }
-   return IntDestroyMenuObject(Menu, FALSE, TRUE);
+   return IntDestroyMenuObject(Menu, FALSE);
 }
 
 /*
@@ -1788,7 +2086,7 @@ NtUserDestroyMenu(
       EngSetLastError(ERROR_ACCESS_DENIED);
       RETURN( FALSE);
    }
-   RETURN( IntDestroyMenuObject(Menu, TRUE, TRUE));
+   RETURN( IntDestroyMenuObject(Menu, TRUE));
 
 CLEANUP:
    TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_);
@@ -1870,7 +2168,7 @@ NtUserGetMenuBarInfo(
         break;
     case OBJID_SYSMENU:
         if (!(pWnd->style & WS_SYSMENU)) RETURN(FALSE);
-        Menu = IntGetSystemMenu(pWnd, FALSE, FALSE);
+        Menu = IntGetSystemMenu(pWnd, FALSE);
         hMenu = Menu->head.h;
         break;
     default:
@@ -1925,15 +2223,10 @@ NtUserGetMenuBarInfo(
    //kmbi.fBarFocused = top_popup_hmenu == hMenu;
    if (idItem)
    {
-       //PITEM MenuItem;
-       //UINT nPos = idItem-1;
        kmbi.fFocused = Menu->iItem == idItem-1;
        if (kmbi.fFocused && (Menu->rgItems[idItem - 1].spSubMenu))
-       //MenuItem = MENU_FindItem (&Menu, &nPos, MF_BYPOSITION);
-       //if ( MenuItem && kmbi.fFocused && MenuItem->spSubMenu )
        {
           kmbi.hwndMenu = Menu->rgItems[idItem - 1].spSubMenu->hWnd;
-          //kmbi.hwndMenu = MenuItem->spSubMenu->hWnd;
        }
    }
 /*   else