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