xref: /reactos/win32ss/user/ntuser/menu.c (revision 144e984b)
1 /*
2  * COPYRIGHT:        See COPYING in the top level directory
3  * PROJECT:          ReactOS kernel
4  * PURPOSE:          Menus
5  * FILE:             win32ss/user/ntuser/menu.c
6  * PROGRAMER:        Thomas Weidenmueller (w3seek@users.sourceforge.net)
7  */
8 
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserMenu);
11 
12 /* INTERNAL ******************************************************************/
13 
14 BOOL FASTCALL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags); /* draw.c */
15 
16 HFONT ghMenuFont = NULL;
17 HFONT ghMenuFontBold = NULL;
18 static SIZE MenuCharSize;
19 
20 /* Use global popup window because there's no way 2 menus can
21  * be tracked at the same time.  */
22 static HWND top_popup = NULL;
23 static HMENU top_popup_hmenu = NULL;
24 
25 BOOL fInsideMenuLoop = FALSE;
26 BOOL fInEndMenu = FALSE;
27 
28 /* internal popup menu window messages */
29 
30 #define MM_SETMENUHANDLE        (WM_USER + 0)
31 #define MM_GETMENUHANDLE        (WM_USER + 1)
32 
33 /* internal flags for menu tracking */
34 
35 #define TF_ENDMENU              0x10000
36 #define TF_SUSPENDPOPUP         0x20000
37 #define TF_SKIPREMOVE           0x40000
38 
39 
40 /* maximum allowed depth of any branch in the menu tree.
41  * This value is slightly larger than in windows (25) to
42  * stay on the safe side. */
43 #define MAXMENUDEPTH 30
44 
45 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
46 
47 #define MENUITEMINFO_TYPE_MASK \
48                 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
49                  MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
50                  MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
51 
52 #define TYPE_MASK  (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
53 
54 #define STATE_MASK (~TYPE_MASK)
55 
56 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
57 
58 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
59 
60 #define IS_SYSTEM_MENU(MenuInfo)  \
61 	(!((MenuInfo)->fFlags & MNF_POPUP) && ((MenuInfo)->fFlags & MNF_SYSMENU))
62 
63 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
64 
65 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
66 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
67 
68 /* Maximum number of menu items a menu can contain */
69 #define MAX_MENU_ITEMS (0x4000)
70 #define MAX_GOINTOSUBMENU (0x10)
71 
72 /* Space between 2 columns */
73 #define MENU_COL_SPACE 4
74 
75 #define MENU_ITEM_HBMP_SPACE (5)
76 #define MENU_BAR_ITEMS_SPACE (12)
77 #define SEPARATOR_HEIGHT (5)
78 #define MENU_TAB_SPACE (8)
79 
80 typedef struct
81 {
82   UINT  TrackFlags;
83   PMENU CurrentMenu; /* current submenu (can be equal to hTopMenu)*/
84   PMENU TopMenu;     /* initial menu */
85   PWND  OwnerWnd;    /* where notifications are sent */
86   POINT Pt;
87 } MTRACKER;
88 
89 /* Internal MenuTrackMenu() flags */
90 #define TPM_INTERNAL            0xF0000000
91 #define TPM_BUTTONDOWN          0x40000000              /* menu was clicked before tracking */
92 #define TPM_POPUPMENU           0x20000000              /* menu is a popup menu */
93 
94 #define ITEM_PREV               -1
95 #define ITEM_NEXT                1
96 
97 #define UpdateMenuItemState(state, change) \
98 {\
99   if((change) & MF_GRAYED) { \
100     (state) |= MF_GRAYED; \
101   } else { \
102     (state) &= ~MF_GRAYED; \
103   } /* Separate the two for test_menu_resource_layout.*/ \
104   if((change) & MF_DISABLED) { \
105     (state) |= MF_DISABLED; \
106   } else { \
107     (state) &= ~MF_DISABLED; \
108   } \
109   if((change) & MFS_CHECKED) { \
110     (state) |= MFS_CHECKED; \
111   } else { \
112     (state) &= ~MFS_CHECKED; \
113   } \
114   if((change) & MFS_HILITE) { \
115     (state) |= MFS_HILITE; \
116   } else { \
117     (state) &= ~MFS_HILITE; \
118   } \
119   if((change) & MFS_DEFAULT) { \
120     (state) |= MFS_DEFAULT; \
121   } else { \
122     (state) &= ~MFS_DEFAULT; \
123   } \
124   if((change) & MF_MOUSESELECT) { \
125     (state) |= MF_MOUSESELECT; \
126   } else { \
127     (state) &= ~MF_MOUSESELECT; \
128   } \
129 }
130 
131 #if 0
132 void FASTCALL
133 DumpMenuItemList(PMENU Menu, PITEM MenuItem)
134 {
135    UINT cnt = 0, i = Menu->cItems;
136    while(i)
137    {
138       if(MenuItem->lpstr.Length)
139          DbgPrint(" %d. %wZ\n", ++cnt, &MenuItem->lpstr);
140       else
141          DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt, (DWORD)MenuItem->lpstr.Buffer);
142       DbgPrint("   fType=");
143       if(MFT_BITMAP & MenuItem->fType)
144          DbgPrint("MFT_BITMAP ");
145       if(MFT_MENUBARBREAK & MenuItem->fType)
146          DbgPrint("MFT_MENUBARBREAK ");
147       if(MFT_MENUBREAK & MenuItem->fType)
148          DbgPrint("MFT_MENUBREAK ");
149       if(MFT_OWNERDRAW & MenuItem->fType)
150          DbgPrint("MFT_OWNERDRAW ");
151       if(MFT_RADIOCHECK & MenuItem->fType)
152          DbgPrint("MFT_RADIOCHECK ");
153       if(MFT_RIGHTJUSTIFY & MenuItem->fType)
154          DbgPrint("MFT_RIGHTJUSTIFY ");
155       if(MFT_SEPARATOR & MenuItem->fType)
156          DbgPrint("MFT_SEPARATOR ");
157       if(MFT_STRING & MenuItem->fType)
158          DbgPrint("MFT_STRING ");
159       DbgPrint("\n   fState=");
160       if(MFS_DISABLED & MenuItem->fState)
161          DbgPrint("MFS_DISABLED ");
162       else
163          DbgPrint("MFS_ENABLED ");
164       if(MFS_CHECKED & MenuItem->fState)
165          DbgPrint("MFS_CHECKED ");
166       else
167          DbgPrint("MFS_UNCHECKED ");
168       if(MFS_HILITE & MenuItem->fState)
169          DbgPrint("MFS_HILITE ");
170       else
171          DbgPrint("MFS_UNHILITE ");
172       if(MFS_DEFAULT & MenuItem->fState)
173          DbgPrint("MFS_DEFAULT ");
174       if(MFS_GRAYED & MenuItem->fState)
175          DbgPrint("MFS_GRAYED ");
176       DbgPrint("\n   wId=%d\n", MenuItem->wID);
177       MenuItem++;
178       i--;
179    }
180    DbgPrint("Entries: %d\n", cnt);
181    return;
182 }
183 #endif
184 
185 #define FreeMenuText(Menu,MenuItem) \
186 { \
187   if((MENU_ITEM_TYPE((MenuItem)->fType) == MF_STRING) && \
188            (MenuItem)->lpstr.Length) { \
189     DesktopHeapFree(((PMENU)Menu)->head.rpdesk, (MenuItem)->lpstr.Buffer); \
190   } \
191 }
192 
193 PMENU FASTCALL
194 IntGetMenuObject(HMENU hMenu)
195 {
196    PMENU Menu = UserGetMenuObject(hMenu);
197    if (Menu)
198       Menu->head.cLockObj++;
199 
200    return Menu;
201 }
202 
203 PMENU FASTCALL VerifyMenu(PMENU pMenu)
204 {
205    HMENU hMenu;
206    PITEM pItem;
207    ULONG Error;
208    UINT i;
209    if (!pMenu) return NULL;
210 
211    Error = EngGetLastError();
212 
213    _SEH2_TRY
214    {
215       hMenu = UserHMGetHandle(pMenu);
216       pItem = pMenu->rgItems;
217       if (pItem)
218       {
219          i = pItem[0].wID;
220          pItem[0].wID = i;
221       }
222    }
223    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
224    {
225       ERR("Run away LOOP!\n");
226       EngSetLastError(Error);
227       _SEH2_YIELD(return NULL);
228    }
229    _SEH2_END
230 
231    if ( UserObjectInDestroy(hMenu))
232    {
233       ERR("Menu is marked for destruction!\n");
234       pMenu = NULL;
235    }
236    EngSetLastError(Error);
237    return pMenu;
238 }
239 
240 BOOL
241 FASTCALL
242 IntIsMenu(HMENU Menu)
243 {
244   if (UserGetMenuObject(Menu)) return TRUE;
245   return FALSE;
246 }
247 
248 
249 PMENU WINAPI
250 IntGetMenu(HWND hWnd)
251 {
252        PWND Wnd = ValidateHwndNoErr(hWnd);
253 
254        if (!Wnd)
255                return NULL;
256 
257        return UserGetMenuObject(UlongToHandle(Wnd->IDMenu));
258 }
259 
260 PMENU get_win_sys_menu( HWND hwnd )
261 {
262    PMENU ret = 0;
263    WND *win = ValidateHwndNoErr( hwnd );
264    if (win)
265    {
266       ret = UserGetMenuObject(win->SystemMenu);
267    }
268    return ret;
269 }
270 
271 BOOL IntDestroyMenu( PMENU pMenu, BOOL bRecurse)
272 {
273     PMENU SubMenu;
274 
275     ASSERT(UserIsEnteredExclusive());
276     if (pMenu->rgItems) /* recursively destroy submenus */
277     {
278        int i;
279        ITEM *item = pMenu->rgItems;
280        for (i = pMenu->cItems; i > 0; i--, item++)
281        {
282            SubMenu = item->spSubMenu;
283            item->spSubMenu = NULL;
284 
285            /* Remove Item Text */
286            FreeMenuText(pMenu,item);
287 
288            /* Remove Item Bitmap and set it for this process */
289            if (item->hbmp && !(item->fState & MFS_HBMMENUBMP))
290            {
291               GreSetObjectOwner(item->hbmp, GDI_OBJ_HMGR_POWNED);
292               item->hbmp = NULL;
293            }
294 
295            /* Remove Item submenu */
296            if (bRecurse && SubMenu)//VerifyMenu(SubMenu))
297            {
298               /* Release submenu since it was referenced when inserted */
299               IntReleaseMenuObject(SubMenu);
300               IntDestroyMenuObject(SubMenu, bRecurse);
301            }
302        }
303        /* Free the Item */
304        DesktopHeapFree(pMenu->head.rpdesk, pMenu->rgItems );
305        pMenu->rgItems = NULL;
306        pMenu->cItems = 0;
307     }
308     return TRUE;
309 }
310 
311 /* Callback for the object manager */
312 BOOLEAN
313 UserDestroyMenuObject(PVOID Object)
314 {
315     return IntDestroyMenuObject(Object, TRUE);
316 }
317 
318 BOOL FASTCALL
319 IntDestroyMenuObject(PMENU Menu, BOOL bRecurse)
320 {
321    ASSERT(UserIsEnteredExclusive());
322    if (Menu)
323    {
324       PWND Window;
325 
326       if (PsGetCurrentProcessSessionId() == Menu->head.rpdesk->rpwinstaParent->dwSessionId)
327       {
328          BOOL ret;
329          if (Menu->hWnd)
330          {
331             Window = ValidateHwndNoErr(Menu->hWnd);
332             if (Window)
333             {
334                //Window->IDMenu = 0; Only in Win9x!! wine win test_SetMenu test...
335 
336                /* DestroyMenu should not destroy system menu popup owner */
337                if ((Menu->fFlags & (MNF_POPUP | MNF_SYSSUBMENU)) == MNF_POPUP)
338                {
339                   // Should we check it to see if it has Class?
340                   ERR("FIXME Pop up menu window thing'ie\n");
341                   //co_UserDestroyWindow( Window );
342                   //Menu->hWnd = 0;
343                }
344             }
345          }
346 
347          if (!UserMarkObjectDestroy(Menu)) return TRUE;
348 
349          /* Remove all menu items */
350          IntDestroyMenu( Menu, bRecurse);
351 
352          ret = UserDeleteObject(Menu->head.h, TYPE_MENU);
353          TRACE("IntDestroyMenuObject %d\n",ret);
354          return ret;
355       }
356    }
357    return FALSE;
358 }
359 
360 BOOL
361 MenuInit(VOID)
362 {
363   NONCLIENTMETRICSW ncm;
364 
365   /* get the menu font */
366   if (!ghMenuFont || !ghMenuFontBold)
367   {
368     ncm.cbSize = sizeof(ncm);
369     if(!UserSystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
370     {
371       ERR("MenuInit(): SystemParametersInfo(SPI_GETNONCLIENTMETRICS) failed!\n");
372       return FALSE;
373     }
374 
375     ghMenuFont = GreCreateFontIndirectW(&ncm.lfMenuFont);
376     if (ghMenuFont == NULL)
377     {
378       ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
379       return FALSE;
380     }
381     ncm.lfMenuFont.lfWeight = min(ncm.lfMenuFont.lfWeight + (FW_BOLD - FW_NORMAL), FW_HEAVY);
382     ghMenuFontBold = GreCreateFontIndirectW(&ncm.lfMenuFont);
383     if (ghMenuFontBold == NULL)
384     {
385       ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
386       GreDeleteObject(ghMenuFont);
387       ghMenuFont = NULL;
388       return FALSE;
389     }
390 
391     GreSetObjectOwner(ghMenuFont, GDI_OBJ_HMGR_PUBLIC);
392     GreSetObjectOwner(ghMenuFontBold, GDI_OBJ_HMGR_PUBLIC);
393 
394     co_IntSetupOBM();
395   }
396 
397   return TRUE;
398 }
399 
400 
401 /**********************************************************************
402  *		MENU_depth
403  *
404  * detect if there are loops in the menu tree (or the depth is too large)
405  */
406 int FASTCALL MENU_depth( PMENU pmenu, int depth)
407 {
408     UINT i;
409     ITEM *item;
410     int subdepth;
411 
412     if (!pmenu) return depth;
413 
414     depth++;
415     if( depth > MAXMENUDEPTH) return depth;
416     item = pmenu->rgItems;
417     subdepth = depth;
418     for( i = 0; i < pmenu->cItems && subdepth <= MAXMENUDEPTH; i++, item++)
419     {
420         if( item->spSubMenu)//VerifyMenu(item->spSubMenu))
421         {
422             int bdepth = MENU_depth( item->spSubMenu, depth);
423             if( bdepth > subdepth) subdepth = bdepth;
424         }
425         if( subdepth > MAXMENUDEPTH)
426             TRACE("<- hmenu %p\n", item->spSubMenu);
427     }
428     return subdepth;
429 }
430 
431 
432 /******************************************************************************
433  *
434  *   UINT MenuGetStartOfNextColumn(
435  *     PMENU Menu)
436  *
437  *****************************************************************************/
438 
439 static UINT  MENU_GetStartOfNextColumn(
440     PMENU  menu )
441 {
442     PITEM pItem;
443     UINT i;
444 
445     if(!menu)
446 	return NO_SELECTED_ITEM;
447 
448     i = menu->iItem + 1;
449     if( i == NO_SELECTED_ITEM )
450 	return i;
451 
452     pItem = menu->rgItems;
453     if (!pItem) return NO_SELECTED_ITEM;
454 
455     for( ; i < menu->cItems; ++i ) {
456 	if (pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))
457 	    return i;
458     }
459 
460     return NO_SELECTED_ITEM;
461 }
462 
463 /******************************************************************************
464  *
465  *   UINT MenuGetStartOfPrevColumn(
466  *     PMENU Menu)
467  *
468  *****************************************************************************/
469 static UINT  MENU_GetStartOfPrevColumn(
470     PMENU  menu )
471 {
472     UINT  i;
473     PITEM pItem;
474 
475     if( !menu )
476 	return NO_SELECTED_ITEM;
477 
478     if( menu->iItem == 0 || menu->iItem == NO_SELECTED_ITEM )
479 	return NO_SELECTED_ITEM;
480 
481     pItem = menu->rgItems;
482     if (!pItem) return NO_SELECTED_ITEM;
483 
484     /* Find the start of the column */
485 
486     for(i = menu->iItem; i != 0 &&
487 	 !(pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK));
488 	--i); /* empty */
489 
490     if(i == 0)
491 	return NO_SELECTED_ITEM;
492 
493     for(--i; i != 0; --i) {
494 	if (pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))
495 	    break;
496     }
497 
498     TRACE("ret %d.\n", i );
499 
500     return i;
501 }
502 
503 /***********************************************************************
504  *           MENU_FindItem
505  *
506  * Find a menu item. Return a pointer on the item, and modifies *hmenu
507  * in case the item was in a sub-menu.
508  */
509 PITEM FASTCALL MENU_FindItem( PMENU *pmenu, UINT *nPos, UINT wFlags )
510 {
511     MENU *menu = *pmenu;
512     ITEM *fallback = NULL;
513     UINT fallback_pos = 0;
514     UINT i;
515 
516     if (!menu) return NULL;
517 
518     if (wFlags & MF_BYPOSITION)
519     {
520         if (!menu->cItems) return NULL;
521 	if (*nPos >= menu->cItems) return NULL;
522 	return &menu->rgItems[*nPos];
523     }
524     else
525     {
526         PITEM item = menu->rgItems;
527 	for (i = 0; i < menu->cItems; i++, item++)
528 	{
529 	    if (item->spSubMenu)
530 	    {
531 		PMENU psubmenu = item->spSubMenu;//VerifyMenu(item->spSubMenu);
532 		PITEM subitem = MENU_FindItem( &psubmenu, nPos, wFlags );
533 		if (subitem)
534 		{
535 		    *pmenu = psubmenu;
536 		    return subitem;
537 		}
538 		else if (item->wID == *nPos)
539 		{
540 		    /* fallback to this item if nothing else found */
541 		    fallback_pos = i;
542 		    fallback = item;
543 		}
544 	    }
545 	    else if (item->wID == *nPos)
546 	    {
547 		*nPos = i;
548 		return item;
549 	    }
550 	}
551     }
552 
553     if (fallback)
554         *nPos = fallback_pos;
555 
556     return fallback;
557 }
558 
559 /***********************************************************************
560  *           MenuFindSubMenu
561  *
562  * Find a Sub menu. Return the position of the submenu, and modifies
563  * *hmenu in case it is found in another sub-menu.
564  * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
565  */
566 static UINT FASTCALL MENU_FindSubMenu(PMENU *menu, PMENU SubTarget )
567 {
568     UINT i;
569     PITEM item;
570 
571     item = ((PMENU)*menu)->rgItems;
572     for (i = 0; i < ((PMENU)*menu)->cItems; i++, item++)
573     {
574         if (!item->spSubMenu)
575            continue;
576         else
577         {
578            if (item->spSubMenu == SubTarget)
579            {
580               return i;
581            }
582            else
583            {
584               PMENU pSubMenu = item->spSubMenu;
585               UINT pos = MENU_FindSubMenu( &pSubMenu, SubTarget );
586               if (pos != NO_SELECTED_ITEM)
587               {
588                   *menu = pSubMenu;
589                   return pos;
590               }
591            }
592         }
593     }
594     return NO_SELECTED_ITEM;
595 }
596 
597 BOOL FASTCALL
598 IntRemoveMenuItem( PMENU pMenu, UINT nPos, UINT wFlags, BOOL bRecurse )
599 {
600     PITEM item;
601     PITEM newItems;
602 
603     TRACE("(menu=%p pos=%04x flags=%04x)\n",pMenu, nPos, wFlags);
604     if (!(item = MENU_FindItem( &pMenu, &nPos, wFlags ))) return FALSE;
605 
606     /* Remove item */
607 
608     FreeMenuText(pMenu,item);
609     if (bRecurse && item->spSubMenu)
610     {
611        IntDestroyMenuObject(item->spSubMenu, bRecurse);
612     }
613     ////// Use cAlloced with inc's of 8's....
614     if (--pMenu->cItems == 0)
615     {
616         DesktopHeapFree(pMenu->head.rpdesk, pMenu->rgItems );
617         pMenu->rgItems = NULL;
618     }
619     else
620     {
621         while (nPos < pMenu->cItems)
622         {
623             *item = *(item+1);
624             item++;
625             nPos++;
626         }
627         newItems = DesktopHeapReAlloc(pMenu->head.rpdesk, pMenu->rgItems, pMenu->cItems * sizeof(ITEM));
628         if (newItems)
629         {
630             pMenu->rgItems = newItems;
631         }
632     }
633     return TRUE;
634 }
635 
636 /**********************************************************************
637  *         MENU_InsertItem
638  *
639  * Insert (allocate) a new item into a menu.
640  */
641 ITEM *MENU_InsertItem( PMENU menu, UINT pos, UINT flags, PMENU *submenu, UINT *npos )
642 {
643     ITEM *newItems;
644 
645     /* Find where to insert new item */
646 
647     if (flags & MF_BYPOSITION) {
648         if (pos > menu->cItems)
649             pos = menu->cItems;
650     } else {
651         if (!MENU_FindItem( &menu, &pos, flags ))
652         {
653             if (submenu) *submenu = menu;
654             if (npos) *npos = pos;
655             pos = menu->cItems;
656         }
657     }
658 
659     /* Make sure that MDI system buttons stay on the right side.
660      * Note: XP treats only bitmap handles 1 - 6 as "magic" ones
661      * regardless of their id.
662      */
663     while ( pos > 0 &&
664            (INT_PTR)menu->rgItems[pos - 1].hbmp >= (INT_PTR)HBMMENU_SYSTEM &&
665            (INT_PTR)menu->rgItems[pos - 1].hbmp <= (INT_PTR)HBMMENU_MBAR_CLOSE_D)
666         pos--;
667 
668     TRACE("inserting at %u flags %x\n", pos, flags);
669 
670     /* Create new items array */
671 
672     newItems = DesktopHeapAlloc(menu->head.rpdesk, sizeof(ITEM) * (menu->cItems+1) );
673     if (!newItems)
674     {
675         WARN("allocation failed\n" );
676         return NULL;
677     }
678     if (menu->cItems > 0)
679     {
680        /* Copy the old array into the new one */
681        if (pos > 0) RtlCopyMemory( newItems, menu->rgItems, pos * sizeof(ITEM) );
682        if (pos < menu->cItems) RtlCopyMemory( &newItems[pos+1], &menu->rgItems[pos], (menu->cItems-pos)*sizeof(ITEM) );
683        DesktopHeapFree(menu->head.rpdesk, menu->rgItems );
684     }
685     menu->rgItems = newItems;
686     menu->cItems++;
687     RtlZeroMemory( &newItems[pos], sizeof(*newItems) );
688     menu->cyMenu = 0; /* force size recalculate */
689     return &newItems[pos];
690 }
691 
692 BOOL FASTCALL
693 IntInsertMenuItem(
694     _In_ PMENU MenuObject,
695     UINT uItem,
696     BOOL fByPosition,
697     PROSMENUITEMINFO ItemInfo,
698     PUNICODE_STRING lpstr)
699 {
700    PITEM MenuItem;
701    PMENU SubMenu = NULL;
702 
703    NT_ASSERT(MenuObject != NULL);
704 
705    if (MAX_MENU_ITEMS <= MenuObject->cItems)
706    {
707       EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
708       return FALSE;
709    }
710 
711    SubMenu = MenuObject;
712 
713    if(!(MenuItem = MENU_InsertItem( SubMenu, uItem, fByPosition ? MF_BYPOSITION : MF_BYCOMMAND, &SubMenu, &uItem ))) return FALSE;
714 
715    if(!IntSetMenuItemInfo(SubMenu, MenuItem, ItemInfo, lpstr))
716    {
717       IntRemoveMenuItem(SubMenu, uItem, fByPosition ? MF_BYPOSITION : MF_BYCOMMAND, FALSE);
718       return FALSE;
719    }
720 
721    /* Force size recalculation! */
722    SubMenu->cyMenu = 0;
723    MenuItem->hbmpChecked = MenuItem->hbmpUnchecked = 0;
724 
725    TRACE("IntInsertMenuItemToList = %u %i\n", uItem, (BOOL)((INT)uItem >= 0));
726 
727    return TRUE;
728 }
729 
730 PMENU FASTCALL
731 IntCreateMenu(
732     _Out_ PHANDLE Handle,
733     _In_ BOOL IsMenuBar,
734     _In_ PDESKTOP Desktop,
735     _In_ PPROCESSINFO ppi)
736 {
737    PMENU Menu;
738 
739    Menu = (PMENU)UserCreateObject( gHandleTable,
740                                           Desktop,
741                                           ppi->ptiList,
742                                           Handle,
743                                           TYPE_MENU,
744                                           sizeof(MENU));
745    if(!Menu)
746    {
747       *Handle = 0;
748       return NULL;
749    }
750 
751    Menu->cyMax = 0; /* Default */
752    Menu->hbrBack = NULL; /* No brush */
753    Menu->dwContextHelpId = 0; /* Default */
754    Menu->dwMenuData = 0; /* Default */
755    Menu->iItem = NO_SELECTED_ITEM; // Focused item
756    Menu->fFlags = (IsMenuBar ? 0 : MNF_POPUP);
757    Menu->spwndNotify = NULL;
758    Menu->cyMenu = 0; // Height
759    Menu->cxMenu = 0; // Width
760    Menu->cItems = 0; // Item count
761    Menu->iTop = 0;
762    Menu->iMaxTop = 0;
763    Menu->cxTextAlign = 0;
764    Menu->rgItems = NULL;
765 
766    Menu->hWnd = NULL;
767    Menu->TimeToHide = FALSE;
768 
769    return Menu;
770 }
771 
772 BOOL FASTCALL
773 IntCloneMenuItems(PMENU Destination, PMENU Source)
774 {
775    PITEM MenuItem, NewMenuItem = NULL;
776    UINT i;
777 
778    if(!Source->cItems)
779       return FALSE;
780 
781    NewMenuItem = DesktopHeapAlloc(Destination->head.rpdesk, Source->cItems * sizeof(ITEM));
782    if(!NewMenuItem) return FALSE;
783 
784    RtlZeroMemory(NewMenuItem, Source->cItems * sizeof(ITEM));
785 
786    Destination->rgItems = NewMenuItem;
787 
788    MenuItem = Source->rgItems;
789    for (i = 0; i < Source->cItems; i++, MenuItem++, NewMenuItem++)
790    {
791       NewMenuItem->fType = MenuItem->fType;
792       NewMenuItem->fState = MenuItem->fState;
793       NewMenuItem->wID = MenuItem->wID;
794       NewMenuItem->spSubMenu = MenuItem->spSubMenu;
795       NewMenuItem->hbmpChecked = MenuItem->hbmpChecked;
796       NewMenuItem->hbmpUnchecked = MenuItem->hbmpUnchecked;
797       NewMenuItem->dwItemData = MenuItem->dwItemData;
798       if (MenuItem->lpstr.Length)
799       {
800          NewMenuItem->lpstr.Length = 0;
801          NewMenuItem->lpstr.MaximumLength = MenuItem->lpstr.MaximumLength;
802          NewMenuItem->lpstr.Buffer = DesktopHeapAlloc(Destination->head.rpdesk, MenuItem->lpstr.MaximumLength);
803          if (!NewMenuItem->lpstr.Buffer)
804          {
805              DesktopHeapFree(Destination->head.rpdesk, NewMenuItem);
806              break;
807          }
808          RtlCopyUnicodeString(&NewMenuItem->lpstr, &MenuItem->lpstr);
809          NewMenuItem->lpstr.Buffer[MenuItem->lpstr.Length / sizeof(WCHAR)] = 0;
810          NewMenuItem->Xlpstr = NewMenuItem->lpstr.Buffer;
811       }
812       else
813       {
814          NewMenuItem->lpstr.Buffer = MenuItem->lpstr.Buffer;
815          NewMenuItem->Xlpstr = NewMenuItem->lpstr.Buffer;
816       }
817       NewMenuItem->hbmp = MenuItem->hbmp;
818       Destination->cItems = i + 1;
819    }
820    return TRUE;
821 }
822 
823 PMENU FASTCALL
824 IntCloneMenu(PMENU Source)
825 {
826    HANDLE hMenu;
827    PMENU Menu;
828 
829    if(!Source)
830       return NULL;
831 
832    /* A menu is valid process wide. We can pass to the object manager any thread ptr */
833    Menu = (PMENU)UserCreateObject( gHandleTable,
834                                    Source->head.rpdesk,
835                                    ((PPROCESSINFO)Source->head.hTaskWow)->ptiList,
836                                    &hMenu,
837                                    TYPE_MENU,
838                                    sizeof(MENU));
839    if(!Menu)
840       return NULL;
841 
842    Menu->fFlags = Source->fFlags;
843    Menu->cyMax = Source->cyMax;
844    Menu->hbrBack = Source->hbrBack;
845    Menu->dwContextHelpId = Source->dwContextHelpId;
846    Menu->dwMenuData = Source->dwMenuData;
847    Menu->iItem = NO_SELECTED_ITEM;
848    Menu->spwndNotify = NULL;
849    Menu->cyMenu = 0;
850    Menu->cxMenu = 0;
851    Menu->cItems = 0;
852    Menu->iTop = 0;
853    Menu->iMaxTop = 0;
854    Menu->cxTextAlign = 0;
855    Menu->rgItems = NULL;
856 
857    Menu->hWnd = NULL;
858    Menu->TimeToHide = FALSE;
859 
860    IntCloneMenuItems(Menu, Source);
861 
862    return Menu;
863 }
864 
865 BOOL FASTCALL
866 IntSetMenuFlagRtoL(PMENU Menu)
867 {
868    ERR("SetMenuFlagRtoL\n");
869    Menu->fFlags |= MNF_RTOL;
870    return TRUE;
871 }
872 
873 BOOL FASTCALL
874 IntSetMenuContextHelpId(PMENU Menu, DWORD dwContextHelpId)
875 {
876    Menu->dwContextHelpId = dwContextHelpId;
877    return TRUE;
878 }
879 
880 BOOL FASTCALL
881 IntGetMenuInfo(PMENU Menu, PROSMENUINFO lpmi)
882 {
883    if(lpmi->fMask & MIM_BACKGROUND)
884       lpmi->hbrBack = Menu->hbrBack;
885    if(lpmi->fMask & MIM_HELPID)
886       lpmi->dwContextHelpID = Menu->dwContextHelpId;
887    if(lpmi->fMask & MIM_MAXHEIGHT)
888       lpmi->cyMax = Menu->cyMax;
889    if(lpmi->fMask & MIM_MENUDATA)
890       lpmi->dwMenuData = Menu->dwMenuData;
891    if(lpmi->fMask & MIM_STYLE)
892       lpmi->dwStyle = Menu->fFlags & MNS_STYLE_MASK;
893 
894    if (sizeof(MENUINFO) < lpmi->cbSize)
895    {
896      lpmi->cItems = Menu->cItems;
897 
898      lpmi->iItem = Menu->iItem;
899      lpmi->cxMenu = Menu->cxMenu;
900      lpmi->cyMenu = Menu->cyMenu;
901      lpmi->spwndNotify = Menu->spwndNotify;
902      lpmi->cxTextAlign = Menu->cxTextAlign;
903      lpmi->iTop = Menu->iTop;
904      lpmi->iMaxTop = Menu->iMaxTop;
905      lpmi->dwArrowsOn = Menu->dwArrowsOn;
906 
907      lpmi->fFlags = Menu->fFlags;
908      lpmi->Self = Menu->head.h;
909      lpmi->TimeToHide = Menu->TimeToHide;
910      lpmi->Wnd = Menu->hWnd;
911    }
912    return TRUE;
913 }
914 
915 BOOL FASTCALL
916 IntSetMenuInfo(PMENU Menu, PROSMENUINFO lpmi)
917 {
918    if(lpmi->fMask & MIM_BACKGROUND)
919       Menu->hbrBack = lpmi->hbrBack;
920    if(lpmi->fMask & MIM_HELPID)
921       Menu->dwContextHelpId = lpmi->dwContextHelpID;
922    if(lpmi->fMask & MIM_MAXHEIGHT)
923       Menu->cyMax = lpmi->cyMax;
924    if(lpmi->fMask & MIM_MENUDATA)
925       Menu->dwMenuData = lpmi->dwMenuData;
926    if(lpmi->fMask & MIM_STYLE)
927       Menu->fFlags ^= (Menu->fFlags ^ lpmi->dwStyle) & MNS_STYLE_MASK;
928    if(lpmi->fMask & MIM_APPLYTOSUBMENUS)
929    {
930       int i;
931       PITEM item = Menu->rgItems;
932       for ( i = Menu->cItems; i; i--, item++)
933       {
934          if ( item->spSubMenu )
935          {
936             IntSetMenuInfo( item->spSubMenu, lpmi);
937          }
938       }
939    }
940    if (sizeof(MENUINFO) < lpmi->cbSize)
941    {
942       Menu->iItem = lpmi->iItem;
943       Menu->cyMenu = lpmi->cyMenu;
944       Menu->cxMenu = lpmi->cxMenu;
945       Menu->spwndNotify = lpmi->spwndNotify;
946       Menu->cxTextAlign = lpmi->cxTextAlign;
947       Menu->iTop = lpmi->iTop;
948       Menu->iMaxTop = lpmi->iMaxTop;
949       Menu->dwArrowsOn = lpmi->dwArrowsOn;
950 
951       Menu->TimeToHide = lpmi->TimeToHide;
952       Menu->hWnd = lpmi->Wnd;
953    }
954    if ( lpmi->fMask & MIM_STYLE)
955    {
956       if (lpmi->dwStyle & MNS_AUTODISMISS) FIXME("MNS_AUTODISMISS unimplemented wine\n");
957       if (lpmi->dwStyle & MNS_DRAGDROP)    FIXME("MNS_DRAGDROP unimplemented wine\n");
958       if (lpmi->dwStyle & MNS_MODELESS)    FIXME("MNS_MODELESS unimplemented wine\n");
959    }
960    return TRUE;
961 }
962 
963 BOOL FASTCALL
964 IntGetMenuItemInfo(PMENU Menu, /* UNUSED PARAM!! */
965                    PITEM MenuItem, PROSMENUITEMINFO lpmii)
966 {
967    NTSTATUS Status;
968 
969    if(lpmii->fMask & (MIIM_FTYPE | MIIM_TYPE))
970    {
971       lpmii->fType = MenuItem->fType;
972    }
973    if(lpmii->fMask & MIIM_BITMAP)
974    {
975       lpmii->hbmpItem = MenuItem->hbmp;
976    }
977    if(lpmii->fMask & MIIM_CHECKMARKS)
978    {
979       lpmii->hbmpChecked = MenuItem->hbmpChecked;
980       lpmii->hbmpUnchecked = MenuItem->hbmpUnchecked;
981    }
982    if(lpmii->fMask & MIIM_DATA)
983    {
984       lpmii->dwItemData = MenuItem->dwItemData;
985    }
986    if(lpmii->fMask & MIIM_ID)
987    {
988       lpmii->wID = MenuItem->wID;
989    }
990    if(lpmii->fMask & MIIM_STATE)
991    {
992       lpmii->fState = MenuItem->fState;
993    }
994    if(lpmii->fMask & MIIM_SUBMENU)
995    {
996       lpmii->hSubMenu = MenuItem->spSubMenu ? MenuItem->spSubMenu->head.h : NULL;
997    }
998 
999    if ((lpmii->fMask & MIIM_STRING) ||
1000       ((lpmii->fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(lpmii->fType) == MF_STRING)))
1001    {
1002       if (lpmii->dwTypeData == NULL)
1003       {
1004          lpmii->cch = MenuItem->lpstr.Length / sizeof(WCHAR);
1005       }
1006       else
1007       {  //// lpmii->lpstr can be read in user mode!!!!
1008          Status = MmCopyToCaller(lpmii->dwTypeData, MenuItem->lpstr.Buffer,
1009                                  min(lpmii->cch * sizeof(WCHAR),
1010                                      MenuItem->lpstr.MaximumLength));
1011          if (! NT_SUCCESS(Status))
1012          {
1013             SetLastNtError(Status);
1014             return FALSE;
1015          }
1016       }
1017    }
1018 
1019    if (sizeof(ROSMENUITEMINFO) == lpmii->cbSize)
1020    {
1021       lpmii->Rect.left   = MenuItem->xItem;
1022       lpmii->Rect.top    = MenuItem->yItem;
1023       lpmii->Rect.right  = MenuItem->cxItem; // Do this for now......
1024       lpmii->Rect.bottom = MenuItem->cyItem;
1025       lpmii->dxTab = MenuItem->dxTab;
1026       lpmii->lpstr = MenuItem->lpstr.Buffer;
1027       lpmii->maxBmpSize.cx = MenuItem->cxBmp;
1028       lpmii->maxBmpSize.cy = MenuItem->cyBmp;
1029    }
1030 
1031    return TRUE;
1032 }
1033 
1034 BOOL FASTCALL
1035 IntSetMenuItemInfo(PMENU MenuObject, PITEM MenuItem, PROSMENUITEMINFO lpmii, PUNICODE_STRING lpstr)
1036 {
1037    PMENU SubMenuObject;
1038    BOOL circref = FALSE;
1039 
1040    if(!MenuItem || !MenuObject || !lpmii)
1041    {
1042       return FALSE;
1043    }
1044    if ( lpmii->fMask & MIIM_FTYPE )
1045    {
1046       MenuItem->fType &= ~MENUITEMINFO_TYPE_MASK;
1047       MenuItem->fType |= lpmii->fType & MENUITEMINFO_TYPE_MASK;
1048    }
1049    if (lpmii->fMask & MIIM_TYPE)
1050    {
1051       #if 0 //// Done in User32.
1052       if (lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP))
1053       {
1054          ERR("IntSetMenuItemInfo: Invalid combination of fMask bits used\n");
1055          KeRosDumpStackFrames(NULL, 20);
1056          /* This does not happen on Win9x/ME */
1057          SetLastNtError( ERROR_INVALID_PARAMETER);
1058          return FALSE;
1059       }
1060       #endif
1061       /*
1062        * Delete the menu item type when changing type from
1063        * MF_STRING.
1064        */
1065       if (MenuItem->fType != lpmii->fType &&
1066             MENU_ITEM_TYPE(MenuItem->fType) == MFT_STRING)
1067       {
1068          FreeMenuText(MenuObject,MenuItem);
1069          RtlInitUnicodeString(&MenuItem->lpstr, NULL);
1070          MenuItem->Xlpstr = NULL;
1071       }
1072       if(lpmii->fType & MFT_BITMAP)
1073       {
1074          if(lpmii->hbmpItem)
1075            MenuItem->hbmp = lpmii->hbmpItem;
1076          else
1077          { /* Win 9x/Me stuff */
1078            MenuItem->hbmp = (HBITMAP)((ULONG_PTR)(LOWORD(lpmii->dwTypeData)));
1079          }
1080          lpmii->dwTypeData = 0;
1081       }
1082    }
1083    if(lpmii->fMask & MIIM_BITMAP)
1084    {
1085       MenuItem->hbmp = lpmii->hbmpItem;
1086       if (MenuItem->hbmp <= HBMMENU_POPUP_MINIMIZE && MenuItem->hbmp >= HBMMENU_CALLBACK)
1087          MenuItem->fState |= MFS_HBMMENUBMP;
1088       else
1089          MenuItem->fState &= ~MFS_HBMMENUBMP;
1090    }
1091    if(lpmii->fMask & MIIM_CHECKMARKS)
1092    {
1093       MenuItem->hbmpChecked = lpmii->hbmpChecked;
1094       MenuItem->hbmpUnchecked = lpmii->hbmpUnchecked;
1095    }
1096    if(lpmii->fMask & MIIM_DATA)
1097    {
1098       MenuItem->dwItemData = lpmii->dwItemData;
1099    }
1100    if(lpmii->fMask & MIIM_ID)
1101    {
1102       MenuItem->wID = lpmii->wID;
1103    }
1104    if(lpmii->fMask & MIIM_STATE)
1105    {
1106       /* Remove MFS_DEFAULT flag from all other menu items if this item
1107          has the MFS_DEFAULT state */
1108       if(lpmii->fState & MFS_DEFAULT)
1109          UserSetMenuDefaultItem(MenuObject, -1, 0);
1110       /* Update the menu item state flags */
1111       UpdateMenuItemState(MenuItem->fState, lpmii->fState);
1112    }
1113 
1114    if(lpmii->fMask & MIIM_SUBMENU)
1115    {
1116       if (lpmii->hSubMenu)
1117       {
1118          SubMenuObject = UserGetMenuObject(lpmii->hSubMenu);
1119          if ( SubMenuObject && !(UserObjectInDestroy(lpmii->hSubMenu)) )
1120          {
1121             //// wine Bug 12171 : Adding Popup Menu to itself! Could create endless loops.
1122             //// CORE-7967.
1123             if (MenuObject == SubMenuObject)
1124             {
1125                HANDLE hMenu;
1126                ERR("Pop Up Menu Double Trouble!\n");
1127                SubMenuObject = IntCreateMenu(&hMenu,
1128                    FALSE,
1129                    MenuObject->head.rpdesk,
1130                    (PPROCESSINFO)MenuObject->head.hTaskWow); // It will be marked.
1131                if (!SubMenuObject) return FALSE;
1132                IntReleaseMenuObject(SubMenuObject); // This will be referenced again after insertion.
1133                circref = TRUE;
1134             }
1135             if ( MENU_depth( SubMenuObject, 0) > MAXMENUDEPTH )
1136             {
1137                ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n");
1138                if (circref) IntDestroyMenuObject(SubMenuObject, FALSE);
1139                return FALSE;
1140             }
1141             /* Make sure the submenu is marked as a popup menu */
1142             SubMenuObject->fFlags |= MNF_POPUP;
1143             // Now fix the test_subpopup_locked_by_menu tests....
1144             if (MenuItem->spSubMenu) IntReleaseMenuObject(MenuItem->spSubMenu);
1145             MenuItem->spSubMenu = SubMenuObject;
1146             UserReferenceObject(SubMenuObject);
1147          }
1148          else
1149          {
1150             EngSetLastError( ERROR_INVALID_PARAMETER);
1151             return FALSE;
1152          }
1153       }
1154       else
1155       {  // If submenu just dereference it.
1156          if (MenuItem->spSubMenu) IntReleaseMenuObject(MenuItem->spSubMenu);
1157          MenuItem->spSubMenu = NULL;
1158       }
1159    }
1160 
1161    if ((lpmii->fMask & MIIM_STRING) ||
1162       ((lpmii->fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(lpmii->fType) == MF_STRING)))
1163    {
1164       /* free the string when used */
1165       FreeMenuText(MenuObject,MenuItem);
1166       RtlInitUnicodeString(&MenuItem->lpstr, NULL);
1167       MenuItem->Xlpstr = NULL;
1168 
1169       if(lpmii->dwTypeData && lpmii->cch && lpstr && lpstr->Buffer)
1170       {
1171          UNICODE_STRING Source;
1172 
1173          if (!NT_VERIFY(lpmii->cch <= UNICODE_STRING_MAX_CHARS))
1174          {
1175              return FALSE;
1176          }
1177 
1178          Source.Length = Source.MaximumLength = (USHORT)(lpmii->cch * sizeof(WCHAR));
1179          Source.Buffer = lpmii->dwTypeData;
1180 
1181          MenuItem->lpstr.Buffer = DesktopHeapAlloc( MenuObject->head.rpdesk, Source.Length + sizeof(WCHAR));
1182          if(MenuItem->lpstr.Buffer != NULL)
1183          {
1184             MenuItem->lpstr.Length = 0;
1185             MenuItem->lpstr.MaximumLength = Source.Length + sizeof(WCHAR);
1186             RtlCopyUnicodeString(&MenuItem->lpstr, &Source);
1187             MenuItem->lpstr.Buffer[MenuItem->lpstr.Length / sizeof(WCHAR)] = 0;
1188 
1189             MenuItem->cch = MenuItem->lpstr.Length / sizeof(WCHAR);
1190             MenuItem->Xlpstr = (USHORT*)MenuItem->lpstr.Buffer;
1191          }
1192       }
1193    }
1194 
1195    if( !(MenuObject->fFlags & MNF_SYSMENU) &&
1196        !MenuItem->Xlpstr &&
1197        !lpmii->dwTypeData &&
1198        !(MenuItem->fType & MFT_OWNERDRAW) &&
1199        !MenuItem->hbmp)
1200       MenuItem->fType |= MFT_SEPARATOR;
1201 
1202    if (sizeof(ROSMENUITEMINFO) == lpmii->cbSize)
1203    {
1204       MenuItem->xItem  = lpmii->Rect.left;
1205       MenuItem->yItem  = lpmii->Rect.top;
1206       MenuItem->cxItem = lpmii->Rect.right; // Do this for now......
1207       MenuItem->cyItem = lpmii->Rect.bottom;
1208       MenuItem->dxTab = lpmii->dxTab;
1209       lpmii->lpstr = MenuItem->lpstr.Buffer; /* Send back new allocated string or zero */
1210       MenuItem->cxBmp = lpmii->maxBmpSize.cx;
1211       MenuItem->cyBmp = lpmii->maxBmpSize.cy;
1212    }
1213 
1214    return TRUE;
1215 }
1216 
1217 
1218 UINT FASTCALL
1219 IntEnableMenuItem(PMENU MenuObject, UINT uIDEnableItem, UINT uEnable)
1220 {
1221    PITEM MenuItem;
1222    UINT res;
1223 
1224    if (!(MenuItem = MENU_FindItem( &MenuObject, &uIDEnableItem, uEnable ))) return (UINT)-1;
1225 
1226    res = MenuItem->fState & (MF_GRAYED | MF_DISABLED);
1227 
1228    MenuItem->fState ^= (res ^ uEnable) & (MF_GRAYED | MF_DISABLED);
1229 
1230    /* If the close item in the system menu change update the close button */
1231    if (res != uEnable)
1232    {
1233       switch (MenuItem->wID) // More than just close.
1234       {
1235         case SC_CLOSE:
1236         case SC_MAXIMIZE:
1237         case SC_MINIMIZE:
1238         case SC_MOVE:
1239         case SC_RESTORE:
1240         case SC_SIZE:
1241 	if (MenuObject->fFlags & MNF_SYSSUBMENU && MenuObject->spwndNotify != 0)
1242 	{
1243             //RECTL rc = MenuObject->spwndNotify->rcWindow;
1244 
1245             /* Refresh the frame to reflect the change */
1246             //IntMapWindowPoints(0, MenuObject->spwndNotify, (POINT *)&rc, 2);
1247             //rc.bottom = 0;
1248             //co_UserRedrawWindow(MenuObject->spwndNotify, &rc, 0, RDW_FRAME | RDW_INVALIDATE | RDW_NOCHILDREN);
1249 
1250             // Allow UxTheme!
1251             UserPaintCaption(MenuObject->spwndNotify, DC_BUTTONS);
1252 	}
1253 	default:
1254            break;
1255       }
1256    }
1257    return res;
1258 }
1259 
1260 DWORD FASTCALL
1261 IntCheckMenuItem(PMENU MenuObject, UINT uIDCheckItem, UINT uCheck)
1262 {
1263    PITEM MenuItem;
1264    DWORD res;
1265 
1266    if (!(MenuItem = MENU_FindItem( &MenuObject, &uIDCheckItem, uCheck ))) return -1;
1267 
1268    res = (DWORD)(MenuItem->fState & MF_CHECKED);
1269 
1270    MenuItem->fState ^= (res ^ uCheck) & MF_CHECKED;
1271 
1272    return res;
1273 }
1274 
1275 BOOL FASTCALL
1276 UserSetMenuDefaultItem(PMENU MenuObject, UINT uItem, UINT fByPos)
1277 {
1278    UINT i;
1279    PITEM MenuItem = MenuObject->rgItems;
1280 
1281    if (!MenuItem) return FALSE;
1282 
1283    /* reset all default-item flags */
1284    for (i = 0; i < MenuObject->cItems; i++, MenuItem++)
1285    {
1286        MenuItem->fState &= ~MFS_DEFAULT;
1287    }
1288 
1289    /* no default item */
1290    if(uItem == (UINT)-1)
1291    {
1292       return TRUE;
1293    }
1294    MenuItem = MenuObject->rgItems;
1295    if ( fByPos )
1296    {
1297       if ( uItem >= MenuObject->cItems ) return FALSE;
1298          MenuItem[uItem].fState |= MFS_DEFAULT;
1299       return TRUE;
1300    }
1301    else
1302    {
1303       for (i = 0; i < MenuObject->cItems; i++, MenuItem++)
1304       {
1305           if (MenuItem->wID == uItem)
1306           {
1307              MenuItem->fState |= MFS_DEFAULT;
1308              return TRUE;
1309           }
1310       }
1311 
1312    }
1313    return FALSE;
1314 }
1315 
1316 UINT FASTCALL
1317 IntGetMenuDefaultItem(PMENU MenuObject, UINT fByPos, UINT gmdiFlags, DWORD *gismc)
1318 {
1319    UINT i = 0;
1320    PITEM MenuItem = MenuObject->rgItems;
1321 
1322    /* empty menu */
1323    if (!MenuItem) return -1;
1324 
1325    while ( !( MenuItem->fState & MFS_DEFAULT ) )
1326    {
1327       i++; MenuItem++;
1328       if  (i >= MenuObject->cItems ) return -1;
1329    }
1330 
1331    /* default: don't return disabled items */
1332    if ( (!(GMDI_USEDISABLED & gmdiFlags)) && (MenuItem->fState & MFS_DISABLED )) return -1;
1333 
1334    /* search rekursiv when needed */
1335    if ( (gmdiFlags & GMDI_GOINTOPOPUPS) && MenuItem->spSubMenu )
1336    {
1337       UINT ret;
1338       (*gismc)++;
1339       ret = IntGetMenuDefaultItem( MenuItem->spSubMenu, fByPos, gmdiFlags, gismc );
1340       (*gismc)--;
1341       if ( -1 != ret ) return ret;
1342 
1343       /* when item not found in submenu, return the popup item */
1344    }
1345    return ( fByPos ) ? i : MenuItem->wID;
1346 }
1347 
1348 PMENU
1349 FASTCALL
1350 co_IntGetSubMenu(
1351   PMENU pMenu,
1352   int nPos)
1353 {
1354   PITEM pItem;
1355   if (!(pItem = MENU_FindItem( &pMenu, (UINT*)&nPos, MF_BYPOSITION ))) return NULL;
1356   return pItem->spSubMenu;
1357 }
1358 
1359 /***********************************************************************
1360  *           MenuInitSysMenuPopup
1361  *
1362  * Grey the appropriate items in System menu.
1363  */
1364 void FASTCALL MENU_InitSysMenuPopup(PMENU menu, DWORD style, DWORD clsStyle, LONG HitTest )
1365 {
1366     BOOL gray;
1367     UINT DefItem;
1368 
1369     gray = !(style & WS_THICKFRAME) || (style & (WS_MAXIMIZE | WS_MINIMIZE));
1370     IntEnableMenuItem( menu, SC_SIZE, (gray ? MF_GRAYED : MF_ENABLED) );
1371     gray = ((style & WS_MAXIMIZE) != 0);
1372     IntEnableMenuItem( menu, SC_MOVE, (gray ? MF_GRAYED : MF_ENABLED) );
1373     gray = !(style & WS_MINIMIZEBOX) || (style & WS_MINIMIZE);
1374     IntEnableMenuItem( menu, SC_MINIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
1375     gray = !(style & WS_MAXIMIZEBOX) || (style & WS_MAXIMIZE);
1376     IntEnableMenuItem( menu, SC_MAXIMIZE, (gray ? MF_GRAYED : MF_ENABLED) );
1377     gray = !(style & (WS_MAXIMIZE | WS_MINIMIZE));
1378     IntEnableMenuItem( menu, SC_RESTORE, (gray ? MF_GRAYED : MF_ENABLED) );
1379     gray = (clsStyle & CS_NOCLOSE) != 0;
1380 
1381     /* The menu item must keep its state if it's disabled */
1382     if(gray)
1383         IntEnableMenuItem( menu, SC_CLOSE, MF_GRAYED);
1384 
1385     /* Set default menu item */
1386     if(style & WS_MINIMIZE) DefItem = SC_RESTORE;
1387     else if(HitTest == HTCAPTION) DefItem = ((style & (WS_MAXIMIZE | WS_MINIMIZE)) ? SC_RESTORE : SC_MAXIMIZE);
1388     else DefItem = SC_CLOSE;
1389 
1390     UserSetMenuDefaultItem(menu, DefItem, MF_BYCOMMAND);
1391 }
1392 
1393 
1394 /***********************************************************************
1395  *           MenuDrawPopupGlyph
1396  *
1397  * Draws popup magic glyphs (can be found in system menu).
1398  */
1399 static void FASTCALL
1400 MENU_DrawPopupGlyph(HDC dc, LPRECT r, INT_PTR popupMagic, BOOL inactive, BOOL hilite)
1401 {
1402   LOGFONTW lf;
1403   HFONT hFont, hOldFont;
1404   COLORREF clrsave;
1405   INT bkmode;
1406   WCHAR symbol;
1407   switch (popupMagic)
1408   {
1409   case (INT_PTR) HBMMENU_POPUP_RESTORE:
1410     symbol = '2';
1411     break;
1412   case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
1413     symbol = '0';
1414     break;
1415   case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
1416     symbol = '1';
1417     break;
1418   case (INT_PTR) HBMMENU_POPUP_CLOSE:
1419     symbol = 'r';
1420     break;
1421   default:
1422     ERR("Invalid popup magic bitmap %d\n", (int)popupMagic);
1423     return;
1424   }
1425   RtlZeroMemory(&lf, sizeof(LOGFONTW));
1426   RECTL_vInflateRect(r, -2, -2);
1427   lf.lfHeight = r->bottom - r->top;
1428   lf.lfWidth = 0;
1429   lf.lfWeight = FW_NORMAL;
1430   lf.lfCharSet = DEFAULT_CHARSET;
1431   RtlCopyMemory(lf.lfFaceName, L"Marlett", sizeof(L"Marlett"));
1432   hFont = GreCreateFontIndirectW(&lf);
1433   /* save font and text color */
1434   hOldFont = NtGdiSelectFont(dc, hFont);
1435   clrsave = GreGetTextColor(dc);
1436   bkmode = GreGetBkMode(dc);
1437   /* set color and drawing mode */
1438   IntGdiSetBkMode(dc, TRANSPARENT);
1439   if (inactive)
1440   {
1441     /* draw shadow */
1442     if (!hilite)
1443     {
1444       IntGdiSetTextColor(dc, IntGetSysColor(COLOR_HIGHLIGHTTEXT));
1445       GreTextOutW(dc, r->left + 1, r->top + 1, &symbol, 1);
1446     }
1447   }
1448   IntGdiSetTextColor(dc, IntGetSysColor(inactive ? COLOR_GRAYTEXT : (hilite ? COLOR_HIGHLIGHTTEXT : COLOR_MENUTEXT)));
1449   /* draw selected symbol */
1450   GreTextOutW(dc, r->left, r->top, &symbol, 1);
1451   /* restore previous settings */
1452   IntGdiSetTextColor(dc, clrsave);
1453   NtGdiSelectFont(dc, hOldFont);
1454   IntGdiSetBkMode(dc, bkmode);
1455   GreDeleteObject(hFont);
1456 }
1457 
1458 /***********************************************************************
1459  *           MENU_AdjustMenuItemRect
1460  *
1461  * Adjust menu item rectangle according to scrolling state.
1462  */
1463 VOID FASTCALL
1464 MENU_AdjustMenuItemRect(PMENU menu, PRECTL rect)
1465 {
1466     if (menu->dwArrowsOn)
1467     {
1468         UINT arrow_bitmap_height;
1469         arrow_bitmap_height = gpsi->oembmi[OBI_UPARROW].cy; ///// Menu up arrow! OBM_UPARROW
1470         rect->top += arrow_bitmap_height - menu->iTop;
1471         rect->bottom += arrow_bitmap_height - menu->iTop;
1472     }
1473 }
1474 
1475 /***********************************************************************
1476  *           MENU_FindItemByCoords
1477  *
1478  * Find the item at the specified coordinates (screen coords). Does
1479  * not work for child windows and therefore should not be called for
1480  * an arbitrary system menu.
1481  */
1482 static ITEM *MENU_FindItemByCoords( MENU *menu, POINT pt, UINT *pos )
1483 {
1484     ITEM *item;
1485     UINT i;
1486     INT cx, cy;
1487     RECT rect;
1488     PWND pWnd = ValidateHwndNoErr(menu->hWnd);
1489 
1490     if (!IntGetWindowRect(pWnd, &rect)) return NULL;
1491 
1492     cx = UserGetSystemMetrics(SM_CXDLGFRAME);
1493     cy = UserGetSystemMetrics(SM_CYDLGFRAME);
1494     RECTL_vInflateRect(&rect, -cx, -cy);
1495 
1496     if (pWnd->ExStyle & WS_EX_LAYOUTRTL)
1497        pt.x = rect.right - 1 - pt.x;
1498     else
1499        pt.x -= rect.left;
1500     pt.y -= rect.top;
1501     item = menu->rgItems;
1502     for (i = 0; i < menu->cItems; i++, item++)
1503     {
1504         //rect = item->rect;
1505         rect.left   = item->xItem;
1506         rect.top    = item->yItem;
1507         rect.right  = item->cxItem; // Do this for now......
1508         rect.bottom = item->cyItem;
1509 
1510         MENU_AdjustMenuItemRect(menu, &rect);
1511 	if (RECTL_bPointInRect(&rect, pt.x, pt.y))
1512 	{
1513 	    if (pos) *pos = i;
1514 	    return item;
1515 	}
1516     }
1517     return NULL;
1518 }
1519 
1520 INT FASTCALL IntMenuItemFromPoint(PWND pWnd, HMENU hMenu, POINT ptScreen)
1521 {
1522     MENU *menu = UserGetMenuObject(hMenu);
1523     UINT pos;
1524 
1525     /*FIXME: Do we have to handle hWnd here? */
1526     if (!menu) return -1;
1527     if (!MENU_FindItemByCoords(menu, ptScreen, &pos)) return -1;
1528     return pos;
1529 }
1530 
1531 /***********************************************************************
1532  *           MenuFindItemByKey
1533  *
1534  * Find the menu item selected by a key press.
1535  * Return item id, -1 if none, -2 if we should close the menu.
1536  */
1537 static UINT FASTCALL MENU_FindItemByKey(PWND WndOwner, PMENU menu,
1538                   WCHAR Key, BOOL ForceMenuChar)
1539 {
1540   LRESULT MenuChar;
1541   WORD Flags = 0;
1542 
1543   TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key, Key, menu );
1544 
1545   if (!menu || !VerifyMenu(menu))
1546      menu = co_IntGetSubMenu( UserGetMenuObject(WndOwner->SystemMenu), 0 );
1547   if (menu)
1548   {
1549      ITEM *item = menu->rgItems;
1550 
1551      if ( !ForceMenuChar )
1552      {
1553         UINT i;
1554         BOOL cjk = UserGetSystemMetrics( SM_DBCSENABLED );
1555 
1556         for (i = 0; i < menu->cItems; i++, item++)
1557         {
1558            LPWSTR text = item->Xlpstr;
1559            if( text)
1560            {
1561               const WCHAR *p = text - 2;
1562               do
1563               {
1564                  const WCHAR *q = p + 2;
1565                  p = wcschr (q, '&');
1566                  if (!p && cjk) p = wcschr (q, '\036'); /* Japanese Win16 */
1567               }
1568               while (p != NULL && p [1] == '&');
1569               if (p && (towupper(p[1]) == towupper(Key))) return i;
1570            }
1571         }
1572      }
1573 
1574      Flags |= menu->fFlags & MNF_POPUP ? MF_POPUP : 0;
1575      Flags |= menu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0;
1576 
1577      MenuChar = co_IntSendMessage( UserHMGetHandle(WndOwner), WM_MENUCHAR,
1578                               MAKEWPARAM(Key, Flags), (LPARAM) UserHMGetHandle(menu));
1579      if (HIWORD(MenuChar) == MNC_EXECUTE) return LOWORD(MenuChar);
1580      if (HIWORD(MenuChar) == MNC_CLOSE) return (UINT)(-2);
1581   }
1582   return (UINT)(-1);
1583 }
1584 
1585 /***********************************************************************
1586  *           MenuGetBitmapItemSize
1587  *
1588  * Get the size of a bitmap item.
1589  */
1590 static void FASTCALL MENU_GetBitmapItemSize(PITEM lpitem, SIZE *size, PWND WndOwner)
1591 {
1592     BITMAP bm;
1593     HBITMAP bmp = lpitem->hbmp;
1594 
1595     size->cx = size->cy = 0;
1596 
1597     /* check if there is a magic menu item associated with this item */
1598     if (IS_MAGIC_BITMAP(bmp))
1599     {
1600       switch((INT_PTR) bmp)
1601         {
1602             case (INT_PTR)HBMMENU_CALLBACK:
1603             {
1604                 MEASUREITEMSTRUCT measItem;
1605                 measItem.CtlType = ODT_MENU;
1606                 measItem.CtlID = 0;
1607                 measItem.itemID = lpitem->wID;
1608                 measItem.itemWidth  = lpitem->cxItem - lpitem->xItem; //lpitem->Rect.right  - lpitem->Rect.left;
1609                 measItem.itemHeight = lpitem->cyItem - lpitem->yItem; //lpitem->Rect.bottom - lpitem->Rect.top;
1610                 measItem.itemData = lpitem->dwItemData;
1611                 co_IntSendMessage( UserHMGetHandle(WndOwner), WM_MEASUREITEM, 0, (LPARAM)&measItem);
1612                 size->cx = measItem.itemWidth;
1613                 size->cy = measItem.itemHeight;
1614                 TRACE("HBMMENU_CALLBACK Height %d Width %d\n",measItem.itemHeight,measItem.itemWidth);
1615                 return;
1616             }
1617             break;
1618 
1619           case (INT_PTR) HBMMENU_SYSTEM:
1620             if (lpitem->dwItemData)
1621               {
1622                 bmp = (HBITMAP) lpitem->dwItemData;
1623                 break;
1624               }
1625             /* fall through */
1626           case (INT_PTR) HBMMENU_MBAR_RESTORE:
1627           case (INT_PTR) HBMMENU_MBAR_MINIMIZE:
1628           case (INT_PTR) HBMMENU_MBAR_CLOSE:
1629           case (INT_PTR) HBMMENU_MBAR_MINIMIZE_D:
1630           case (INT_PTR) HBMMENU_MBAR_CLOSE_D:
1631           case (INT_PTR) HBMMENU_POPUP_CLOSE:
1632           case (INT_PTR) HBMMENU_POPUP_RESTORE:
1633           case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
1634           case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
1635             /* FIXME: Why we need to subtract these magic values? */
1636             /* to make them smaller than the menu bar? */
1637             size->cx = UserGetSystemMetrics(SM_CXSIZE) - 2;
1638             size->cy = UserGetSystemMetrics(SM_CYSIZE) - 4;
1639             return;
1640         }
1641     }
1642 
1643     if (GreGetObject(bmp, sizeof(BITMAP), &bm))
1644     {
1645         size->cx = bm.bmWidth;
1646         size->cy = bm.bmHeight;
1647     }
1648 }
1649 
1650 /***********************************************************************
1651  *           MenuDrawBitmapItem
1652  *
1653  * Draw a bitmap item.
1654  */
1655 static void FASTCALL MENU_DrawBitmapItem(HDC hdc, PITEM lpitem, const RECT *rect,
1656                     PMENU Menu, PWND WndOwner, UINT odaction, BOOL MenuBar)
1657 {
1658     BITMAP bm;
1659     DWORD rop;
1660     HDC hdcMem;
1661     HBITMAP bmp;
1662     int w = rect->right - rect->left;
1663     int h = rect->bottom - rect->top;
1664     int bmp_xoffset = 0;
1665     int left, top;
1666     BOOL flat_menu;
1667     HBITMAP hbmToDraw = lpitem->hbmp;
1668     bmp = hbmToDraw;
1669 
1670     UserSystemParametersInfo(SPI_GETFLATMENU, 0, &flat_menu, 0);
1671 
1672     /* Check if there is a magic menu item associated with this item */
1673     if (IS_MAGIC_BITMAP(hbmToDraw))
1674     {
1675         UINT flags = 0;
1676         RECT r;
1677 
1678       r = *rect;
1679       switch ((INT_PTR)hbmToDraw)
1680       {
1681         case (INT_PTR)HBMMENU_SYSTEM:
1682             if (lpitem->dwItemData)
1683             {
1684                 if (ValidateHwndNoErr((HWND)lpitem->dwItemData))
1685                 {
1686                    ERR("Get Item Data from this Window!!!\n");
1687                 }
1688 
1689                 ERR("Draw Bitmap\n");
1690                 bmp = (HBITMAP)lpitem->dwItemData;
1691                 if (!GreGetObject( bmp, sizeof(bm), &bm )) return;
1692             }
1693             else
1694             {
1695                 PCURICON_OBJECT pIcon = NULL;
1696                 //if (!BmpSysMenu) BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE));
1697                 //bmp = BmpSysMenu;
1698                 //if (! GreGetObject(bmp, sizeof(bm), &bm)) return;
1699                 /* only use right half of the bitmap */
1700                 //bmp_xoffset = bm.bmWidth / 2;
1701                 //bm.bmWidth -= bmp_xoffset;
1702                 if (WndOwner)
1703                 {
1704                     pIcon = NC_IconForWindow(WndOwner);
1705                     // FIXME: NC_IconForWindow should reference it for us */
1706                     if (pIcon) UserReferenceObject(pIcon);
1707                 }
1708                 ERR("Draw ICON\n");
1709                 if (pIcon)
1710                 {
1711                    LONG cx = UserGetSystemMetrics(SM_CXSMICON);
1712                    LONG cy = UserGetSystemMetrics(SM_CYSMICON);
1713                    LONG x = rect->left - cx/2 + 1 + (rect->bottom - rect->top)/2; // this is really what Window does
1714                    LONG y = (rect->top + rect->bottom)/2 - cy/2; // center
1715                    UserDrawIconEx(hdc, x, y, pIcon, cx, cy, 0, NULL, DI_NORMAL);
1716                    UserDereferenceObject(pIcon);
1717                  }
1718                  return;
1719             }
1720             goto got_bitmap;
1721         case (INT_PTR)HBMMENU_MBAR_RESTORE:
1722             flags = DFCS_CAPTIONRESTORE;
1723             break;
1724         case (INT_PTR)HBMMENU_MBAR_MINIMIZE:
1725             r.right += 1;
1726             flags = DFCS_CAPTIONMIN;
1727             break;
1728         case (INT_PTR)HBMMENU_MBAR_MINIMIZE_D:
1729             r.right += 1;
1730             flags = DFCS_CAPTIONMIN | DFCS_INACTIVE;
1731             break;
1732         case (INT_PTR)HBMMENU_MBAR_CLOSE:
1733             flags = DFCS_CAPTIONCLOSE;
1734             break;
1735         case (INT_PTR)HBMMENU_MBAR_CLOSE_D:
1736             flags = DFCS_CAPTIONCLOSE | DFCS_INACTIVE;
1737             break;
1738         case (INT_PTR)HBMMENU_CALLBACK:
1739             {
1740                 DRAWITEMSTRUCT drawItem;
1741                 POINT origorg;
1742                 drawItem.CtlType = ODT_MENU;
1743                 drawItem.CtlID = 0;
1744                 drawItem.itemID = lpitem->wID;
1745                 drawItem.itemAction = odaction;
1746                 drawItem.itemState = (lpitem->fState & MF_CHECKED)?ODS_CHECKED:0;
1747                 drawItem.itemState |= (lpitem->fState & MF_DEFAULT)?ODS_DEFAULT:0;
1748                 drawItem.itemState |= (lpitem->fState & MF_DISABLED)?ODS_DISABLED:0;
1749                 drawItem.itemState |= (lpitem->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0;
1750                 drawItem.itemState |= (lpitem->fState & MF_HILITE)?ODS_SELECTED:0;
1751                 drawItem.itemState |= (!(Menu->fFlags & MNF_UNDERLINE))?ODS_NOACCEL:0;
1752                 drawItem.itemState |= (Menu->fFlags & MNF_INACTIVE)?ODS_INACTIVE:0;
1753                 drawItem.hwndItem = (HWND)UserHMGetHandle(Menu);
1754                 drawItem.hDC = hdc;
1755                 drawItem.rcItem = *rect;
1756                 drawItem.itemData = lpitem->dwItemData;
1757                 /* some applications make this assumption on the DC's origin */
1758                 GreSetViewportOrgEx( hdc, lpitem->xItem, lpitem->yItem, &origorg);
1759                 RECTL_vOffsetRect(&drawItem.rcItem, -(LONG)lpitem->xItem, -(LONG)lpitem->yItem);
1760                 co_IntSendMessage( UserHMGetHandle(WndOwner), WM_DRAWITEM, 0, (LPARAM)&drawItem);
1761                 GreSetViewportOrgEx( hdc, origorg.x, origorg.y, NULL);
1762                 return;
1763             }
1764             break;
1765 
1766           case (INT_PTR) HBMMENU_POPUP_CLOSE:
1767           case (INT_PTR) HBMMENU_POPUP_RESTORE:
1768           case (INT_PTR) HBMMENU_POPUP_MAXIMIZE:
1769           case (INT_PTR) HBMMENU_POPUP_MINIMIZE:
1770             MENU_DrawPopupGlyph(hdc, &r, (INT_PTR)hbmToDraw, lpitem->fState & MF_GRAYED, lpitem->fState & MF_HILITE);
1771             return;
1772       }
1773       RECTL_vInflateRect(&r, -1, -1);
1774       if (lpitem->fState & MF_HILITE) flags |= DFCS_PUSHED;
1775       DrawFrameControl(hdc, &r, DFC_CAPTION, flags);
1776       return;
1777     }
1778 
1779     if (!bmp || !GreGetObject( bmp, sizeof(bm), &bm )) return;
1780 
1781  got_bitmap:
1782     hdcMem = NtGdiCreateCompatibleDC( hdc );
1783     NtGdiSelectBitmap( hdcMem, bmp );
1784     /* handle fontsize > bitmap_height */
1785     top = (h>bm.bmHeight) ? rect->top+(h-bm.bmHeight)/2 : rect->top;
1786     left=rect->left;
1787     rop=((lpitem->fState & MF_HILITE) && !IS_MAGIC_BITMAP(hbmToDraw)) ? NOTSRCCOPY : SRCCOPY;
1788     if ((lpitem->fState & MF_HILITE) && lpitem->hbmp)
1789         IntGdiSetBkColor(hdc, IntGetSysColor(COLOR_HIGHLIGHT));
1790     if (MenuBar &&
1791         !flat_menu &&
1792         (lpitem->fState & (MF_HILITE | MF_GRAYED)) == MF_HILITE)
1793     {
1794         ++left;
1795         ++top;
1796     }
1797     NtGdiBitBlt( hdc, left, top, w, h, hdcMem, bmp_xoffset, 0, rop , 0, 0);
1798     IntGdiDeleteDC( hdcMem, FALSE );
1799 }
1800 
1801 LONG
1802 IntGetDialogBaseUnits(VOID)
1803 {
1804     static DWORD units;
1805 
1806     if (!units)
1807     {
1808         HDC hdc;
1809         SIZE size;
1810 
1811         if ((hdc = UserGetDCEx(NULL, NULL, DCX_CACHE)))
1812         {
1813             size.cx = IntGetCharDimensions( hdc, NULL, (PDWORD)&size.cy );
1814             if (size.cx) units = MAKELONG( size.cx, size.cy );
1815             UserReleaseDC( 0, hdc, FALSE);
1816         }
1817     }
1818     return units;
1819 }
1820 
1821 
1822 /***********************************************************************
1823  *           MenuCalcItemSize
1824  *
1825  * Calculate the size of the menu item and store it in lpitem->rect.
1826  */
1827 static void FASTCALL MENU_CalcItemSize( HDC hdc, PITEM lpitem, PMENU Menu, PWND pwndOwner,
1828                  INT orgX, INT orgY, BOOL menuBar, BOOL textandbmp)
1829 {
1830     WCHAR *p;
1831     UINT check_bitmap_width = UserGetSystemMetrics( SM_CXMENUCHECK );
1832     UINT arrow_bitmap_width;
1833     RECT Rect;
1834     INT itemheight = 0;
1835 
1836     TRACE("dc=%x owner=%x (%d,%d)\n", hdc, pwndOwner, orgX, orgY);
1837 
1838     arrow_bitmap_width = gpsi->oembmi[OBI_MNARROW].cx;
1839 
1840     MenuCharSize.cx = IntGetCharDimensions( hdc, NULL, (PDWORD)&MenuCharSize.cy );
1841 
1842     RECTL_vSetRect( &Rect, orgX, orgY, orgX, orgY );
1843 
1844     if (lpitem->fType & MF_OWNERDRAW)
1845     {
1846         MEASUREITEMSTRUCT mis;
1847         mis.CtlType    = ODT_MENU;
1848         mis.CtlID      = 0;
1849         mis.itemID     = lpitem->wID;
1850         mis.itemData   = lpitem->dwItemData;
1851         mis.itemHeight = HIWORD( IntGetDialogBaseUnits());
1852         mis.itemWidth  = 0;
1853         co_IntSendMessage( UserHMGetHandle(pwndOwner), WM_MEASUREITEM, 0, (LPARAM)&mis );
1854         /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1855          * width of a menufont character to the width of an owner-drawn menu.
1856          */
1857         Rect.right += mis.itemWidth + 2 * MenuCharSize.cx;
1858         if (menuBar) {
1859             /* under at least win95 you seem to be given a standard
1860                height for the menu and the height value is ignored */
1861             Rect.bottom += UserGetSystemMetrics(SM_CYMENUSIZE);
1862         } else
1863             Rect.bottom += mis.itemHeight;
1864         // Or this,
1865         //lpitem->cxBmp = mis.itemWidth;
1866         //lpitem->cyBmp = mis.itemHeight;
1867         TRACE("MF_OWNERDRAW Height %d Width %d\n",mis.itemHeight,mis.itemWidth);
1868         TRACE("MF_OWNERDRAW id=%04lx size=%dx%d cx %d cy %d\n",
1869                 lpitem->wID, Rect.right-Rect.left,
1870                  Rect.bottom-Rect.top, MenuCharSize.cx, MenuCharSize.cy);
1871 
1872         lpitem->xItem = Rect.left;
1873         lpitem->yItem = Rect.top;
1874         lpitem->cxItem = Rect.right;
1875         lpitem->cyItem = Rect.bottom;
1876 
1877         return;
1878     }
1879 
1880     lpitem->xItem  = orgX;
1881     lpitem->yItem  = orgY;
1882     lpitem->cxItem = orgX;
1883     lpitem->cyItem = orgY;
1884 
1885     if (lpitem->fType & MF_SEPARATOR)
1886     {
1887         lpitem->cyItem += UserGetSystemMetrics( SM_CYMENUSIZE)/2;//SEPARATOR_HEIGHT;
1888         if( !menuBar)
1889             lpitem->cxItem += arrow_bitmap_width + MenuCharSize.cx;
1890         return;
1891     }
1892 
1893     lpitem->dxTab = 0;
1894 
1895     if (lpitem->hbmp)
1896     {
1897         SIZE size;
1898 
1899         if (!menuBar) {
1900             MENU_GetBitmapItemSize(lpitem, &size, pwndOwner );
1901             /* Keep the size of the bitmap in callback mode to be able
1902              * to draw it correctly */
1903             lpitem->cxBmp = size.cx;
1904             lpitem->cyBmp = size.cy;
1905             Menu->cxTextAlign = max(Menu->cxTextAlign, size.cx);
1906             lpitem->cxItem += size.cx + 2;
1907             itemheight = size.cy + 2;
1908 
1909             if( !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK))
1910                 lpitem->cxItem += 2 * check_bitmap_width;
1911             lpitem->cxItem += 4 + MenuCharSize.cx;
1912             lpitem->dxTab = lpitem->cxItem;
1913             lpitem->cxItem += arrow_bitmap_width;
1914         } else /* hbmpItem & MenuBar */ {
1915             MENU_GetBitmapItemSize(lpitem, &size, pwndOwner );
1916             lpitem->cxItem  += size.cx;
1917             if( lpitem->Xlpstr) lpitem->cxItem  += 2;
1918             itemheight = size.cy;
1919 
1920             /* Special case: Minimize button doesn't have a space behind it. */
1921             if (lpitem->hbmp == (HBITMAP)HBMMENU_MBAR_MINIMIZE ||
1922                 lpitem->hbmp == (HBITMAP)HBMMENU_MBAR_MINIMIZE_D)
1923             lpitem->cxItem -= 1;
1924         }
1925     }
1926     else if (!menuBar) {
1927         if( !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK))
1928              lpitem->cxItem += check_bitmap_width;
1929         lpitem->cxItem += 4 + MenuCharSize.cx;
1930         lpitem->dxTab = lpitem->cxItem;
1931         lpitem->cxItem += arrow_bitmap_width;
1932     }
1933 
1934     /* it must be a text item - unless it's the system menu */
1935     if (!(lpitem->fType & MF_SYSMENU) && lpitem->Xlpstr) {
1936         HFONT hfontOld = NULL;
1937         RECT rc;// = lpitem->Rect;
1938         LONG txtheight, txtwidth;
1939 
1940         rc.left   = lpitem->xItem;
1941         rc.top    = lpitem->yItem;
1942         rc.right  = lpitem->cxItem; // Do this for now......
1943         rc.bottom = lpitem->cyItem;
1944 
1945         if ( lpitem->fState & MFS_DEFAULT ) {
1946             hfontOld = NtGdiSelectFont( hdc, ghMenuFontBold );
1947         }
1948         if (menuBar) {
1949             txtheight = DrawTextW( hdc, lpitem->Xlpstr, -1, &rc, DT_SINGLELINE|DT_CALCRECT);
1950 
1951             lpitem->cxItem  += rc.right - rc.left;
1952             itemheight = max( max( itemheight, txtheight), UserGetSystemMetrics( SM_CYMENU) - 1);
1953 
1954             lpitem->cxItem +=  2 * MenuCharSize.cx;
1955         } else {
1956             if ((p = wcschr( lpitem->Xlpstr, '\t' )) != NULL) {
1957                 RECT tmprc = rc;
1958                 LONG tmpheight;
1959                 int n = (int)( p - lpitem->Xlpstr);
1960                 /* Item contains a tab (only meaningful in popup menus) */
1961                 /* get text size before the tab */
1962                 txtheight = DrawTextW( hdc, lpitem->Xlpstr, n, &rc,
1963                         DT_SINGLELINE|DT_CALCRECT);
1964                 txtwidth = rc.right - rc.left;
1965                 p += 1; /* advance past the Tab */
1966                 /* get text size after the tab */
1967                 tmpheight = DrawTextW( hdc, p, -1, &tmprc,
1968                         DT_SINGLELINE|DT_CALCRECT);
1969                 lpitem->dxTab += txtwidth;
1970                 txtheight = max( txtheight, tmpheight);
1971                 txtwidth += MenuCharSize.cx + /* space for the tab */
1972                     tmprc.right - tmprc.left; /* space for the short cut */
1973             } else {
1974                 txtheight = DrawTextW( hdc, lpitem->Xlpstr, -1, &rc,
1975                         DT_SINGLELINE|DT_CALCRECT);
1976                 txtwidth = rc.right - rc.left;
1977                 lpitem->dxTab += txtwidth;
1978             }
1979             lpitem->cxItem  += 2 + txtwidth;
1980             itemheight = max( itemheight,
1981 				    max( txtheight + 2, MenuCharSize.cy + 4));
1982         }
1983         if (hfontOld)
1984         {
1985            NtGdiSelectFont (hdc, hfontOld);
1986         }
1987     } else if( menuBar) {
1988         itemheight = max( itemheight, UserGetSystemMetrics(SM_CYMENU)-1);
1989     }
1990     lpitem->cyItem += itemheight;
1991     TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem->xItem, lpitem->yItem, lpitem->cxItem, lpitem->cyItem);
1992 }
1993 
1994 /***********************************************************************
1995  *           MENU_GetMaxPopupHeight
1996  */
1997 static UINT
1998 MENU_GetMaxPopupHeight(PMENU lppop)
1999 {
2000     if (lppop->cyMax)
2001     {
2002        //ERR("MGMaxPH cyMax %d\n",lppop->cyMax);
2003        return lppop->cyMax;
2004     }
2005     //ERR("MGMaxPH SyMax %d\n",UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER));
2006     return UserGetSystemMetrics(SM_CYSCREEN) - UserGetSystemMetrics(SM_CYBORDER);
2007 }
2008 
2009 /***********************************************************************
2010  *           MenuPopupMenuCalcSize
2011  *
2012  * Calculate the size of a popup menu.
2013  */
2014 static void FASTCALL MENU_PopupMenuCalcSize(PMENU Menu, PWND WndOwner)
2015 {
2016     PITEM lpitem;
2017     HDC hdc;
2018     int start, i;
2019     int orgX, orgY, maxX, maxTab, maxTabWidth, maxHeight;
2020     BOOL textandbmp = FALSE;
2021 
2022     Menu->cxMenu = Menu->cyMenu = 0;
2023     if (Menu->cItems == 0) return;
2024 
2025     hdc = UserGetDCEx(NULL, NULL, DCX_CACHE);
2026 
2027     NtGdiSelectFont( hdc, ghMenuFont );
2028 
2029     start = 0;
2030     maxX = 0;
2031 
2032     Menu->cxTextAlign = 0;
2033 
2034     while (start < Menu->cItems)
2035     {
2036       lpitem = &Menu->rgItems[start];
2037       orgX = maxX;
2038       if( lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))
2039           orgX += MENU_COL_SPACE;
2040       orgY = 0;
2041 
2042       maxTab = maxTabWidth = 0;
2043       /* Parse items until column break or end of menu */
2044       for (i = start; i < Menu->cItems; i++, lpitem++)
2045       {
2046           if (i != start &&
2047                (lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
2048 
2049           MENU_CalcItemSize(hdc, lpitem, Menu, WndOwner, orgX, orgY, FALSE, textandbmp);
2050           maxX = max(maxX, lpitem->cxItem);
2051           orgY = lpitem->cyItem;
2052           if (IS_STRING_ITEM(lpitem->fType) && lpitem->dxTab )
2053           {
2054               maxTab = max( maxTab, lpitem->dxTab );
2055               maxTabWidth = max(maxTabWidth, lpitem->cxItem - lpitem->dxTab);
2056           }
2057           if( lpitem->Xlpstr && lpitem->hbmp) textandbmp = TRUE;
2058       }
2059 
2060         /* Finish the column (set all items to the largest width found) */
2061       maxX = max( maxX, maxTab + maxTabWidth );
2062       for (lpitem = &Menu->rgItems[start]; start < i; start++, lpitem++)
2063       {
2064           lpitem->cxItem = maxX;
2065            if (IS_STRING_ITEM(lpitem->fType) && lpitem->dxTab)
2066                lpitem->dxTab = maxTab;
2067       }
2068       Menu->cyMenu = max(Menu->cyMenu, orgY);
2069     }
2070 
2071     Menu->cxMenu  = maxX;
2072     /* if none of the items have both text and bitmap then
2073      * the text and bitmaps are all aligned on the left. If there is at
2074      * least one item with both text and bitmap then bitmaps are
2075      * on the left and texts left aligned with the right hand side
2076      * of the bitmaps */
2077     if( !textandbmp) Menu->cxTextAlign = 0;
2078 
2079     /* Adjust popup height if it exceeds maximum */
2080     maxHeight = MENU_GetMaxPopupHeight(Menu);
2081     Menu->iMaxTop = Menu->cyMenu;
2082     if (Menu->cyMenu >= maxHeight)
2083     {
2084        Menu->cyMenu = maxHeight;
2085        Menu->dwArrowsOn = 1;
2086     }
2087     else
2088     {
2089        Menu->dwArrowsOn = 0;
2090     }
2091     UserReleaseDC( 0, hdc, FALSE );
2092 }
2093 
2094 /***********************************************************************
2095  *           MENU_MenuBarCalcSize
2096  *
2097  * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
2098  * height is off by 1 pixel which causes lengthy window relocations when
2099  * active document window is maximized/restored.
2100  *
2101  * Calculate the size of the menu bar.
2102  */
2103 static void MENU_MenuBarCalcSize( HDC hdc, LPRECT lprect, PMENU lppop, PWND pwndOwner )
2104 {
2105     ITEM *lpitem;
2106     UINT start, i, helpPos;
2107     int orgX, orgY, maxY;
2108 
2109     if ((lprect == NULL) || (lppop == NULL)) return;
2110     if (lppop->cItems == 0) return;
2111     //TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect));
2112     lppop->cxMenu  = lprect->right - lprect->left;
2113     lppop->cyMenu = 0;
2114     maxY = lprect->top;
2115     start = 0;
2116     helpPos = ~0U;
2117     lppop->cxTextAlign = 0;
2118     while (start < lppop->cItems)
2119     {
2120 	lpitem = &lppop->rgItems[start];
2121 	orgX = lprect->left;
2122 	orgY = maxY;
2123 
2124 	  /* Parse items until line break or end of menu */
2125 	for (i = start; i < lppop->cItems; i++, lpitem++)
2126 	{
2127 	    if ((helpPos == ~0U) && (lpitem->fType & MF_RIGHTJUSTIFY)) helpPos = i;
2128 	    if ((i != start) &&
2129 		(lpitem->fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break;
2130 
2131 	    TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX, orgY );
2132 	    //debug_print_menuitem ("  item: ", lpitem, "");
2133 	    //MENU_CalcItemSize( hdc, lpitem, pwndOwner, orgX, orgY, TRUE, lppop );
2134             MENU_CalcItemSize(hdc, lpitem, lppop, pwndOwner, orgX, orgY, TRUE, FALSE);
2135 
2136 	    if (lpitem->cxItem > lprect->right)
2137 	    {
2138 		if (i != start) break;
2139 		else lpitem->cxItem = lprect->right;
2140 	    }
2141 	    maxY = max( maxY, lpitem->cyItem );
2142 	    orgX = lpitem->cxItem;
2143 	}
2144 
2145 	  /* Finish the line (set all items to the largest height found) */
2146 
2147 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
2148    HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
2149 #if 0
2150 	while (start < i) lppop->rgItems[start++].cyItem = maxY;
2151 #endif
2152 	start = i; /* This works! */
2153     }
2154 
2155     lprect->bottom = maxY + 1;
2156     lppop->cyMenu = lprect->bottom - lprect->top;
2157 
2158     /* Flush right all items between the MF_RIGHTJUSTIFY and */
2159     /* the last item (if several lines, only move the last line) */
2160     if (helpPos == ~0U) return;
2161     lpitem = &lppop->rgItems[lppop->cItems-1];
2162     orgY = lpitem->yItem;
2163     orgX = lprect->right;
2164     for (i = lppop->cItems - 1; i >= helpPos; i--, lpitem--) {
2165         if (lpitem->yItem != orgY) break;	/* Other line */
2166         if (lpitem->cxItem >= orgX) break;	/* Too far right already */
2167         lpitem->xItem += orgX - lpitem->cxItem;
2168         lpitem->cxItem = orgX;
2169         orgX = lpitem->xItem;
2170     }
2171 }
2172 
2173 /***********************************************************************
2174  *           MENU_DrawScrollArrows
2175  *
2176  * Draw scroll arrows.
2177  */
2178 static void MENU_DrawScrollArrows(PMENU lppop, HDC hdc)
2179 {
2180     UINT arrow_bitmap_height;
2181     RECT rect;
2182     UINT Flags = 0;
2183 
2184     arrow_bitmap_height = gpsi->oembmi[OBI_DNARROW].cy;
2185 
2186     rect.left = 0;
2187     rect.top = 0;
2188     rect.right = lppop->cxMenu;
2189     rect.bottom = arrow_bitmap_height;
2190     FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENU));
2191     UITOOLS95_DrawFrameMenu(hdc, &rect, (lppop->iTop ? 0 : DFCS_INACTIVE) | DFCS_MENUARROWUP);
2192 
2193     rect.top = lppop->cyMenu - arrow_bitmap_height;
2194     rect.bottom = lppop->cyMenu;
2195     FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENU));
2196     if (!(lppop->iTop < lppop->iMaxTop - (MENU_GetMaxPopupHeight(lppop) - 2 * arrow_bitmap_height)))
2197        Flags = DFCS_INACTIVE;
2198     UITOOLS95_DrawFrameMenu(hdc, &rect, Flags | DFCS_MENUARROWDOWN);
2199 }
2200 
2201 /***********************************************************************
2202  *           MenuDrawMenuItem
2203  *
2204  * Draw a single menu item.
2205  */
2206 static void FASTCALL MENU_DrawMenuItem(PWND Wnd, PMENU Menu, PWND WndOwner, HDC hdc,
2207                  PITEM lpitem, UINT Height, BOOL menuBar, UINT odaction)
2208 {
2209     RECT rect;
2210     PWCHAR Text;
2211     BOOL flat_menu = FALSE;
2212     int bkgnd;
2213     UINT arrow_bitmap_width = 0;
2214     //RECT bmprc;
2215 
2216     if (!menuBar) {
2217         arrow_bitmap_width  = gpsi->oembmi[OBI_MNARROW].cx;
2218     }
2219 
2220     if (lpitem->fType & MF_SYSMENU)
2221     {
2222         if (!(Wnd->style & WS_MINIMIZE))
2223         {
2224           NC_GetInsideRect(Wnd, &rect);
2225           UserDrawSysMenuButton(Wnd, hdc, &rect, lpitem->fState & (MF_HILITE | MF_MOUSESELECT));
2226 	}
2227         return;
2228     }
2229 
2230     UserSystemParametersInfo (SPI_GETFLATMENU, 0, &flat_menu, 0);
2231     bkgnd = (menuBar && flat_menu) ? COLOR_MENUBAR : COLOR_MENU;
2232 
2233     /* Setup colors */
2234 
2235     if (lpitem->fState & MF_HILITE)
2236     {
2237         if(menuBar && !flat_menu) {
2238             IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_MENUTEXT));
2239             IntGdiSetBkColor(hdc, IntGetSysColor(COLOR_MENU));
2240         } else {
2241             if (lpitem->fState & MF_GRAYED)
2242                 IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_GRAYTEXT));
2243             else
2244                 IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_HIGHLIGHTTEXT));
2245             IntGdiSetBkColor(hdc, IntGetSysColor(COLOR_HIGHLIGHT));
2246         }
2247     }
2248     else
2249     {
2250         if (lpitem->fState & MF_GRAYED)
2251             IntGdiSetTextColor( hdc, IntGetSysColor( COLOR_GRAYTEXT ) );
2252         else
2253             IntGdiSetTextColor( hdc, IntGetSysColor( COLOR_MENUTEXT ) );
2254         IntGdiSetBkColor( hdc, IntGetSysColor( bkgnd ) );
2255     }
2256 
2257     //TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect));
2258     //rect = lpitem->Rect;
2259     rect.left   = lpitem->xItem;
2260     rect.top    = lpitem->yItem;
2261     rect.right  = lpitem->cxItem; // Do this for now......
2262     rect.bottom = lpitem->cyItem;
2263 
2264     MENU_AdjustMenuItemRect(Menu, &rect);
2265 
2266     if (lpitem->fType & MF_OWNERDRAW)
2267     {
2268         /*
2269         ** Experimentation under Windows reveals that an owner-drawn
2270         ** menu is given the rectangle which includes the space it requested
2271         ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
2272         ** and a popup-menu arrow.  This is the value of lpitem->rect.
2273         ** Windows will leave all drawing to the application except for
2274         ** the popup-menu arrow.  Windows always draws that itself, after
2275         ** the menu owner has finished drawing.
2276         */
2277         DRAWITEMSTRUCT dis;
2278         COLORREF old_bk, old_text;
2279 
2280         dis.CtlType   = ODT_MENU;
2281         dis.CtlID     = 0;
2282         dis.itemID    = lpitem->wID;
2283         dis.itemData  = (DWORD)lpitem->dwItemData;
2284         dis.itemState = 0;
2285         if (lpitem->fState & MF_CHECKED)  dis.itemState |= ODS_CHECKED;
2286         if (lpitem->fState & MF_DEFAULT)  dis.itemState |= ODS_DEFAULT;
2287         if (lpitem->fState & MF_DISABLED) dis.itemState |= ODS_DISABLED;
2288         if (lpitem->fState & MF_GRAYED)   dis.itemState |= ODS_GRAYED | ODS_DISABLED;
2289         if (lpitem->fState & MF_HILITE)   dis.itemState |= ODS_SELECTED;
2290         if (!(Menu->fFlags & MNF_UNDERLINE)) dis.itemState |= ODS_NOACCEL;
2291         if (Menu->fFlags & MNF_INACTIVE) dis.itemState |= ODS_INACTIVE;
2292         dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
2293         dis.hwndItem   = (HWND) UserHMGetHandle(Menu);
2294         dis.hDC        = hdc;
2295         dis.rcItem     = rect;
2296         TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
2297 	        "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", Wnd,
2298 	        dis.itemID, dis.itemState, dis.itemAction, dis.hwndItem,
2299 	        dis.hDC, dis.rcItem.left, dis.rcItem.top, dis.rcItem.right,
2300 	        dis.rcItem.bottom);
2301         TRACE("Ownerdraw: Width %d Height %d\n", dis.rcItem.right-dis.rcItem.left, dis.rcItem.bottom-dis.rcItem.top);
2302         old_bk = GreGetBkColor(hdc);
2303         old_text = GreGetTextColor(hdc);
2304         co_IntSendMessage(UserHMGetHandle(WndOwner), WM_DRAWITEM, 0, (LPARAM) &dis);
2305         IntGdiSetBkColor(hdc, old_bk);
2306         IntGdiSetTextColor(hdc, old_text);
2307         /* Draw the popup-menu arrow */
2308         if (!menuBar && lpitem->spSubMenu)
2309         {
2310             RECT rectTemp;
2311             RtlCopyMemory(&rectTemp, &rect, sizeof(RECT));
2312             rectTemp.left = rectTemp.right - UserGetSystemMetrics(SM_CXMENUCHECK);
2313             UITOOLS95_DrawFrameMenu(hdc, &rectTemp, DFCS_MENUARROW);
2314         }
2315         return;
2316     }
2317 
2318     if (menuBar && (lpitem->fType & MF_SEPARATOR)) return;
2319 
2320     if (lpitem->fState & MF_HILITE)
2321     {
2322         if (flat_menu)
2323         {
2324             RECTL_vInflateRect (&rect, -1, -1);
2325             FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENUHILIGHT));
2326             RECTL_vInflateRect (&rect, 1, 1);
2327             FrameRect(hdc, &rect, IntGetSysColorBrush(COLOR_HIGHLIGHT));
2328         }
2329         else
2330         {
2331             if (menuBar)
2332             {
2333                 FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_MENU));
2334                 DrawEdge(hdc, &rect, BDR_SUNKENOUTER, BF_RECT);
2335             }
2336             else
2337             {
2338                 FillRect(hdc, &rect, IntGetSysColorBrush(COLOR_HIGHLIGHT));
2339             }
2340         }
2341     }
2342     else
2343         FillRect( hdc, &rect, IntGetSysColorBrush(bkgnd) );
2344 
2345     IntGdiSetBkMode( hdc, TRANSPARENT );
2346 
2347     /* vertical separator */
2348     if (!menuBar && (lpitem->fType & MF_MENUBARBREAK))
2349     {
2350         HPEN oldPen;
2351         RECT rc = rect;
2352 
2353         rc.left -= 3;//MENU_COL_SPACE / 2 + 1; == 3!!
2354         rc.top = 3;
2355         rc.bottom = Height - 3;
2356         if (flat_menu)
2357         {
2358             oldPen = NtGdiSelectPen( hdc, NtGdiGetStockObject(DC_PEN) );
2359             IntSetDCPenColor(hdc, IntGetSysColor(COLOR_BTNSHADOW));
2360             GreMoveTo( hdc, rc.left, rc.top, NULL );
2361             NtGdiLineTo( hdc, rc.left, rc.bottom );
2362             NtGdiSelectPen( hdc, oldPen );
2363         }
2364         else
2365             DrawEdge (hdc, &rc, EDGE_ETCHED, BF_LEFT);
2366     }
2367 
2368     /* horizontal separator */
2369     if (lpitem->fType & MF_SEPARATOR)
2370     {
2371         HPEN oldPen;
2372         RECT rc = rect;
2373 
2374         rc.left++;
2375         rc.right--;
2376         rc.top = (rc.top + rc.bottom) / 2 - 1;
2377         if (flat_menu)
2378         {
2379             oldPen = NtGdiSelectPen( hdc, NtGdiGetStockObject(DC_PEN) );
2380             IntSetDCPenColor( hdc, IntGetSysColor(COLOR_BTNSHADOW));
2381             GreMoveTo( hdc, rc.left, rc.top, NULL );
2382             NtGdiLineTo( hdc, rc.right, rc.top );
2383             NtGdiSelectPen( hdc, oldPen );
2384         }
2385         else
2386             DrawEdge (hdc, &rc, EDGE_ETCHED, BF_TOP);
2387         return;
2388     }
2389 #if 0
2390     /* helper lines for debugging */
2391     /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
2392     FrameRect(hdc, &rect, NtGdiGetStockObject(BLACK_BRUSH));
2393     NtGdiSelectPen(hdc, NtGdiGetStockObject(DC_PEN));
2394     IntSetDCPenColor(hdc, IntGetSysColor(COLOR_WINDOWFRAME));
2395     GreMoveTo(hdc, rect.left, (rect.top + rect.bottom) / 2, NULL);
2396     NtGdiLineTo(hdc, rect.right, (rect.top + rect.bottom) / 2);
2397 #endif
2398 #if 0 // breaks mdi menu bar icons.
2399     if (lpitem->hbmp) {
2400         /* calculate the bitmap rectangle in coordinates relative
2401          * to the item rectangle */
2402         if( menuBar) {
2403             if( lpitem->hbmp == HBMMENU_CALLBACK)
2404                 bmprc.left = 3;
2405             else
2406                 bmprc.left = lpitem->Xlpstr ? MenuCharSize.cx : 0;
2407         }
2408         else if ((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK)
2409             bmprc.left = 4;
2410         else if ((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP)
2411             bmprc.left = 2;
2412         else
2413             bmprc.left = 4 + UserGetSystemMetrics(SM_CXMENUCHECK);
2414 
2415         bmprc.right =  bmprc.left + lpitem->cxBmp;
2416 
2417         if( menuBar && !(lpitem->hbmp == HBMMENU_CALLBACK))
2418             bmprc.top = 0;
2419         else
2420             bmprc.top = (rect.bottom - rect.top - lpitem->cyBmp) / 2;
2421 
2422         bmprc.bottom =  bmprc.top + lpitem->cyBmp;
2423     }
2424 #endif
2425     if (!menuBar)
2426     {
2427         HBITMAP bm;
2428         INT y = rect.top + rect.bottom;
2429         RECT rc = rect;
2430         BOOL checked = FALSE;
2431         UINT check_bitmap_width = UserGetSystemMetrics( SM_CXMENUCHECK );
2432         UINT check_bitmap_height = UserGetSystemMetrics( SM_CYMENUCHECK );
2433         /* Draw the check mark
2434          *
2435          * FIXME:
2436          * Custom checkmark bitmaps are monochrome but not always 1bpp.
2437          */
2438         if( !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK)) {
2439             bm = (lpitem->fState & MF_CHECKED) ? lpitem->hbmpChecked :
2440                 lpitem->hbmpUnchecked;
2441             if (bm)  /* we have a custom bitmap */
2442             {
2443                 HDC hdcMem = NtGdiCreateCompatibleDC( hdc );
2444 
2445                 NtGdiSelectBitmap( hdcMem, bm );
2446                 NtGdiBitBlt( hdc, rc.left, (y - check_bitmap_height) / 2,
2447                         check_bitmap_width, check_bitmap_height,
2448                         hdcMem, 0, 0, SRCCOPY, 0,0);
2449                 IntGdiDeleteDC( hdcMem, FALSE );
2450                 checked = TRUE;
2451             }
2452             else if (lpitem->fState & MF_CHECKED) /* standard bitmaps */
2453             {
2454                 RECT r;
2455                 r = rect;
2456                 r.right = r.left + check_bitmap_width;
2457                 UITOOLS95_DrawFrameMenu(hdc, &r,
2458                                         (lpitem->fType & MFT_RADIOCHECK) ?
2459                                         DFCS_MENUBULLET : DFCS_MENUCHECK);
2460                 checked = TRUE;
2461             }
2462         }
2463         if ( lpitem->hbmp )//&& !( checked && ((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP)))
2464         {
2465             RECT bmpRect = rect;
2466             if (!((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP) && !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK))
2467                 bmpRect.left += check_bitmap_width + 2;
2468             if (!(checked && ((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP)))
2469             {
2470                 bmpRect.right = bmpRect.left + lpitem->cxBmp;
2471                 MENU_DrawBitmapItem(hdc, lpitem, &bmpRect, Menu, WndOwner, odaction, menuBar);
2472             }
2473         }
2474         /* Draw the popup-menu arrow */
2475         if (lpitem->spSubMenu)
2476         {
2477             RECT rectTemp;
2478             RtlCopyMemory(&rectTemp, &rect, sizeof(RECT));
2479             rectTemp.left = rectTemp.right - check_bitmap_width;
2480             UITOOLS95_DrawFrameMenu(hdc, &rectTemp, DFCS_MENUARROW);
2481         }
2482         rect.left += 4;
2483         if( !((Menu->fFlags & MNS_STYLE_MASK) & MNS_NOCHECK))
2484             rect.left += check_bitmap_width;
2485         rect.right -= arrow_bitmap_width;
2486     }
2487     else if( lpitem->hbmp)
2488     { /* Draw the bitmap */
2489         MENU_DrawBitmapItem(hdc, lpitem, &rect/*bmprc*/, Menu, WndOwner, odaction, menuBar);
2490     }
2491 
2492     /* process text if present */
2493     if (lpitem->Xlpstr)
2494     {
2495         int i = 0;
2496         HFONT hfontOld = 0;
2497 
2498         UINT uFormat = menuBar ?
2499                        DT_CENTER | DT_VCENTER | DT_SINGLELINE :
2500                        DT_LEFT | DT_VCENTER | DT_SINGLELINE;
2501 
2502         if (((Menu->fFlags & MNS_STYLE_MASK) & MNS_CHECKORBMP))
2503              rect.left += max(0, (int)(Menu->cxTextAlign - UserGetSystemMetrics(SM_CXMENUCHECK)));
2504         else
2505              rect.left += Menu->cxTextAlign;
2506 
2507         if ( lpitem->fState & MFS_DEFAULT )
2508         {
2509             hfontOld = NtGdiSelectFont(hdc, ghMenuFontBold);
2510         }
2511 
2512         if (menuBar) {
2513             if( lpitem->hbmp)
2514               rect.left += lpitem->cxBmp;
2515             if( !(lpitem->hbmp == HBMMENU_CALLBACK))
2516               rect.left += MenuCharSize.cx;
2517             rect.right -= MenuCharSize.cx;
2518         }
2519 
2520         Text = lpitem->Xlpstr;
2521         if(Text)
2522         {
2523             for (i = 0; Text[i]; i++)
2524                 if (Text[i] == L'\t' || Text[i] == L'\b')
2525                     break;
2526         }
2527 
2528         if (menuBar &&
2529             !flat_menu &&
2530             (lpitem->fState & (MF_HILITE | MF_GRAYED)) == MF_HILITE)
2531         {
2532             RECTL_vOffsetRect(&rect, +1, +1);
2533         }
2534 
2535         if (!menuBar)
2536             --rect.bottom;
2537 
2538         if(lpitem->fState & MF_GRAYED)
2539         {
2540             if (!(lpitem->fState & MF_HILITE) )
2541             {
2542                 ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
2543                 IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_BTNHIGHLIGHT));
2544                 DrawTextW( hdc, Text, i, &rect, uFormat );
2545                 --rect.left; --rect.top; --rect.right; --rect.bottom;
2546             }
2547             IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_BTNSHADOW));
2548         }
2549         DrawTextW( hdc, Text, i, &rect, uFormat);
2550 
2551         /* paint the shortcut text */
2552         if (!menuBar && L'\0' != Text[i])  /* There's a tab or flush-right char */
2553         {
2554             if (L'\t' == Text[i])
2555             {
2556                 rect.left = lpitem->dxTab;
2557                 uFormat = DT_LEFT | DT_VCENTER | DT_SINGLELINE;
2558             }
2559             else
2560             {
2561                 rect.right = lpitem->dxTab;
2562                 uFormat = DT_RIGHT | DT_VCENTER | DT_SINGLELINE;
2563             }
2564 
2565             if (lpitem->fState & MF_GRAYED)
2566             {
2567                 if (!(lpitem->fState & MF_HILITE) )
2568                 {
2569                     ++rect.left; ++rect.top; ++rect.right; ++rect.bottom;
2570                     IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_BTNHIGHLIGHT));
2571                     DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat);
2572                     --rect.left; --rect.top; --rect.right; --rect.bottom;
2573                 }
2574                 IntGdiSetTextColor(hdc, IntGetSysColor(COLOR_BTNSHADOW));
2575             }
2576             DrawTextW( hdc, Text + i + 1, -1, &rect, uFormat );
2577         }
2578 
2579         if (!menuBar)
2580             ++rect.bottom;
2581 
2582         if (menuBar &&
2583             !flat_menu &&
2584             (lpitem->fState & (MF_HILITE | MF_GRAYED)) == MF_HILITE)
2585         {
2586             RECTL_vOffsetRect(&rect, -1, -1);
2587         }
2588 
2589         if (hfontOld)
2590         {
2591            NtGdiSelectFont (hdc, hfontOld);
2592         }
2593     }
2594 }
2595 
2596 /***********************************************************************
2597  *           MenuDrawPopupMenu
2598  *
2599  * Paint a popup menu.
2600  */
2601 static void FASTCALL MENU_DrawPopupMenu(PWND wnd, HDC hdc, PMENU menu )
2602 {
2603     HBRUSH hPrevBrush = 0, brush = IntGetSysColorBrush(COLOR_MENU);
2604     RECT rect;
2605 
2606     TRACE("DPM wnd=%p dc=%p menu=%p\n", wnd, hdc, menu);
2607 
2608     IntGetClientRect( wnd, &rect );
2609 
2610     if (menu && menu->hbrBack) brush = menu->hbrBack;
2611     if((hPrevBrush = NtGdiSelectBrush( hdc, brush ))
2612         && (NtGdiSelectFont( hdc, ghMenuFont)))
2613     {
2614         HPEN hPrevPen;
2615 
2616         /* FIXME: Maybe we don't have to fill the background manually */
2617         FillRect(hdc, &rect, brush);
2618 
2619         hPrevPen = NtGdiSelectPen( hdc, NtGdiGetStockObject( NULL_PEN ) );
2620         if ( hPrevPen )
2621         {
2622             TRACE("hmenu %p Style %08x\n", UserHMGetHandle(menu), (menu->fFlags & MNS_STYLE_MASK));
2623             /* draw menu items */
2624             if (menu && menu->cItems)
2625             {
2626                 ITEM *item;
2627                 UINT u;
2628 
2629                 item = menu->rgItems;
2630                 for( u = menu->cItems; u > 0; u--, item++)
2631                 {
2632                     MENU_DrawMenuItem(wnd, menu, menu->spwndNotify, hdc, item,
2633                                          menu->cyMenu, FALSE, ODA_DRAWENTIRE);
2634                 }
2635                 /* draw scroll arrows */
2636                 if (menu->dwArrowsOn)
2637                 {
2638                    MENU_DrawScrollArrows(menu, hdc);
2639                 }
2640             }
2641         }
2642         else
2643         {
2644             NtGdiSelectBrush( hdc, hPrevBrush );
2645         }
2646     }
2647 }
2648 
2649 /**********************************************************************
2650  *         MENU_IsMenuActive
2651  */
2652 PWND MENU_IsMenuActive(VOID)
2653 {
2654    return ValidateHwndNoErr(top_popup);
2655 }
2656 
2657 /**********************************************************************
2658  *         MENU_EndMenu
2659  *
2660  * Calls EndMenu() if the hwnd parameter belongs to the menu owner
2661  *
2662  * Does the (menu stuff) of the default window handling of WM_CANCELMODE
2663  */
2664 void MENU_EndMenu( PWND pwnd )
2665 {
2666     PMENU menu = NULL;
2667     menu = UserGetMenuObject(top_popup_hmenu);
2668     if ( menu && ( UserHMGetHandle(pwnd) == menu->hWnd || pwnd == menu->spwndNotify ) )
2669     {
2670        if (fInsideMenuLoop && top_popup)
2671        {
2672           fInsideMenuLoop = FALSE;
2673 
2674           if (fInEndMenu)
2675           {
2676              ERR("Already in End loop\n");
2677              return;
2678           }
2679 
2680           fInEndMenu = TRUE;
2681           UserPostMessage( top_popup, WM_CANCELMODE, 0, 0);
2682        }
2683     }
2684 }
2685 
2686 DWORD WINAPI
2687 IntDrawMenuBarTemp(PWND pWnd, HDC hDC, LPRECT Rect, PMENU pMenu, HFONT Font)
2688 {
2689   UINT i;
2690   HFONT FontOld = NULL;
2691   BOOL flat_menu = FALSE;
2692 
2693   UserSystemParametersInfo(SPI_GETFLATMENU, 0, &flat_menu, 0);
2694 
2695   if (!pMenu)
2696   {
2697       pMenu = UserGetMenuObject(UlongToHandle(pWnd->IDMenu));
2698   }
2699 
2700   if (!Font)
2701   {
2702       Font = ghMenuFont;
2703   }
2704 
2705   if (Rect == NULL || !pMenu)
2706   {
2707       return UserGetSystemMetrics(SM_CYMENU);
2708   }
2709 
2710   TRACE("(%x, %x, %p, %x, %x)\n", pWnd, hDC, Rect, pMenu, Font);
2711 
2712   FontOld = NtGdiSelectFont(hDC, Font);
2713 
2714   if (pMenu->cyMenu == 0)
2715   {
2716       MENU_MenuBarCalcSize(hDC, Rect, pMenu, pWnd);
2717   }
2718 
2719   Rect->bottom = Rect->top + pMenu->cyMenu;
2720 
2721   FillRect(hDC, Rect, IntGetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU));
2722 
2723   NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN));
2724   IntSetDCPenColor(hDC, IntGetSysColor(COLOR_3DFACE));
2725   GreMoveTo(hDC, Rect->left, Rect->bottom - 1, NULL);
2726   NtGdiLineTo(hDC, Rect->right, Rect->bottom - 1);
2727 
2728   if (pMenu->cItems == 0)
2729   {
2730       NtGdiSelectFont(hDC, FontOld);
2731       return UserGetSystemMetrics(SM_CYMENU);
2732   }
2733 
2734   for (i = 0; i < pMenu->cItems; i++)
2735   {
2736       MENU_DrawMenuItem(pWnd, pMenu, pWnd, hDC, &pMenu->rgItems[i], pMenu->cyMenu, TRUE, ODA_DRAWENTIRE);
2737   }
2738 
2739   NtGdiSelectFont(hDC, FontOld);
2740 
2741   return pMenu->cyMenu;
2742 }
2743 
2744 UINT MENU_DrawMenuBar( HDC hDC, LPRECT lprect, PWND pWnd, BOOL suppress_draw )
2745 {
2746     HFONT hfontOld = 0;
2747     PMENU lppop = UserGetMenuObject(UlongToHandle(pWnd->IDMenu));
2748 
2749     if (lppop == NULL)
2750     {
2751         // No menu. Do not reserve any space
2752         return 0;
2753     }
2754 
2755     if (lprect == NULL)
2756     {
2757         return UserGetSystemMetrics(SM_CYMENU);
2758     }
2759 
2760     if (suppress_draw)
2761     {
2762        hfontOld = NtGdiSelectFont(hDC, ghMenuFont);
2763 
2764        MENU_MenuBarCalcSize(hDC, lprect, lppop, pWnd);
2765 
2766        lprect->bottom = lprect->top + lppop->cyMenu;
2767 
2768        if (hfontOld) NtGdiSelectFont( hDC, hfontOld);
2769 
2770        return lppop->cyMenu;
2771     }
2772     else
2773     {
2774        return IntDrawMenuBarTemp(pWnd, hDC, lprect, lppop, NULL);
2775     }
2776 }
2777 
2778 /***********************************************************************
2779  *           MENU_InitPopup
2780  *
2781  * Popup menu initialization before WM_ENTERMENULOOP.
2782  */
2783 static BOOL MENU_InitPopup( PWND pWndOwner, PMENU menu, UINT flags )
2784 {
2785     PWND pWndCreated;
2786     PPOPUPMENU pPopupMenu;
2787     CREATESTRUCTW Cs;
2788     LARGE_STRING WindowName;
2789     UNICODE_STRING ClassName;
2790     DWORD ex_style = WS_EX_PALETTEWINDOW | WS_EX_DLGMODALFRAME;
2791 
2792     TRACE("owner=%p hmenu=%p\n", pWndOwner, menu);
2793 
2794     menu->spwndNotify = pWndOwner;
2795 
2796     if (flags & TPM_LAYOUTRTL || pWndOwner->ExStyle & WS_EX_LAYOUTRTL)
2797        ex_style |= WS_EX_LAYOUTRTL;
2798 
2799     ClassName.Buffer = WC_MENU;
2800     ClassName.Length = 0;
2801 
2802     RtlZeroMemory(&WindowName, sizeof(WindowName));
2803     RtlZeroMemory(&Cs, sizeof(Cs));
2804     Cs.style = WS_POPUP | WS_CLIPSIBLINGS | WS_BORDER;
2805     Cs.dwExStyle = ex_style;
2806     Cs.hInstance = hModClient; // hModuleWin; // Server side winproc!
2807     Cs.lpszName = (LPCWSTR) &WindowName;
2808     Cs.lpszClass = (LPCWSTR) &ClassName;
2809     Cs.lpCreateParams = UserHMGetHandle(menu);
2810     Cs.hwndParent = UserHMGetHandle(pWndOwner);
2811 
2812     /* NOTE: In Windows, top menu popup is not owned. */
2813     pWndCreated = co_UserCreateWindowEx( &Cs, &ClassName, &WindowName, NULL, WINVER );
2814 
2815     if( !pWndCreated ) return FALSE;
2816 
2817     //
2818     //  Setup pop up menu structure.
2819     //
2820     menu->hWnd = UserHMGetHandle(pWndCreated);
2821 
2822     pPopupMenu = ((PMENUWND)pWndCreated)->ppopupmenu;
2823 
2824     pPopupMenu->spwndActivePopup = pWndCreated; // top_popup = MenuInfo.Wnd or menu->hWnd
2825     pPopupMenu->spwndNotify = pWndOwner;        // Same as MenuInfo.spwndNotify(which could be wrong) or menu->hwndOwner
2826     //pPopupMenu->spmenu = menu; Should be set up already from WM_CREATE!
2827 
2828     pPopupMenu->fIsTrackPopup = !!(flags & TPM_POPUPMENU);
2829     pPopupMenu->fIsSysMenu    = !!(flags & TPM_SYSTEM_MENU);
2830     pPopupMenu->fNoNotify     = !!(flags & TPM_NONOTIFY);
2831     pPopupMenu->fRightButton  = !!(flags & TPM_RIGHTBUTTON);
2832     pPopupMenu->fSynchronous  = !!(flags & TPM_RETURNCMD);
2833 
2834     if (pPopupMenu->fRightButton)
2835        pPopupMenu->fFirstClick = !!(UserGetKeyState(VK_RBUTTON) & 0x8000);
2836     else
2837        pPopupMenu->fFirstClick = !!(UserGetKeyState(VK_LBUTTON) & 0x8000);
2838 
2839     if (gpsi->aiSysMet[SM_MENUDROPALIGNMENT] ||
2840         menu->fFlags & MNF_RTOL)
2841     {
2842        pPopupMenu->fDroppedLeft = TRUE;
2843     }
2844     return TRUE;
2845 }
2846 
2847 
2848 #define SHOW_DEBUGRECT      0
2849 
2850 #if SHOW_DEBUGRECT
2851 static void DebugRect(const RECT* rectl, COLORREF color)
2852 {
2853     HBRUSH brush;
2854     RECT rr;
2855     HDC hdc;
2856 
2857     if (!rectl)
2858         return;
2859 
2860     hdc = UserGetDCEx(NULL, 0, DCX_USESTYLE);
2861 
2862     brush = IntGdiCreateSolidBrush(color);
2863 
2864     rr = *rectl;
2865     RECTL_vInflateRect(&rr, 1, 1);
2866     FrameRect(hdc, rectl, brush);
2867     FrameRect(hdc, &rr, brush);
2868 
2869     NtGdiDeleteObjectApp(brush);
2870     UserReleaseDC(NULL, hdc, TRUE);
2871 }
2872 
2873 static void DebugPoint(INT x, INT y, COLORREF color)
2874 {
2875     RECT r1 = {x-10, y, x+10, y};
2876     RECT r2 = {x, y-10, x, y+10};
2877     DebugRect(&r1, color);
2878     DebugRect(&r2, color);
2879 }
2880 #endif
2881 
2882 static BOOL RECTL_Intersect(const RECT* pRect, INT x, INT y, UINT width, UINT height)
2883 {
2884     RECT other = {x, y, x + width, y + height};
2885     RECT dum;
2886 
2887     return RECTL_bIntersectRect(&dum, pRect, &other);
2888 }
2889 
2890 static BOOL MENU_MoveRect(UINT flags, INT* x, INT* y, INT width, INT height, const RECT* pExclude, PMONITOR monitor)
2891 {
2892     /* Figure out if we should move vertical or horizontal */
2893     if (flags & TPM_VERTICAL)
2894     {
2895         /* Move in the vertical direction: TPM_BOTTOMALIGN means drop it above, otherways drop it below */
2896         if (flags & TPM_BOTTOMALIGN)
2897         {
2898             if (pExclude->top - height >= monitor->rcMonitor.top)
2899             {
2900                 *y = pExclude->top - height;
2901                 return TRUE;
2902             }
2903         }
2904         else
2905         {
2906             if (pExclude->bottom + height < monitor->rcMonitor.bottom)
2907             {
2908                 *y = pExclude->bottom;
2909                 return TRUE;
2910             }
2911         }
2912     }
2913     else
2914     {
2915         /* Move in the horizontal direction: TPM_RIGHTALIGN means drop it to the left, otherways go right */
2916         if (flags & TPM_RIGHTALIGN)
2917         {
2918             if (pExclude->left - width >= monitor->rcMonitor.left)
2919             {
2920                 *x = pExclude->left - width;
2921                 return TRUE;
2922             }
2923         }
2924         else
2925         {
2926             if (pExclude->right + width < monitor->rcMonitor.right)
2927             {
2928                 *x = pExclude->right;
2929                 return TRUE;
2930             }
2931         }
2932     }
2933     return FALSE;
2934 }
2935 
2936 /***********************************************************************
2937  *           MenuShowPopup
2938  *
2939  * Display a popup menu.
2940  */
2941 static BOOL FASTCALL MENU_ShowPopup(PWND pwndOwner, PMENU menu, UINT id, UINT flags,
2942                               INT x, INT y, const RECT* pExclude)
2943 {
2944     INT width, height;
2945     POINT ptx;
2946     PMONITOR monitor;
2947     PWND pWnd;
2948     USER_REFERENCE_ENTRY Ref;
2949     BOOL bIsPopup = (flags & TPM_POPUPMENU) != 0;
2950 
2951     TRACE("owner=%p menu=%p id=0x%04x x=0x%04x y=0x%04x\n",
2952           pwndOwner, menu, id, x, y);
2953 
2954     if (menu->iItem != NO_SELECTED_ITEM)
2955     {
2956         menu->rgItems[menu->iItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
2957         menu->iItem = NO_SELECTED_ITEM;
2958     }
2959 
2960 #if SHOW_DEBUGRECT
2961     if (pExclude)
2962         DebugRect(pExclude, RGB(255, 0, 0));
2963 #endif
2964 
2965     menu->dwArrowsOn = 0;
2966     MENU_PopupMenuCalcSize(menu, pwndOwner);
2967 
2968     /* adjust popup menu pos so that it fits within the desktop */
2969 
2970     width = menu->cxMenu + UserGetSystemMetrics(SM_CXDLGFRAME) * 2;
2971     height = menu->cyMenu + UserGetSystemMetrics(SM_CYDLGFRAME) * 2;
2972 
2973     if (flags & TPM_LAYOUTRTL)
2974         flags ^= TPM_RIGHTALIGN;
2975 
2976     if (flags & TPM_RIGHTALIGN)
2977         x -= width;
2978     if (flags & TPM_CENTERALIGN)
2979         x -= width / 2;
2980 
2981     if (flags & TPM_BOTTOMALIGN)
2982         y -= height;
2983     if (flags & TPM_VCENTERALIGN)
2984         y -= height / 2;
2985 
2986     /* FIXME: should use item rect */
2987     ptx.x = x;
2988     ptx.y = y;
2989 #if SHOW_DEBUGRECT
2990     DebugPoint(x, y, RGB(0, 0, 255));
2991 #endif
2992     monitor = UserMonitorFromPoint( ptx, MONITOR_DEFAULTTONEAREST );
2993 
2994     /* We are off the right side of the screen */
2995     if (x + width > monitor->rcMonitor.right)
2996     {
2997         if ((x - width) < monitor->rcMonitor.left || x >= monitor->rcMonitor.right)
2998             x = monitor->rcMonitor.right - width;
2999         else
3000             x -= width;
3001     }
3002 
3003     /* We are off the left side of the screen */
3004     if (x < monitor->rcMonitor.left)
3005     {
3006         /* Re-orient the menu around the x-axis */
3007         x += width;
3008 
3009         if (x < monitor->rcMonitor.left || x >= monitor->rcMonitor.right || bIsPopup)
3010             x = monitor->rcMonitor.left;
3011     }
3012 
3013     /* Same here, but then the top */
3014     if (y < monitor->rcMonitor.top)
3015     {
3016         y += height;
3017 
3018         if (y < monitor->rcMonitor.top || y >= monitor->rcMonitor.bottom || bIsPopup)
3019             y = monitor->rcMonitor.top;
3020     }
3021 
3022     /* And the bottom */
3023     if (y + height > monitor->rcMonitor.bottom)
3024     {
3025         if ((y - height) < monitor->rcMonitor.top || y >= monitor->rcMonitor.bottom)
3026             y = monitor->rcMonitor.bottom - height;
3027         else
3028             y -= height;
3029     }
3030 
3031     if (pExclude)
3032     {
3033         RECT Cleaned;
3034 
3035         if (RECTL_bIntersectRect(&Cleaned, pExclude, &monitor->rcMonitor) &&
3036             RECTL_Intersect(&Cleaned, x, y, width, height))
3037         {
3038             UINT flag_mods[] = {
3039                 0,                                                  /* First try the 'normal' way */
3040                 TPM_BOTTOMALIGN | TPM_RIGHTALIGN,                   /* Then try the opposite side */
3041                 TPM_VERTICAL,                                       /* Then swap horizontal / vertical */
3042                 TPM_BOTTOMALIGN | TPM_RIGHTALIGN | TPM_VERTICAL,    /* Then the other side again (still swapped hor/ver) */
3043             };
3044 
3045             UINT n;
3046             for (n = 0; n < RTL_NUMBER_OF(flag_mods); ++n)
3047             {
3048                 INT tx = x;
3049                 INT ty = y;
3050 
3051                 /* Try to move a bit around */
3052                 if (MENU_MoveRect(flags ^ flag_mods[n], &tx, &ty, width, height, &Cleaned, monitor) &&
3053                     !RECTL_Intersect(&Cleaned, tx, ty, width, height))
3054                 {
3055                     x = tx;
3056                     y = ty;
3057                     break;
3058                 }
3059             }
3060             /* If none worked, we go with the original x/y */
3061         }
3062     }
3063 
3064 #if SHOW_DEBUGRECT
3065     {
3066         RECT rr = {x, y, x + width, y + height};
3067         DebugRect(&rr, RGB(0, 255, 0));
3068     }
3069 #endif
3070 
3071     pWnd = ValidateHwndNoErr( menu->hWnd );
3072 
3073     if (!pWnd)
3074     {
3075        ERR("menu->hWnd bad hwnd %p\n",menu->hWnd);
3076        return FALSE;
3077     }
3078 
3079     if (!top_popup) {
3080         top_popup = menu->hWnd;
3081         top_popup_hmenu = UserHMGetHandle(menu);
3082     }
3083 
3084     /* Display the window */
3085     UserRefObjectCo(pWnd, &Ref);
3086     co_WinPosSetWindowPos( pWnd, HWND_TOPMOST, x, y, width, height, SWP_SHOWWINDOW | SWP_NOACTIVATE);
3087 
3088     co_IntUpdateWindows(pWnd, RDW_ALLCHILDREN, FALSE);
3089 
3090     IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, pWnd, OBJID_CLIENT, CHILDID_SELF, 0);
3091     UserDerefObjectCo(pWnd);
3092 
3093     return TRUE;
3094 }
3095 
3096 /***********************************************************************
3097  *           MENU_EnsureMenuItemVisible
3098  */
3099 void MENU_EnsureMenuItemVisible(PMENU lppop, UINT wIndex, HDC hdc)
3100 {
3101     USER_REFERENCE_ENTRY Ref;
3102     if (lppop->dwArrowsOn)
3103     {
3104         ITEM *item = &lppop->rgItems[wIndex];
3105         UINT nMaxHeight = MENU_GetMaxPopupHeight(lppop);
3106         UINT nOldPos = lppop->iTop;
3107         RECT rc;
3108         UINT arrow_bitmap_height;
3109         PWND pWnd = ValidateHwndNoErr(lppop->hWnd);
3110 
3111         IntGetClientRect(pWnd, &rc);
3112 
3113         arrow_bitmap_height = gpsi->oembmi[OBI_DNARROW].cy;
3114 
3115         rc.top += arrow_bitmap_height;
3116         rc.bottom -= arrow_bitmap_height;
3117 
3118         nMaxHeight -= UserGetSystemMetrics(SM_CYBORDER) + 2 * arrow_bitmap_height;
3119         UserRefObjectCo(pWnd, &Ref);
3120         if (item->cyItem > lppop->iTop + nMaxHeight)
3121         {
3122             lppop->iTop = item->cyItem - nMaxHeight;
3123             IntScrollWindow(pWnd, 0, nOldPos - lppop->iTop, &rc, &rc);
3124             MENU_DrawScrollArrows(lppop, hdc);
3125             //ERR("Scroll Down iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
3126         }
3127         else if (item->yItem < lppop->iTop)
3128         {
3129             lppop->iTop = item->yItem;
3130             IntScrollWindow(pWnd, 0, nOldPos - lppop->iTop, &rc, &rc);
3131             MENU_DrawScrollArrows(lppop, hdc);
3132             //ERR("Scroll Up   iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
3133         }
3134         UserDerefObjectCo(pWnd);
3135     }
3136 }
3137 
3138 /***********************************************************************
3139  *           MenuSelectItem
3140  */
3141 static void FASTCALL MENU_SelectItem(PWND pwndOwner, PMENU menu, UINT wIndex,
3142                                     BOOL sendMenuSelect, PMENU topmenu)
3143 {
3144     HDC hdc;
3145     PWND pWnd;
3146 
3147     TRACE("M_SI: owner=%p menu=%p index=0x%04x select=0x%04x\n", pwndOwner, menu, wIndex, sendMenuSelect);
3148 
3149     if (!menu || !menu->cItems) return;
3150 
3151     pWnd = ValidateHwndNoErr(menu->hWnd);
3152 
3153     if (!pWnd) return;
3154 
3155     if (menu->iItem == wIndex) return;
3156 
3157     if (menu->fFlags & MNF_POPUP)
3158        hdc = UserGetDCEx(pWnd, 0, DCX_USESTYLE);
3159     else
3160        hdc = UserGetDCEx(pWnd, 0, DCX_CACHE | DCX_WINDOW);
3161 
3162     if (!top_popup) {
3163         top_popup = menu->hWnd;                  //pPopupMenu->spwndActivePopup or
3164                                                  //pPopupMenu->fIsTrackPopup set pPopupMenu->spwndPopupMenu;
3165         top_popup_hmenu = UserHMGetHandle(menu); //pPopupMenu->spmenu
3166     }
3167 
3168     NtGdiSelectFont( hdc, ghMenuFont );
3169 
3170      /* Clear previous highlighted item */
3171     if (menu->iItem != NO_SELECTED_ITEM)
3172     {
3173         menu->rgItems[menu->iItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
3174         MENU_DrawMenuItem(pWnd, menu, pwndOwner, hdc, &menu->rgItems[menu->iItem],
3175                        menu->cyMenu, !(menu->fFlags & MNF_POPUP),
3176                        ODA_SELECT);
3177     }
3178 
3179     /* Highlight new item (if any) */
3180     menu->iItem = wIndex;
3181     if (menu->iItem != NO_SELECTED_ITEM)
3182     {
3183         if (!(menu->rgItems[wIndex].fType & MF_SEPARATOR))
3184         {
3185              menu->rgItems[wIndex].fState |= MF_HILITE;
3186              MENU_EnsureMenuItemVisible(menu, wIndex, hdc);
3187              MENU_DrawMenuItem(pWnd, menu, pwndOwner, hdc,
3188                                &menu->rgItems[wIndex], menu->cyMenu, !(menu->fFlags & MNF_POPUP), ODA_SELECT);
3189         }
3190         if (sendMenuSelect)
3191         {
3192            ITEM *ip = &menu->rgItems[menu->iItem];
3193            WPARAM wParam = MAKEWPARAM( ip->spSubMenu ? wIndex : ip->wID,
3194                                        ip->fType | ip->fState |
3195                                       (ip->spSubMenu ? MF_POPUP : 0) |
3196                                       (menu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0 ) );
3197 
3198            co_IntSendMessage(UserHMGetHandle(pwndOwner), WM_MENUSELECT, wParam, (LPARAM) UserHMGetHandle(menu));
3199         }
3200     }
3201     else if (sendMenuSelect)
3202     {
3203         if (topmenu)
3204         {
3205             int pos;
3206             pos = MENU_FindSubMenu(&topmenu, menu);
3207             if (pos != NO_SELECTED_ITEM)
3208             {
3209                ITEM *ip = &topmenu->rgItems[pos];
3210                WPARAM wParam = MAKEWPARAM( Pos, ip->fType | ip->fState |
3211                                            (ip->spSubMenu ? MF_POPUP : 0) |
3212                                            (topmenu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0 ) );
3213 
3214                co_IntSendMessage(UserHMGetHandle(pwndOwner), WM_MENUSELECT, wParam, (LPARAM) UserHMGetHandle(topmenu));
3215             }
3216         }
3217     }
3218     UserReleaseDC(pWnd, hdc, FALSE);
3219 }
3220 
3221 /***********************************************************************
3222  *           MenuMoveSelection
3223  *
3224  * Moves currently selected item according to the Offset parameter.
3225  * If there is no selection then it should select the last item if
3226  * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
3227  */
3228 static void FASTCALL MENU_MoveSelection(PWND pwndOwner, PMENU menu, INT offset)
3229 {
3230     INT i;
3231 
3232     TRACE("pwnd=%x menu=%x off=0x%04x\n", pwndOwner, menu, offset);
3233 
3234     if ((!menu) || (!menu->rgItems)) return;
3235 
3236     if ( menu->iItem != NO_SELECTED_ITEM )
3237     {
3238 	if ( menu->cItems == 1 )
3239 	   return;
3240 	else
3241 	for (i = menu->iItem + offset ; i >= 0 && i < menu->cItems
3242 					    ; i += offset)
3243 	    if (!(menu->rgItems[i].fType & MF_SEPARATOR))
3244 	    {
3245 		MENU_SelectItem( pwndOwner, menu, i, TRUE, 0 );
3246 		return;
3247 	    }
3248     }
3249 
3250     for ( i = (offset > 0) ? 0 : menu->cItems - 1;
3251 		  i >= 0 && i < menu->cItems ; i += offset)
3252 	if (!(menu->rgItems[i].fType & MF_SEPARATOR))
3253 	{
3254 	    MENU_SelectItem( pwndOwner, menu, i, TRUE, 0 );
3255 	    return;
3256 	}
3257 }
3258 
3259 /***********************************************************************
3260  *           MenuHideSubPopups
3261  *
3262  * Hide the sub-popup menus of this menu.
3263  */
3264 static void FASTCALL MENU_HideSubPopups(PWND pWndOwner, PMENU Menu,
3265                                BOOL SendMenuSelect, UINT wFlags)
3266 {
3267   TRACE("owner=%x menu=%x 0x%04x\n", pWndOwner, Menu, SendMenuSelect);
3268 
3269   if ( Menu && top_popup )
3270   {
3271       PITEM Item;
3272 
3273       if (Menu->iItem != NO_SELECTED_ITEM)
3274       {
3275          Item = &Menu->rgItems[Menu->iItem];
3276          if (!(Item->spSubMenu) ||
3277              !(Item->fState & MF_MOUSESELECT)) return;
3278          Item->fState &= ~MF_MOUSESELECT;
3279       }
3280       else
3281          return;
3282 
3283       if (Item->spSubMenu)
3284       {
3285           PWND pWnd;
3286           if (!VerifyMenu(Item->spSubMenu)) return;
3287           pWnd = ValidateHwndNoErr(Item->spSubMenu->hWnd);
3288           MENU_HideSubPopups(pWndOwner, Item->spSubMenu, FALSE, wFlags);
3289           MENU_SelectItem(pWndOwner, Item->spSubMenu, NO_SELECTED_ITEM, SendMenuSelect, NULL);
3290           TRACE("M_HSP top p hm %p  pWndOwner IDMenu %p\n",top_popup_hmenu,pWndOwner->IDMenu);
3291           co_UserDestroyWindow(pWnd);
3292 
3293           /* Native returns handle to destroyed window */
3294           if (!(wFlags & TPM_NONOTIFY))
3295           {
3296              co_IntSendMessage( UserHMGetHandle(pWndOwner), WM_UNINITMENUPOPUP, (WPARAM)UserHMGetHandle(Item->spSubMenu),
3297                                  MAKELPARAM(0, IS_SYSTEM_MENU(Item->spSubMenu)) );
3298           }
3299           ////
3300           // Call WM_UNINITMENUPOPUP FIRST before destroy!!
3301           // Fixes todo_wine User32 test menu.c line 2239 GetMenuBarInfo callback....
3302           //
3303           Item->spSubMenu->hWnd = NULL;
3304           ////
3305       }
3306   }
3307 }
3308 
3309 /***********************************************************************
3310  *           MenuShowSubPopup
3311  *
3312  * Display the sub-menu of the selected item of this menu.
3313  * Return the handle of the submenu, or menu if no submenu to display.
3314  */
3315 static PMENU FASTCALL MENU_ShowSubPopup(PWND WndOwner, PMENU Menu, BOOL SelectFirst, UINT Flags)
3316 {
3317   RECT Rect, ParentRect;
3318   ITEM *Item;
3319   HDC Dc;
3320   PWND pWnd;
3321 
3322   TRACE("owner=%x menu=%p 0x%04x\n", WndOwner, Menu, SelectFirst);
3323 
3324   if (!Menu) return Menu;
3325 
3326   if (Menu->iItem == NO_SELECTED_ITEM) return Menu;
3327 
3328   Item = &Menu->rgItems[Menu->iItem];
3329   if (!(Item->spSubMenu) || (Item->fState & (MF_GRAYED | MF_DISABLED)))
3330       return Menu;
3331 
3332   /* message must be sent before using item,
3333      because nearly everything may be changed by the application ! */
3334 
3335   /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3336   if (!(Flags & TPM_NONOTIFY))
3337   {
3338       co_IntSendMessage(UserHMGetHandle(WndOwner), WM_INITMENUPOPUP,
3339                         (WPARAM) UserHMGetHandle(Item->spSubMenu),
3340                          MAKELPARAM(Menu->iItem, IS_SYSTEM_MENU(Menu)));
3341   }
3342 
3343   Item = &Menu->rgItems[Menu->iItem];
3344   //Rect = ItemInfo.Rect;
3345   Rect.left   = Item->xItem;
3346   Rect.top    = Item->yItem;
3347   Rect.right  = Item->cxItem; // Do this for now......
3348   Rect.bottom = Item->cyItem;
3349 
3350   pWnd = ValidateHwndNoErr(Menu->hWnd);
3351 
3352   /* Grab the rect of our (entire) parent menu, so we can try to not overlap it */
3353   if (Menu->fFlags & MNF_POPUP)
3354   {
3355     if (!IntGetWindowRect(pWnd, &ParentRect))
3356     {
3357         ERR("No pWnd\n");
3358         ParentRect = Rect;
3359     }
3360 
3361     /* Ensure we can slightly overlap our parent */
3362     RECTL_vInflateRect(&ParentRect, -UserGetSystemMetrics(SM_CXEDGE) * 2, 0);
3363   }
3364   else
3365   {
3366     /* Inside the menu bar, we do not want to grab the entire window... */
3367     ParentRect = Rect;
3368     if (pWnd)
3369         RECTL_vOffsetRect(&ParentRect, pWnd->rcWindow.left, pWnd->rcWindow.top);
3370   }
3371 
3372   /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
3373   if (!(Item->fState & MF_HILITE))
3374   {
3375       if (Menu->fFlags & MNF_POPUP) Dc = UserGetDCEx(pWnd, NULL, DCX_USESTYLE);
3376       else Dc = UserGetDCEx(pWnd, 0, DCX_CACHE | DCX_WINDOW);
3377 
3378       NtGdiSelectFont(Dc, ghMenuFont);
3379 
3380       Item->fState |= MF_HILITE;
3381       MENU_DrawMenuItem(pWnd, Menu, WndOwner, Dc, Item, Menu->cyMenu,
3382                        !(Menu->fFlags & MNF_POPUP), ODA_DRAWENTIRE);
3383 
3384       UserReleaseDC(pWnd, Dc, FALSE);
3385   }
3386 
3387   if (!Item->yItem && !Item->xItem && !Item->cyItem && !Item->cxItem)
3388   {
3389       Item->xItem  = Rect.left;
3390       Item->yItem  = Rect.top;
3391       Item->cxItem = Rect.right; // Do this for now......
3392       Item->cyItem = Rect.bottom;
3393   }
3394   Item->fState |= MF_MOUSESELECT;
3395 
3396   if (IS_SYSTEM_MENU(Menu))
3397   {
3398       MENU_InitSysMenuPopup(Item->spSubMenu, pWnd->style, pWnd->pcls->style, HTSYSMENU);
3399 
3400       NC_GetSysPopupPos(pWnd, &Rect);
3401       /* Ensure we do not overlap this */
3402       ParentRect = Rect;
3403       if (Flags & TPM_LAYOUTRTL) Rect.left = Rect.right;
3404       Rect.top = Rect.bottom;
3405       Rect.right = UserGetSystemMetrics(SM_CXSIZE);
3406       Rect.bottom = UserGetSystemMetrics(SM_CYSIZE);
3407   }
3408   else
3409   {
3410       IntGetWindowRect(pWnd, &Rect);
3411       if (Menu->fFlags & MNF_POPUP)
3412       {
3413           RECT rc;
3414           rc.left   = Item->xItem;
3415           rc.top    = Item->yItem;
3416           rc.right  = Item->cxItem;
3417           rc.bottom = Item->cyItem;
3418 
3419           MENU_AdjustMenuItemRect(Menu, &rc);
3420 
3421           /* The first item in the popup menu has to be at the
3422              same y position as the focused menu item */
3423           if(Flags & TPM_LAYOUTRTL)
3424              Rect.left += UserGetSystemMetrics(SM_CXDLGFRAME);
3425           else
3426              Rect.left += rc.right - UserGetSystemMetrics(SM_CXDLGFRAME);
3427 
3428           Rect.top += rc.top;
3429       }
3430       else
3431       {
3432           if(Flags & TPM_LAYOUTRTL)
3433               Rect.left += Rect.right - Item->xItem; //ItemInfo.Rect.left;
3434           else
3435               Rect.left += Item->xItem; //ItemInfo.Rect.left;
3436           Rect.top += Item->cyItem; //ItemInfo.Rect.bottom;
3437           Rect.right  = Item->cxItem - Item->xItem; //ItemInfo.Rect.right - ItemInfo.Rect.left;
3438           Rect.bottom = Item->cyItem - Item->yItem; //ItemInfo.Rect.bottom - ItemInfo.Rect.top;
3439       }
3440   }
3441 
3442   /* Next menu does not need to be shown vertical anymore */
3443   if (Menu->fFlags & MNF_POPUP)
3444       Flags &= (~TPM_VERTICAL);
3445 
3446 
3447 
3448   /* use default alignment for submenus */
3449   Flags &= ~(TPM_CENTERALIGN | TPM_RIGHTALIGN | TPM_VCENTERALIGN | TPM_BOTTOMALIGN);
3450 
3451   MENU_InitPopup( WndOwner, Item->spSubMenu, Flags );
3452 
3453   MENU_ShowPopup( WndOwner, Item->spSubMenu, Menu->iItem, Flags,
3454                 Rect.left, Rect.top, &ParentRect);
3455   if (SelectFirst)
3456   {
3457       MENU_MoveSelection(WndOwner, Item->spSubMenu, ITEM_NEXT);
3458   }
3459   return Item->spSubMenu;
3460 }
3461 
3462 /***********************************************************************
3463  *           MenuExecFocusedItem
3464  *
3465  * Execute a menu item (for instance when user pressed Enter).
3466  * Return the wID of the executed item. Otherwise, -1 indicating
3467  * that no menu item was executed, -2 if a popup is shown;
3468  * Have to receive the flags for the TrackPopupMenu options to avoid
3469  * sending unwanted message.
3470  *
3471  */
3472 static INT FASTCALL MENU_ExecFocusedItem(MTRACKER *pmt, PMENU Menu, UINT Flags)
3473 {
3474   PITEM Item;
3475 
3476   TRACE("%p menu=%p\n", pmt, Menu);
3477 
3478   if (!Menu || !Menu->cItems || Menu->iItem == NO_SELECTED_ITEM)
3479   {
3480       return -1;
3481   }
3482 
3483   Item = &Menu->rgItems[Menu->iItem];
3484 
3485   TRACE("%p %08x %p\n", Menu, Item->wID, Item->spSubMenu);
3486 
3487   if (!(Item->spSubMenu))
3488   {
3489       if (!(Item->fState & (MF_GRAYED | MF_DISABLED)) && !(Item->fType & MF_SEPARATOR))
3490       {
3491           /* If TPM_RETURNCMD is set you return the id, but
3492             do not send a message to the owner */
3493           if (!(Flags & TPM_RETURNCMD))
3494           {
3495               if (Menu->fFlags & MNF_SYSMENU)
3496               {
3497                   UserPostMessage(UserHMGetHandle(pmt->OwnerWnd), WM_SYSCOMMAND, Item->wID,
3498                                MAKELPARAM((SHORT) pmt->Pt.x, (SHORT) pmt->Pt.y));
3499               }
3500               else
3501               {
3502                   DWORD dwStyle = ((Menu->fFlags & MNS_STYLE_MASK) | ( pmt->TopMenu ? (pmt->TopMenu->fFlags & MNS_STYLE_MASK) : 0) );
3503 
3504                   if (dwStyle & MNS_NOTIFYBYPOS)
3505                       UserPostMessage(UserHMGetHandle(pmt->OwnerWnd), WM_MENUCOMMAND, Menu->iItem, (LPARAM)UserHMGetHandle(Menu));
3506                   else
3507                       UserPostMessage(UserHMGetHandle(pmt->OwnerWnd), WM_COMMAND, Item->wID, 0);
3508               }
3509           }
3510           return Item->wID;
3511       }
3512   }
3513   else
3514   {
3515       pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, Menu, TRUE, Flags);
3516       return -2;
3517   }
3518 
3519   return -1;
3520 }
3521 
3522 /***********************************************************************
3523  *           MenuSwitchTracking
3524  *
3525  * Helper function for menu navigation routines.
3526  */
3527 static void FASTCALL MENU_SwitchTracking(MTRACKER* pmt, PMENU PtMenu, UINT Index, UINT wFlags)
3528 {
3529   TRACE("%x menu=%x 0x%04x\n", pmt, PtMenu, Index);
3530 
3531   if ( pmt->TopMenu != PtMenu &&
3532       !((PtMenu->fFlags | pmt->TopMenu->fFlags) & MNF_POPUP) )
3533   {
3534       /* both are top level menus (system and menu-bar) */
3535       MENU_HideSubPopups(pmt->OwnerWnd, pmt->TopMenu, FALSE, wFlags);
3536       MENU_SelectItem(pmt->OwnerWnd, pmt->TopMenu, NO_SELECTED_ITEM, FALSE, NULL);
3537       pmt->TopMenu = PtMenu;
3538   }
3539   else
3540   {
3541       MENU_HideSubPopups(pmt->OwnerWnd, PtMenu, FALSE, wFlags);
3542   }
3543 
3544   MENU_SelectItem(pmt->OwnerWnd, PtMenu, Index, TRUE, NULL);
3545 }
3546 
3547 /***********************************************************************
3548  *           MenuButtonDown
3549  *
3550  * Return TRUE if we can go on with menu tracking.
3551  */
3552 static BOOL FASTCALL MENU_ButtonDown(MTRACKER* pmt, PMENU PtMenu, UINT Flags)
3553 {
3554   TRACE("%x PtMenu=%p\n", pmt, PtMenu);
3555 
3556   if (PtMenu)
3557   {
3558       UINT id = 0;
3559       PITEM item;
3560       if (IS_SYSTEM_MENU(PtMenu))
3561       {
3562          item = PtMenu->rgItems;
3563       }
3564       else
3565       {
3566          item = MENU_FindItemByCoords( PtMenu, pmt->Pt, &id );
3567       }
3568 
3569       if (item)
3570       {
3571           if (PtMenu->iItem != id)
3572               MENU_SwitchTracking(pmt, PtMenu, id, Flags);
3573 
3574           /* If the popup menu is not already "popped" */
3575           if (!(item->fState & MF_MOUSESELECT))
3576           {
3577               pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, PtMenu, FALSE, Flags);
3578           }
3579 
3580           return TRUE;
3581       }
3582       /* Else the click was on the menu bar, finish the tracking */
3583   }
3584   return FALSE;
3585 }
3586 
3587 /***********************************************************************
3588  *           MenuButtonUp
3589  *
3590  * Return the value of MenuExecFocusedItem if
3591  * the selected item was not a popup. Else open the popup.
3592  * A -1 return value indicates that we go on with menu tracking.
3593  *
3594  */
3595 static INT FASTCALL MENU_ButtonUp(MTRACKER *pmt, PMENU PtMenu, UINT Flags)
3596 {
3597   TRACE("%p pmenu=%x\n", pmt, PtMenu);
3598 
3599   if (PtMenu)
3600   {
3601       UINT Id = 0;
3602       ITEM *item;
3603 
3604       if ( IS_SYSTEM_MENU(PtMenu) )
3605       {
3606           item = PtMenu->rgItems;
3607       }
3608       else
3609       {
3610           item = MENU_FindItemByCoords( PtMenu, pmt->Pt, &Id );
3611       }
3612 
3613       if (item && ( PtMenu->iItem == Id))
3614       {
3615           if (!(item->spSubMenu))
3616           {
3617               INT ExecutedMenuId = MENU_ExecFocusedItem( pmt, PtMenu, Flags);
3618               if (ExecutedMenuId == -1 || ExecutedMenuId == -2) return -1;
3619               return ExecutedMenuId;
3620           }
3621 
3622           /* If we are dealing with the menu bar                  */
3623           /* and this is a click on an already "popped" item:     */
3624           /* Stop the menu tracking and close the opened submenus */
3625           if (pmt->TopMenu == PtMenu && PtMenu->TimeToHide)
3626           {
3627               return 0;
3628           }
3629       }
3630       if ( IntGetMenu(PtMenu->hWnd) == PtMenu )
3631       {
3632           PtMenu->TimeToHide = TRUE;
3633       }
3634   }
3635   return -1;
3636 }
3637 
3638 /***********************************************************************
3639  *           MenuPtMenu
3640  *
3641  * Walks menu chain trying to find a menu pt maps to.
3642  */
3643 static PMENU FASTCALL MENU_PtMenu(PMENU menu, POINT pt)
3644 {
3645   PITEM pItem;
3646   PMENU ret = NULL;
3647 
3648   if (!menu) return NULL;
3649 
3650   /* try subpopup first (if any) */
3651   if (menu->iItem != NO_SELECTED_ITEM)
3652   {
3653      pItem = menu->rgItems;
3654      if ( pItem ) pItem = &pItem[menu->iItem];
3655      if ( pItem && pItem->spSubMenu && pItem->fState & MF_MOUSESELECT)
3656      {
3657         ret = MENU_PtMenu( pItem->spSubMenu, pt);
3658      }
3659   }
3660 
3661   /* check the current window (avoiding WM_HITTEST) */
3662   if (!ret)
3663   {
3664      PWND pWnd = ValidateHwndNoErr(menu->hWnd);
3665      INT ht = GetNCHitEx(pWnd, pt);
3666      if ( menu->fFlags & MNF_POPUP )
3667      {
3668         if (ht != HTNOWHERE && ht != HTERROR) ret = menu;
3669      }
3670      else if (ht == HTSYSMENU)
3671         ret = get_win_sys_menu(menu->hWnd);
3672      else if (ht == HTMENU)
3673         ret = IntGetMenu( menu->hWnd );
3674   }
3675   return ret;
3676 }
3677 
3678 /***********************************************************************
3679  *           MenuMouseMove
3680  *
3681  * Return TRUE if we can go on with menu tracking.
3682  */
3683 static BOOL FASTCALL MENU_MouseMove(MTRACKER *pmt, PMENU PtMenu, UINT Flags)
3684 {
3685   UINT Index = NO_SELECTED_ITEM;
3686 
3687   if ( PtMenu )
3688   {
3689       if (IS_SYSTEM_MENU(PtMenu))
3690       {
3691           Index = 0;
3692           //// ReactOS only HACK: CORE-2338
3693           // Windows tracks mouse moves to the system menu but does not open it.
3694           // Only keyboard tracking can do that.
3695           //
3696           TRACE("SystemMenu\n");
3697           return TRUE; // Stay inside the Loop!
3698       }
3699       else
3700           MENU_FindItemByCoords( PtMenu, pmt->Pt, &Index );
3701   }
3702 
3703   if (Index == NO_SELECTED_ITEM)
3704   {
3705       MENU_SelectItem(pmt->OwnerWnd, pmt->CurrentMenu, NO_SELECTED_ITEM, TRUE, pmt->TopMenu);
3706   }
3707   else if (PtMenu->iItem != Index)
3708   {
3709       MENU_SwitchTracking(pmt, PtMenu, Index, Flags);
3710       pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, PtMenu, FALSE, Flags);
3711   }
3712   return TRUE;
3713 }
3714 
3715 /***********************************************************************
3716  *           MenuGetSubPopup
3717  *
3718  * Return the handle of the selected sub-popup menu (if any).
3719  */
3720 static PMENU MENU_GetSubPopup( PMENU menu )
3721 {
3722     ITEM *item;
3723 
3724     if ((!menu) || (menu->iItem == NO_SELECTED_ITEM)) return 0;
3725 
3726     item = &menu->rgItems[menu->iItem];
3727     if (item && (item->spSubMenu) && (item->fState & MF_MOUSESELECT))
3728     {
3729        return item->spSubMenu;
3730     }
3731     return 0;
3732 }
3733 
3734 /***********************************************************************
3735  *           MenuDoNextMenu
3736  *
3737  * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3738  */
3739 static LRESULT FASTCALL MENU_DoNextMenu(MTRACKER* pmt, UINT Vk, UINT wFlags)
3740 {
3741     BOOL atEnd = FALSE;
3742 
3743     /* When skipping left, we need to do something special after the
3744        first menu.                                                  */
3745     if (Vk == VK_LEFT && pmt->TopMenu->iItem == 0)
3746     {
3747         atEnd = TRUE;
3748     }
3749     /* When skipping right, for the non-system menu, we need to
3750        handle the last non-special menu item (ie skip any window
3751        icons such as MDI maximize, restore or close)             */
3752     else if ((Vk == VK_RIGHT) && !IS_SYSTEM_MENU(pmt->TopMenu))
3753     {
3754         UINT i = pmt->TopMenu->iItem + 1;
3755         while (i < pmt->TopMenu->cItems) {
3756             if ((pmt->TopMenu->rgItems[i].wID >= SC_SIZE &&
3757                  pmt->TopMenu->rgItems[i].wID <= SC_RESTORE)) {
3758                 i++;
3759             } else break;
3760         }
3761         if (i == pmt->TopMenu->cItems) {
3762             atEnd = TRUE;
3763         }
3764     }
3765     /* When skipping right, we need to cater for the system menu */
3766     else if ((Vk == VK_RIGHT) && IS_SYSTEM_MENU(pmt->TopMenu))
3767     {
3768         if (pmt->TopMenu->iItem == (pmt->TopMenu->cItems - 1)) {
3769             atEnd = TRUE;
3770         }
3771     }
3772 
3773    if ( atEnd )
3774    {
3775       MDINEXTMENU NextMenu;
3776       PMENU MenuTmp;
3777       PWND pwndTemp;
3778       HMENU hNewMenu;
3779       HWND hNewWnd;
3780       UINT Id = 0;
3781 
3782       MenuTmp = (IS_SYSTEM_MENU(pmt->TopMenu)) ? co_IntGetSubMenu(pmt->TopMenu, 0) : pmt->TopMenu;
3783       NextMenu.hmenuIn = UserHMGetHandle(MenuTmp);
3784       NextMenu.hmenuNext = NULL;
3785       NextMenu.hwndNext = NULL;
3786       co_IntSendMessage(UserHMGetHandle(pmt->OwnerWnd), WM_NEXTMENU, Vk, (LPARAM) &NextMenu);
3787 
3788       TRACE("%p [%p] -> %p [%p]\n",
3789              pmt->CurrentMenu, pmt->OwnerWnd, NextMenu.hmenuNext, NextMenu.hwndNext );
3790 
3791       if (NULL == NextMenu.hmenuNext || NULL == NextMenu.hwndNext)
3792       {
3793           hNewWnd = UserHMGetHandle(pmt->OwnerWnd);
3794           if (IS_SYSTEM_MENU(pmt->TopMenu))
3795           {
3796               /* switch to the menu bar */
3797 
3798               if (pmt->OwnerWnd->style & WS_CHILD || !(MenuTmp = IntGetMenu(hNewWnd))) return FALSE;
3799 
3800               if (Vk == VK_LEFT)
3801               {
3802                   Id = MenuTmp->cItems - 1;
3803 
3804                   /* Skip backwards over any system predefined icons,
3805                      eg. MDI close, restore etc icons                 */
3806                    while ((Id > 0) &&
3807                           (MenuTmp->rgItems[Id].wID >= SC_SIZE &&
3808                            MenuTmp->rgItems[Id].wID <= SC_RESTORE)) Id--;
3809 
3810               }
3811               hNewMenu = UserHMGetHandle(MenuTmp);
3812           }
3813           else if (pmt->OwnerWnd->style & WS_SYSMENU)
3814           {
3815               /* switch to the system menu */
3816               MenuTmp = get_win_sys_menu(hNewWnd);
3817               if (MenuTmp) hNewMenu = UserHMGetHandle(MenuTmp);
3818               else hNewMenu = NULL;
3819           }
3820           else
3821               return FALSE;
3822       }
3823       else    /* application returned a new menu to switch to */
3824       {
3825           hNewMenu = NextMenu.hmenuNext;
3826           hNewWnd = NextMenu.hwndNext;
3827 
3828           if ((MenuTmp = UserGetMenuObject(hNewMenu)) && (pwndTemp = ValidateHwndNoErr(hNewWnd)))
3829           {
3830               if ( pwndTemp->style & WS_SYSMENU && (get_win_sys_menu(hNewWnd) == MenuTmp) )
3831               {
3832                   /* get the real system menu */
3833                   MenuTmp = get_win_sys_menu(hNewWnd);
3834                   hNewMenu = UserHMGetHandle(MenuTmp);
3835               }
3836               else if (pwndTemp->style & WS_CHILD || IntGetMenu(hNewWnd) != MenuTmp)
3837               {
3838                   /* FIXME: Not sure what to do here;
3839                    * perhaps try to track NewMenu as a popup? */
3840 
3841                   WARN(" -- got confused.\n");
3842                   return FALSE;
3843               }
3844           }
3845           else return FALSE;
3846       }
3847 
3848       if (hNewMenu != UserHMGetHandle(pmt->TopMenu))
3849       {
3850           MENU_SelectItem(pmt->OwnerWnd, pmt->TopMenu, NO_SELECTED_ITEM, FALSE, 0 );
3851 
3852           if (pmt->CurrentMenu != pmt->TopMenu)
3853               MENU_HideSubPopups(pmt->OwnerWnd, pmt->TopMenu, FALSE, wFlags);
3854       }
3855 
3856       if (hNewWnd != UserHMGetHandle(pmt->OwnerWnd))
3857       {
3858           PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
3859           pmt->OwnerWnd = ValidateHwndNoErr(hNewWnd);
3860           ///// Use thread pms!!!!
3861           MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, hNewWnd);
3862           pti->MessageQueue->QF_flags &= ~QF_CAPTURELOCKED;
3863           co_UserSetCapture(UserHMGetHandle(pmt->OwnerWnd));
3864           pti->MessageQueue->QF_flags |= QF_CAPTURELOCKED;
3865       }
3866 
3867       pmt->TopMenu = pmt->CurrentMenu = UserGetMenuObject(hNewMenu); /* all subpopups are hidden */
3868       MENU_SelectItem(pmt->OwnerWnd, pmt->TopMenu, Id, TRUE, 0);
3869 
3870       return TRUE;
3871    }
3872    return FALSE;
3873 }
3874 
3875 /***********************************************************************
3876  *           MenuSuspendPopup
3877  *
3878  * The idea is not to show the popup if the next input message is
3879  * going to hide it anyway.
3880  */
3881 static BOOL FASTCALL MENU_SuspendPopup(MTRACKER* pmt, UINT uMsg)
3882 {
3883     MSG msg;
3884 
3885     msg.hwnd = UserHMGetHandle(pmt->OwnerWnd); ////// ? silly wine'isms?
3886 
3887     co_IntGetPeekMessage( &msg, 0, uMsg, uMsg, PM_NOYIELD | PM_REMOVE, FALSE);
3888     pmt->TrackFlags |= TF_SKIPREMOVE;
3889 
3890     switch( uMsg )
3891     {
3892     case WM_KEYDOWN:
3893         co_IntGetPeekMessage( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE, FALSE);
3894         if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
3895         {
3896             co_IntGetPeekMessage( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE, FALSE);
3897             co_IntGetPeekMessage( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE, FALSE);
3898             if( msg.message == WM_KEYDOWN &&
3899                 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
3900             {
3901                  pmt->TrackFlags |= TF_SUSPENDPOPUP;
3902                  return TRUE;
3903             }
3904         }
3905         break;
3906     }
3907     /* failures go through this */
3908     pmt->TrackFlags &= ~TF_SUSPENDPOPUP;
3909     return FALSE;
3910 }
3911 
3912 /***********************************************************************
3913  *           MenuKeyEscape
3914  *
3915  * Handle a VK_ESCAPE key event in a menu.
3916  */
3917 static BOOL FASTCALL MENU_KeyEscape(MTRACKER *pmt, UINT Flags)
3918 {
3919   BOOL EndMenu = TRUE;
3920 
3921   if (pmt->CurrentMenu != pmt->TopMenu)
3922   {
3923       if (pmt->CurrentMenu && (pmt->CurrentMenu->fFlags & MNF_POPUP))
3924       {
3925           PMENU MenuPrev, MenuTmp;
3926 
3927           MenuPrev = MenuTmp = pmt->TopMenu;
3928 
3929           /* close topmost popup */
3930           while (MenuTmp != pmt->CurrentMenu)
3931           {
3932               MenuPrev = MenuTmp;
3933               MenuTmp = MENU_GetSubPopup(MenuPrev);
3934           }
3935 
3936           MENU_HideSubPopups(pmt->OwnerWnd, MenuPrev, TRUE, Flags);
3937           pmt->CurrentMenu = MenuPrev;
3938           EndMenu = FALSE;
3939       }
3940   }
3941 
3942   return EndMenu;
3943 }
3944 
3945 /***********************************************************************
3946  *           MenuKeyLeft
3947  *
3948  * Handle a VK_LEFT key event in a menu.
3949  */
3950 static void FASTCALL MENU_KeyLeft(MTRACKER* pmt, UINT Flags, UINT msg)
3951 {
3952   PMENU MenuTmp, MenuPrev;
3953   UINT PrevCol;
3954 
3955   MenuPrev = MenuTmp = pmt->TopMenu;
3956 
3957   /* Try to move 1 column left (if possible) */
3958   if ( (PrevCol = MENU_GetStartOfPrevColumn(pmt->CurrentMenu)) != NO_SELECTED_ITEM)
3959   {
3960      MENU_SelectItem(pmt->OwnerWnd, pmt->CurrentMenu, PrevCol, TRUE, 0);
3961      return;
3962   }
3963 
3964   /* close topmost popup */
3965   while (MenuTmp != pmt->CurrentMenu)
3966   {
3967       MenuPrev = MenuTmp;
3968       MenuTmp = MENU_GetSubPopup(MenuPrev);
3969   }
3970 
3971   MENU_HideSubPopups(pmt->OwnerWnd, MenuPrev, TRUE, Flags);
3972   pmt->CurrentMenu = MenuPrev;
3973 
3974   if ((MenuPrev == pmt->TopMenu) && !(pmt->TopMenu->fFlags & MNF_POPUP))
3975   {
3976       /* move menu bar selection if no more popups are left */
3977 
3978       if (!MENU_DoNextMenu(pmt, VK_LEFT, Flags))
3979           MENU_MoveSelection(pmt->OwnerWnd, pmt->TopMenu, ITEM_PREV);
3980 
3981       if (MenuPrev != MenuTmp || pmt->TrackFlags & TF_SUSPENDPOPUP)
3982       {
3983           /* A sublevel menu was displayed - display the next one
3984            * unless there is another displacement coming up */
3985 
3986           if (!MENU_SuspendPopup(pmt, msg))
3987               pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, pmt->TopMenu,
3988                                                  TRUE, Flags);
3989       }
3990   }
3991 }
3992 
3993 /***********************************************************************
3994  *           MenuKeyRight
3995  *
3996  * Handle a VK_RIGHT key event in a menu.
3997  */
3998 static void FASTCALL MENU_KeyRight(MTRACKER *pmt, UINT Flags, UINT msg)
3999 {
4000     PMENU menutmp;
4001     UINT NextCol;
4002 
4003     TRACE("MenuKeyRight called, cur %p, top %p.\n",
4004          pmt->CurrentMenu, pmt->TopMenu);
4005 
4006     if ((pmt->TopMenu->fFlags & MNF_POPUP) || (pmt->CurrentMenu != pmt->TopMenu))
4007     {
4008       /* If already displaying a popup, try to display sub-popup */
4009 
4010       menutmp = pmt->CurrentMenu;
4011       pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, menutmp, TRUE, Flags);
4012 
4013       /* if subpopup was displayed then we are done */
4014       if (menutmp != pmt->CurrentMenu) return;
4015     }
4016 
4017     /* Check to see if there's another column */
4018     if ( (NextCol = MENU_GetStartOfNextColumn(pmt->CurrentMenu)) != NO_SELECTED_ITEM)
4019     {
4020        TRACE("Going to %d.\n", NextCol);
4021        MENU_SelectItem(pmt->OwnerWnd, pmt->CurrentMenu, NextCol, TRUE, 0);
4022        return;
4023     }
4024 
4025     if (!(pmt->TopMenu->fFlags & MNF_POPUP)) /* menu bar tracking */
4026     {
4027        if (pmt->CurrentMenu != pmt->TopMenu)
4028        {
4029           MENU_HideSubPopups(pmt->OwnerWnd, pmt->TopMenu, FALSE, Flags);
4030           menutmp = pmt->CurrentMenu = pmt->TopMenu;
4031        }
4032        else
4033        {
4034           menutmp = NULL;
4035        }
4036 
4037        /* try to move to the next item */
4038        if ( !MENU_DoNextMenu(pmt, VK_RIGHT, Flags))
4039            MENU_MoveSelection(pmt->OwnerWnd, pmt->TopMenu, ITEM_NEXT);
4040 
4041        if ( menutmp || pmt->TrackFlags & TF_SUSPENDPOPUP )
4042        {
4043            if ( !MENU_SuspendPopup(pmt, msg) )
4044                pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, pmt->TopMenu, TRUE, Flags);
4045        }
4046     }
4047 }
4048 
4049 /***********************************************************************
4050  *           MenuTrackMenu
4051  *
4052  * Menu tracking code.
4053  */
4054 static INT FASTCALL MENU_TrackMenu(PMENU pmenu, UINT wFlags, INT x, INT y,
4055                             PWND pwnd)
4056 {
4057     MSG msg;
4058     BOOL fRemove;
4059     INT executedMenuId = -1;
4060     MTRACKER mt;
4061     HWND capture_win;
4062     PMENU pmMouse;
4063     BOOL enterIdleSent = FALSE;
4064     PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
4065 
4066     if (pti != pwnd->head.pti)
4067     {
4068        ERR("Not the same PTI!!!!\n");
4069     }
4070 
4071     mt.TrackFlags = 0;
4072     mt.CurrentMenu = pmenu;
4073     mt.TopMenu = pmenu;
4074     mt.OwnerWnd = pwnd;
4075     mt.Pt.x = x;
4076     mt.Pt.y = y;
4077 
4078     TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x\n",
4079          UserHMGetHandle(pmenu), wFlags, x, y, UserHMGetHandle(pwnd));
4080 
4081     pti->MessageQueue->QF_flags &= ~QF_ACTIVATIONCHANGE;
4082 
4083     if (wFlags & TPM_BUTTONDOWN)
4084     {
4085         /* Get the result in order to start the tracking or not */
4086         fRemove = MENU_ButtonDown( &mt, pmenu, wFlags );
4087         fInsideMenuLoop = fRemove;
4088     }
4089 
4090     if (wFlags & TF_ENDMENU) fInsideMenuLoop = FALSE;
4091 
4092     if (wFlags & TPM_POPUPMENU && pmenu->cItems == 0) // Tracking empty popup menu...
4093     {
4094        MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);
4095        pti->MessageQueue->QF_flags &= ~QF_CAPTURELOCKED;
4096        co_UserSetCapture(NULL); /* release the capture */
4097        return 0;
4098     }
4099 
4100     capture_win = IntGetCapture();
4101 
4102     while (fInsideMenuLoop)
4103     {
4104         BOOL ErrorExit = FALSE;
4105         if (!VerifyMenu( mt.CurrentMenu )) /* sometimes happens if I do a window manager close */
4106            break;
4107 
4108         /* we have to keep the message in the queue until it's
4109          * clear that menu loop is not over yet. */
4110 
4111         for (;;)
4112         {
4113             if (co_IntGetPeekMessage( &msg, 0, 0, 0, PM_NOREMOVE, FALSE ))
4114             {
4115                 if (!IntCallMsgFilter( &msg, MSGF_MENU )) break;
4116                 /* remove the message from the queue */
4117                 co_IntGetPeekMessage( &msg, 0, msg.message, msg.message, PM_REMOVE, FALSE );
4118             }
4119             else
4120             {
4121                 /* ReactOS Checks */
4122                 if (!VerifyWnd(mt.OwnerWnd)                            ||
4123                     !ValidateHwndNoErr(mt.CurrentMenu->hWnd)           ||
4124                      //pti->MessageQueue->QF_flags & QF_ACTIVATIONCHANGE || // See CORE-17338
4125                      capture_win != IntGetCapture() ) // Should not happen, but this is ReactOS...
4126                 {
4127                    ErrorExit = TRUE; // Do not wait on dead windows, now win test_capture_4 works.
4128                    break;
4129                 }
4130 
4131                 if (!enterIdleSent)
4132                 {
4133                   HWND win = mt.CurrentMenu->fFlags & MNF_POPUP ? mt.CurrentMenu->hWnd : NULL;
4134                   enterIdleSent = TRUE;
4135                   co_IntSendMessage( UserHMGetHandle(mt.OwnerWnd), WM_ENTERIDLE, MSGF_MENU, (LPARAM) win);
4136                 }
4137                 co_IntWaitMessage(NULL, 0, 0);
4138             }
4139         }
4140 
4141         if (ErrorExit) break; // Gracefully dropout.
4142 
4143         /* check if EndMenu() tried to cancel us, by posting this message */
4144         if (msg.message == WM_CANCELMODE)
4145         {
4146             /* we are now out of the loop */
4147             fInsideMenuLoop = FALSE;
4148 
4149             /* remove the message from the queue */
4150             co_IntGetPeekMessage( &msg, 0, msg.message, msg.message, PM_REMOVE, FALSE );
4151 
4152             /* break out of internal loop, ala ESCAPE */
4153             break;
4154         }
4155 
4156         mt.Pt = msg.pt;
4157 
4158         if ( (msg.hwnd == mt.CurrentMenu->hWnd) || ((msg.message!=WM_TIMER) && (msg.message!=WM_SYSTIMER)) )
4159             enterIdleSent=FALSE;
4160 
4161         fRemove = FALSE;
4162         if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
4163         {
4164             /*
4165              * Use the mouse coordinates in lParam instead of those in the MSG
4166              * struct to properly handle synthetic messages. They are already
4167              * in screen coordinates.
4168              */
4169             mt.Pt.x = (short)LOWORD(msg.lParam);
4170             mt.Pt.y = (short)HIWORD(msg.lParam);
4171 
4172             /* Find a menu for this mouse event */
4173             pmMouse = MENU_PtMenu( mt.TopMenu, mt.Pt );
4174 
4175             switch(msg.message)
4176             {
4177                 /* no WM_NC... messages in captured state */
4178 
4179                 case WM_RBUTTONDBLCLK:
4180                 case WM_RBUTTONDOWN:
4181                      if (!(wFlags & TPM_RIGHTBUTTON))
4182                      {
4183                         if ( msg.message == WM_RBUTTONDBLCLK ) fInsideMenuLoop = FALSE; // Must exit or loop forever!
4184                         break;
4185                      }
4186                     /* fall through */
4187                 case WM_LBUTTONDBLCLK:
4188                 case WM_LBUTTONDOWN:
4189                     /* If the message belongs to the menu, removes it from the queue */
4190                     /* Else, end menu tracking */
4191                     fRemove = MENU_ButtonDown(&mt, pmMouse, wFlags);
4192                     fInsideMenuLoop = fRemove;
4193                     if ( msg.message == WM_LBUTTONDBLCLK ||
4194                          msg.message == WM_RBUTTONDBLCLK ) fInsideMenuLoop = FALSE; // Must exit or loop forever!
4195                     break;
4196 
4197                 case WM_RBUTTONUP:
4198                     if (!(wFlags & TPM_RIGHTBUTTON)) break;
4199                     /* fall through */
4200                 case WM_LBUTTONUP:
4201                     /* Check if a menu was selected by the mouse */
4202                     if (pmMouse)
4203                     {
4204                         executedMenuId = MENU_ButtonUp( &mt, pmMouse, wFlags);
4205 
4206                     /* End the loop if executedMenuId is an item ID */
4207                     /* or if the job was done (executedMenuId = 0). */
4208                         fRemove = (executedMenuId != -1);
4209                         fInsideMenuLoop = !fRemove;
4210                     }
4211                     /* No menu was selected by the mouse */
4212                     /* if the function was called by TrackPopupMenu, continue
4213                        with the menu tracking. If not, stop it */
4214                     else
4215                         fInsideMenuLoop = ((wFlags & TPM_POPUPMENU) ? TRUE : FALSE);
4216 
4217                     break;
4218 
4219                 case WM_MOUSEMOVE:
4220                     /* the selected menu item must be changed every time */
4221                     /* the mouse moves. */
4222 
4223                     if (pmMouse)
4224                         fInsideMenuLoop |= MENU_MouseMove( &mt, pmMouse, wFlags );
4225 
4226 	    } /* switch(msg.message) - mouse */
4227         }
4228         else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
4229         {
4230             fRemove = TRUE;  /* Keyboard messages are always removed */
4231             switch(msg.message)
4232             {
4233                 case WM_KEYDOWN:
4234                 case WM_SYSKEYDOWN:
4235                 switch(msg.wParam)
4236                 {
4237                     case VK_MENU:
4238                     case VK_F10:
4239                         fInsideMenuLoop = FALSE;
4240                         break;
4241 
4242                     case VK_HOME:
4243                     case VK_END:
4244                         MENU_SelectItem(mt.OwnerWnd, mt.CurrentMenu, NO_SELECTED_ITEM, FALSE, 0 );
4245                         MENU_MoveSelection(mt.OwnerWnd, mt.CurrentMenu, VK_HOME == msg.wParam ? ITEM_NEXT : ITEM_PREV);
4246                         break;
4247 
4248                     case VK_UP:
4249                     case VK_DOWN: /* If on menu bar, pull-down the menu */
4250                         if (!(mt.CurrentMenu->fFlags & MNF_POPUP))
4251                             mt.CurrentMenu = MENU_ShowSubPopup(mt.OwnerWnd, mt.TopMenu, TRUE, wFlags);
4252                         else      /* otherwise try to move selection */
4253                             MENU_MoveSelection(mt.OwnerWnd, mt.CurrentMenu, (msg.wParam == VK_UP)? ITEM_PREV : ITEM_NEXT );
4254                         break;
4255 
4256                     case VK_LEFT:
4257                         MENU_KeyLeft( &mt, wFlags, msg.message );
4258                         break;
4259 
4260                     case VK_RIGHT:
4261                         MENU_KeyRight( &mt, wFlags, msg.message );
4262                         break;
4263 
4264                     case VK_ESCAPE:
4265                         fInsideMenuLoop = !MENU_KeyEscape(&mt, wFlags);
4266                         break;
4267 
4268                     case VK_F1:
4269                     {
4270                         HELPINFO hi;
4271                         hi.cbSize = sizeof(HELPINFO);
4272                         hi.iContextType = HELPINFO_MENUITEM;
4273                         if (mt.CurrentMenu->iItem == NO_SELECTED_ITEM)
4274                             hi.iCtrlId = 0;
4275                         else
4276                             hi.iCtrlId = pmenu->rgItems[mt.CurrentMenu->iItem].wID;
4277                         hi.hItemHandle = UserHMGetHandle(mt.CurrentMenu);
4278                         hi.dwContextId = pmenu->dwContextHelpId;
4279                         hi.MousePos = msg.pt;
4280                         co_IntSendMessage( UserHMGetHandle(pwnd), WM_HELP, 0, (LPARAM)&hi);
4281                         break;
4282                     }
4283 
4284                     default:
4285                         IntTranslateKbdMessage(&msg, 0);
4286                         break;
4287                 }
4288                 break;  /* WM_KEYDOWN */
4289 
4290                 case WM_CHAR:
4291                 case WM_SYSCHAR:
4292                 {
4293                     UINT pos;
4294                     BOOL fEndMenu;
4295 
4296                     if (msg.wParam == L'\r' || msg.wParam == L' ')
4297                     {
4298                         executedMenuId = MENU_ExecFocusedItem(&mt, mt.CurrentMenu, wFlags);
4299                         fEndMenu = (executedMenuId != -2);
4300                         fInsideMenuLoop = !fEndMenu;
4301                         break;
4302                     }
4303 
4304                     /* Hack to avoid control chars. */
4305                     /* We will find a better way real soon... */
4306                     if (msg.wParam < 32) break;
4307 
4308                     pos = MENU_FindItemByKey(mt.OwnerWnd, mt.CurrentMenu, LOWORD(msg.wParam), FALSE);
4309 
4310                     if (pos == (UINT)-2) fInsideMenuLoop = FALSE;
4311                     else if (pos == (UINT)-1) UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_MESSAGE_BEEP, 0); //MessageBeep(0);
4312                     else
4313                     {
4314                         MENU_SelectItem(mt.OwnerWnd, mt.CurrentMenu, pos, TRUE, 0);
4315                         executedMenuId = MENU_ExecFocusedItem(&mt, mt.CurrentMenu, wFlags);
4316                         fEndMenu = (executedMenuId != -2);
4317                         fInsideMenuLoop = !fEndMenu;
4318                     }
4319                 }
4320                 break;
4321             }  /* switch(msg.message) - kbd */
4322         }
4323         else
4324         {
4325             co_IntGetPeekMessage( &msg, 0, msg.message, msg.message, PM_REMOVE, FALSE );
4326             IntDispatchMessage( &msg );
4327             continue;
4328         }
4329 
4330         if (fInsideMenuLoop) fRemove = TRUE;
4331 
4332         /* finally remove message from the queue */
4333 
4334         if (fRemove && !(mt.TrackFlags & TF_SKIPREMOVE) )
4335             co_IntGetPeekMessage( &msg, 0, msg.message, msg.message, PM_REMOVE, FALSE );
4336         else mt.TrackFlags &= ~TF_SKIPREMOVE;
4337     }
4338 
4339     MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);
4340     pti->MessageQueue->QF_flags &= ~QF_CAPTURELOCKED;
4341     co_UserSetCapture(NULL); /* release the capture */
4342 
4343     /* If dropdown is still painted and the close box is clicked on
4344        then the menu will be destroyed as part of the DispatchMessage above.
4345        This will then invalidate the menu handle in mt.hTopMenu. We should
4346        check for this first.  */
4347     if ( VerifyMenu( mt.TopMenu ) )
4348     {
4349        if (VerifyWnd(mt.OwnerWnd))
4350        {
4351            MENU_HideSubPopups(mt.OwnerWnd, mt.TopMenu, FALSE, wFlags);
4352 
4353            if (mt.TopMenu->fFlags & MNF_POPUP)
4354            {
4355               PWND pwndTM = ValidateHwndNoErr(mt.TopMenu->hWnd);
4356               if (pwndTM)
4357               {
4358                  IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND, pwndTM, OBJID_CLIENT, CHILDID_SELF, 0);
4359 
4360                  co_UserDestroyWindow(pwndTM);
4361               }
4362               mt.TopMenu->hWnd = NULL;
4363 
4364               if (!(wFlags & TPM_NONOTIFY))
4365               {
4366                  co_IntSendMessage( UserHMGetHandle(mt.OwnerWnd), WM_UNINITMENUPOPUP, (WPARAM)UserHMGetHandle(mt.TopMenu),
4367                                  MAKELPARAM(0, IS_SYSTEM_MENU(mt.TopMenu)) );
4368               }
4369             }
4370             MENU_SelectItem( mt.OwnerWnd, mt.TopMenu, NO_SELECTED_ITEM, FALSE, 0 );
4371             co_IntSendMessage( UserHMGetHandle(mt.OwnerWnd), WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0 );
4372        }
4373 
4374        /* Reset the variable for hiding menu */
4375        mt.TopMenu->TimeToHide = FALSE;
4376     }
4377 
4378     EngSetLastError( ERROR_SUCCESS );
4379     /* The return value is only used by TrackPopupMenu */
4380     if (!(wFlags & TPM_RETURNCMD)) return TRUE;
4381     if (executedMenuId == -1) executedMenuId = 0;
4382     return executedMenuId;
4383 }
4384 
4385 /***********************************************************************
4386  *           MenuInitTracking
4387  */
4388 static BOOL FASTCALL MENU_InitTracking(PWND pWnd, PMENU Menu, BOOL bPopup, UINT wFlags)
4389 {
4390     HWND capture_win;
4391     PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
4392 
4393     TRACE("hwnd=%p hmenu=%p\n", UserHMGetHandle(pWnd), UserHMGetHandle(Menu));
4394 
4395     co_UserHideCaret(0);
4396 
4397     /* This makes the menus of applications built with Delphi work.
4398      * It also enables menus to be displayed in more than one window,
4399      * but there are some bugs left that need to be fixed in this case.
4400      */
4401     if (!bPopup)
4402     {
4403         Menu->hWnd = UserHMGetHandle(pWnd);
4404     }
4405 
4406     if (!top_popup) {
4407        top_popup = Menu->hWnd;
4408        top_popup_hmenu = UserHMGetHandle(Menu);
4409     }
4410 
4411     fInsideMenuLoop = TRUE;
4412     fInEndMenu = FALSE;
4413 
4414     /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4415     if (!(wFlags & TPM_NONOTIFY))
4416     {
4417        co_IntSendMessage( UserHMGetHandle(pWnd), WM_ENTERMENULOOP, bPopup, 0 );
4418     }
4419 
4420     //
4421     // Capture is set before calling WM_INITMENU and after WM_ENTERMENULOOP, see msg_menu.
4422     //
4423     capture_win = (wFlags & TPM_POPUPMENU) ? Menu->hWnd : UserHMGetHandle(pWnd);
4424     MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, capture_win); // 1
4425     co_UserSetCapture(capture_win);                           // 2
4426     pti->MessageQueue->QF_flags |= QF_CAPTURELOCKED; // Set the Q bits so noone can change this!
4427 
4428     co_IntSendMessage( UserHMGetHandle(pWnd), WM_SETCURSOR, (WPARAM)UserHMGetHandle(pWnd), HTCAPTION );
4429 
4430     if (!(wFlags & TPM_NONOTIFY))
4431     {
4432        co_IntSendMessage( UserHMGetHandle(pWnd), WM_INITMENU, (WPARAM)UserHMGetHandle(Menu), 0 );
4433        /* If an app changed/recreated menu bar entries in WM_INITMENU
4434         * menu sizes will be recalculated once the menu created/shown.
4435         */
4436     }
4437 
4438     IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART,
4439                        pWnd,
4440                        Menu->fFlags & MNF_SYSMENU ? OBJID_SYSMENU : OBJID_MENU,
4441                        CHILDID_SELF, 0);
4442     return TRUE;
4443 }
4444 
4445 /***********************************************************************
4446  *           MenuExitTracking
4447  */
4448 static BOOL FASTCALL MENU_ExitTracking(PWND pWnd, BOOL bPopup, UINT wFlags)
4449 {
4450     TRACE("Exit Track hwnd=%p bPopup %d\n", UserHMGetHandle(pWnd), bPopup);
4451 
4452     IntNotifyWinEvent( EVENT_SYSTEM_MENUEND, pWnd, OBJID_WINDOW, CHILDID_SELF, 0);
4453 
4454     if (!(wFlags & TPM_NONOTIFY))
4455        co_IntSendMessage( UserHMGetHandle(pWnd), WM_EXITMENULOOP, bPopup, 0 );
4456 
4457     co_UserShowCaret(0);
4458 
4459     top_popup = 0;
4460     top_popup_hmenu = NULL;
4461 
4462     return TRUE;
4463 }
4464 
4465 /***********************************************************************
4466  *           MenuTrackMouseMenuBar
4467  *
4468  * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4469  */
4470 VOID MENU_TrackMouseMenuBar( PWND pWnd, ULONG ht, POINT pt)
4471 {
4472     PMENU pMenu = (ht == HTSYSMENU) ? IntGetSystemMenu(pWnd, FALSE) : IntGetMenu( UserHMGetHandle(pWnd) ); // See 74276 and CORE-12801
4473     UINT wFlags = TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL;
4474 
4475     TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", pWnd, ht, pt.x, pt.y);
4476 
4477     if (pWnd->ExStyle & WS_EX_LAYOUTRTL) wFlags |= TPM_LAYOUTRTL;
4478     if (VerifyMenu(pMenu))
4479     {
4480         /* map point to parent client coordinates */
4481         PWND Parent = UserGetAncestor(pWnd, GA_PARENT );
4482         if (Parent != UserGetDesktopWindow())
4483         {
4484             IntScreenToClient(Parent, &pt);
4485         }
4486 
4487         MENU_InitTracking(pWnd, pMenu, FALSE, wFlags);
4488         /* fetch the window menu again, it may have changed */
4489         pMenu = (ht == HTSYSMENU) ? get_win_sys_menu( UserHMGetHandle(pWnd) ) : IntGetMenu( UserHMGetHandle(pWnd) );
4490         MENU_TrackMenu(pMenu, wFlags, pt.x, pt.y, pWnd);
4491         MENU_ExitTracking(pWnd, FALSE, wFlags);
4492     }
4493 }
4494 
4495 /***********************************************************************
4496  *           MenuTrackKbdMenuBar
4497  *
4498  * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4499  */
4500 VOID MENU_TrackKbdMenuBar(PWND pwnd, UINT wParam, WCHAR wChar)
4501 {
4502     UINT uItem = NO_SELECTED_ITEM;
4503     PMENU TrackMenu;
4504     UINT wFlags = TPM_LEFTALIGN | TPM_LEFTBUTTON;
4505 
4506     TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", UserHMGetHandle(pwnd), wParam, wChar);
4507 
4508     /* find window that has a menu */
4509 
4510     while (!( (pwnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD ) )
4511         if (!(pwnd = UserGetAncestor( pwnd, GA_PARENT ))) return;
4512 
4513     /* check if we have to track a system menu */
4514 
4515     TrackMenu = IntGetMenu( UserHMGetHandle(pwnd) );
4516     if (!TrackMenu || (pwnd->style & WS_MINIMIZE) != 0 || wChar == ' ' )
4517     {
4518         if (!(pwnd->style & WS_SYSMENU)) return;
4519         TrackMenu = get_win_sys_menu( UserHMGetHandle(pwnd) );
4520         uItem = 0;
4521         wParam |= HTSYSMENU; /* prevent item lookup */
4522     }
4523 
4524     if (!VerifyMenu( TrackMenu )) return;
4525 
4526     MENU_InitTracking( pwnd, TrackMenu, FALSE, wFlags );
4527 
4528     /* fetch the window menu again, it may have changed */
4529     TrackMenu = (wParam & HTSYSMENU) ? get_win_sys_menu( UserHMGetHandle(pwnd) ) : IntGetMenu( UserHMGetHandle(pwnd) );
4530 
4531     if( wChar && wChar != ' ' )
4532     {
4533         uItem = MENU_FindItemByKey( pwnd, TrackMenu, wChar, (wParam & HTSYSMENU) );
4534         if ( uItem >= (UINT)(-2) )
4535         {
4536             if( uItem == (UINT)(-1) ) UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_MESSAGE_BEEP, 0); //MessageBeep(0);
4537             /* schedule end of menu tracking */
4538             wFlags |= TF_ENDMENU;
4539             goto track_menu;
4540         }
4541     }
4542 
4543     MENU_SelectItem( pwnd, TrackMenu, uItem, TRUE, 0 );
4544 
4545     if (!(wParam & HTSYSMENU) || wChar == ' ')
4546     {
4547         if( uItem == NO_SELECTED_ITEM )
4548             MENU_MoveSelection( pwnd, TrackMenu, ITEM_NEXT );
4549         else
4550             UserPostMessage( UserHMGetHandle(pwnd), WM_KEYDOWN, VK_RETURN, 0 );
4551     }
4552 
4553 track_menu:
4554     MENU_TrackMenu( TrackMenu, wFlags, 0, 0, pwnd );
4555     MENU_ExitTracking( pwnd, FALSE, wFlags);
4556 }
4557 
4558 /**********************************************************************
4559  *           TrackPopupMenuEx   (USER32.@)
4560  */
4561 BOOL WINAPI IntTrackPopupMenuEx( PMENU menu, UINT wFlags, int x, int y,
4562                               PWND pWnd, LPTPMPARAMS lpTpm)
4563 {
4564     BOOL ret = FALSE;
4565     PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
4566 
4567     if (pti != pWnd->head.pti)
4568     {
4569        ERR("Must be the same pti!\n");
4570        return ret;
4571     }
4572 
4573     TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p \n", //rect %s\n",
4574             UserHMGetHandle(menu), wFlags, x, y, UserHMGetHandle(pWnd), lpTpm); //,
4575             //lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" );
4576 
4577     if (menu->hWnd && IntIsWindow(menu->hWnd))
4578     {
4579         EngSetLastError( ERROR_POPUP_ALREADY_ACTIVE );
4580         return FALSE;
4581     }
4582 
4583     if (MENU_InitPopup( pWnd, menu, wFlags ))
4584     {
4585        MENU_InitTracking(pWnd, menu, TRUE, wFlags);
4586 
4587        /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4588        if (!(wFlags & TPM_NONOTIFY))
4589        {
4590           co_IntSendMessage( UserHMGetHandle(pWnd), WM_INITMENUPOPUP, (WPARAM) UserHMGetHandle(menu), 0);
4591        }
4592 
4593        if (menu->fFlags & MNF_SYSMENU)
4594           MENU_InitSysMenuPopup( menu, pWnd->style, pWnd->pcls->style, HTSYSMENU);
4595 
4596        if (MENU_ShowPopup(pWnd, menu, 0, wFlags | TPM_POPUPMENU, x, y, lpTpm ? &lpTpm->rcExclude : NULL))
4597           ret = MENU_TrackMenu( menu, wFlags | TPM_POPUPMENU, 0, 0, pWnd);
4598        else
4599        {
4600           MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);
4601           pti->MessageQueue->QF_flags &= ~QF_CAPTURELOCKED;
4602           co_UserSetCapture(NULL); /* release the capture */
4603        }
4604 
4605        MENU_ExitTracking(pWnd, TRUE, wFlags);
4606 
4607        if (menu->hWnd)
4608        {
4609           PWND pwndM = ValidateHwndNoErr( menu->hWnd );
4610           if (pwndM) // wine hack around this with their destroy function.
4611           {
4612              if (!(pWnd->state & WNDS_DESTROYED))
4613                 co_UserDestroyWindow( pwndM ); // Fix wrong error return.
4614           }
4615           menu->hWnd = 0;
4616 
4617           if (!(wFlags & TPM_NONOTIFY))
4618           {
4619              co_IntSendMessage( UserHMGetHandle(pWnd), WM_UNINITMENUPOPUP, (WPARAM)UserHMGetHandle(menu),
4620                                             MAKELPARAM(0, IS_SYSTEM_MENU(menu)) );
4621           }
4622        }
4623     }
4624     return ret;
4625 }
4626 
4627 //
4628 // Menu Class Proc.
4629 //
4630 BOOL WINAPI
4631 PopupMenuWndProc(
4632    PWND Wnd,
4633    UINT Message,
4634    WPARAM wParam,
4635    LPARAM lParam,
4636    LRESULT *lResult)
4637 {
4638   PPOPUPMENU pPopupMenu;
4639 
4640   *lResult = 0;
4641 
4642   TRACE("PMWP : pwnd=%x msg=%d wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
4643 
4644   if (Wnd)
4645   {
4646      if (!Wnd->fnid)
4647      {
4648         if (Message != WM_NCCREATE)
4649         {
4650            *lResult = IntDefWindowProc(Wnd, Message, wParam, lParam, FALSE);
4651            return TRUE;
4652         }
4653         Wnd->fnid = FNID_MENU;
4654         pPopupMenu = DesktopHeapAlloc( Wnd->head.rpdesk, sizeof(POPUPMENU) );
4655         if (pPopupMenu == NULL)
4656         {
4657             return TRUE;
4658         }
4659         pPopupMenu->posSelectedItem = NO_SELECTED_ITEM;
4660         pPopupMenu->spwndPopupMenu = Wnd;
4661         ((PMENUWND)Wnd)->ppopupmenu = pPopupMenu;
4662         TRACE("Pop Up Menu is Setup! Msg %d\n",Message);
4663         *lResult = 1;
4664         return TRUE;
4665      }
4666      else
4667      {
4668         if (Wnd->fnid != FNID_MENU)
4669         {
4670            ERR("Wrong window class for Menu! fnid %x\n",Wnd->fnid);
4671            return TRUE;
4672         }
4673         pPopupMenu = ((PMENUWND)Wnd)->ppopupmenu;
4674      }
4675   }
4676 
4677   switch(Message)
4678     {
4679     case WM_CREATE:
4680       {
4681         CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
4682         pPopupMenu->spmenu = UserGetMenuObject(cs->lpCreateParams);
4683         if (pPopupMenu->spmenu)
4684         {
4685            UserReferenceObject(pPopupMenu->spmenu);
4686         }
4687         break;
4688       }
4689 
4690     case WM_MOUSEACTIVATE:  /* We don't want to be activated */
4691       *lResult = MA_NOACTIVATE;
4692       break;
4693 
4694     case WM_PAINT:
4695       {
4696         PAINTSTRUCT ps;
4697         IntBeginPaint(Wnd, &ps);
4698         MENU_DrawPopupMenu(Wnd, ps.hdc, pPopupMenu->spmenu);
4699         IntEndPaint(Wnd, &ps);
4700         break;
4701       }
4702 
4703     case WM_PRINTCLIENT:
4704       {
4705          MENU_DrawPopupMenu( Wnd, (HDC)wParam, pPopupMenu->spmenu);
4706          break;
4707       }
4708 
4709     case WM_ERASEBKGND:
4710       *lResult = 1;
4711       break;
4712 
4713     case WM_DESTROY:
4714       /* zero out global pointer in case resident popup window was destroyed. */
4715       if (pPopupMenu)
4716       {
4717          if (UserHMGetHandle(Wnd) == top_popup)
4718          {
4719              top_popup = NULL;
4720              top_popup_hmenu = NULL;
4721          }
4722       }
4723       else
4724       {
4725          ERR("No Window Pop Up!\n");
4726       }
4727       break;
4728 
4729     case WM_NCDESTROY:
4730       {
4731          if (pPopupMenu->spmenu)
4732          {
4733             IntReleaseMenuObject(pPopupMenu->spmenu);
4734          }
4735          DesktopHeapFree(Wnd->head.rpdesk, pPopupMenu );
4736          ((PMENUWND)Wnd)->ppopupmenu = 0;
4737          Wnd->fnid = FNID_DESTROY;
4738          break;
4739       }
4740 
4741     case MM_SETMENUHANDLE: // wine'isms
4742     case MN_SETHMENU:
4743       {
4744         PMENU pmenu = UserGetMenuObject((HMENU)wParam);
4745         if (!pmenu)
4746         {
4747            ERR("Bad Menu Handle\n");
4748            break;
4749         }
4750         UserReferenceObject(pmenu);
4751         if (pPopupMenu->spmenu)
4752         {
4753            IntReleaseMenuObject(pPopupMenu->spmenu);
4754         }
4755         pPopupMenu->spmenu = pmenu;
4756         break;
4757       }
4758 
4759     case MM_GETMENUHANDLE: // wine'isms
4760     case MN_GETHMENU:
4761          *lResult = (LRESULT)(pPopupMenu ? (pPopupMenu->spmenu ? UserHMGetHandle(pPopupMenu->spmenu) : NULL) : NULL);
4762          break;
4763 
4764     default:
4765       if (Message > MN_GETHMENU && Message < MN_GETHMENU+19)
4766       {
4767          ERR("Someone is passing unknown menu messages %d\n",Message);
4768       }
4769       TRACE("PMWP to IDWP %d\n",Message);
4770       *lResult = IntDefWindowProc(Wnd, Message, wParam, lParam, FALSE);
4771       break;
4772     }
4773 
4774   return TRUE;
4775 }
4776 
4777 BOOL FASTCALL
4778 IntHiliteMenuItem(PWND WindowObject,
4779                   PMENU MenuObject,
4780                   UINT uItemHilite,
4781                   UINT uHilite)
4782 {
4783    PITEM MenuItem;
4784    UINT uItem = uItemHilite;
4785 
4786    if (!(MenuItem = MENU_FindItem( &MenuObject, &uItem, uHilite ))) return TRUE;
4787 
4788    if (uHilite & MF_HILITE)
4789    {
4790       MenuItem->fState |= MF_HILITE;
4791    }
4792    else
4793    {
4794       MenuItem->fState &= ~MF_HILITE;
4795    }
4796    if (MenuObject->iItem == uItemHilite) return TRUE;
4797    MENU_HideSubPopups( WindowObject, MenuObject, FALSE, 0 );
4798    MENU_SelectItem( WindowObject, MenuObject, uItemHilite, TRUE, 0 );
4799 
4800    return TRUE; // Always returns true!!!!
4801 }
4802 
4803 BOOLEAN APIENTRY
4804 intGetTitleBarInfo(PWND pWindowObject, PTITLEBARINFO bti)
4805 {
4806 
4807     DWORD dwStyle = 0;
4808     DWORD dwExStyle = 0;
4809     BOOLEAN retValue = TRUE;
4810 
4811     if (bti->cbSize == sizeof(TITLEBARINFO))
4812     {
4813         RtlZeroMemory(&bti->rgstate[0],sizeof(DWORD)*(CCHILDREN_TITLEBAR+1));
4814 
4815         bti->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
4816 
4817         dwStyle = pWindowObject->style;
4818         dwExStyle = pWindowObject->ExStyle;
4819 
4820         bti->rcTitleBar.top  = 0;
4821         bti->rcTitleBar.left = 0;
4822         bti->rcTitleBar.right  = pWindowObject->rcWindow.right - pWindowObject->rcWindow.left;
4823         bti->rcTitleBar.bottom = pWindowObject->rcWindow.bottom - pWindowObject->rcWindow.top;
4824 
4825         /* Is it iconiced ? */
4826         if ((dwStyle & WS_ICONIC)!=WS_ICONIC)
4827         {
4828             /* Remove frame from rectangle */
4829             if (HAS_THICKFRAME( dwStyle, dwExStyle ))
4830             {
4831                 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
4832                 RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) );
4833             }
4834             else if (HAS_DLGFRAME( dwStyle, dwExStyle ))
4835             {
4836                 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
4837                 RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
4838             }
4839             else if (HAS_THINFRAME( dwStyle, dwExStyle))
4840             {
4841                 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4842                 RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER) );
4843             }
4844 
4845             /* We have additional border information if the window
4846              * is a child (but not an MDI child) */
4847             if ( (dwStyle & WS_CHILD)  &&
4848                  ((dwExStyle & WS_EX_MDICHILD) == 0 ) )
4849             {
4850                 if (dwExStyle & WS_EX_CLIENTEDGE)
4851                 {
4852                     /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
4853                     RECTL_vInflateRect (&bti->rcTitleBar, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE));
4854                 }
4855 
4856                 if (dwExStyle & WS_EX_STATICEDGE)
4857                 {
4858                     /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4859                     RECTL_vInflateRect (&bti->rcTitleBar, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
4860                 }
4861             }
4862         }
4863 
4864         bti->rcTitleBar.top += pWindowObject->rcWindow.top;
4865         bti->rcTitleBar.left += pWindowObject->rcWindow.left;
4866         bti->rcTitleBar.right += pWindowObject->rcWindow.left;
4867 
4868         bti->rcTitleBar.bottom = bti->rcTitleBar.top;
4869         if (dwExStyle & WS_EX_TOOLWINDOW)
4870         {
4871             /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
4872             bti->rcTitleBar.bottom += UserGetSystemMetrics(SM_CYSMCAPTION);
4873         }
4874         else
4875         {
4876             /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
4877             bti->rcTitleBar.bottom += UserGetSystemMetrics(SM_CYCAPTION);
4878             bti->rcTitleBar.left += UserGetSystemMetrics(SM_CXSIZE);
4879         }
4880 
4881         if (dwStyle & WS_CAPTION)
4882         {
4883             bti->rgstate[1] = STATE_SYSTEM_INVISIBLE;
4884             if (dwStyle & WS_SYSMENU)
4885             {
4886                 if (!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX)))
4887                 {
4888                     bti->rgstate[2] = STATE_SYSTEM_INVISIBLE;
4889                     bti->rgstate[3] = STATE_SYSTEM_INVISIBLE;
4890                 }
4891                 else
4892                 {
4893                     if (!(dwStyle & WS_MINIMIZEBOX))
4894                     {
4895                         bti->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
4896                     }
4897                     if (!(dwStyle & WS_MAXIMIZEBOX))
4898                     {
4899                         bti->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
4900                     }
4901                 }
4902 
4903                 if (!(dwExStyle & WS_EX_CONTEXTHELP))
4904                 {
4905                     bti->rgstate[4] = STATE_SYSTEM_INVISIBLE;
4906                 }
4907                 if (pWindowObject->pcls->style & CS_NOCLOSE)
4908                 {
4909                     bti->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
4910                 }
4911             }
4912             else
4913             {
4914                 bti->rgstate[2] = STATE_SYSTEM_INVISIBLE;
4915                 bti->rgstate[3] = STATE_SYSTEM_INVISIBLE;
4916                 bti->rgstate[4] = STATE_SYSTEM_INVISIBLE;
4917                 bti->rgstate[5] = STATE_SYSTEM_INVISIBLE;
4918             }
4919         }
4920         else
4921         {
4922             bti->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
4923         }
4924     }
4925     else
4926     {
4927         EngSetLastError(ERROR_INVALID_PARAMETER);
4928         retValue = FALSE;
4929     }
4930 
4931     return retValue;
4932 }
4933 
4934 DWORD FASTCALL
4935 UserInsertMenuItem(
4936    PMENU Menu,
4937    UINT uItem,
4938    BOOL fByPosition,
4939    LPCMENUITEMINFOW UnsafeItemInfo,
4940    PUNICODE_STRING lpstr)
4941 {
4942    NTSTATUS Status;
4943    ROSMENUITEMINFO ItemInfo;
4944 
4945    /* Try to copy the whole MENUITEMINFOW structure */
4946    Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, sizeof(MENUITEMINFOW));
4947    if (NT_SUCCESS(Status))
4948    {
4949       if (sizeof(MENUITEMINFOW) != ItemInfo.cbSize
4950          && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize)
4951       {
4952          EngSetLastError(ERROR_INVALID_PARAMETER);
4953          return FALSE;
4954       }
4955       return IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo, lpstr);
4956    }
4957 
4958    /* Try to copy without last field (not present in older versions) */
4959    Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, FIELD_OFFSET(MENUITEMINFOW, hbmpItem));
4960    if (NT_SUCCESS(Status))
4961    {
4962       if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize)
4963       {
4964          EngSetLastError(ERROR_INVALID_PARAMETER);
4965          return FALSE;
4966       }
4967       ItemInfo.hbmpItem = (HBITMAP)0;
4968       return IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo, lpstr);
4969    }
4970 
4971    SetLastNtError(Status);
4972    return FALSE;
4973 }
4974 
4975 UINT FASTCALL IntGetMenuState( HMENU hMenu, UINT uId, UINT uFlags)
4976 {
4977    PMENU MenuObject;
4978    PITEM pItem;
4979 
4980    if (!(MenuObject = UserGetMenuObject(hMenu)))
4981    {
4982       return (UINT)-1;
4983    }
4984 
4985    if (!(pItem = MENU_FindItem( &MenuObject, &uId, uFlags ))) return -1;
4986 
4987    if (pItem->spSubMenu)
4988    {
4989       return (pItem->spSubMenu->cItems << 8) | ((pItem->fState|pItem->fType|MF_POPUP) & 0xff);
4990    }
4991    else
4992       return (pItem->fType | pItem->fState);
4993 }
4994 
4995 HMENU FASTCALL IntGetSubMenu( HMENU hMenu, int nPos)
4996 {
4997    PMENU MenuObject;
4998    PITEM pItem;
4999 
5000    if (!(MenuObject = UserGetMenuObject(hMenu)))
5001    {
5002       return NULL;
5003    }
5004 
5005    if (!(pItem = MENU_FindItem( &MenuObject, (UINT*)&nPos, MF_BYPOSITION ))) return NULL;
5006 
5007    if (pItem->spSubMenu)
5008    {
5009       HMENU hsubmenu = UserHMGetHandle(pItem->spSubMenu);
5010       return hsubmenu;
5011    }
5012    return NULL;
5013 }
5014 
5015 UINT FASTCALL IntFindSubMenu(HMENU *hMenu, HMENU hSubTarget )
5016 {
5017     PMENU menu, pSubTarget;
5018     UINT Pos;
5019     if (((*hMenu)==(HMENU)0xffff) ||(!(menu = UserGetMenuObject(*hMenu))))
5020         return NO_SELECTED_ITEM;
5021 
5022     pSubTarget = UserGetMenuObject(hSubTarget);
5023 
5024     Pos = MENU_FindSubMenu(&menu, pSubTarget );
5025 
5026     *hMenu = (menu ? UserHMGetHandle(menu) : NULL);
5027 
5028     return Pos;
5029 }
5030 
5031 
5032 HMENU FASTCALL UserCreateMenu(PDESKTOP Desktop, BOOL PopupMenu)
5033 {
5034    PWINSTATION_OBJECT WinStaObject;
5035    HANDLE Handle;
5036    PMENU Menu;
5037    NTSTATUS Status;
5038    PEPROCESS CurrentProcess = PsGetCurrentProcess();
5039 
5040    if (gpepCSRSS != CurrentProcess)
5041    {
5042       /*
5043        * gpepCSRSS does not have a Win32WindowStation
5044        */
5045 
5046       Status = IntValidateWindowStationHandle(CurrentProcess->Win32WindowStation,
5047                      UserMode,
5048                      0,
5049                      &WinStaObject,
5050                      0);
5051 
5052        if (!NT_SUCCESS(Status))
5053        {
5054           ERR("Validation of window station handle (%p) failed\n",
5055               CurrentProcess->Win32WindowStation);
5056           SetLastNtError(Status);
5057           return (HMENU)0;
5058        }
5059        Menu = IntCreateMenu(&Handle, !PopupMenu, Desktop, GetW32ProcessInfo());
5060        if (Menu && Menu->head.rpdesk->rpwinstaParent != WinStaObject)
5061        {
5062           ERR("Desktop Window Station does not match Process one!\n");
5063        }
5064        ObDereferenceObject(WinStaObject);
5065    }
5066    else
5067    {
5068        Menu = IntCreateMenu(&Handle, !PopupMenu, GetW32ThreadInfo()->rpdesk, GetW32ProcessInfo());
5069    }
5070 
5071    if (Menu) UserDereferenceObject(Menu);
5072    return (HMENU)Handle;
5073 }
5074 
5075 BOOL FASTCALL
5076 IntMenuItemInfo(
5077    PMENU Menu,
5078    UINT Item,
5079    BOOL ByPosition,
5080    PROSMENUITEMINFO ItemInfo,
5081    BOOL SetOrGet,
5082    PUNICODE_STRING lpstr)
5083 {
5084    PITEM MenuItem;
5085    BOOL Ret;
5086 
5087    if (!(MenuItem = MENU_FindItem( &Menu, &Item, (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND) )))
5088    {
5089       EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND);
5090       return( FALSE);
5091    }
5092    if (SetOrGet)
5093    {
5094       Ret = IntSetMenuItemInfo(Menu, MenuItem, ItemInfo, lpstr);
5095    }
5096    else
5097    {
5098       Ret = IntGetMenuItemInfo(Menu, MenuItem, ItemInfo);
5099    }
5100    return( Ret);
5101 }
5102 
5103 BOOL FASTCALL
5104 UserMenuItemInfo(
5105    PMENU Menu,
5106    UINT Item,
5107    BOOL ByPosition,
5108    PROSMENUITEMINFO UnsafeItemInfo,
5109    BOOL SetOrGet,
5110    PUNICODE_STRING lpstr)
5111 {
5112    PITEM MenuItem;
5113    ROSMENUITEMINFO ItemInfo;
5114    NTSTATUS Status;
5115    UINT Size;
5116    BOOL Ret;
5117 
5118    Status = MmCopyFromCaller(&Size, &UnsafeItemInfo->cbSize, sizeof(UINT));
5119    if (! NT_SUCCESS(Status))
5120    {
5121       SetLastNtError(Status);
5122       return( FALSE);
5123    }
5124    if ( Size != sizeof(MENUITEMINFOW) &&
5125         Size != FIELD_OFFSET(MENUITEMINFOW, hbmpItem) &&
5126         Size != sizeof(ROSMENUITEMINFO) )
5127    {
5128       EngSetLastError(ERROR_INVALID_PARAMETER);
5129       return( FALSE);
5130    }
5131    Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, Size);
5132    if (! NT_SUCCESS(Status))
5133    {
5134       SetLastNtError(Status);
5135       return( FALSE);
5136    }
5137    /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
5138       set/get hbmpItem */
5139    if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) == Size
5140          && 0 != (ItemInfo.fMask & MIIM_BITMAP))
5141    {
5142       EngSetLastError(ERROR_INVALID_PARAMETER);
5143       return( FALSE);
5144    }
5145 
5146    if (!(MenuItem = MENU_FindItem( &Menu, &Item, (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND) )))
5147    {
5148       /* workaround for Word 95: pretend that SC_TASKLIST item exists. */
5149       if ( SetOrGet && Item == SC_TASKLIST && !ByPosition )
5150          return TRUE;
5151 
5152       EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND);
5153       return( FALSE);
5154    }
5155 
5156    if (SetOrGet)
5157    {
5158       Ret = IntSetMenuItemInfo(Menu, MenuItem, &ItemInfo, lpstr);
5159    }
5160    else
5161    {
5162       Ret = IntGetMenuItemInfo(Menu, MenuItem, &ItemInfo);
5163       if (Ret)
5164       {
5165          Status = MmCopyToCaller(UnsafeItemInfo, &ItemInfo, Size);
5166          if (! NT_SUCCESS(Status))
5167          {
5168             SetLastNtError(Status);
5169             return( FALSE);
5170          }
5171       }
5172    }
5173 
5174    return( Ret);
5175 }
5176 
5177 BOOL FASTCALL
5178 UserMenuInfo(
5179    PMENU Menu,
5180    PROSMENUINFO UnsafeMenuInfo,
5181    BOOL SetOrGet)
5182 {
5183    BOOL Res;
5184    DWORD Size;
5185    NTSTATUS Status;
5186    ROSMENUINFO MenuInfo;
5187 
5188    Status = MmCopyFromCaller(&Size, &UnsafeMenuInfo->cbSize, sizeof(DWORD));
5189    if (! NT_SUCCESS(Status))
5190    {
5191       SetLastNtError(Status);
5192       return( FALSE);
5193    }
5194    if ( Size < sizeof(MENUINFO) || Size > sizeof(ROSMENUINFO) )
5195    {
5196       EngSetLastError(ERROR_INVALID_PARAMETER);
5197       return( FALSE);
5198    }
5199    Status = MmCopyFromCaller(&MenuInfo, UnsafeMenuInfo, Size);
5200    if (! NT_SUCCESS(Status))
5201    {
5202       SetLastNtError(Status);
5203       return( FALSE);
5204    }
5205 
5206    if(SetOrGet)
5207    {
5208       /* Set MenuInfo */
5209       Res = IntSetMenuInfo(Menu, &MenuInfo);
5210    }
5211    else
5212    {
5213       /* Get MenuInfo */
5214       Res = IntGetMenuInfo(Menu, &MenuInfo);
5215       if (Res)
5216       {
5217          Status = MmCopyToCaller(UnsafeMenuInfo, &MenuInfo, Size);
5218          if (! NT_SUCCESS(Status))
5219          {
5220             SetLastNtError(Status);
5221             return( FALSE);
5222          }
5223       }
5224    }
5225 
5226    return( Res);
5227 }
5228 
5229 BOOL FASTCALL
5230 IntGetMenuItemRect(
5231    PWND pWnd,
5232    PMENU Menu,
5233    UINT uItem,
5234    PRECTL Rect)
5235 {
5236    LONG XMove, YMove;
5237    PITEM MenuItem;
5238    UINT I = uItem;
5239 
5240    if ((MenuItem = MENU_FindItem (&Menu, &I, MF_BYPOSITION)))
5241    {
5242       Rect->left   = MenuItem->xItem;
5243       Rect->top    = MenuItem->yItem;
5244       Rect->right  = MenuItem->cxItem; // Do this for now......
5245       Rect->bottom = MenuItem->cyItem;
5246    }
5247    else
5248    {
5249       ERR("Failed Item Lookup! %u\n", uItem);
5250       return FALSE;
5251    }
5252 
5253    if (!pWnd)
5254    {
5255       HWND hWnd = Menu->hWnd;
5256       if (!(pWnd = UserGetWindowObject(hWnd))) return FALSE;
5257    }
5258 
5259    if (Menu->fFlags & MNF_POPUP)
5260    {
5261      XMove = pWnd->rcClient.left;
5262      YMove = pWnd->rcClient.top;
5263    }
5264    else
5265    {
5266      XMove = pWnd->rcWindow.left;
5267      YMove = pWnd->rcWindow.top;
5268    }
5269 
5270    Rect->left   += XMove;
5271    Rect->top    += YMove;
5272    Rect->right  += XMove;
5273    Rect->bottom += YMove;
5274 
5275    return TRUE;
5276 }
5277 
5278 PMENU FASTCALL MENU_GetSystemMenu(PWND Window, PMENU Popup)
5279 {
5280    PMENU Menu, NewMenu = NULL, SysMenu = NULL;
5281    HMENU hSysMenu, hNewMenu = NULL;
5282    ROSMENUITEMINFO ItemInfoSet = {0};
5283    ROSMENUITEMINFO ItemInfo = {0};
5284    UNICODE_STRING MenuName;
5285 
5286    hSysMenu = UserCreateMenu(Window->head.rpdesk, FALSE);
5287    if (NULL == hSysMenu)
5288    {
5289       return NULL;
5290    }
5291    SysMenu = UserGetMenuObject(hSysMenu);
5292    if (NULL == SysMenu)
5293    {
5294        UserDestroyMenu(hSysMenu);
5295        return NULL;
5296    }
5297 
5298    SysMenu->fFlags |= MNF_SYSMENU;
5299    SysMenu->hWnd = UserHMGetHandle(Window);
5300 
5301    if (!Popup)
5302    {
5303       //hNewMenu = co_IntLoadSysMenuTemplate();
5304       if ( Window->ExStyle & WS_EX_MDICHILD )
5305       {
5306          RtlInitUnicodeString( &MenuName, L"SYSMENUMDI");
5307          hNewMenu = co_IntCallLoadMenu( hModClient, &MenuName);
5308       }
5309       else
5310       {
5311          RtlInitUnicodeString( &MenuName, L"SYSMENU");
5312          hNewMenu = co_IntCallLoadMenu( hModClient, &MenuName);
5313          //ERR("%wZ\n",&MenuName);
5314       }
5315       if (!hNewMenu)
5316       {
5317          ERR("No Menu!!\n");
5318          IntDestroyMenuObject(SysMenu, FALSE);
5319          return NULL;
5320       }
5321       Menu = UserGetMenuObject(hNewMenu);
5322       if (!Menu)
5323       {
5324          IntDestroyMenuObject(SysMenu, FALSE);
5325          return NULL;
5326       }
5327 
5328       // Do the rest in here.
5329 
5330       Menu->fFlags |= MNS_CHECKORBMP | MNF_SYSMENU  | MNF_POPUP;
5331 
5332       ItemInfoSet.cbSize = sizeof( MENUITEMINFOW);
5333       ItemInfoSet.fMask = MIIM_BITMAP;
5334       ItemInfoSet.hbmpItem = HBMMENU_POPUP_CLOSE;
5335       IntMenuItemInfo(Menu, SC_CLOSE, FALSE, &ItemInfoSet, TRUE, NULL);
5336       ItemInfoSet.hbmpItem = HBMMENU_POPUP_RESTORE;
5337       IntMenuItemInfo(Menu, SC_RESTORE, FALSE, &ItemInfoSet, TRUE, NULL);
5338       ItemInfoSet.hbmpItem = HBMMENU_POPUP_MAXIMIZE;
5339       IntMenuItemInfo(Menu, SC_MAXIMIZE, FALSE, &ItemInfoSet, TRUE, NULL);
5340       ItemInfoSet.hbmpItem = HBMMENU_POPUP_MINIMIZE;
5341       IntMenuItemInfo(Menu, SC_MINIMIZE, FALSE, &ItemInfoSet, TRUE, NULL);
5342 
5343       NewMenu = IntCloneMenu(Menu);
5344       if (NewMenu == NULL)
5345       {
5346          IntDestroyMenuObject(Menu, FALSE);
5347          IntDestroyMenuObject(SysMenu, FALSE);
5348          return NULL;
5349       }
5350 
5351       IntReleaseMenuObject(NewMenu);
5352       UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE);
5353 
5354       IntDestroyMenuObject(Menu, FALSE);
5355    }
5356    else
5357    {
5358       NewMenu = Popup;
5359    }
5360    if (NewMenu)
5361    {
5362       NewMenu->fFlags |= MNF_SYSMENU | MNF_POPUP;
5363 
5364       if (Window->pcls->style & CS_NOCLOSE)
5365          IntRemoveMenuItem(NewMenu, SC_CLOSE, MF_BYCOMMAND, TRUE);
5366 
5367       ItemInfo.cbSize = sizeof(MENUITEMINFOW);
5368       ItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU;
5369       ItemInfo.fType = MF_POPUP;
5370       ItemInfo.fState = MFS_ENABLED;
5371       ItemInfo.dwTypeData = NULL;
5372       ItemInfo.cch = 0;
5373       ItemInfo.hSubMenu = UserHMGetHandle(NewMenu);
5374       IntInsertMenuItem(SysMenu, (UINT) -1, TRUE, &ItemInfo, NULL);
5375 
5376       return SysMenu;
5377    }
5378    ERR("failed to load system menu!\n");
5379    return NULL;
5380 }
5381 
5382 PMENU FASTCALL
5383 IntGetSystemMenu(PWND Window, BOOL bRevert)
5384 {
5385    PMENU Menu;
5386 
5387    if (bRevert)
5388    {
5389       if (Window->SystemMenu)
5390       {
5391          Menu = UserGetMenuObject(Window->SystemMenu);
5392          if (Menu && !(Menu->fFlags & MNF_SYSDESKMN))
5393          {
5394             IntDestroyMenuObject(Menu, TRUE);
5395             Window->SystemMenu = NULL;
5396          }
5397       }
5398    }
5399    else
5400    {
5401       Menu = Window->SystemMenu ? UserGetMenuObject(Window->SystemMenu) : NULL;
5402       if ((!Menu || Menu->fFlags & MNF_SYSDESKMN) && Window->style & WS_SYSMENU)
5403       {
5404          Menu = MENU_GetSystemMenu(Window, NULL);
5405          Window->SystemMenu = Menu ? UserHMGetHandle(Menu) : NULL;
5406       }
5407    }
5408 
5409    if (Window->SystemMenu)
5410    {
5411       HMENU hMenu = IntGetSubMenu( Window->SystemMenu, 0);
5412       /* Store the dummy sysmenu handle to facilitate the refresh */
5413       /* of the close button if the SC_CLOSE item change */
5414       Menu = UserGetMenuObject(hMenu);
5415       if (Menu)
5416       {
5417          Menu->spwndNotify = Window;
5418          Menu->fFlags |= MNF_SYSSUBMENU;
5419       }
5420       return Menu;
5421    }
5422    return NULL;
5423 }
5424 
5425 BOOL FASTCALL
5426 IntSetSystemMenu(PWND Window, PMENU Menu)
5427 {
5428    PMENU OldMenu;
5429 
5430    if (!(Window->style & WS_SYSMENU)) return FALSE;
5431 
5432    if (Window->SystemMenu)
5433    {
5434       OldMenu = UserGetMenuObject(Window->SystemMenu);
5435       if (OldMenu)
5436       {
5437           OldMenu->fFlags &= ~MNF_SYSMENU;
5438           IntDestroyMenuObject(OldMenu, TRUE);
5439       }
5440    }
5441 
5442    OldMenu = MENU_GetSystemMenu(Window, Menu);
5443    if (OldMenu)
5444    {  // Use spmenuSys too!
5445       Window->SystemMenu = UserHMGetHandle(OldMenu);
5446    }
5447    else
5448       Window->SystemMenu = NULL;
5449 
5450    if (Menu && Window != Menu->spwndNotify)
5451    {
5452       Menu->spwndNotify = Window;
5453    }
5454 
5455    return TRUE;
5456 }
5457 
5458 BOOL FASTCALL
5459 IntSetMenu(
5460    PWND Wnd,
5461    HMENU Menu,
5462    BOOL *Changed)
5463 {
5464    PMENU OldMenu, NewMenu = NULL;
5465 
5466    if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
5467    {
5468       ERR("SetMenu: Window is a Child 0x%p!\n",UserHMGetHandle(Wnd));
5469       EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
5470       return FALSE;
5471    }
5472 
5473    *Changed = (UlongToHandle(Wnd->IDMenu) != Menu);
5474    if (! *Changed)
5475    {
5476       return TRUE;
5477    }
5478 
5479    if (Wnd->IDMenu)
5480    {
5481       OldMenu = IntGetMenuObject(UlongToHandle(Wnd->IDMenu));
5482       ASSERT(NULL == OldMenu || OldMenu->hWnd == UserHMGetHandle(Wnd));
5483    }
5484    else
5485    {
5486       OldMenu = NULL;
5487    }
5488 
5489    if (NULL != Menu)
5490    {
5491       NewMenu = IntGetMenuObject(Menu);
5492       if (NULL == NewMenu)
5493       {
5494          if (NULL != OldMenu)
5495          {
5496             IntReleaseMenuObject(OldMenu);
5497          }
5498          EngSetLastError(ERROR_INVALID_MENU_HANDLE);
5499          return FALSE;
5500       }
5501       if (NULL != NewMenu->hWnd)
5502       {
5503          /* Can't use the same menu for two windows */
5504          if (NULL != OldMenu)
5505          {
5506             IntReleaseMenuObject(OldMenu);
5507          }
5508          EngSetLastError(ERROR_INVALID_MENU_HANDLE);
5509          return FALSE;
5510       }
5511 
5512    }
5513 
5514    Wnd->IDMenu = (UINT_PTR) Menu;
5515    if (NULL != NewMenu)
5516    {
5517       NewMenu->hWnd = UserHMGetHandle(Wnd);
5518       IntReleaseMenuObject(NewMenu);
5519    }
5520    if (NULL != OldMenu)
5521    {
5522       OldMenu->hWnd = NULL;
5523       IntReleaseMenuObject(OldMenu);
5524    }
5525 
5526    return TRUE;
5527 }
5528 
5529 
5530 /* FUNCTIONS *****************************************************************/
5531 
5532 /*
5533  * @implemented
5534  */
5535 /* http://www.cyber-ta.org/releases/malware-analysis/public/SOURCES/b47155634ccb2c30630da7e3666d3d07/b47155634ccb2c30630da7e3666d3d07.trace.html#NtUserGetIconSize */
5536 DWORD
5537 APIENTRY
5538 NtUserCalcMenuBar(
5539     HWND   hwnd,
5540     DWORD  leftBorder,
5541     DWORD  rightBorder,
5542     DWORD  top,
5543     LPRECT prc )
5544 {
5545     HDC hdc;
5546     PWND Window;
5547     RECT Rect;
5548     DWORD ret;
5549 
5550     UserEnterExclusive();
5551 
5552     if(!(Window = UserGetWindowObject(hwnd)))
5553     {
5554         EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
5555         UserLeave();
5556         return 0;
5557     }
5558 
5559     hdc = UserGetDCEx(NULL, NULL, DCX_CACHE);
5560     if (!hdc)
5561     {
5562         UserLeave();
5563         return 0;
5564     }
5565 
5566     Rect.left = leftBorder;
5567     Rect.right = Window->rcWindow.right - Window->rcWindow.left - rightBorder;
5568     Rect.top = top;
5569     Rect.bottom = 0;
5570 
5571     ret = MENU_DrawMenuBar(hdc, &Rect, Window, TRUE);
5572 
5573     UserReleaseDC( 0, hdc, FALSE );
5574 
5575     UserLeave();
5576 
5577     return ret;
5578 }
5579 
5580 /*
5581  * @implemented
5582  */
5583 DWORD APIENTRY
5584 NtUserCheckMenuItem(
5585    HMENU hMenu,
5586    UINT uIDCheckItem,
5587    UINT uCheck)
5588 {
5589    PMENU Menu;
5590    DECLARE_RETURN(DWORD);
5591 
5592    TRACE("Enter NtUserCheckMenuItem\n");
5593    UserEnterExclusive();
5594 
5595    if(!(Menu = UserGetMenuObject(hMenu)))
5596    {
5597       RETURN( (DWORD)-1);
5598    }
5599 
5600    RETURN( IntCheckMenuItem(Menu, uIDCheckItem, uCheck));
5601 
5602 CLEANUP:
5603    TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_);
5604    UserLeave();
5605    END_CLEANUP;
5606 }
5607 
5608 /*
5609  * @implemented
5610  */
5611 BOOL APIENTRY
5612 NtUserDeleteMenu(
5613    HMENU hMenu,
5614    UINT uPosition,
5615    UINT uFlags)
5616 {
5617    PMENU Menu;
5618    DECLARE_RETURN(BOOL);
5619 
5620    TRACE("Enter NtUserDeleteMenu\n");
5621    UserEnterExclusive();
5622 
5623    if(!(Menu = UserGetMenuObject(hMenu)))
5624    {
5625       RETURN( FALSE);
5626    }
5627 
5628    RETURN( IntRemoveMenuItem(Menu, uPosition, uFlags, TRUE));
5629 
5630 CLEANUP:
5631    TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_);
5632    UserLeave();
5633    END_CLEANUP;
5634 }
5635 
5636 /*
5637  * NtUserGetSystemMenu
5638  *
5639  * The NtUserGetSystemMenu function allows the application to access the
5640  * window menu (also known as the system menu or the control menu) for
5641  * copying and modifying.
5642  *
5643  * Parameters
5644  *    hWnd
5645  *       Handle to the window that will own a copy of the window menu.
5646  *    bRevert
5647  *       Specifies the action to be taken. If this parameter is FALSE,
5648  *       NtUserGetSystemMenu returns a handle to the copy of the window menu
5649  *       currently in use. The copy is initially identical to the window menu
5650  *       but it can be modified.
5651  *       If this parameter is TRUE, GetSystemMenu resets the window menu back
5652  *       to the default state. The previous window menu, if any, is destroyed.
5653  *
5654  * Return Value
5655  *    If the bRevert parameter is FALSE, the return value is a handle to a
5656  *    copy of the window menu. If the bRevert parameter is TRUE, the return
5657  *    value is NULL.
5658  *
5659  * Status
5660  *    @implemented
5661  */
5662 
5663 HMENU APIENTRY
5664 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
5665 {
5666    PWND Window;
5667    PMENU Menu;
5668    DECLARE_RETURN(HMENU);
5669 
5670    TRACE("Enter NtUserGetSystemMenu\n");
5671    UserEnterExclusive();
5672 
5673    if (!(Window = UserGetWindowObject(hWnd)))
5674    {
5675       RETURN(NULL);
5676    }
5677 
5678    if (!(Menu = IntGetSystemMenu(Window, bRevert)))
5679    {
5680       RETURN(NULL);
5681    }
5682 
5683    RETURN(Menu->head.h);
5684 
5685 CLEANUP:
5686    TRACE("Leave NtUserGetSystemMenu, ret=%p\n", _ret_);
5687    UserLeave();
5688    END_CLEANUP;
5689 }
5690 
5691 /*
5692  * NtUserSetSystemMenu
5693  *
5694  * Status
5695  *    @implemented
5696  */
5697 
5698 BOOL APIENTRY
5699 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
5700 {
5701    BOOL Result = FALSE;
5702    PWND Window;
5703    PMENU Menu;
5704    DECLARE_RETURN(BOOL);
5705 
5706    TRACE("Enter NtUserSetSystemMenu\n");
5707    UserEnterExclusive();
5708 
5709    if (!(Window = UserGetWindowObject(hWnd)))
5710    {
5711       RETURN( FALSE);
5712    }
5713 
5714    if (hMenu)
5715    {
5716       /*
5717        * Assign new menu handle and Up the Lock Count.
5718        */
5719       if (!(Menu = IntGetMenuObject(hMenu)))
5720       {
5721          RETURN( FALSE);
5722       }
5723 
5724       Result = IntSetSystemMenu(Window, Menu);
5725    }
5726    else
5727       EngSetLastError(ERROR_INVALID_MENU_HANDLE);
5728 
5729    RETURN( Result);
5730 
5731 CLEANUP:
5732    TRACE("Leave NtUserSetSystemMenu, ret=%i\n",_ret_);
5733    UserLeave();
5734    END_CLEANUP;
5735 }
5736 
5737 /*
5738  * @implemented
5739  */
5740 BOOLEAN APIENTRY
5741 NtUserGetTitleBarInfo(
5742     HWND hwnd,
5743     PTITLEBARINFO bti)
5744 {
5745     PWND WindowObject;
5746     TITLEBARINFO bartitleinfo;
5747     DECLARE_RETURN(BOOLEAN);
5748     BOOLEAN retValue = TRUE;
5749 
5750     TRACE("Enter NtUserGetTitleBarInfo\n");
5751     UserEnterExclusive();
5752 
5753     /* Vaildate the windows handle */
5754     if (!(WindowObject = UserGetWindowObject(hwnd)))
5755     {
5756         EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
5757         retValue = FALSE;
5758     }
5759 
5760     _SEH2_TRY
5761     {
5762         /* Copy our usermode buffer bti to local buffer bartitleinfo */
5763         ProbeForRead(bti, sizeof(TITLEBARINFO), 1);
5764         RtlCopyMemory(&bartitleinfo, bti, sizeof(TITLEBARINFO));
5765     }
5766     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5767     {
5768         /* Fail copy the data */
5769         EngSetLastError(ERROR_INVALID_PARAMETER);
5770         retValue = FALSE;
5771     }
5772     _SEH2_END
5773 
5774     /* Get the tile bar info */
5775     if (retValue)
5776     {
5777         retValue = intGetTitleBarInfo(WindowObject, &bartitleinfo);
5778         if (retValue)
5779         {
5780             _SEH2_TRY
5781             {
5782                 /* Copy our buffer to user mode buffer bti */
5783                 ProbeForWrite(bti, sizeof(TITLEBARINFO), 1);
5784                 RtlCopyMemory(bti, &bartitleinfo, sizeof(TITLEBARINFO));
5785             }
5786             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5787             {
5788                 /* Fail copy the data */
5789                 EngSetLastError(ERROR_INVALID_PARAMETER);
5790                 retValue = FALSE;
5791             }
5792             _SEH2_END
5793         }
5794     }
5795 
5796     RETURN( retValue );
5797 
5798 CLEANUP:
5799     TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_);
5800     UserLeave();
5801     END_CLEANUP;
5802 }
5803 
5804 /*
5805  * @implemented
5806  */
5807 BOOL FASTCALL UserDestroyMenu(HMENU hMenu)
5808 {
5809    PMENU Menu;
5810    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
5811 
5812    if(!(Menu = UserGetMenuObject(hMenu)))
5813    {
5814       return FALSE;
5815    }
5816 
5817    if (Menu->head.rpdesk != pti->rpdesk)
5818    {
5819       EngSetLastError(ERROR_ACCESS_DENIED);
5820       return FALSE;
5821    }
5822    return IntDestroyMenuObject(Menu, FALSE);
5823 }
5824 
5825 /*
5826  * @implemented
5827  */
5828 BOOL APIENTRY
5829 NtUserDestroyMenu(
5830    HMENU hMenu)
5831 {
5832    PMENU Menu;
5833    DECLARE_RETURN(BOOL);
5834 
5835    TRACE("Enter NtUserDestroyMenu\n");
5836    UserEnterExclusive();
5837 
5838    if(!(Menu = UserGetMenuObject(hMenu)))
5839    {
5840       RETURN( FALSE);
5841    }
5842    if (Menu->head.rpdesk != gptiCurrent->rpdesk)
5843    {
5844       EngSetLastError(ERROR_ACCESS_DENIED);
5845       RETURN( FALSE);
5846    }
5847    RETURN( IntDestroyMenuObject(Menu, TRUE));
5848 
5849 CLEANUP:
5850    TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_);
5851    UserLeave();
5852    END_CLEANUP;
5853 }
5854 
5855 /*
5856  * @implemented
5857  */
5858 UINT APIENTRY
5859 NtUserEnableMenuItem(
5860    HMENU hMenu,
5861    UINT uIDEnableItem,
5862    UINT uEnable)
5863 {
5864    PMENU Menu;
5865    DECLARE_RETURN(UINT);
5866 
5867    TRACE("Enter NtUserEnableMenuItem\n");
5868    UserEnterExclusive();
5869 
5870    if(!(Menu = UserGetMenuObject(hMenu)))
5871    {
5872       RETURN(-1);
5873    }
5874 
5875    RETURN( IntEnableMenuItem(Menu, uIDEnableItem, uEnable));
5876 
5877 CLEANUP:
5878    TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_);
5879    UserLeave();
5880    END_CLEANUP;
5881 }
5882 
5883 /*
5884  * @implemented
5885  */
5886 BOOL APIENTRY
5887 NtUserEndMenu(VOID)
5888 {
5889    //PWND pWnd;
5890    TRACE("Enter NtUserEndMenu\n");
5891    UserEnterExclusive();
5892  /*  if ( gptiCurrent->pMenuState &&
5893         gptiCurrent->pMenuState->pGlobalPopupMenu )
5894    {
5895        pWnd = IntGetMSWND(gptiCurrent->pMenuState);
5896        if (pWnd)
5897        {
5898           UserPostMessage( UserHMGetHandle(pWnd), WM_CANCELMODE, 0, 0);
5899        }
5900        else
5901           gptiCurrent->pMenuState->fInsideMenuLoop = FALSE;
5902    }*/
5903    if (fInsideMenuLoop && top_popup)
5904    {
5905       fInsideMenuLoop = FALSE;
5906       UserPostMessage( top_popup, WM_CANCELMODE, 0, 0);
5907    }
5908    UserLeave();
5909    TRACE("Leave NtUserEndMenu\n");
5910    return TRUE;
5911 }
5912 
5913 /*
5914  * @implemented
5915  */
5916 BOOL APIENTRY
5917 NtUserGetMenuBarInfo(
5918    HWND hwnd,
5919    LONG idObject,
5920    LONG idItem,
5921    PMENUBARINFO pmbi)
5922 {
5923    PWND pWnd;
5924    HMENU hMenu;
5925    MENUBARINFO kmbi;
5926    BOOL Ret;
5927    PPOPUPMENU pPopupMenu;
5928    USER_REFERENCE_ENTRY Ref;
5929    NTSTATUS Status = STATUS_SUCCESS;
5930    PMENU Menu = NULL;
5931    DECLARE_RETURN(BOOL);
5932 
5933    TRACE("Enter NtUserGetMenuBarInfo\n");
5934    UserEnterShared();
5935 
5936    if (!(pWnd = UserGetWindowObject(hwnd)))
5937    {
5938         EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
5939         RETURN(FALSE);
5940    }
5941 
5942    UserRefObjectCo(pWnd, &Ref);
5943 
5944    RECTL_vSetEmptyRect(&kmbi.rcBar);
5945    kmbi.hMenu = NULL;
5946    kmbi.hwndMenu = NULL;
5947    kmbi.fBarFocused = FALSE;
5948    kmbi.fFocused = FALSE;
5949 
5950    switch (idObject)
5951    {
5952     case OBJID_CLIENT:
5953         if (!pWnd->pcls->fnid)
5954             RETURN(FALSE);
5955         if (pWnd->pcls->fnid != FNID_MENU)
5956         {
5957             WARN("called on invalid window: %u\n", pWnd->pcls->fnid);
5958             EngSetLastError(ERROR_INVALID_MENU_HANDLE);
5959             RETURN(FALSE);
5960         }
5961         // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
5962         hMenu = (HMENU)co_IntSendMessage(hwnd, MN_GETHMENU, 0, 0);
5963         pPopupMenu = ((PMENUWND)pWnd)->ppopupmenu;
5964         if (pPopupMenu && pPopupMenu->spmenu)
5965         {
5966            if (UserHMGetHandle(pPopupMenu->spmenu) != hMenu)
5967            {
5968               ERR("Window Pop Up hMenu %p not the same as Get hMenu %p!\n",pPopupMenu->spmenu->head.h,hMenu);
5969            }
5970         }
5971         break;
5972     case OBJID_MENU:
5973         if (pWnd->style & WS_CHILD) RETURN(FALSE);
5974         hMenu = UlongToHandle(pWnd->IDMenu);
5975         TRACE("GMBI: OBJID_MENU hMenu %p\n",hMenu);
5976         break;
5977     case OBJID_SYSMENU:
5978         if (!(pWnd->style & WS_SYSMENU)) RETURN(FALSE);
5979         Menu = IntGetSystemMenu(pWnd, FALSE);
5980         hMenu = UserHMGetHandle(Menu);
5981         break;
5982     default:
5983         RETURN(FALSE);
5984    }
5985 
5986    if (!hMenu)
5987       RETURN(FALSE);
5988 
5989    _SEH2_TRY
5990    {
5991        ProbeForRead(pmbi, sizeof(MENUBARINFO), 1);
5992        kmbi.cbSize = pmbi->cbSize;
5993    }
5994    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5995    {
5996        kmbi.cbSize = 0;
5997    }
5998    _SEH2_END
5999 
6000    if (kmbi.cbSize != sizeof(MENUBARINFO))
6001    {
6002        EngSetLastError(ERROR_INVALID_PARAMETER);
6003        RETURN(FALSE);
6004    }
6005 
6006    if (!Menu) Menu = UserGetMenuObject(hMenu);
6007    if (!Menu)
6008        RETURN(FALSE);
6009 
6010    if ((idItem < 0) || ((ULONG)idItem > Menu->cItems))
6011        RETURN(FALSE);
6012 
6013    if (idItem == 0)
6014    {
6015       Ret = IntGetMenuItemRect(pWnd, Menu, 0, &kmbi.rcBar);
6016       kmbi.rcBar.right = kmbi.rcBar.left + Menu->cxMenu;
6017       kmbi.rcBar.bottom = kmbi.rcBar.top + Menu->cyMenu;
6018       TRACE("idItem a 0 %d\n",Ret);
6019    }
6020    else
6021    {
6022       Ret = IntGetMenuItemRect(pWnd, Menu, idItem-1, &kmbi.rcBar);
6023       TRACE("idItem b %d %d\n", idItem-1, Ret);
6024    }
6025 
6026    kmbi.hMenu = hMenu;
6027    kmbi.fBarFocused = top_popup_hmenu == hMenu;
6028    TRACE("GMBI: top p hm %p hMenu %p\n",top_popup_hmenu, hMenu);
6029    if (idItem)
6030    {
6031        kmbi.fFocused = Menu->iItem == idItem-1;
6032        if (kmbi.fFocused && (Menu->rgItems[idItem - 1].spSubMenu))
6033        {
6034           kmbi.hwndMenu = Menu->rgItems[idItem - 1].spSubMenu->hWnd;
6035        }
6036    }
6037    else
6038    {
6039        kmbi.fFocused = kmbi.fBarFocused;
6040    }
6041 
6042    _SEH2_TRY
6043    {
6044       ProbeForWrite(pmbi, sizeof(MENUBARINFO), 1);
6045       RtlCopyMemory(pmbi, &kmbi, sizeof(MENUBARINFO));
6046    }
6047    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6048    {
6049       Status = _SEH2_GetExceptionCode();
6050    }
6051    _SEH2_END
6052 
6053    if (!NT_SUCCESS(Status))
6054    {
6055       SetLastNtError(Status);
6056       RETURN(FALSE);
6057    }
6058 
6059    RETURN(TRUE);
6060 
6061 CLEANUP:
6062    if (pWnd) UserDerefObjectCo(pWnd);
6063    TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_);
6064    UserLeave();
6065    END_CLEANUP;
6066 }
6067 
6068 /*
6069  * @implemented
6070  */
6071 UINT APIENTRY
6072 NtUserGetMenuIndex(
6073    HMENU hMenu,
6074    HMENU hSubMenu)
6075 {
6076    PMENU Menu, SubMenu;
6077    PITEM MenuItem;
6078    UINT i;
6079    DECLARE_RETURN(UINT);
6080 
6081    TRACE("Enter NtUserGetMenuIndex\n");
6082    UserEnterShared();
6083 
6084    if ( !(Menu = UserGetMenuObject(hMenu)) ||
6085         !(SubMenu = UserGetMenuObject(hSubMenu)) )
6086       RETURN(0xFFFFFFFF);
6087 
6088    MenuItem = Menu->rgItems;
6089    for (i = 0; i < Menu->cItems; i++, MenuItem++)
6090    {
6091        if (MenuItem->spSubMenu == SubMenu)
6092           RETURN(MenuItem->wID);
6093    }
6094    RETURN(0xFFFFFFFF);
6095 
6096 CLEANUP:
6097    TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_);
6098    UserLeave();
6099    END_CLEANUP;
6100 }
6101 
6102 /*
6103  * @implemented
6104  */
6105 BOOL APIENTRY
6106 NtUserGetMenuItemRect(
6107    HWND hWnd,
6108    HMENU hMenu,
6109    UINT uItem,
6110    PRECTL lprcItem)
6111 {
6112    PWND ReferenceWnd;
6113    LONG XMove, YMove;
6114    RECTL Rect;
6115    PMENU Menu;
6116    PITEM MenuItem;
6117    NTSTATUS Status = STATUS_SUCCESS;
6118    DECLARE_RETURN(BOOL);
6119 
6120    TRACE("Enter NtUserGetMenuItemRect\n");
6121    UserEnterShared();
6122 
6123    if (!(Menu = UserGetMenuObject(hMenu)))
6124    {
6125       RETURN(FALSE);
6126    }
6127 
6128    if ((MenuItem = MENU_FindItem (&Menu, &uItem, MF_BYPOSITION)))
6129    {
6130       Rect.left   = MenuItem->xItem;
6131       Rect.top    = MenuItem->yItem;
6132       Rect.right  = MenuItem->cxItem; // Do this for now......
6133       Rect.bottom = MenuItem->cyItem;
6134    }
6135    else
6136       RETURN(FALSE);
6137 
6138    if(!hWnd)
6139    {
6140        hWnd = Menu->hWnd;
6141    }
6142 
6143    if (lprcItem == NULL) RETURN( FALSE);
6144 
6145    if (!(ReferenceWnd = UserGetWindowObject(hWnd))) RETURN( FALSE);
6146 
6147    if (Menu->fFlags & MNF_POPUP)
6148    {
6149      XMove = ReferenceWnd->rcClient.left;
6150      YMove = ReferenceWnd->rcClient.top;
6151    }
6152    else
6153    {
6154      XMove = ReferenceWnd->rcWindow.left;
6155      YMove = ReferenceWnd->rcWindow.top;
6156    }
6157 
6158    Rect.left   += XMove;
6159    Rect.top    += YMove;
6160    Rect.right  += XMove;
6161    Rect.bottom += YMove;
6162 
6163    _SEH2_TRY
6164    {
6165       RtlCopyMemory(lprcItem, &Rect, sizeof(RECTL));
6166    }
6167    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6168    {
6169       Status = _SEH2_GetExceptionCode();
6170    }
6171    _SEH2_END
6172 
6173    if (!NT_SUCCESS(Status))
6174    {
6175       SetLastNtError(Status);
6176       RETURN(FALSE);
6177    }
6178    RETURN(TRUE);
6179 
6180 CLEANUP:
6181    TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_);
6182    UserLeave();
6183    END_CLEANUP;
6184 }
6185 
6186 /*
6187  * @implemented
6188  */
6189 BOOL APIENTRY
6190 NtUserHiliteMenuItem(
6191    HWND hWnd,
6192    HMENU hMenu,
6193    UINT uItemHilite,
6194    UINT uHilite)
6195 {
6196    PMENU Menu;
6197    PWND Window;
6198    DECLARE_RETURN(BOOLEAN);
6199 
6200    TRACE("Enter NtUserHiliteMenuItem\n");
6201    UserEnterExclusive();
6202 
6203    if(!(Window = UserGetWindowObject(hWnd)))
6204    {
6205       EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
6206       RETURN(FALSE);
6207    }
6208 
6209    if(!(Menu = UserGetMenuObject(hMenu)))
6210    {
6211       EngSetLastError(ERROR_INVALID_MENU_HANDLE);
6212       RETURN(FALSE);
6213    }
6214 
6215    RETURN( IntHiliteMenuItem(Window, Menu, uItemHilite, uHilite));
6216 
6217 CLEANUP:
6218    TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_);
6219    UserLeave();
6220    END_CLEANUP;
6221 }
6222 
6223 /*
6224  * @implemented
6225  */
6226 DWORD
6227 APIENTRY
6228 NtUserDrawMenuBarTemp(
6229    HWND hWnd,
6230    HDC hDC,
6231    PRECT pRect,
6232    HMENU hMenu,
6233    HFONT hFont)
6234 {
6235    PMENU Menu;
6236    PWND Window;
6237    RECT Rect;
6238    NTSTATUS Status = STATUS_SUCCESS;
6239    DECLARE_RETURN(DWORD);
6240 
6241    ERR("Enter NtUserDrawMenuBarTemp\n");
6242    UserEnterExclusive();
6243 
6244    if(!(Window = UserGetWindowObject(hWnd)))
6245    {
6246       EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
6247       RETURN(0);
6248    }
6249 
6250    if(!(Menu = UserGetMenuObject(hMenu)))
6251    {
6252       EngSetLastError(ERROR_INVALID_MENU_HANDLE);
6253       RETURN(0);
6254    }
6255 
6256    _SEH2_TRY
6257    {
6258       ProbeForRead(pRect, sizeof(RECT), sizeof(ULONG));
6259       RtlCopyMemory(&Rect, pRect, sizeof(RECT));
6260    }
6261    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6262    {
6263       Status = _SEH2_GetExceptionCode();
6264    }
6265    _SEH2_END;
6266 
6267    if (Status != STATUS_SUCCESS)
6268    {
6269       SetLastNtError(Status);
6270       RETURN(0);
6271    }
6272 
6273    RETURN( IntDrawMenuBarTemp(Window, hDC, &Rect, Menu, hFont));
6274 
6275 CLEANUP:
6276    ERR("Leave NtUserDrawMenuBarTemp, ret=%u\n",_ret_);
6277    UserLeave();
6278    END_CLEANUP;
6279 }
6280 
6281 /*
6282  * @implemented
6283  */
6284 int APIENTRY
6285 NtUserMenuItemFromPoint(
6286    HWND hWnd,
6287    HMENU hMenu,
6288    DWORD X,
6289    DWORD Y)
6290 {
6291    PMENU Menu;
6292    PWND Window = NULL;
6293    PITEM mi;
6294    ULONG i;
6295    DECLARE_RETURN(int);
6296 
6297    TRACE("Enter NtUserMenuItemFromPoint\n");
6298    UserEnterExclusive();
6299 
6300    if (!(Menu = UserGetMenuObject(hMenu)))
6301    {
6302       RETURN( -1);
6303    }
6304 
6305    if (!(Window = UserGetWindowObject(Menu->hWnd)))
6306    {
6307       RETURN( -1);
6308    }
6309 
6310    X -= Window->rcWindow.left;
6311    Y -= Window->rcWindow.top;
6312 
6313    mi = Menu->rgItems;
6314    for (i = 0; i < Menu->cItems; i++, mi++)
6315    {
6316       RECTL Rect;
6317 
6318       Rect.left   = mi->xItem;
6319       Rect.top    = mi->yItem;
6320       Rect.right  = mi->cxItem;
6321       Rect.bottom = mi->cyItem;
6322 
6323       MENU_AdjustMenuItemRect(Menu, &Rect);
6324 
6325       if (RECTL_bPointInRect(&Rect, X, Y))
6326       {
6327          break;
6328       }
6329    }
6330 
6331    RETURN( (mi ? i : NO_SELECTED_ITEM));
6332 
6333 CLEANUP:
6334    TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_);
6335    UserLeave();
6336    END_CLEANUP;
6337 }
6338 
6339 
6340 DWORD
6341 APIENTRY
6342 NtUserPaintMenuBar(
6343     HWND hWnd,
6344     HDC hDC,
6345     ULONG leftBorder,
6346     ULONG rightBorder,
6347     ULONG top,
6348     BOOL bActive)
6349 {
6350    PWND Window;
6351    RECT Rect;
6352    DWORD ret;
6353 
6354    UserEnterExclusive();
6355 
6356    if(!(Window = UserGetWindowObject(hWnd)))
6357    {
6358       EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
6359       UserLeave();
6360       return 0;
6361    }
6362 
6363    Rect.left = leftBorder;
6364    Rect.right = Window->rcWindow.right - Window->rcWindow.left - rightBorder;
6365    Rect.top = top;
6366    Rect.bottom = 0;
6367 
6368    ret = MENU_DrawMenuBar(hDC, &Rect, Window, FALSE);
6369 
6370    UserLeave();
6371 
6372    return ret;
6373 }
6374 
6375 /*
6376  * @implemented
6377  */
6378 BOOL APIENTRY
6379 NtUserRemoveMenu(
6380    HMENU hMenu,
6381    UINT uPosition,
6382    UINT uFlags)
6383 {
6384    PMENU Menu;
6385    DECLARE_RETURN(BOOL);
6386 
6387    TRACE("Enter NtUserRemoveMenu\n");
6388    UserEnterExclusive();
6389 
6390    if(!(Menu = UserGetMenuObject(hMenu)))
6391    {
6392       RETURN( FALSE);
6393    }
6394 
6395    RETURN(IntRemoveMenuItem(Menu, uPosition, uFlags, FALSE));
6396 
6397 CLEANUP:
6398    TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_);
6399    UserLeave();
6400    END_CLEANUP;
6401 
6402 }
6403 
6404 /*
6405  * @implemented
6406  */
6407 BOOL APIENTRY
6408 NtUserSetMenu(
6409    HWND hWnd,
6410    HMENU Menu,
6411    BOOL Repaint)
6412 {
6413    PWND Window;
6414    BOOL Changed;
6415    DECLARE_RETURN(BOOL);
6416 
6417    TRACE("Enter NtUserSetMenu\n");
6418    UserEnterExclusive();
6419 
6420    if (!(Window = UserGetWindowObject(hWnd)))
6421    {
6422       RETURN( FALSE);
6423    }
6424 
6425    if (!IntSetMenu(Window, Menu, &Changed))
6426    {
6427       RETURN( FALSE);
6428    }
6429 
6430    // Not minimized and please repaint!!!
6431    if (!(Window->style & WS_MINIMIZE) && (Repaint || Changed))
6432    {
6433       USER_REFERENCE_ENTRY Ref;
6434       UserRefObjectCo(Window, &Ref);
6435       co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
6436       UserDerefObjectCo(Window);
6437    }
6438 
6439    RETURN( TRUE);
6440 
6441 CLEANUP:
6442    TRACE("Leave NtUserSetMenu, ret=%i\n",_ret_);
6443    UserLeave();
6444    END_CLEANUP;
6445 }
6446 
6447 /*
6448  * @implemented
6449  */
6450 BOOL APIENTRY
6451 NtUserSetMenuContextHelpId(
6452    HMENU hMenu,
6453    DWORD dwContextHelpId)
6454 {
6455    PMENU Menu;
6456    DECLARE_RETURN(BOOL);
6457 
6458    TRACE("Enter NtUserSetMenuContextHelpId\n");
6459    UserEnterExclusive();
6460 
6461    if(!(Menu = UserGetMenuObject(hMenu)))
6462    {
6463       RETURN( FALSE);
6464    }
6465 
6466    RETURN(IntSetMenuContextHelpId(Menu, dwContextHelpId));
6467 
6468 CLEANUP:
6469    TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_);
6470    UserLeave();
6471    END_CLEANUP;
6472 }
6473 
6474 /*
6475  * @implemented
6476  */
6477 BOOL APIENTRY
6478 NtUserSetMenuDefaultItem(
6479    HMENU hMenu,
6480    UINT uItem,
6481    UINT fByPos)
6482 {
6483    PMENU Menu;
6484    DECLARE_RETURN(BOOL);
6485 
6486    TRACE("Enter NtUserSetMenuDefaultItem\n");
6487    UserEnterExclusive();
6488 
6489    if(!(Menu = UserGetMenuObject(hMenu)))
6490    {
6491       RETURN( FALSE);
6492    }
6493 
6494    RETURN( UserSetMenuDefaultItem(Menu, uItem, fByPos));
6495 
6496 CLEANUP:
6497    TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_);
6498    UserLeave();
6499    END_CLEANUP;
6500 }
6501 
6502 /*
6503  * @implemented
6504  */
6505 BOOL APIENTRY
6506 NtUserSetMenuFlagRtoL(
6507    HMENU hMenu)
6508 {
6509    PMENU Menu;
6510    DECLARE_RETURN(BOOL);
6511 
6512    TRACE("Enter NtUserSetMenuFlagRtoL\n");
6513    UserEnterExclusive();
6514 
6515    if(!(Menu = UserGetMenuObject(hMenu)))
6516    {
6517       RETURN( FALSE);
6518    }
6519 
6520    RETURN(IntSetMenuFlagRtoL(Menu));
6521 
6522 CLEANUP:
6523    TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_);
6524    UserLeave();
6525    END_CLEANUP;
6526 }
6527 
6528 /*
6529  * @implemented
6530  */
6531 BOOL APIENTRY
6532 NtUserThunkedMenuInfo(
6533    HMENU hMenu,
6534    LPCMENUINFO lpcmi)
6535 {
6536    PMENU Menu;
6537    DECLARE_RETURN(BOOL);
6538 
6539    TRACE("Enter NtUserThunkedMenuInfo\n");
6540    UserEnterExclusive();
6541 
6542    if (!(Menu = UserGetMenuObject(hMenu)))
6543    {
6544       RETURN(FALSE);
6545    }
6546 
6547    RETURN(UserMenuInfo(Menu, (PROSMENUINFO)lpcmi, TRUE));
6548 
6549 CLEANUP:
6550    TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_);
6551    UserLeave();
6552    END_CLEANUP;
6553 }
6554 
6555 /*
6556  * @implemented
6557  */
6558 BOOL APIENTRY
6559 NtUserThunkedMenuItemInfo(
6560    HMENU hMenu,
6561    UINT uItem,
6562    BOOL fByPosition,
6563    BOOL bInsert,
6564    LPMENUITEMINFOW lpmii,
6565    PUNICODE_STRING lpszCaption)
6566 {
6567    PMENU Menu;
6568    NTSTATUS Status;
6569    UNICODE_STRING lstrCaption;
6570    DECLARE_RETURN(BOOL);
6571 
6572    TRACE("Enter NtUserThunkedMenuItemInfo\n");
6573    UserEnterExclusive();
6574 
6575    /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
6576       if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo()   */
6577 
6578    RtlInitEmptyUnicodeString(&lstrCaption, NULL, 0);
6579 
6580    if (!(Menu = UserGetMenuObject(hMenu)))
6581    {
6582       RETURN(FALSE);
6583    }
6584 
6585    /* Check if we got a Caption */
6586    if (lpszCaption && lpszCaption->Buffer)
6587    {
6588       /* Copy the string to kernel mode */
6589       Status = ProbeAndCaptureUnicodeString( &lstrCaption,
6590                                                  UserMode,
6591                                               lpszCaption);
6592       if (!NT_SUCCESS(Status))
6593       {
6594          ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status);
6595          SetLastNtError(Status);
6596          RETURN(FALSE);
6597       }
6598    }
6599 
6600    if (bInsert) RETURN( UserInsertMenuItem(Menu, uItem, fByPosition, lpmii, &lstrCaption));
6601 
6602    RETURN( UserMenuItemInfo(Menu, uItem, fByPosition, (PROSMENUITEMINFO)lpmii, TRUE, &lstrCaption));
6603 
6604 CLEANUP:
6605    if (lstrCaption.Buffer)
6606    {
6607       ReleaseCapturedUnicodeString(&lstrCaption, UserMode);
6608    }
6609 
6610    TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_);
6611    UserLeave();
6612    END_CLEANUP;
6613 }
6614 
6615 /*
6616  * @implemented
6617  */
6618 BOOL APIENTRY
6619 NtUserTrackPopupMenuEx(
6620    HMENU hMenu,
6621    UINT fuFlags,
6622    int x,
6623    int y,
6624    HWND hWnd,
6625    LPTPMPARAMS lptpm)
6626 {
6627    PMENU menu;
6628    PWND pWnd;
6629    TPMPARAMS tpm;
6630    BOOL Ret = FALSE;
6631    USER_REFERENCE_ENTRY Ref;
6632 
6633    TRACE("Enter NtUserTrackPopupMenuEx\n");
6634    UserEnterExclusive();
6635    /* Parameter check */
6636    if (!(menu = UserGetMenuObject( hMenu )))
6637    {
6638       ERR("TPME : Invalid Menu handle.\n");
6639       EngSetLastError( ERROR_INVALID_MENU_HANDLE );
6640       goto Exit;
6641    }
6642 
6643    if (!(pWnd = UserGetWindowObject(hWnd)))
6644    {
6645       ERR("TPME : Invalid Window handle.\n");
6646       goto Exit;
6647    }
6648 
6649    if (lptpm)
6650    {
6651       _SEH2_TRY
6652       {
6653          ProbeForRead(lptpm, sizeof(TPMPARAMS), sizeof(ULONG));
6654          tpm = *lptpm;
6655       }
6656       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6657       {
6658          _SEH2_YIELD(goto Exit);
6659       }
6660       _SEH2_END
6661    }
6662    UserRefObjectCo(pWnd, &Ref);
6663    Ret = IntTrackPopupMenuEx(menu, fuFlags, x, y, pWnd, lptpm ? &tpm : NULL);
6664    UserDerefObjectCo(pWnd);
6665 
6666 Exit:
6667    TRACE("Leave NtUserTrackPopupMenuEx, ret=%i\n",Ret);
6668    UserLeave();
6669    return Ret;
6670 }
6671 
6672 /* EOF */
6673