xref: /reactos/win32ss/user/ntuser/menu.c (revision ac0bcf4a)
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         /* Re-orient the menu around the x-axis */
3005         x += width;
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             y -= height;
3027     }
3028 
3029     if (pExclude)
3030     {
3031         RECT Cleaned;
3032 
3033         if (RECTL_bIntersectRect(&Cleaned, pExclude, &monitor->rcMonitor) &&
3034             RECTL_Intersect(&Cleaned, x, y, width, height))
3035         {
3036             UINT flag_mods[] = {
3037                 0,                                                  /* First try the 'normal' way */
3038                 TPM_BOTTOMALIGN | TPM_RIGHTALIGN,                   /* Then try the opposite side */
3039                 TPM_VERTICAL,                                       /* Then swap horizontal / vertical */
3040                 TPM_BOTTOMALIGN | TPM_RIGHTALIGN | TPM_VERTICAL,    /* Then the other side again (still swapped hor/ver) */
3041             };
3042 
3043             UINT n;
3044             for (n = 0; n < RTL_NUMBER_OF(flag_mods); ++n)
3045             {
3046                 INT tx = x;
3047                 INT ty = y;
3048 
3049                 /* Try to move a bit around */
3050                 if (MENU_MoveRect(flags ^ flag_mods[n], &tx, &ty, width, height, &Cleaned, monitor) &&
3051                     !RECTL_Intersect(&Cleaned, tx, ty, width, height))
3052                 {
3053                     x = tx;
3054                     y = ty;
3055                     break;
3056                 }
3057             }
3058             /* If none worked, we go with the original x/y */
3059         }
3060     }
3061 
3062 #if SHOW_DEBUGRECT
3063     {
3064         RECT rr = {x, y, x + width, y + height};
3065         DebugRect(&rr, RGB(0, 255, 0));
3066     }
3067 #endif
3068 
3069     pWnd = ValidateHwndNoErr( menu->hWnd );
3070 
3071     if (!pWnd)
3072     {
3073        ERR("menu->hWnd bad hwnd %p\n",menu->hWnd);
3074        return FALSE;
3075     }
3076 
3077     if (!top_popup) {
3078         top_popup = menu->hWnd;
3079         top_popup_hmenu = UserHMGetHandle(menu);
3080     }
3081 
3082     /* Display the window */
3083     UserRefObjectCo(pWnd, &Ref);
3084     co_WinPosSetWindowPos( pWnd, HWND_TOPMOST, x, y, width, height, SWP_SHOWWINDOW | SWP_NOACTIVATE);
3085 
3086     co_IntUpdateWindows(pWnd, RDW_ALLCHILDREN, FALSE);
3087 
3088     IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, pWnd, OBJID_CLIENT, CHILDID_SELF, 0);
3089     UserDerefObjectCo(pWnd);
3090 
3091     return TRUE;
3092 }
3093 
3094 /***********************************************************************
3095  *           MENU_EnsureMenuItemVisible
3096  */
3097 void MENU_EnsureMenuItemVisible(PMENU lppop, UINT wIndex, HDC hdc)
3098 {
3099     USER_REFERENCE_ENTRY Ref;
3100     if (lppop->dwArrowsOn)
3101     {
3102         ITEM *item = &lppop->rgItems[wIndex];
3103         UINT nMaxHeight = MENU_GetMaxPopupHeight(lppop);
3104         UINT nOldPos = lppop->iTop;
3105         RECT rc;
3106         UINT arrow_bitmap_height;
3107         PWND pWnd = ValidateHwndNoErr(lppop->hWnd);
3108 
3109         IntGetClientRect(pWnd, &rc);
3110 
3111         arrow_bitmap_height = gpsi->oembmi[OBI_DNARROW].cy;
3112 
3113         rc.top += arrow_bitmap_height;
3114         rc.bottom -= arrow_bitmap_height;
3115 
3116         nMaxHeight -= UserGetSystemMetrics(SM_CYBORDER) + 2 * arrow_bitmap_height;
3117         UserRefObjectCo(pWnd, &Ref);
3118         if (item->cyItem > lppop->iTop + nMaxHeight)
3119         {
3120             lppop->iTop = item->cyItem - nMaxHeight;
3121             IntScrollWindow(pWnd, 0, nOldPos - lppop->iTop, &rc, &rc);
3122             MENU_DrawScrollArrows(lppop, hdc);
3123             //ERR("Scroll Down iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
3124         }
3125         else if (item->yItem < lppop->iTop)
3126         {
3127             lppop->iTop = item->yItem;
3128             IntScrollWindow(pWnd, 0, nOldPos - lppop->iTop, &rc, &rc);
3129             MENU_DrawScrollArrows(lppop, hdc);
3130             //ERR("Scroll Up   iTop %d iMaxTop %d nMaxHeight %d\n",lppop->iTop,lppop->iMaxTop,nMaxHeight);
3131         }
3132         UserDerefObjectCo(pWnd);
3133     }
3134 }
3135 
3136 /***********************************************************************
3137  *           MenuSelectItem
3138  */
3139 static void FASTCALL MENU_SelectItem(PWND pwndOwner, PMENU menu, UINT wIndex,
3140                                     BOOL sendMenuSelect, PMENU topmenu)
3141 {
3142     HDC hdc;
3143     PWND pWnd;
3144 
3145     TRACE("M_SI: owner=%p menu=%p index=0x%04x select=0x%04x\n", pwndOwner, menu, wIndex, sendMenuSelect);
3146 
3147     if (!menu || !menu->cItems) return;
3148 
3149     pWnd = ValidateHwndNoErr(menu->hWnd);
3150 
3151     if (!pWnd) return;
3152 
3153     if (menu->iItem == wIndex) return;
3154 
3155     if (menu->fFlags & MNF_POPUP)
3156        hdc = UserGetDCEx(pWnd, 0, DCX_USESTYLE);
3157     else
3158        hdc = UserGetDCEx(pWnd, 0, DCX_CACHE | DCX_WINDOW);
3159 
3160     if (!top_popup) {
3161         top_popup = menu->hWnd;                  //pPopupMenu->spwndActivePopup or
3162                                                  //pPopupMenu->fIsTrackPopup set pPopupMenu->spwndPopupMenu;
3163         top_popup_hmenu = UserHMGetHandle(menu); //pPopupMenu->spmenu
3164     }
3165 
3166     NtGdiSelectFont( hdc, ghMenuFont );
3167 
3168      /* Clear previous highlighted item */
3169     if (menu->iItem != NO_SELECTED_ITEM)
3170     {
3171         menu->rgItems[menu->iItem].fState &= ~(MF_HILITE|MF_MOUSESELECT);
3172         MENU_DrawMenuItem(pWnd, menu, pwndOwner, hdc, &menu->rgItems[menu->iItem],
3173                        menu->cyMenu, !(menu->fFlags & MNF_POPUP),
3174                        ODA_SELECT);
3175     }
3176 
3177     /* Highlight new item (if any) */
3178     menu->iItem = wIndex;
3179     if (menu->iItem != NO_SELECTED_ITEM)
3180     {
3181         if (!(menu->rgItems[wIndex].fType & MF_SEPARATOR))
3182         {
3183              menu->rgItems[wIndex].fState |= MF_HILITE;
3184              MENU_EnsureMenuItemVisible(menu, wIndex, hdc);
3185              MENU_DrawMenuItem(pWnd, menu, pwndOwner, hdc,
3186                                &menu->rgItems[wIndex], menu->cyMenu, !(menu->fFlags & MNF_POPUP), ODA_SELECT);
3187         }
3188         if (sendMenuSelect)
3189         {
3190            ITEM *ip = &menu->rgItems[menu->iItem];
3191            WPARAM wParam = MAKEWPARAM( ip->spSubMenu ? wIndex : ip->wID,
3192                                        ip->fType | ip->fState |
3193                                       (ip->spSubMenu ? MF_POPUP : 0) |
3194                                       (menu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0 ) );
3195 
3196            co_IntSendMessage(UserHMGetHandle(pwndOwner), WM_MENUSELECT, wParam, (LPARAM) UserHMGetHandle(menu));
3197         }
3198     }
3199     else if (sendMenuSelect)
3200     {
3201         if (topmenu)
3202         {
3203             int pos;
3204             pos = MENU_FindSubMenu(&topmenu, menu);
3205             if (pos != NO_SELECTED_ITEM)
3206             {
3207                ITEM *ip = &topmenu->rgItems[pos];
3208                WPARAM wParam = MAKEWPARAM( Pos, ip->fType | ip->fState |
3209                                            (ip->spSubMenu ? MF_POPUP : 0) |
3210                                            (topmenu->fFlags & MNF_SYSMENU ? MF_SYSMENU : 0 ) );
3211 
3212                co_IntSendMessage(UserHMGetHandle(pwndOwner), WM_MENUSELECT, wParam, (LPARAM) UserHMGetHandle(topmenu));
3213             }
3214         }
3215     }
3216     UserReleaseDC(pWnd, hdc, FALSE);
3217 }
3218 
3219 /***********************************************************************
3220  *           MenuMoveSelection
3221  *
3222  * Moves currently selected item according to the Offset parameter.
3223  * If there is no selection then it should select the last item if
3224  * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
3225  */
3226 static void FASTCALL MENU_MoveSelection(PWND pwndOwner, PMENU menu, INT offset)
3227 {
3228     INT i;
3229 
3230     TRACE("pwnd=%x menu=%x off=0x%04x\n", pwndOwner, menu, offset);
3231 
3232     if ((!menu) || (!menu->rgItems)) return;
3233 
3234     if ( menu->iItem != NO_SELECTED_ITEM )
3235     {
3236 	if ( menu->cItems == 1 )
3237 	   return;
3238 	else
3239 	for (i = menu->iItem + offset ; i >= 0 && i < menu->cItems
3240 					    ; i += offset)
3241 	    if (!(menu->rgItems[i].fType & MF_SEPARATOR))
3242 	    {
3243 		MENU_SelectItem( pwndOwner, menu, i, TRUE, 0 );
3244 		return;
3245 	    }
3246     }
3247 
3248     for ( i = (offset > 0) ? 0 : menu->cItems - 1;
3249 		  i >= 0 && i < menu->cItems ; i += offset)
3250 	if (!(menu->rgItems[i].fType & MF_SEPARATOR))
3251 	{
3252 	    MENU_SelectItem( pwndOwner, menu, i, TRUE, 0 );
3253 	    return;
3254 	}
3255 }
3256 
3257 /***********************************************************************
3258  *           MenuHideSubPopups
3259  *
3260  * Hide the sub-popup menus of this menu.
3261  */
3262 static void FASTCALL MENU_HideSubPopups(PWND pWndOwner, PMENU Menu,
3263                                BOOL SendMenuSelect, UINT wFlags)
3264 {
3265   TRACE("owner=%x menu=%x 0x%04x\n", pWndOwner, Menu, SendMenuSelect);
3266 
3267   if ( Menu && top_popup )
3268   {
3269       PITEM Item;
3270 
3271       if (Menu->iItem != NO_SELECTED_ITEM)
3272       {
3273          Item = &Menu->rgItems[Menu->iItem];
3274          if (!(Item->spSubMenu) ||
3275              !(Item->fState & MF_MOUSESELECT)) return;
3276          Item->fState &= ~MF_MOUSESELECT;
3277       }
3278       else
3279          return;
3280 
3281       if (Item->spSubMenu)
3282       {
3283           PWND pWnd;
3284           if (!VerifyMenu(Item->spSubMenu)) return;
3285           MENU_HideSubPopups(pWndOwner, Item->spSubMenu, FALSE, wFlags);
3286           MENU_SelectItem(pWndOwner, Item->spSubMenu, NO_SELECTED_ITEM, SendMenuSelect, NULL);
3287           TRACE("M_HSP top p hm %p  pWndOwner IDMenu %p\n",top_popup_hmenu,pWndOwner->IDMenu);
3288           pWnd = ValidateHwndNoErr(Item->spSubMenu->hWnd);
3289           if (pWnd != NULL)
3290           {
3291               co_UserDestroyWindow(pWnd);
3292           }
3293 
3294           /* Native returns handle to destroyed window */
3295           if (!(wFlags & TPM_NONOTIFY))
3296           {
3297              co_IntSendMessage( UserHMGetHandle(pWndOwner), WM_UNINITMENUPOPUP, (WPARAM)UserHMGetHandle(Item->spSubMenu),
3298                                  MAKELPARAM(0, IS_SYSTEM_MENU(Item->spSubMenu) ? MF_SYSMENU : 0));
3299           }
3300           ////
3301           // Call WM_UNINITMENUPOPUP FIRST before destroy!!
3302           // Fixes todo_wine User32 test menu.c line 2239 GetMenuBarInfo callback....
3303           //
3304           Item->spSubMenu->hWnd = NULL;
3305           ////
3306       }
3307   }
3308 }
3309 
3310 /***********************************************************************
3311  *           MenuShowSubPopup
3312  *
3313  * Display the sub-menu of the selected item of this menu.
3314  * Return the handle of the submenu, or menu if no submenu to display.
3315  */
3316 static PMENU FASTCALL MENU_ShowSubPopup(PWND WndOwner, PMENU Menu, BOOL SelectFirst, UINT Flags)
3317 {
3318   RECT Rect, ParentRect;
3319   ITEM *Item;
3320   HDC Dc;
3321   PWND pWnd;
3322 
3323   TRACE("owner=%x menu=%p 0x%04x\n", WndOwner, Menu, SelectFirst);
3324 
3325   if (!Menu) return Menu;
3326 
3327   if (Menu->iItem == NO_SELECTED_ITEM) return Menu;
3328 
3329   Item = &Menu->rgItems[Menu->iItem];
3330   if (!(Item->spSubMenu) || (Item->fState & (MF_GRAYED | MF_DISABLED)))
3331       return Menu;
3332 
3333   /* message must be sent before using item,
3334      because nearly everything may be changed by the application ! */
3335 
3336   /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
3337   if (!(Flags & TPM_NONOTIFY))
3338   {
3339       co_IntSendMessage(UserHMGetHandle(WndOwner), WM_INITMENUPOPUP,
3340                         (WPARAM) UserHMGetHandle(Item->spSubMenu),
3341                          MAKELPARAM(Menu->iItem, IS_SYSTEM_MENU(Menu)));
3342   }
3343 
3344   Item = &Menu->rgItems[Menu->iItem];
3345   //Rect = ItemInfo.Rect;
3346   Rect.left   = Item->xItem;
3347   Rect.top    = Item->yItem;
3348   Rect.right  = Item->cxItem; // Do this for now......
3349   Rect.bottom = Item->cyItem;
3350 
3351   pWnd = ValidateHwndNoErr(Menu->hWnd);
3352 
3353   /* Grab the rect of our (entire) parent menu, so we can try to not overlap it */
3354   if (Menu->fFlags & MNF_POPUP)
3355   {
3356     if (!IntGetWindowRect(pWnd, &ParentRect))
3357     {
3358         ERR("No pWnd\n");
3359         ParentRect = Rect;
3360     }
3361 
3362     /* Ensure we can slightly overlap our parent */
3363     RECTL_vInflateRect(&ParentRect, -UserGetSystemMetrics(SM_CXEDGE) * 2, 0);
3364   }
3365   else
3366   {
3367     /* Inside the menu bar, we do not want to grab the entire window... */
3368     ParentRect = Rect;
3369     if (pWnd)
3370         RECTL_vOffsetRect(&ParentRect, pWnd->rcWindow.left, pWnd->rcWindow.top);
3371   }
3372 
3373   /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
3374   if (!(Item->fState & MF_HILITE))
3375   {
3376       if (Menu->fFlags & MNF_POPUP) Dc = UserGetDCEx(pWnd, NULL, DCX_USESTYLE);
3377       else Dc = UserGetDCEx(pWnd, 0, DCX_CACHE | DCX_WINDOW);
3378 
3379       NtGdiSelectFont(Dc, ghMenuFont);
3380 
3381       Item->fState |= MF_HILITE;
3382       MENU_DrawMenuItem(pWnd, Menu, WndOwner, Dc, Item, Menu->cyMenu,
3383                        !(Menu->fFlags & MNF_POPUP), ODA_DRAWENTIRE);
3384 
3385       UserReleaseDC(pWnd, Dc, FALSE);
3386   }
3387 
3388   if (!Item->yItem && !Item->xItem && !Item->cyItem && !Item->cxItem)
3389   {
3390       Item->xItem  = Rect.left;
3391       Item->yItem  = Rect.top;
3392       Item->cxItem = Rect.right; // Do this for now......
3393       Item->cyItem = Rect.bottom;
3394   }
3395   Item->fState |= MF_MOUSESELECT;
3396 
3397   if (IS_SYSTEM_MENU(Menu))
3398   {
3399       MENU_InitSysMenuPopup(Item->spSubMenu, pWnd->style, pWnd->pcls->style, HTSYSMENU);
3400 
3401       NC_GetSysPopupPos(pWnd, &Rect);
3402       /* Ensure we do not overlap this */
3403       ParentRect = Rect;
3404       if (Flags & TPM_LAYOUTRTL) Rect.left = Rect.right;
3405       Rect.top = Rect.bottom;
3406       Rect.right = UserGetSystemMetrics(SM_CXSIZE);
3407       Rect.bottom = UserGetSystemMetrics(SM_CYSIZE);
3408   }
3409   else
3410   {
3411       IntGetWindowRect(pWnd, &Rect);
3412       if (Menu->fFlags & MNF_POPUP)
3413       {
3414           RECT rc;
3415           rc.left   = Item->xItem;
3416           rc.top    = Item->yItem;
3417           rc.right  = Item->cxItem;
3418           rc.bottom = Item->cyItem;
3419 
3420           MENU_AdjustMenuItemRect(Menu, &rc);
3421 
3422           /* The first item in the popup menu has to be at the
3423              same y position as the focused menu item */
3424           if(Flags & TPM_LAYOUTRTL)
3425              Rect.left += UserGetSystemMetrics(SM_CXDLGFRAME);
3426           else
3427              Rect.left += rc.right - UserGetSystemMetrics(SM_CXDLGFRAME);
3428 
3429           Rect.top += rc.top;
3430       }
3431       else
3432       {
3433           if(Flags & TPM_LAYOUTRTL)
3434               Rect.left += Rect.right - Item->xItem; //ItemInfo.Rect.left;
3435           else
3436               Rect.left += Item->xItem; //ItemInfo.Rect.left;
3437           Rect.top += Item->cyItem; //ItemInfo.Rect.bottom;
3438           Rect.right  = Item->cxItem - Item->xItem; //ItemInfo.Rect.right - ItemInfo.Rect.left;
3439           Rect.bottom = Item->cyItem - Item->yItem; //ItemInfo.Rect.bottom - ItemInfo.Rect.top;
3440       }
3441   }
3442 
3443   /* Next menu does not need to be shown vertical anymore */
3444   if (Menu->fFlags & MNF_POPUP)
3445       Flags &= (~TPM_VERTICAL);
3446 
3447 
3448 
3449   /* use default alignment for submenus */
3450   Flags &= ~(TPM_CENTERALIGN | TPM_RIGHTALIGN | TPM_VCENTERALIGN | TPM_BOTTOMALIGN);
3451 
3452   MENU_InitPopup( WndOwner, Item->spSubMenu, Flags );
3453 
3454   MENU_ShowPopup( WndOwner, Item->spSubMenu, Menu->iItem, Flags,
3455                 Rect.left, Rect.top, &ParentRect);
3456   if (SelectFirst)
3457   {
3458       MENU_MoveSelection(WndOwner, Item->spSubMenu, ITEM_NEXT);
3459   }
3460   return Item->spSubMenu;
3461 }
3462 
3463 /***********************************************************************
3464  *           MenuExecFocusedItem
3465  *
3466  * Execute a menu item (for instance when user pressed Enter).
3467  * Return the wID of the executed item. Otherwise, -1 indicating
3468  * that no menu item was executed, -2 if a popup is shown;
3469  * Have to receive the flags for the TrackPopupMenu options to avoid
3470  * sending unwanted message.
3471  *
3472  */
3473 static INT FASTCALL MENU_ExecFocusedItem(MTRACKER *pmt, PMENU Menu, UINT Flags)
3474 {
3475   PITEM Item;
3476 
3477   TRACE("%p menu=%p\n", pmt, Menu);
3478 
3479   if (!Menu || !Menu->cItems || Menu->iItem == NO_SELECTED_ITEM)
3480   {
3481       return -1;
3482   }
3483 
3484   Item = &Menu->rgItems[Menu->iItem];
3485 
3486   TRACE("%p %08x %p\n", Menu, Item->wID, Item->spSubMenu);
3487 
3488   if (!(Item->spSubMenu))
3489   {
3490       if (!(Item->fState & (MF_GRAYED | MF_DISABLED)) && !(Item->fType & MF_SEPARATOR))
3491       {
3492           /* If TPM_RETURNCMD is set you return the id, but
3493             do not send a message to the owner */
3494           if (!(Flags & TPM_RETURNCMD))
3495           {
3496               if (Menu->fFlags & MNF_SYSMENU)
3497               {
3498                   UserPostMessage(UserHMGetHandle(pmt->OwnerWnd), WM_SYSCOMMAND, Item->wID,
3499                                MAKELPARAM((SHORT) pmt->Pt.x, (SHORT) pmt->Pt.y));
3500               }
3501               else
3502               {
3503                   DWORD dwStyle = ((Menu->fFlags & MNS_STYLE_MASK) | ( pmt->TopMenu ? (pmt->TopMenu->fFlags & MNS_STYLE_MASK) : 0) );
3504 
3505                   if (dwStyle & MNS_NOTIFYBYPOS)
3506                       UserPostMessage(UserHMGetHandle(pmt->OwnerWnd), WM_MENUCOMMAND, Menu->iItem, (LPARAM)UserHMGetHandle(Menu));
3507                   else
3508                       UserPostMessage(UserHMGetHandle(pmt->OwnerWnd), WM_COMMAND, Item->wID, 0);
3509               }
3510           }
3511           return Item->wID;
3512       }
3513   }
3514   else
3515   {
3516       pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, Menu, TRUE, Flags);
3517       return -2;
3518   }
3519 
3520   return -1;
3521 }
3522 
3523 /***********************************************************************
3524  *           MenuSwitchTracking
3525  *
3526  * Helper function for menu navigation routines.
3527  */
3528 static void FASTCALL MENU_SwitchTracking(MTRACKER* pmt, PMENU PtMenu, UINT Index, UINT wFlags)
3529 {
3530   TRACE("%x menu=%x 0x%04x\n", pmt, PtMenu, Index);
3531 
3532   if ( pmt->TopMenu != PtMenu &&
3533       !((PtMenu->fFlags | pmt->TopMenu->fFlags) & MNF_POPUP) )
3534   {
3535       /* both are top level menus (system and menu-bar) */
3536       MENU_HideSubPopups(pmt->OwnerWnd, pmt->TopMenu, FALSE, wFlags);
3537       MENU_SelectItem(pmt->OwnerWnd, pmt->TopMenu, NO_SELECTED_ITEM, FALSE, NULL);
3538       pmt->TopMenu = PtMenu;
3539   }
3540   else
3541   {
3542       MENU_HideSubPopups(pmt->OwnerWnd, PtMenu, FALSE, wFlags);
3543   }
3544 
3545   MENU_SelectItem(pmt->OwnerWnd, PtMenu, Index, TRUE, NULL);
3546 }
3547 
3548 /***********************************************************************
3549  *           MenuButtonDown
3550  *
3551  * Return TRUE if we can go on with menu tracking.
3552  */
3553 static BOOL FASTCALL MENU_ButtonDown(MTRACKER* pmt, PMENU PtMenu, UINT Flags)
3554 {
3555   TRACE("%x PtMenu=%p\n", pmt, PtMenu);
3556 
3557   if (PtMenu)
3558   {
3559       UINT id = 0;
3560       PITEM item;
3561 
3562       // Special check for the icon system menu
3563       if (IS_SYSTEM_MENU(PtMenu) && !(PtMenu->fFlags & MNF_POPUP))
3564       {
3565          item = PtMenu->rgItems;
3566       }
3567       else
3568       {
3569          item = MENU_FindItemByCoords( PtMenu, pmt->Pt, &id );
3570       }
3571 
3572       if (item)
3573       {
3574           if (PtMenu->iItem != id)
3575               MENU_SwitchTracking(pmt, PtMenu, id, Flags);
3576 
3577           /* If the popup menu is not already "popped" */
3578           if (!(item->fState & MF_MOUSESELECT))
3579           {
3580               pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, PtMenu, FALSE, Flags);
3581           }
3582 
3583           return TRUE;
3584       }
3585       /* Else the click was on the menu bar, finish the tracking */
3586   }
3587   return FALSE;
3588 }
3589 
3590 /***********************************************************************
3591  *           MenuButtonUp
3592  *
3593  * Return the value of MenuExecFocusedItem if
3594  * the selected item was not a popup. Else open the popup.
3595  * A -1 return value indicates that we go on with menu tracking.
3596  *
3597  */
3598 static INT FASTCALL MENU_ButtonUp(MTRACKER *pmt, PMENU PtMenu, UINT Flags)
3599 {
3600   TRACE("%p pmenu=%x\n", pmt, PtMenu);
3601 
3602   if (PtMenu)
3603   {
3604       UINT Id = 0;
3605       ITEM *item;
3606 
3607       // Special check for the icon system menu
3608       if (IS_SYSTEM_MENU(PtMenu) && !(PtMenu->fFlags & MNF_POPUP))
3609       {
3610           item = PtMenu->rgItems;
3611       }
3612       else
3613       {
3614           item = MENU_FindItemByCoords( PtMenu, pmt->Pt, &Id );
3615       }
3616 
3617       if (item && ( PtMenu->iItem == Id))
3618       {
3619           if (!(item->spSubMenu))
3620           {
3621               INT ExecutedMenuId = MENU_ExecFocusedItem( pmt, PtMenu, Flags);
3622               if (ExecutedMenuId == -1 || ExecutedMenuId == -2) return -1;
3623               return ExecutedMenuId;
3624           }
3625 
3626           /* If we are dealing with the menu bar                  */
3627           /* and this is a click on an already "popped" item:     */
3628           /* Stop the menu tracking and close the opened submenus */
3629           if (pmt->TopMenu == PtMenu && PtMenu->TimeToHide)
3630           {
3631               return 0;
3632           }
3633       }
3634       if ( IntGetMenu(PtMenu->hWnd) == PtMenu )
3635       {
3636           PtMenu->TimeToHide = TRUE;
3637       }
3638   }
3639   return -1;
3640 }
3641 
3642 /***********************************************************************
3643  *           MenuPtMenu
3644  *
3645  * Walks menu chain trying to find a menu pt maps to.
3646  */
3647 static PMENU FASTCALL MENU_PtMenu(PMENU menu, POINT pt)
3648 {
3649   PITEM pItem;
3650   PMENU ret = NULL;
3651 
3652   if (!menu) return NULL;
3653 
3654   /* try subpopup first (if any) */
3655   if (menu->iItem != NO_SELECTED_ITEM)
3656   {
3657      pItem = menu->rgItems;
3658      if ( pItem ) pItem = &pItem[menu->iItem];
3659      if ( pItem && pItem->spSubMenu && pItem->fState & MF_MOUSESELECT)
3660      {
3661         ret = MENU_PtMenu( pItem->spSubMenu, pt);
3662      }
3663   }
3664 
3665   /* check the current window (avoiding WM_HITTEST) */
3666   if (!ret)
3667   {
3668      PWND pWnd = ValidateHwndNoErr(menu->hWnd);
3669      INT ht = GetNCHitEx(pWnd, pt);
3670      if ( menu->fFlags & MNF_POPUP )
3671      {
3672         if (ht != HTNOWHERE && ht != HTERROR) ret = menu;
3673      }
3674      else if (ht == HTSYSMENU)
3675         ret = get_win_sys_menu(menu->hWnd);
3676      else if (ht == HTMENU)
3677         ret = IntGetMenu( menu->hWnd );
3678   }
3679   return ret;
3680 }
3681 
3682 /***********************************************************************
3683  *           MenuMouseMove
3684  *
3685  * Return TRUE if we can go on with menu tracking.
3686  */
3687 static BOOL FASTCALL MENU_MouseMove(MTRACKER *pmt, PMENU PtMenu, UINT Flags)
3688 {
3689   UINT Index = NO_SELECTED_ITEM;
3690 
3691   if ( PtMenu )
3692       MENU_FindItemByCoords( PtMenu, pmt->Pt, &Index );
3693 
3694   if (Index == NO_SELECTED_ITEM)
3695   {
3696       MENU_SelectItem(pmt->OwnerWnd, pmt->CurrentMenu, NO_SELECTED_ITEM, TRUE, pmt->TopMenu);
3697   }
3698   else if (PtMenu->iItem != Index)
3699   {
3700       MENU_SwitchTracking(pmt, PtMenu, Index, Flags);
3701       pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, PtMenu, FALSE, Flags);
3702   }
3703   return TRUE;
3704 }
3705 
3706 /***********************************************************************
3707  *           MenuGetSubPopup
3708  *
3709  * Return the handle of the selected sub-popup menu (if any).
3710  */
3711 static PMENU MENU_GetSubPopup( PMENU menu )
3712 {
3713     ITEM *item;
3714 
3715     if ((!menu) || (menu->iItem == NO_SELECTED_ITEM)) return 0;
3716 
3717     item = &menu->rgItems[menu->iItem];
3718     if (item && (item->spSubMenu) && (item->fState & MF_MOUSESELECT))
3719     {
3720        return item->spSubMenu;
3721     }
3722     return 0;
3723 }
3724 
3725 /***********************************************************************
3726  *           MenuDoNextMenu
3727  *
3728  * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
3729  */
3730 static LRESULT FASTCALL MENU_DoNextMenu(MTRACKER* pmt, UINT Vk, UINT wFlags)
3731 {
3732     BOOL atEnd = FALSE;
3733 
3734     /* When skipping left, we need to do something special after the
3735        first menu.                                                  */
3736     if (Vk == VK_LEFT && pmt->TopMenu->iItem == 0)
3737     {
3738         atEnd = TRUE;
3739     }
3740     /* When skipping right, for the non-system menu, we need to
3741        handle the last non-special menu item (ie skip any window
3742        icons such as MDI maximize, restore or close)             */
3743     else if ((Vk == VK_RIGHT) && !IS_SYSTEM_MENU(pmt->TopMenu))
3744     {
3745         UINT i = pmt->TopMenu->iItem + 1;
3746         while (i < pmt->TopMenu->cItems) {
3747             if ((pmt->TopMenu->rgItems[i].wID >= SC_SIZE &&
3748                  pmt->TopMenu->rgItems[i].wID <= SC_RESTORE)) {
3749                 i++;
3750             } else break;
3751         }
3752         if (i == pmt->TopMenu->cItems) {
3753             atEnd = TRUE;
3754         }
3755     }
3756     /* When skipping right, we need to cater for the system menu */
3757     else if ((Vk == VK_RIGHT) && IS_SYSTEM_MENU(pmt->TopMenu))
3758     {
3759         if (pmt->TopMenu->iItem == (pmt->TopMenu->cItems - 1)) {
3760             atEnd = TRUE;
3761         }
3762     }
3763 
3764    if ( atEnd )
3765    {
3766       MDINEXTMENU NextMenu;
3767       PMENU MenuTmp;
3768       PWND pwndTemp;
3769       HMENU hNewMenu;
3770       HWND hNewWnd;
3771       UINT Id = 0;
3772 
3773       MenuTmp = (IS_SYSTEM_MENU(pmt->TopMenu)) ? co_IntGetSubMenu(pmt->TopMenu, 0) : pmt->TopMenu;
3774       NextMenu.hmenuIn = UserHMGetHandle(MenuTmp);
3775       NextMenu.hmenuNext = NULL;
3776       NextMenu.hwndNext = NULL;
3777       co_IntSendMessage(UserHMGetHandle(pmt->OwnerWnd), WM_NEXTMENU, Vk, (LPARAM) &NextMenu);
3778 
3779       TRACE("%p [%p] -> %p [%p]\n",
3780              pmt->CurrentMenu, pmt->OwnerWnd, NextMenu.hmenuNext, NextMenu.hwndNext );
3781 
3782       if (NULL == NextMenu.hmenuNext || NULL == NextMenu.hwndNext)
3783       {
3784           hNewWnd = UserHMGetHandle(pmt->OwnerWnd);
3785           if (IS_SYSTEM_MENU(pmt->TopMenu))
3786           {
3787               /* switch to the menu bar */
3788 
3789               if (pmt->OwnerWnd->style & WS_CHILD || !(MenuTmp = IntGetMenu(hNewWnd))) return FALSE;
3790 
3791               if (Vk == VK_LEFT)
3792               {
3793                   Id = MenuTmp->cItems - 1;
3794 
3795                   /* Skip backwards over any system predefined icons,
3796                      eg. MDI close, restore etc icons                 */
3797                    while ((Id > 0) &&
3798                           (MenuTmp->rgItems[Id].wID >= SC_SIZE &&
3799                            MenuTmp->rgItems[Id].wID <= SC_RESTORE)) Id--;
3800 
3801               }
3802               hNewMenu = UserHMGetHandle(MenuTmp);
3803           }
3804           else if (pmt->OwnerWnd->style & WS_SYSMENU)
3805           {
3806               /* switch to the system menu */
3807               MenuTmp = get_win_sys_menu(hNewWnd);
3808               if (MenuTmp) hNewMenu = UserHMGetHandle(MenuTmp);
3809               else hNewMenu = NULL;
3810           }
3811           else
3812               return FALSE;
3813       }
3814       else    /* application returned a new menu to switch to */
3815       {
3816           hNewMenu = NextMenu.hmenuNext;
3817           hNewWnd = NextMenu.hwndNext;
3818 
3819           if ((MenuTmp = UserGetMenuObject(hNewMenu)) && (pwndTemp = ValidateHwndNoErr(hNewWnd)))
3820           {
3821               if ( pwndTemp->style & WS_SYSMENU && (get_win_sys_menu(hNewWnd) == MenuTmp) )
3822               {
3823                   /* get the real system menu */
3824                   MenuTmp = get_win_sys_menu(hNewWnd);
3825                   hNewMenu = UserHMGetHandle(MenuTmp);
3826               }
3827               else if (pwndTemp->style & WS_CHILD || IntGetMenu(hNewWnd) != MenuTmp)
3828               {
3829                   /* FIXME: Not sure what to do here;
3830                    * perhaps try to track NewMenu as a popup? */
3831 
3832                   WARN(" -- got confused.\n");
3833                   return FALSE;
3834               }
3835           }
3836           else return FALSE;
3837       }
3838 
3839       if (hNewMenu != UserHMGetHandle(pmt->TopMenu))
3840       {
3841           MENU_SelectItem(pmt->OwnerWnd, pmt->TopMenu, NO_SELECTED_ITEM, FALSE, 0 );
3842 
3843           if (pmt->CurrentMenu != pmt->TopMenu)
3844               MENU_HideSubPopups(pmt->OwnerWnd, pmt->TopMenu, FALSE, wFlags);
3845       }
3846 
3847       if (hNewWnd != UserHMGetHandle(pmt->OwnerWnd))
3848       {
3849           PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
3850           pmt->OwnerWnd = ValidateHwndNoErr(hNewWnd);
3851           ///// Use thread pms!!!!
3852           MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, hNewWnd);
3853           pti->MessageQueue->QF_flags &= ~QF_CAPTURELOCKED;
3854           co_UserSetCapture(UserHMGetHandle(pmt->OwnerWnd));
3855           pti->MessageQueue->QF_flags |= QF_CAPTURELOCKED;
3856       }
3857 
3858       pmt->TopMenu = pmt->CurrentMenu = UserGetMenuObject(hNewMenu); /* all subpopups are hidden */
3859       MENU_SelectItem(pmt->OwnerWnd, pmt->TopMenu, Id, TRUE, 0);
3860 
3861       return TRUE;
3862    }
3863    return FALSE;
3864 }
3865 
3866 /***********************************************************************
3867  *           MenuSuspendPopup
3868  *
3869  * The idea is not to show the popup if the next input message is
3870  * going to hide it anyway.
3871  */
3872 static BOOL FASTCALL MENU_SuspendPopup(MTRACKER* pmt, UINT uMsg)
3873 {
3874     MSG msg;
3875 
3876     msg.hwnd = UserHMGetHandle(pmt->OwnerWnd); ////// ? silly wine'isms?
3877 
3878     co_IntGetPeekMessage( &msg, 0, uMsg, uMsg, PM_NOYIELD | PM_REMOVE, FALSE);
3879     pmt->TrackFlags |= TF_SKIPREMOVE;
3880 
3881     switch( uMsg )
3882     {
3883     case WM_KEYDOWN:
3884         co_IntGetPeekMessage( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE, FALSE);
3885         if( msg.message == WM_KEYUP || msg.message == WM_PAINT )
3886         {
3887             co_IntGetPeekMessage( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE, FALSE);
3888             co_IntGetPeekMessage( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE, FALSE);
3889             if( msg.message == WM_KEYDOWN &&
3890                 (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT))
3891             {
3892                  pmt->TrackFlags |= TF_SUSPENDPOPUP;
3893                  return TRUE;
3894             }
3895         }
3896         break;
3897     }
3898     /* failures go through this */
3899     pmt->TrackFlags &= ~TF_SUSPENDPOPUP;
3900     return FALSE;
3901 }
3902 
3903 /***********************************************************************
3904  *           MenuKeyEscape
3905  *
3906  * Handle a VK_ESCAPE key event in a menu.
3907  */
3908 static BOOL FASTCALL MENU_KeyEscape(MTRACKER *pmt, UINT Flags)
3909 {
3910   BOOL EndMenu = TRUE;
3911 
3912   if (pmt->CurrentMenu != pmt->TopMenu)
3913   {
3914       if (pmt->CurrentMenu && (pmt->CurrentMenu->fFlags & MNF_POPUP))
3915       {
3916           PMENU MenuPrev, MenuTmp;
3917 
3918           MenuPrev = MenuTmp = pmt->TopMenu;
3919 
3920           /* close topmost popup */
3921           while (MenuTmp != pmt->CurrentMenu)
3922           {
3923               MenuPrev = MenuTmp;
3924               MenuTmp = MENU_GetSubPopup(MenuPrev);
3925           }
3926 
3927           MENU_HideSubPopups(pmt->OwnerWnd, MenuPrev, TRUE, Flags);
3928           pmt->CurrentMenu = MenuPrev;
3929           EndMenu = FALSE;
3930       }
3931   }
3932 
3933   return EndMenu;
3934 }
3935 
3936 /***********************************************************************
3937  *           MenuKeyLeft
3938  *
3939  * Handle a VK_LEFT key event in a menu.
3940  */
3941 static void FASTCALL MENU_KeyLeft(MTRACKER* pmt, UINT Flags, UINT msg)
3942 {
3943   PMENU MenuTmp, MenuPrev;
3944   UINT PrevCol;
3945 
3946   MenuPrev = MenuTmp = pmt->TopMenu;
3947 
3948   /* Try to move 1 column left (if possible) */
3949   if ( (PrevCol = MENU_GetStartOfPrevColumn(pmt->CurrentMenu)) != NO_SELECTED_ITEM)
3950   {
3951      MENU_SelectItem(pmt->OwnerWnd, pmt->CurrentMenu, PrevCol, TRUE, 0);
3952      return;
3953   }
3954 
3955   /* close topmost popup */
3956   while (MenuTmp != pmt->CurrentMenu)
3957   {
3958       MenuPrev = MenuTmp;
3959       MenuTmp = MENU_GetSubPopup(MenuPrev);
3960   }
3961 
3962   MENU_HideSubPopups(pmt->OwnerWnd, MenuPrev, TRUE, Flags);
3963   pmt->CurrentMenu = MenuPrev;
3964 
3965   if ((MenuPrev == pmt->TopMenu) && !(pmt->TopMenu->fFlags & MNF_POPUP))
3966   {
3967       /* move menu bar selection if no more popups are left */
3968 
3969       if (!MENU_DoNextMenu(pmt, VK_LEFT, Flags))
3970           MENU_MoveSelection(pmt->OwnerWnd, pmt->TopMenu, ITEM_PREV);
3971 
3972       if (MenuPrev != MenuTmp || pmt->TrackFlags & TF_SUSPENDPOPUP)
3973       {
3974           /* A sublevel menu was displayed - display the next one
3975            * unless there is another displacement coming up */
3976 
3977           if (!MENU_SuspendPopup(pmt, msg))
3978               pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, pmt->TopMenu,
3979                                                  TRUE, Flags);
3980       }
3981   }
3982 }
3983 
3984 /***********************************************************************
3985  *           MenuKeyRight
3986  *
3987  * Handle a VK_RIGHT key event in a menu.
3988  */
3989 static void FASTCALL MENU_KeyRight(MTRACKER *pmt, UINT Flags, UINT msg)
3990 {
3991     PMENU menutmp;
3992     UINT NextCol;
3993 
3994     TRACE("MenuKeyRight called, cur %p, top %p.\n",
3995          pmt->CurrentMenu, pmt->TopMenu);
3996 
3997     if ((pmt->TopMenu->fFlags & MNF_POPUP) || (pmt->CurrentMenu != pmt->TopMenu))
3998     {
3999       /* If already displaying a popup, try to display sub-popup */
4000 
4001       menutmp = pmt->CurrentMenu;
4002       pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, menutmp, TRUE, Flags);
4003 
4004       /* if subpopup was displayed then we are done */
4005       if (menutmp != pmt->CurrentMenu) return;
4006     }
4007 
4008     /* Check to see if there's another column */
4009     if ( (NextCol = MENU_GetStartOfNextColumn(pmt->CurrentMenu)) != NO_SELECTED_ITEM)
4010     {
4011        TRACE("Going to %d.\n", NextCol);
4012        MENU_SelectItem(pmt->OwnerWnd, pmt->CurrentMenu, NextCol, TRUE, 0);
4013        return;
4014     }
4015 
4016     if (!(pmt->TopMenu->fFlags & MNF_POPUP)) /* menu bar tracking */
4017     {
4018        if (pmt->CurrentMenu != pmt->TopMenu)
4019        {
4020           MENU_HideSubPopups(pmt->OwnerWnd, pmt->TopMenu, FALSE, Flags);
4021           menutmp = pmt->CurrentMenu = pmt->TopMenu;
4022        }
4023        else
4024        {
4025           menutmp = NULL;
4026        }
4027 
4028        /* try to move to the next item */
4029        if ( !MENU_DoNextMenu(pmt, VK_RIGHT, Flags))
4030            MENU_MoveSelection(pmt->OwnerWnd, pmt->TopMenu, ITEM_NEXT);
4031 
4032        if ( menutmp || pmt->TrackFlags & TF_SUSPENDPOPUP )
4033        {
4034            if ( !MENU_SuspendPopup(pmt, msg) )
4035                pmt->CurrentMenu = MENU_ShowSubPopup(pmt->OwnerWnd, pmt->TopMenu, TRUE, Flags);
4036        }
4037     }
4038 }
4039 
4040 /***********************************************************************
4041  *           MenuTrackMenu
4042  *
4043  * Menu tracking code.
4044  */
4045 static INT FASTCALL MENU_TrackMenu(PMENU pmenu, UINT wFlags, INT x, INT y,
4046                             PWND pwnd)
4047 {
4048     MSG msg;
4049     BOOL fRemove;
4050     INT executedMenuId = -1;
4051     MTRACKER mt;
4052     HWND capture_win;
4053     PMENU pmMouse;
4054     BOOL enterIdleSent = FALSE;
4055     BOOL firstClick = TRUE;
4056     PWND pWnd;
4057     PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
4058 
4059     if (pti != pwnd->head.pti)
4060     {
4061        ERR("Not the same PTI!!!!\n");
4062     }
4063 
4064     mt.TrackFlags = 0;
4065     mt.CurrentMenu = pmenu;
4066     mt.TopMenu = pmenu;
4067     mt.OwnerWnd = pwnd;
4068     mt.Pt.x = x;
4069     mt.Pt.y = y;
4070 
4071     TRACE("MTM : hmenu=%p flags=0x%08x (%d,%d) hwnd=%x\n",
4072          UserHMGetHandle(pmenu), wFlags, x, y, UserHMGetHandle(pwnd));
4073 
4074     pti->MessageQueue->QF_flags &= ~QF_ACTIVATIONCHANGE;
4075 
4076     if (wFlags & TPM_BUTTONDOWN)
4077     {
4078         /* Get the result in order to start the tracking or not */
4079         fRemove = MENU_ButtonDown( &mt, pmenu, wFlags );
4080         fInsideMenuLoop = fRemove;
4081     }
4082 
4083     if (wFlags & TF_ENDMENU) fInsideMenuLoop = FALSE;
4084 
4085     if (wFlags & TPM_POPUPMENU && pmenu->cItems == 0) // Tracking empty popup menu...
4086     {
4087        MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);
4088        pti->MessageQueue->QF_flags &= ~QF_CAPTURELOCKED;
4089        co_UserSetCapture(NULL); /* release the capture */
4090        return 0;
4091     }
4092 
4093     capture_win = IntGetCapture();
4094 
4095     while (fInsideMenuLoop)
4096     {
4097         BOOL ErrorExit = FALSE;
4098         if (!VerifyMenu( mt.CurrentMenu )) /* sometimes happens if I do a window manager close */
4099            break;
4100 
4101         /* we have to keep the message in the queue until it's
4102          * clear that menu loop is not over yet. */
4103 
4104         for (;;)
4105         {
4106             if (co_IntGetPeekMessage( &msg, 0, 0, 0, PM_NOREMOVE, FALSE ))
4107             {
4108                 if (!IntCallMsgFilter( &msg, MSGF_MENU )) break;
4109                 /* remove the message from the queue */
4110                 co_IntGetPeekMessage( &msg, 0, msg.message, msg.message, PM_REMOVE, FALSE );
4111             }
4112             else
4113             {
4114                 /* ReactOS Checks */
4115                 if (!VerifyWnd(mt.OwnerWnd)                            ||
4116                     !ValidateHwndNoErr(mt.CurrentMenu->hWnd)           ||
4117                      //pti->MessageQueue->QF_flags & QF_ACTIVATIONCHANGE || // See CORE-17338
4118                      capture_win != IntGetCapture() ) // Should not happen, but this is ReactOS...
4119                 {
4120                    ErrorExit = TRUE; // Do not wait on dead windows, now win test_capture_4 works.
4121                    break;
4122                 }
4123 
4124                 if (!enterIdleSent)
4125                 {
4126                   HWND win = mt.CurrentMenu->fFlags & MNF_POPUP ? mt.CurrentMenu->hWnd : NULL;
4127                   enterIdleSent = TRUE;
4128                   co_IntSendMessage( UserHMGetHandle(mt.OwnerWnd), WM_ENTERIDLE, MSGF_MENU, (LPARAM) win);
4129                 }
4130                 co_IntWaitMessage(NULL, 0, 0);
4131             }
4132         }
4133 
4134         if (ErrorExit) break; // Gracefully dropout.
4135 
4136         /* check if EndMenu() tried to cancel us, by posting this message */
4137         if (msg.message == WM_CANCELMODE)
4138         {
4139             /* we are now out of the loop */
4140             fInsideMenuLoop = FALSE;
4141 
4142             /* remove the message from the queue */
4143             co_IntGetPeekMessage( &msg, 0, msg.message, msg.message, PM_REMOVE, FALSE );
4144 
4145             /* break out of internal loop, ala ESCAPE */
4146             break;
4147         }
4148 
4149         mt.Pt = msg.pt;
4150 
4151         if ( (msg.hwnd == mt.CurrentMenu->hWnd) || ((msg.message!=WM_TIMER) && (msg.message!=WM_SYSTIMER)) )
4152             enterIdleSent=FALSE;
4153 
4154         fRemove = FALSE;
4155         if ((msg.message >= WM_MOUSEFIRST) && (msg.message <= WM_MOUSELAST))
4156         {
4157             /*
4158              * Use the mouse coordinates in lParam instead of those in the MSG
4159              * struct to properly handle synthetic messages. They are already
4160              * in screen coordinates.
4161              */
4162             mt.Pt.x = (short)LOWORD(msg.lParam);
4163             mt.Pt.y = (short)HIWORD(msg.lParam);
4164 
4165             /* Find a menu for this mouse event */
4166             pmMouse = MENU_PtMenu( mt.TopMenu, mt.Pt );
4167 
4168             switch(msg.message)
4169             {
4170                 /* no WM_NC... messages in captured state */
4171 
4172                 case WM_RBUTTONDBLCLK:
4173                 case WM_RBUTTONDOWN:
4174                      if (!(wFlags & TPM_RIGHTBUTTON))
4175                      {
4176                         if ( msg.message == WM_RBUTTONDBLCLK ) fInsideMenuLoop = FALSE; // Must exit or loop forever!
4177                         break;
4178                      }
4179                     /* fall through */
4180                 case WM_LBUTTONDBLCLK:
4181                 case WM_LBUTTONDOWN:
4182                 {
4183                     /* If the message belongs to the menu, removes it from the queue */
4184                     /* Else, end menu tracking */
4185                     pWnd = ValidateHwndNoErr(mt.TopMenu->hWnd);
4186                     /* Don't remove WM_LBUTTONDBLCLK to allow the closing of a window or program */
4187                     if (msg.message == WM_LBUTTONDBLCLK && GetNCHitEx(pWnd, mt.Pt) == HTSYSMENU)
4188                         fRemove = FALSE;
4189                     else
4190                         fRemove = MENU_ButtonDown(&mt, pmMouse, wFlags);
4191 
4192                     fInsideMenuLoop = fRemove;
4193                     if (msg.message == WM_RBUTTONDBLCLK)
4194                         fInsideMenuLoop = FALSE; // Must exit or loop forever
4195                     break;
4196                 }
4197 
4198                 case WM_RBUTTONUP:
4199                     if (!(wFlags & TPM_RIGHTBUTTON)) break;
4200                     /* fall through */
4201                 case WM_LBUTTONUP:
4202                     /* Check if a menu was selected by the mouse */
4203                     if (pmMouse)
4204                     {
4205                         pWnd = ValidateHwndNoErr(mt.TopMenu->hWnd);
4206                         /* Exit system menu if system icon is clicked a second time */
4207                         if (!firstClick && GetNCHitEx(pWnd, mt.Pt) == HTSYSMENU)
4208                         {
4209                             fRemove = TRUE;
4210                             fInsideMenuLoop = FALSE;
4211                         }
4212                         else
4213                         {
4214                             /* End the loop if executedMenuId is an item ID */
4215                             /* or if the job was done (executedMenuId = 0). */
4216                             executedMenuId = MENU_ButtonUp( &mt, pmMouse, wFlags);
4217                             fRemove = (executedMenuId != -1);
4218                             fInsideMenuLoop = !fRemove;
4219                             firstClick = FALSE;
4220                         }
4221                     }
4222                     /* No menu was selected by the mouse */
4223                     /* if the function was called by TrackPopupMenu, continue
4224                        with the menu tracking. If not, stop it */
4225                     else
4226                         fInsideMenuLoop = ((wFlags & TPM_POPUPMENU) ? TRUE : FALSE);
4227 
4228                     break;
4229 
4230                 case WM_MOUSEMOVE:
4231                     /* the selected menu item must be changed every time */
4232                     /* the mouse moves. */
4233 
4234                     if (pmMouse)
4235                         fInsideMenuLoop |= MENU_MouseMove( &mt, pmMouse, wFlags );
4236 
4237 	    } /* switch(msg.message) - mouse */
4238         }
4239         else if ((msg.message >= WM_KEYFIRST) && (msg.message <= WM_KEYLAST))
4240         {
4241             fRemove = TRUE;  /* Keyboard messages are always removed */
4242             switch(msg.message)
4243             {
4244                 case WM_KEYDOWN:
4245                 case WM_SYSKEYDOWN:
4246                 switch(msg.wParam)
4247                 {
4248                     case VK_MENU:
4249                     case VK_F10:
4250                         fInsideMenuLoop = FALSE;
4251                         break;
4252 
4253                     case VK_HOME:
4254                     case VK_END:
4255                         MENU_SelectItem(mt.OwnerWnd, mt.CurrentMenu, NO_SELECTED_ITEM, FALSE, 0 );
4256                         MENU_MoveSelection(mt.OwnerWnd, mt.CurrentMenu, VK_HOME == msg.wParam ? ITEM_NEXT : ITEM_PREV);
4257                         break;
4258 
4259                     case VK_UP:
4260                     case VK_DOWN: /* If on menu bar, pull-down the menu */
4261                         if (!(mt.CurrentMenu->fFlags & MNF_POPUP))
4262                             mt.CurrentMenu = MENU_ShowSubPopup(mt.OwnerWnd, mt.TopMenu, TRUE, wFlags);
4263                         else      /* otherwise try to move selection */
4264                             MENU_MoveSelection(mt.OwnerWnd, mt.CurrentMenu, (msg.wParam == VK_UP)? ITEM_PREV : ITEM_NEXT );
4265                         break;
4266 
4267                     case VK_LEFT:
4268                         MENU_KeyLeft( &mt, wFlags, msg.message );
4269                         break;
4270 
4271                     case VK_RIGHT:
4272                         MENU_KeyRight( &mt, wFlags, msg.message );
4273                         break;
4274 
4275                     case VK_ESCAPE:
4276                         fInsideMenuLoop = !MENU_KeyEscape(&mt, wFlags);
4277                         break;
4278 
4279                     case VK_F1:
4280                     {
4281                         HELPINFO hi;
4282                         hi.cbSize = sizeof(HELPINFO);
4283                         hi.iContextType = HELPINFO_MENUITEM;
4284                         if (mt.CurrentMenu->iItem == NO_SELECTED_ITEM)
4285                             hi.iCtrlId = 0;
4286                         else
4287                             hi.iCtrlId = pmenu->rgItems[mt.CurrentMenu->iItem].wID;
4288                         hi.hItemHandle = UserHMGetHandle(mt.CurrentMenu);
4289                         hi.dwContextId = pmenu->dwContextHelpId;
4290                         hi.MousePos = msg.pt;
4291                         co_IntSendMessage( UserHMGetHandle(pwnd), WM_HELP, 0, (LPARAM)&hi);
4292                         break;
4293                     }
4294 
4295                     default:
4296                         IntTranslateKbdMessage(&msg, 0);
4297                         break;
4298                 }
4299                 break;  /* WM_KEYDOWN */
4300 
4301                 case WM_CHAR:
4302                 case WM_SYSCHAR:
4303                 {
4304                     UINT pos;
4305                     BOOL fEndMenu;
4306 
4307                     if (msg.wParam == L'\r' || msg.wParam == L' ')
4308                     {
4309                         executedMenuId = MENU_ExecFocusedItem(&mt, mt.CurrentMenu, wFlags);
4310                         fEndMenu = (executedMenuId != -2);
4311                         fInsideMenuLoop = !fEndMenu;
4312                         break;
4313                     }
4314 
4315                     /* Hack to avoid control chars. */
4316                     /* We will find a better way real soon... */
4317                     if (msg.wParam < 32) break;
4318 
4319                     pos = MENU_FindItemByKey(mt.OwnerWnd, mt.CurrentMenu, LOWORD(msg.wParam), FALSE);
4320 
4321                     if (pos == (UINT)-2) fInsideMenuLoop = FALSE;
4322                     else if (pos == (UINT)-1) UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_MESSAGE_BEEP, 0); //MessageBeep(0);
4323                     else
4324                     {
4325                         MENU_SelectItem(mt.OwnerWnd, mt.CurrentMenu, pos, TRUE, 0);
4326                         executedMenuId = MENU_ExecFocusedItem(&mt, mt.CurrentMenu, wFlags);
4327                         fEndMenu = (executedMenuId != -2);
4328                         fInsideMenuLoop = !fEndMenu;
4329                     }
4330                 }
4331                 break;
4332             }  /* switch(msg.message) - kbd */
4333         }
4334         else
4335         {
4336             co_IntGetPeekMessage( &msg, 0, msg.message, msg.message, PM_REMOVE, FALSE );
4337             IntDispatchMessage( &msg );
4338             continue;
4339         }
4340 
4341         if (fInsideMenuLoop) fRemove = TRUE;
4342 
4343         /* finally remove message from the queue */
4344 
4345         if (fRemove && !(mt.TrackFlags & TF_SKIPREMOVE) )
4346             co_IntGetPeekMessage( &msg, 0, msg.message, msg.message, PM_REMOVE, FALSE );
4347         else mt.TrackFlags &= ~TF_SKIPREMOVE;
4348     }
4349 
4350     MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);
4351     pti->MessageQueue->QF_flags &= ~QF_CAPTURELOCKED;
4352     co_UserSetCapture(NULL); /* release the capture */
4353 
4354     /* If dropdown is still painted and the close box is clicked on
4355        then the menu will be destroyed as part of the DispatchMessage above.
4356        This will then invalidate the menu handle in mt.hTopMenu. We should
4357        check for this first.  */
4358     if ( VerifyMenu( mt.TopMenu ) )
4359     {
4360        if (VerifyWnd(mt.OwnerWnd))
4361        {
4362            MENU_HideSubPopups(mt.OwnerWnd, mt.TopMenu, FALSE, wFlags);
4363 
4364            if (mt.TopMenu->fFlags & MNF_POPUP)
4365            {
4366               PWND pwndTM = ValidateHwndNoErr(mt.TopMenu->hWnd);
4367               if (pwndTM)
4368               {
4369                  IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND, pwndTM, OBJID_CLIENT, CHILDID_SELF, 0);
4370 
4371                  co_UserDestroyWindow(pwndTM);
4372               }
4373               mt.TopMenu->hWnd = NULL;
4374 
4375               if (!(wFlags & TPM_NONOTIFY))
4376               {
4377                  co_IntSendMessage( UserHMGetHandle(mt.OwnerWnd), WM_UNINITMENUPOPUP, (WPARAM)UserHMGetHandle(mt.TopMenu),
4378                                  MAKELPARAM(0, IS_SYSTEM_MENU(mt.TopMenu) ? MF_SYSMENU : 0));
4379               }
4380             }
4381             MENU_SelectItem( mt.OwnerWnd, mt.TopMenu, NO_SELECTED_ITEM, FALSE, 0 );
4382             co_IntSendMessage( UserHMGetHandle(mt.OwnerWnd), WM_MENUSELECT, MAKEWPARAM(0, 0xffff), 0 );
4383        }
4384 
4385        /* Reset the variable for hiding menu */
4386        mt.TopMenu->TimeToHide = FALSE;
4387     }
4388 
4389     EngSetLastError( ERROR_SUCCESS );
4390     /* The return value is only used by TrackPopupMenu */
4391     if (!(wFlags & TPM_RETURNCMD)) return TRUE;
4392     if (executedMenuId == -1) executedMenuId = 0;
4393     return executedMenuId;
4394 }
4395 
4396 /***********************************************************************
4397  *           MenuInitTracking
4398  */
4399 static BOOL FASTCALL MENU_InitTracking(PWND pWnd, PMENU Menu, BOOL bPopup, UINT wFlags)
4400 {
4401     HWND capture_win;
4402     PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
4403 
4404     TRACE("hwnd=%p hmenu=%p\n", UserHMGetHandle(pWnd), UserHMGetHandle(Menu));
4405 
4406     co_UserHideCaret(0);
4407 
4408     /* This makes the menus of applications built with Delphi work.
4409      * It also enables menus to be displayed in more than one window,
4410      * but there are some bugs left that need to be fixed in this case.
4411      */
4412     if (!bPopup)
4413     {
4414         Menu->hWnd = UserHMGetHandle(pWnd);
4415     }
4416 
4417     if (!top_popup) {
4418        top_popup = Menu->hWnd;
4419        top_popup_hmenu = UserHMGetHandle(Menu);
4420     }
4421 
4422     fInsideMenuLoop = TRUE;
4423     fInEndMenu = FALSE;
4424 
4425     /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
4426     if (!(wFlags & TPM_NONOTIFY))
4427     {
4428        co_IntSendMessage( UserHMGetHandle(pWnd), WM_ENTERMENULOOP, bPopup, 0 );
4429     }
4430 
4431     //
4432     // Capture is set before calling WM_INITMENU and after WM_ENTERMENULOOP, see msg_menu.
4433     //
4434     capture_win = (wFlags & TPM_POPUPMENU) ? Menu->hWnd : UserHMGetHandle(pWnd);
4435     MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, capture_win); // 1
4436     co_UserSetCapture(capture_win);                           // 2
4437     pti->MessageQueue->QF_flags |= QF_CAPTURELOCKED; // Set the Q bits so noone can change this!
4438 
4439     co_IntSendMessage( UserHMGetHandle(pWnd), WM_SETCURSOR, (WPARAM)UserHMGetHandle(pWnd), HTCAPTION );
4440 
4441     if (!(wFlags & TPM_NONOTIFY))
4442     {
4443        co_IntSendMessage( UserHMGetHandle(pWnd), WM_INITMENU, (WPARAM)UserHMGetHandle(Menu), 0 );
4444        /* If an app changed/recreated menu bar entries in WM_INITMENU
4445         * menu sizes will be recalculated once the menu created/shown.
4446         */
4447     }
4448 
4449     IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART,
4450                        pWnd,
4451                        Menu->fFlags & MNF_SYSMENU ? OBJID_SYSMENU : OBJID_MENU,
4452                        CHILDID_SELF, 0);
4453     return TRUE;
4454 }
4455 
4456 /***********************************************************************
4457  *           MenuExitTracking
4458  */
4459 static BOOL FASTCALL MENU_ExitTracking(PWND pWnd, BOOL bPopup, UINT wFlags)
4460 {
4461     TRACE("Exit Track hwnd=%p bPopup %d\n", UserHMGetHandle(pWnd), bPopup);
4462 
4463     IntNotifyWinEvent( EVENT_SYSTEM_MENUEND, pWnd, OBJID_WINDOW, CHILDID_SELF, 0);
4464 
4465     if (!(wFlags & TPM_NONOTIFY))
4466        co_IntSendMessage( UserHMGetHandle(pWnd), WM_EXITMENULOOP, bPopup, 0 );
4467 
4468     co_UserShowCaret(0);
4469 
4470     top_popup = 0;
4471     top_popup_hmenu = NULL;
4472 
4473     return TRUE;
4474 }
4475 
4476 /***********************************************************************
4477  *           MenuTrackMouseMenuBar
4478  *
4479  * Menu-bar tracking upon a mouse event. Called from NC_HandleSysCommand().
4480  */
4481 VOID MENU_TrackMouseMenuBar( PWND pWnd, ULONG ht, POINT pt)
4482 {
4483     PMENU pMenu = (ht == HTSYSMENU) ? IntGetSystemMenu(pWnd, FALSE) : IntGetMenu( UserHMGetHandle(pWnd) ); // See 74276 and CORE-12801
4484     UINT wFlags = TPM_BUTTONDOWN | TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_VERTICAL;
4485 
4486     TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", pWnd, ht, pt.x, pt.y);
4487 
4488     if (pWnd->ExStyle & WS_EX_LAYOUTRTL) wFlags |= TPM_LAYOUTRTL;
4489     if (VerifyMenu(pMenu))
4490     {
4491         /* map point to parent client coordinates */
4492         PWND Parent = UserGetAncestor(pWnd, GA_PARENT );
4493         if (Parent != UserGetDesktopWindow())
4494         {
4495             IntScreenToClient(Parent, &pt);
4496         }
4497 
4498         MENU_InitTracking(pWnd, pMenu, FALSE, wFlags);
4499         /* fetch the window menu again, it may have changed */
4500         pMenu = (ht == HTSYSMENU) ? get_win_sys_menu( UserHMGetHandle(pWnd) ) : IntGetMenu( UserHMGetHandle(pWnd) );
4501         MENU_TrackMenu(pMenu, wFlags, pt.x, pt.y, pWnd);
4502         MENU_ExitTracking(pWnd, FALSE, wFlags);
4503     }
4504 }
4505 
4506 /***********************************************************************
4507  *           MenuTrackKbdMenuBar
4508  *
4509  * Menu-bar tracking upon a keyboard event. Called from NC_HandleSysCommand().
4510  */
4511 VOID MENU_TrackKbdMenuBar(PWND pwnd, UINT wParam, WCHAR wChar)
4512 {
4513     UINT uItem = NO_SELECTED_ITEM;
4514     PMENU TrackMenu;
4515     UINT wFlags = TPM_LEFTALIGN | TPM_LEFTBUTTON;
4516 
4517     TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", UserHMGetHandle(pwnd), wParam, wChar);
4518 
4519     /* find window that has a menu */
4520 
4521     while (!( (pwnd->style & (WS_CHILD | WS_POPUP)) != WS_CHILD ) )
4522         if (!(pwnd = UserGetAncestor( pwnd, GA_PARENT ))) return;
4523 
4524     /* check if we have to track a system menu */
4525 
4526     TrackMenu = IntGetMenu( UserHMGetHandle(pwnd) );
4527     if (!TrackMenu || (pwnd->style & WS_MINIMIZE) != 0 || wChar == ' ' )
4528     {
4529         if (!(pwnd->style & WS_SYSMENU)) return;
4530         TrackMenu = get_win_sys_menu( UserHMGetHandle(pwnd) );
4531         uItem = 0;
4532         wParam |= HTSYSMENU; /* prevent item lookup */
4533     }
4534 
4535     if (!VerifyMenu( TrackMenu )) return;
4536 
4537     MENU_InitTracking( pwnd, TrackMenu, FALSE, wFlags );
4538 
4539     /* fetch the window menu again, it may have changed */
4540     TrackMenu = (wParam & HTSYSMENU) ? get_win_sys_menu( UserHMGetHandle(pwnd) ) : IntGetMenu( UserHMGetHandle(pwnd) );
4541 
4542     if( wChar && wChar != ' ' )
4543     {
4544         uItem = MENU_FindItemByKey( pwnd, TrackMenu, wChar, (wParam & HTSYSMENU) );
4545         if ( uItem >= (UINT)(-2) )
4546         {
4547             if( uItem == (UINT)(-1) ) UserPostMessage(hwndSAS, WM_LOGONNOTIFY, LN_MESSAGE_BEEP, 0); //MessageBeep(0);
4548             /* schedule end of menu tracking */
4549             wFlags |= TF_ENDMENU;
4550             goto track_menu;
4551         }
4552     }
4553 
4554     MENU_SelectItem( pwnd, TrackMenu, uItem, TRUE, 0 );
4555 
4556     if (!(wParam & HTSYSMENU) || wChar == ' ')
4557     {
4558         if( uItem == NO_SELECTED_ITEM )
4559             MENU_MoveSelection( pwnd, TrackMenu, ITEM_NEXT );
4560         else
4561             UserPostMessage( UserHMGetHandle(pwnd), WM_KEYDOWN, VK_RETURN, 0 );
4562     }
4563 
4564 track_menu:
4565     MENU_TrackMenu( TrackMenu, wFlags, 0, 0, pwnd );
4566     MENU_ExitTracking( pwnd, FALSE, wFlags);
4567 }
4568 
4569 /**********************************************************************
4570  *           TrackPopupMenuEx   (USER32.@)
4571  */
4572 BOOL WINAPI IntTrackPopupMenuEx( PMENU menu, UINT wFlags, int x, int y,
4573                               PWND pWnd, LPTPMPARAMS lpTpm)
4574 {
4575     BOOL ret = FALSE;
4576     PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
4577 
4578     if (pti != pWnd->head.pti)
4579     {
4580        ERR("Must be the same pti!\n");
4581        return ret;
4582     }
4583 
4584     TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p \n", //rect %s\n",
4585             UserHMGetHandle(menu), wFlags, x, y, UserHMGetHandle(pWnd), lpTpm); //,
4586             //lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" );
4587 
4588     if (menu->hWnd && IntIsWindow(menu->hWnd))
4589     {
4590         EngSetLastError( ERROR_POPUP_ALREADY_ACTIVE );
4591         return FALSE;
4592     }
4593 
4594     if (MENU_InitPopup( pWnd, menu, wFlags ))
4595     {
4596        MENU_InitTracking(pWnd, menu, TRUE, wFlags);
4597 
4598        /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
4599        if (!(wFlags & TPM_NONOTIFY))
4600        {
4601           co_IntSendMessage( UserHMGetHandle(pWnd), WM_INITMENUPOPUP, (WPARAM) UserHMGetHandle(menu), MAKELPARAM(0, IS_SYSTEM_MENU(menu)));
4602        }
4603 
4604        if (menu->fFlags & MNF_SYSMENU)
4605           MENU_InitSysMenuPopup( menu, pWnd->style, pWnd->pcls->style, HTSYSMENU);
4606 
4607        if (MENU_ShowPopup(pWnd, menu, 0, wFlags | TPM_POPUPMENU, x, y, lpTpm ? &lpTpm->rcExclude : NULL))
4608           ret = MENU_TrackMenu( menu, wFlags | TPM_POPUPMENU, 0, 0, pWnd);
4609        else
4610        {
4611           MsqSetStateWindow(pti, MSQ_STATE_MENUOWNER, NULL);
4612           pti->MessageQueue->QF_flags &= ~QF_CAPTURELOCKED;
4613           co_UserSetCapture(NULL); /* release the capture */
4614        }
4615 
4616        MENU_ExitTracking(pWnd, TRUE, wFlags);
4617 
4618        if (menu->hWnd)
4619        {
4620           PWND pwndM = ValidateHwndNoErr( menu->hWnd );
4621           if (pwndM) // wine hack around this with their destroy function.
4622           {
4623              if (!(pWnd->state & WNDS_DESTROYED))
4624                 co_UserDestroyWindow( pwndM ); // Fix wrong error return.
4625           }
4626           menu->hWnd = 0;
4627 
4628           if (!(wFlags & TPM_NONOTIFY))
4629           {
4630              co_IntSendMessage( UserHMGetHandle(pWnd), WM_UNINITMENUPOPUP, (WPARAM)UserHMGetHandle(menu),
4631                                             MAKELPARAM(0, IS_SYSTEM_MENU(menu) ? MF_SYSMENU : 0));
4632           }
4633        }
4634     }
4635     return ret;
4636 }
4637 
4638 //
4639 // Menu Class Proc.
4640 //
4641 BOOL WINAPI
4642 PopupMenuWndProc(
4643    PWND Wnd,
4644    UINT Message,
4645    WPARAM wParam,
4646    LPARAM lParam,
4647    LRESULT *lResult)
4648 {
4649   PPOPUPMENU pPopupMenu;
4650 
4651   *lResult = 0;
4652 
4653   TRACE("PMWP : pwnd=%x msg=%d wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
4654 
4655   if (Wnd)
4656   {
4657      if (!Wnd->fnid)
4658      {
4659         if (Message != WM_NCCREATE)
4660         {
4661            *lResult = IntDefWindowProc(Wnd, Message, wParam, lParam, FALSE);
4662            return TRUE;
4663         }
4664         Wnd->fnid = FNID_MENU;
4665         pPopupMenu = DesktopHeapAlloc( Wnd->head.rpdesk, sizeof(POPUPMENU) );
4666         if (pPopupMenu == NULL)
4667         {
4668             return TRUE;
4669         }
4670         pPopupMenu->posSelectedItem = NO_SELECTED_ITEM;
4671         pPopupMenu->spwndPopupMenu = Wnd;
4672         ((PMENUWND)Wnd)->ppopupmenu = pPopupMenu;
4673         TRACE("Pop Up Menu is Setup! Msg %d\n",Message);
4674         *lResult = 1;
4675         return TRUE;
4676      }
4677      else
4678      {
4679         if (Wnd->fnid != FNID_MENU)
4680         {
4681            ERR("Wrong window class for Menu! fnid %x\n",Wnd->fnid);
4682            return TRUE;
4683         }
4684         pPopupMenu = ((PMENUWND)Wnd)->ppopupmenu;
4685      }
4686   }
4687 
4688   switch(Message)
4689     {
4690     case WM_CREATE:
4691       {
4692         CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam;
4693         pPopupMenu->spmenu = UserGetMenuObject(cs->lpCreateParams);
4694         if (pPopupMenu->spmenu)
4695         {
4696            UserReferenceObject(pPopupMenu->spmenu);
4697         }
4698         break;
4699       }
4700 
4701     case WM_MOUSEACTIVATE:  /* We don't want to be activated */
4702       *lResult = MA_NOACTIVATE;
4703       break;
4704 
4705     case WM_PAINT:
4706       {
4707         PAINTSTRUCT ps;
4708         IntBeginPaint(Wnd, &ps);
4709         MENU_DrawPopupMenu(Wnd, ps.hdc, pPopupMenu->spmenu);
4710         IntEndPaint(Wnd, &ps);
4711         break;
4712       }
4713 
4714     case WM_PRINTCLIENT:
4715       {
4716          MENU_DrawPopupMenu( Wnd, (HDC)wParam, pPopupMenu->spmenu);
4717          break;
4718       }
4719 
4720     case WM_ERASEBKGND:
4721       *lResult = 1;
4722       break;
4723 
4724     case WM_DESTROY:
4725       /* zero out global pointer in case resident popup window was destroyed. */
4726       if (pPopupMenu)
4727       {
4728          if (UserHMGetHandle(Wnd) == top_popup)
4729          {
4730              top_popup = NULL;
4731              top_popup_hmenu = NULL;
4732          }
4733       }
4734       else
4735       {
4736          ERR("No Window Pop Up!\n");
4737       }
4738       break;
4739 
4740     case WM_NCDESTROY:
4741       {
4742          if (pPopupMenu->spmenu)
4743          {
4744             IntReleaseMenuObject(pPopupMenu->spmenu);
4745          }
4746          DesktopHeapFree(Wnd->head.rpdesk, pPopupMenu );
4747          ((PMENUWND)Wnd)->ppopupmenu = 0;
4748          Wnd->fnid = FNID_DESTROY;
4749          break;
4750       }
4751 
4752     case MM_SETMENUHANDLE: // wine'isms
4753     case MN_SETHMENU:
4754       {
4755         PMENU pmenu = UserGetMenuObject((HMENU)wParam);
4756         if (!pmenu)
4757         {
4758            ERR("Bad Menu Handle\n");
4759            break;
4760         }
4761         UserReferenceObject(pmenu);
4762         if (pPopupMenu->spmenu)
4763         {
4764            IntReleaseMenuObject(pPopupMenu->spmenu);
4765         }
4766         pPopupMenu->spmenu = pmenu;
4767         break;
4768       }
4769 
4770     case MM_GETMENUHANDLE: // wine'isms
4771     case MN_GETHMENU:
4772          *lResult = (LRESULT)(pPopupMenu ? (pPopupMenu->spmenu ? UserHMGetHandle(pPopupMenu->spmenu) : NULL) : NULL);
4773          break;
4774 
4775     default:
4776       if (Message > MN_GETHMENU && Message < MN_GETHMENU+19)
4777       {
4778          ERR("Someone is passing unknown menu messages %d\n",Message);
4779       }
4780       TRACE("PMWP to IDWP %d\n",Message);
4781       *lResult = IntDefWindowProc(Wnd, Message, wParam, lParam, FALSE);
4782       break;
4783     }
4784 
4785   return TRUE;
4786 }
4787 
4788 BOOL FASTCALL
4789 IntHiliteMenuItem(PWND WindowObject,
4790                   PMENU MenuObject,
4791                   UINT uItemHilite,
4792                   UINT uHilite)
4793 {
4794    PITEM MenuItem;
4795    UINT uItem = uItemHilite;
4796 
4797    if (!(MenuItem = MENU_FindItem( &MenuObject, &uItem, uHilite ))) return TRUE;
4798 
4799    if (uHilite & MF_HILITE)
4800    {
4801       MenuItem->fState |= MF_HILITE;
4802    }
4803    else
4804    {
4805       MenuItem->fState &= ~MF_HILITE;
4806    }
4807    if (MenuObject->iItem == uItemHilite) return TRUE;
4808    MENU_HideSubPopups( WindowObject, MenuObject, FALSE, 0 );
4809    MENU_SelectItem( WindowObject, MenuObject, uItemHilite, TRUE, 0 );
4810 
4811    return TRUE; // Always returns true!!!!
4812 }
4813 
4814 BOOLEAN APIENTRY
4815 intGetTitleBarInfo(PWND pWindowObject, PTITLEBARINFO bti)
4816 {
4817 
4818     DWORD dwStyle = 0;
4819     DWORD dwExStyle = 0;
4820     BOOLEAN retValue = TRUE;
4821 
4822     if (bti->cbSize == sizeof(TITLEBARINFO))
4823     {
4824         RtlZeroMemory(&bti->rgstate[0],sizeof(DWORD)*(CCHILDREN_TITLEBAR+1));
4825 
4826         bti->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
4827 
4828         dwStyle = pWindowObject->style;
4829         dwExStyle = pWindowObject->ExStyle;
4830 
4831         bti->rcTitleBar.top  = 0;
4832         bti->rcTitleBar.left = 0;
4833         bti->rcTitleBar.right  = pWindowObject->rcWindow.right - pWindowObject->rcWindow.left;
4834         bti->rcTitleBar.bottom = pWindowObject->rcWindow.bottom - pWindowObject->rcWindow.top;
4835 
4836         /* Is it iconiced ? */
4837         if ((dwStyle & WS_ICONIC)!=WS_ICONIC)
4838         {
4839             /* Remove frame from rectangle */
4840             if (HAS_THICKFRAME( dwStyle, dwExStyle ))
4841             {
4842                 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
4843                 RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) );
4844             }
4845             else if (HAS_DLGFRAME( dwStyle, dwExStyle ))
4846             {
4847                 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
4848                 RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
4849             }
4850             else if (HAS_THINFRAME( dwStyle, dwExStyle))
4851             {
4852                 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4853                 RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER) );
4854             }
4855 
4856             /* We have additional border information if the window
4857              * is a child (but not an MDI child) */
4858             if ( (dwStyle & WS_CHILD)  &&
4859                  ((dwExStyle & WS_EX_MDICHILD) == 0 ) )
4860             {
4861                 if (dwExStyle & WS_EX_CLIENTEDGE)
4862                 {
4863                     /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
4864                     RECTL_vInflateRect (&bti->rcTitleBar, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE));
4865                 }
4866 
4867                 if (dwExStyle & WS_EX_STATICEDGE)
4868                 {
4869                     /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
4870                     RECTL_vInflateRect (&bti->rcTitleBar, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
4871                 }
4872             }
4873         }
4874 
4875         bti->rcTitleBar.top += pWindowObject->rcWindow.top;
4876         bti->rcTitleBar.left += pWindowObject->rcWindow.left;
4877         bti->rcTitleBar.right += pWindowObject->rcWindow.left;
4878 
4879         bti->rcTitleBar.bottom = bti->rcTitleBar.top;
4880         if (dwExStyle & WS_EX_TOOLWINDOW)
4881         {
4882             /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
4883             bti->rcTitleBar.bottom += UserGetSystemMetrics(SM_CYSMCAPTION);
4884         }
4885         else
4886         {
4887             /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
4888             bti->rcTitleBar.bottom += UserGetSystemMetrics(SM_CYCAPTION);
4889             bti->rcTitleBar.left += UserGetSystemMetrics(SM_CXSIZE);
4890         }
4891 
4892         if (dwStyle & WS_CAPTION)
4893         {
4894             bti->rgstate[1] = STATE_SYSTEM_INVISIBLE;
4895             if (dwStyle & WS_SYSMENU)
4896             {
4897                 if (!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX)))
4898                 {
4899                     bti->rgstate[2] = STATE_SYSTEM_INVISIBLE;
4900                     bti->rgstate[3] = STATE_SYSTEM_INVISIBLE;
4901                 }
4902                 else
4903                 {
4904                     if (!(dwStyle & WS_MINIMIZEBOX))
4905                     {
4906                         bti->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
4907                     }
4908                     if (!(dwStyle & WS_MAXIMIZEBOX))
4909                     {
4910                         bti->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
4911                     }
4912                 }
4913 
4914                 if (!(dwExStyle & WS_EX_CONTEXTHELP))
4915                 {
4916                     bti->rgstate[4] = STATE_SYSTEM_INVISIBLE;
4917                 }
4918                 if (pWindowObject->pcls->style & CS_NOCLOSE)
4919                 {
4920                     bti->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
4921                 }
4922             }
4923             else
4924             {
4925                 bti->rgstate[2] = STATE_SYSTEM_INVISIBLE;
4926                 bti->rgstate[3] = STATE_SYSTEM_INVISIBLE;
4927                 bti->rgstate[4] = STATE_SYSTEM_INVISIBLE;
4928                 bti->rgstate[5] = STATE_SYSTEM_INVISIBLE;
4929             }
4930         }
4931         else
4932         {
4933             bti->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
4934         }
4935     }
4936     else
4937     {
4938         EngSetLastError(ERROR_INVALID_PARAMETER);
4939         retValue = FALSE;
4940     }
4941 
4942     return retValue;
4943 }
4944 
4945 DWORD FASTCALL
4946 UserInsertMenuItem(
4947    PMENU Menu,
4948    UINT uItem,
4949    BOOL fByPosition,
4950    LPCMENUITEMINFOW UnsafeItemInfo,
4951    PUNICODE_STRING lpstr)
4952 {
4953    NTSTATUS Status;
4954    ROSMENUITEMINFO ItemInfo;
4955 
4956    /* Try to copy the whole MENUITEMINFOW structure */
4957    Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, sizeof(MENUITEMINFOW));
4958    if (NT_SUCCESS(Status))
4959    {
4960       if (sizeof(MENUITEMINFOW) != ItemInfo.cbSize
4961          && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize)
4962       {
4963          EngSetLastError(ERROR_INVALID_PARAMETER);
4964          return FALSE;
4965       }
4966       return IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo, lpstr);
4967    }
4968 
4969    /* Try to copy without last field (not present in older versions) */
4970    Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, FIELD_OFFSET(MENUITEMINFOW, hbmpItem));
4971    if (NT_SUCCESS(Status))
4972    {
4973       if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize)
4974       {
4975          EngSetLastError(ERROR_INVALID_PARAMETER);
4976          return FALSE;
4977       }
4978       ItemInfo.hbmpItem = (HBITMAP)0;
4979       return IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo, lpstr);
4980    }
4981 
4982    SetLastNtError(Status);
4983    return FALSE;
4984 }
4985 
4986 UINT FASTCALL IntGetMenuState( HMENU hMenu, UINT uId, UINT uFlags)
4987 {
4988    PMENU MenuObject;
4989    PITEM pItem;
4990 
4991    if (!(MenuObject = UserGetMenuObject(hMenu)))
4992    {
4993       return (UINT)-1;
4994    }
4995 
4996    if (!(pItem = MENU_FindItem( &MenuObject, &uId, uFlags ))) return -1;
4997 
4998    if (pItem->spSubMenu)
4999    {
5000       return (pItem->spSubMenu->cItems << 8) | ((pItem->fState|pItem->fType|MF_POPUP) & 0xff);
5001    }
5002    else
5003       return (pItem->fType | pItem->fState);
5004 }
5005 
5006 HMENU FASTCALL IntGetSubMenu( HMENU hMenu, int nPos)
5007 {
5008    PMENU MenuObject;
5009    PITEM pItem;
5010 
5011    if (!(MenuObject = UserGetMenuObject(hMenu)))
5012    {
5013       return NULL;
5014    }
5015 
5016    if (!(pItem = MENU_FindItem( &MenuObject, (UINT*)&nPos, MF_BYPOSITION ))) return NULL;
5017 
5018    if (pItem->spSubMenu)
5019    {
5020       HMENU hsubmenu = UserHMGetHandle(pItem->spSubMenu);
5021       return hsubmenu;
5022    }
5023    return NULL;
5024 }
5025 
5026 UINT FASTCALL IntFindSubMenu(HMENU *hMenu, HMENU hSubTarget )
5027 {
5028     PMENU menu, pSubTarget;
5029     UINT Pos;
5030     if (((*hMenu)==(HMENU)0xffff) ||(!(menu = UserGetMenuObject(*hMenu))))
5031         return NO_SELECTED_ITEM;
5032 
5033     pSubTarget = UserGetMenuObject(hSubTarget);
5034 
5035     Pos = MENU_FindSubMenu(&menu, pSubTarget );
5036 
5037     *hMenu = (menu ? UserHMGetHandle(menu) : NULL);
5038 
5039     return Pos;
5040 }
5041 
5042 
5043 HMENU FASTCALL UserCreateMenu(PDESKTOP Desktop, BOOL PopupMenu)
5044 {
5045    PWINSTATION_OBJECT WinStaObject;
5046    HANDLE Handle;
5047    PMENU Menu;
5048    NTSTATUS Status;
5049    PEPROCESS CurrentProcess = PsGetCurrentProcess();
5050 
5051    if (gpepCSRSS != CurrentProcess)
5052    {
5053       /*
5054        * gpepCSRSS does not have a Win32WindowStation
5055        */
5056 
5057       Status = IntValidateWindowStationHandle(CurrentProcess->Win32WindowStation,
5058                      UserMode,
5059                      0,
5060                      &WinStaObject,
5061                      0);
5062 
5063        if (!NT_SUCCESS(Status))
5064        {
5065           ERR("Validation of window station handle (%p) failed\n",
5066               CurrentProcess->Win32WindowStation);
5067           SetLastNtError(Status);
5068           return (HMENU)0;
5069        }
5070        Menu = IntCreateMenu(&Handle, !PopupMenu, Desktop, GetW32ProcessInfo());
5071        if (Menu && Menu->head.rpdesk->rpwinstaParent != WinStaObject)
5072        {
5073           ERR("Desktop Window Station does not match Process one!\n");
5074        }
5075        ObDereferenceObject(WinStaObject);
5076    }
5077    else
5078    {
5079        Menu = IntCreateMenu(&Handle, !PopupMenu, GetW32ThreadInfo()->rpdesk, GetW32ProcessInfo());
5080    }
5081 
5082    if (Menu) UserDereferenceObject(Menu);
5083    return (HMENU)Handle;
5084 }
5085 
5086 BOOL FASTCALL
5087 IntMenuItemInfo(
5088    PMENU Menu,
5089    UINT Item,
5090    BOOL ByPosition,
5091    PROSMENUITEMINFO ItemInfo,
5092    BOOL SetOrGet,
5093    PUNICODE_STRING lpstr)
5094 {
5095    PITEM MenuItem;
5096    BOOL Ret;
5097 
5098    if (!(MenuItem = MENU_FindItem( &Menu, &Item, (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND) )))
5099    {
5100       EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND);
5101       return FALSE;
5102    }
5103    if (SetOrGet)
5104    {
5105       Ret = IntSetMenuItemInfo(Menu, MenuItem, ItemInfo, lpstr);
5106    }
5107    else
5108    {
5109       Ret = IntGetMenuItemInfo(Menu, MenuItem, ItemInfo);
5110    }
5111    return Ret;
5112 }
5113 
5114 BOOL FASTCALL
5115 UserMenuItemInfo(
5116    PMENU Menu,
5117    UINT Item,
5118    BOOL ByPosition,
5119    PROSMENUITEMINFO UnsafeItemInfo,
5120    BOOL SetOrGet,
5121    PUNICODE_STRING lpstr)
5122 {
5123    PITEM MenuItem;
5124    ROSMENUITEMINFO ItemInfo;
5125    NTSTATUS Status;
5126    UINT Size;
5127    BOOL Ret;
5128 
5129    Status = MmCopyFromCaller(&Size, &UnsafeItemInfo->cbSize, sizeof(UINT));
5130    if (! NT_SUCCESS(Status))
5131    {
5132       SetLastNtError(Status);
5133       return FALSE;
5134    }
5135    if ( Size != sizeof(MENUITEMINFOW) &&
5136         Size != FIELD_OFFSET(MENUITEMINFOW, hbmpItem) &&
5137         Size != sizeof(ROSMENUITEMINFO) )
5138    {
5139       EngSetLastError(ERROR_INVALID_PARAMETER);
5140       return FALSE;
5141    }
5142    Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, Size);
5143    if (! NT_SUCCESS(Status))
5144    {
5145       SetLastNtError(Status);
5146       return FALSE;
5147    }
5148    /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
5149       set/get hbmpItem */
5150    if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) == Size
5151          && 0 != (ItemInfo.fMask & MIIM_BITMAP))
5152    {
5153       EngSetLastError(ERROR_INVALID_PARAMETER);
5154       return FALSE;
5155    }
5156 
5157    if (!(MenuItem = MENU_FindItem( &Menu, &Item, (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND) )))
5158    {
5159       /* workaround for Word 95: pretend that SC_TASKLIST item exists. */
5160       if ( SetOrGet && Item == SC_TASKLIST && !ByPosition )
5161          return TRUE;
5162 
5163       EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND);
5164       return FALSE;
5165    }
5166 
5167    if (SetOrGet)
5168    {
5169       Ret = IntSetMenuItemInfo(Menu, MenuItem, &ItemInfo, lpstr);
5170    }
5171    else
5172    {
5173       Ret = IntGetMenuItemInfo(Menu, MenuItem, &ItemInfo);
5174       if (Ret)
5175       {
5176          Status = MmCopyToCaller(UnsafeItemInfo, &ItemInfo, Size);
5177          if (! NT_SUCCESS(Status))
5178          {
5179             SetLastNtError(Status);
5180             return FALSE;
5181          }
5182       }
5183    }
5184 
5185    return Ret;
5186 }
5187 
5188 BOOL FASTCALL
5189 UserMenuInfo(
5190    PMENU Menu,
5191    PROSMENUINFO UnsafeMenuInfo,
5192    BOOL SetOrGet)
5193 {
5194    BOOL Res;
5195    DWORD Size;
5196    NTSTATUS Status;
5197    ROSMENUINFO MenuInfo;
5198 
5199    Status = MmCopyFromCaller(&Size, &UnsafeMenuInfo->cbSize, sizeof(DWORD));
5200    if (! NT_SUCCESS(Status))
5201    {
5202       SetLastNtError(Status);
5203       return FALSE;
5204    }
5205    if ( Size < sizeof(MENUINFO) || Size > sizeof(ROSMENUINFO) )
5206    {
5207       EngSetLastError(ERROR_INVALID_PARAMETER);
5208       return FALSE;
5209    }
5210    Status = MmCopyFromCaller(&MenuInfo, UnsafeMenuInfo, Size);
5211    if (! NT_SUCCESS(Status))
5212    {
5213       SetLastNtError(Status);
5214       return FALSE;
5215    }
5216 
5217    if(SetOrGet)
5218    {
5219       /* Set MenuInfo */
5220       Res = IntSetMenuInfo(Menu, &MenuInfo);
5221    }
5222    else
5223    {
5224       /* Get MenuInfo */
5225       Res = IntGetMenuInfo(Menu, &MenuInfo);
5226       if (Res)
5227       {
5228          Status = MmCopyToCaller(UnsafeMenuInfo, &MenuInfo, Size);
5229          if (! NT_SUCCESS(Status))
5230          {
5231             SetLastNtError(Status);
5232             return FALSE;
5233          }
5234       }
5235    }
5236 
5237    return Res;
5238 }
5239 
5240 BOOL FASTCALL
5241 IntGetMenuItemRect(
5242    PWND pWnd,
5243    PMENU Menu,
5244    UINT uItem,
5245    PRECTL Rect)
5246 {
5247    LONG XMove, YMove;
5248    PITEM MenuItem;
5249    UINT I = uItem;
5250 
5251    if ((MenuItem = MENU_FindItem (&Menu, &I, MF_BYPOSITION)))
5252    {
5253       Rect->left   = MenuItem->xItem;
5254       Rect->top    = MenuItem->yItem;
5255       Rect->right  = MenuItem->cxItem; // Do this for now......
5256       Rect->bottom = MenuItem->cyItem;
5257    }
5258    else
5259    {
5260       ERR("Failed Item Lookup! %u\n", uItem);
5261       return FALSE;
5262    }
5263 
5264    if (!pWnd)
5265    {
5266       HWND hWnd = Menu->hWnd;
5267       if (!(pWnd = UserGetWindowObject(hWnd))) return FALSE;
5268    }
5269 
5270    if (Menu->fFlags & MNF_POPUP)
5271    {
5272      XMove = pWnd->rcClient.left;
5273      YMove = pWnd->rcClient.top;
5274    }
5275    else
5276    {
5277      XMove = pWnd->rcWindow.left;
5278      YMove = pWnd->rcWindow.top;
5279    }
5280 
5281    Rect->left   += XMove;
5282    Rect->top    += YMove;
5283    Rect->right  += XMove;
5284    Rect->bottom += YMove;
5285 
5286    return TRUE;
5287 }
5288 
5289 PMENU FASTCALL MENU_GetSystemMenu(PWND Window, PMENU Popup)
5290 {
5291    PMENU Menu, NewMenu = NULL, SysMenu = NULL;
5292    HMENU hSysMenu, hNewMenu = NULL;
5293    ROSMENUITEMINFO ItemInfoSet = {0};
5294    ROSMENUITEMINFO ItemInfo = {0};
5295    UNICODE_STRING MenuName;
5296 
5297    hSysMenu = UserCreateMenu(Window->head.rpdesk, FALSE);
5298    if (NULL == hSysMenu)
5299    {
5300       return NULL;
5301    }
5302    SysMenu = UserGetMenuObject(hSysMenu);
5303    if (NULL == SysMenu)
5304    {
5305        UserDestroyMenu(hSysMenu);
5306        return NULL;
5307    }
5308 
5309    SysMenu->fFlags |= MNF_SYSMENU;
5310    SysMenu->hWnd = UserHMGetHandle(Window);
5311 
5312    if (!Popup)
5313    {
5314       //hNewMenu = co_IntLoadSysMenuTemplate();
5315       if ( Window->ExStyle & WS_EX_MDICHILD )
5316       {
5317          RtlInitUnicodeString( &MenuName, L"SYSMENUMDI");
5318          hNewMenu = co_IntCallLoadMenu( hModClient, &MenuName);
5319       }
5320       else
5321       {
5322          RtlInitUnicodeString( &MenuName, L"SYSMENU");
5323          hNewMenu = co_IntCallLoadMenu( hModClient, &MenuName);
5324          //ERR("%wZ\n",&MenuName);
5325       }
5326       if (!hNewMenu)
5327       {
5328          ERR("No Menu!!\n");
5329          IntDestroyMenuObject(SysMenu, FALSE);
5330          return NULL;
5331       }
5332       Menu = UserGetMenuObject(hNewMenu);
5333       if (!Menu)
5334       {
5335          IntDestroyMenuObject(SysMenu, FALSE);
5336          return NULL;
5337       }
5338 
5339       // Do the rest in here.
5340 
5341       Menu->fFlags |= MNS_CHECKORBMP | MNF_SYSMENU  | MNF_POPUP;
5342 
5343       ItemInfoSet.cbSize = sizeof( MENUITEMINFOW);
5344       ItemInfoSet.fMask = MIIM_BITMAP;
5345       ItemInfoSet.hbmpItem = HBMMENU_POPUP_CLOSE;
5346       IntMenuItemInfo(Menu, SC_CLOSE, FALSE, &ItemInfoSet, TRUE, NULL);
5347       ItemInfoSet.hbmpItem = HBMMENU_POPUP_RESTORE;
5348       IntMenuItemInfo(Menu, SC_RESTORE, FALSE, &ItemInfoSet, TRUE, NULL);
5349       ItemInfoSet.hbmpItem = HBMMENU_POPUP_MAXIMIZE;
5350       IntMenuItemInfo(Menu, SC_MAXIMIZE, FALSE, &ItemInfoSet, TRUE, NULL);
5351       ItemInfoSet.hbmpItem = HBMMENU_POPUP_MINIMIZE;
5352       IntMenuItemInfo(Menu, SC_MINIMIZE, FALSE, &ItemInfoSet, TRUE, NULL);
5353 
5354       NewMenu = IntCloneMenu(Menu);
5355       if (NewMenu == NULL)
5356       {
5357          IntDestroyMenuObject(Menu, FALSE);
5358          IntDestroyMenuObject(SysMenu, FALSE);
5359          return NULL;
5360       }
5361 
5362       IntReleaseMenuObject(NewMenu);
5363       UserSetMenuDefaultItem(NewMenu, SC_CLOSE, FALSE);
5364 
5365       IntDestroyMenuObject(Menu, FALSE);
5366    }
5367    else
5368    {
5369       NewMenu = Popup;
5370    }
5371    if (NewMenu)
5372    {
5373       NewMenu->fFlags |= MNF_SYSMENU | MNF_POPUP;
5374 
5375       if (Window->pcls->style & CS_NOCLOSE)
5376          IntRemoveMenuItem(NewMenu, SC_CLOSE, MF_BYCOMMAND, TRUE);
5377 
5378       ItemInfo.cbSize = sizeof(MENUITEMINFOW);
5379       ItemInfo.fMask = MIIM_FTYPE | MIIM_STRING | MIIM_STATE | MIIM_SUBMENU;
5380       ItemInfo.fType = MF_POPUP;
5381       ItemInfo.fState = MFS_ENABLED;
5382       ItemInfo.dwTypeData = NULL;
5383       ItemInfo.cch = 0;
5384       ItemInfo.hSubMenu = UserHMGetHandle(NewMenu);
5385       IntInsertMenuItem(SysMenu, (UINT) -1, TRUE, &ItemInfo, NULL);
5386 
5387       return SysMenu;
5388    }
5389    ERR("failed to load system menu!\n");
5390    return NULL;
5391 }
5392 
5393 PMENU FASTCALL
5394 IntGetSystemMenu(PWND Window, BOOL bRevert)
5395 {
5396    PMENU Menu;
5397 
5398    if (bRevert)
5399    {
5400       if (Window->SystemMenu)
5401       {
5402          Menu = UserGetMenuObject(Window->SystemMenu);
5403          if (Menu && !(Menu->fFlags & MNF_SYSDESKMN))
5404          {
5405             IntDestroyMenuObject(Menu, TRUE);
5406             Window->SystemMenu = NULL;
5407          }
5408       }
5409    }
5410    else
5411    {
5412       Menu = Window->SystemMenu ? UserGetMenuObject(Window->SystemMenu) : NULL;
5413       if ((!Menu || Menu->fFlags & MNF_SYSDESKMN) && Window->style & WS_SYSMENU)
5414       {
5415          Menu = MENU_GetSystemMenu(Window, NULL);
5416          Window->SystemMenu = Menu ? UserHMGetHandle(Menu) : NULL;
5417       }
5418    }
5419 
5420    if (Window->SystemMenu)
5421    {
5422       HMENU hMenu = IntGetSubMenu( Window->SystemMenu, 0);
5423       /* Store the dummy sysmenu handle to facilitate the refresh */
5424       /* of the close button if the SC_CLOSE item change */
5425       Menu = UserGetMenuObject(hMenu);
5426       if (Menu)
5427       {
5428          Menu->spwndNotify = Window;
5429          Menu->fFlags |= MNF_SYSSUBMENU;
5430       }
5431       return Menu;
5432    }
5433    return NULL;
5434 }
5435 
5436 BOOL FASTCALL
5437 IntSetSystemMenu(PWND Window, PMENU Menu)
5438 {
5439    PMENU OldMenu;
5440 
5441    if (!(Window->style & WS_SYSMENU)) return FALSE;
5442 
5443    if (Window->SystemMenu)
5444    {
5445       OldMenu = UserGetMenuObject(Window->SystemMenu);
5446       if (OldMenu)
5447       {
5448           OldMenu->fFlags &= ~MNF_SYSMENU;
5449           IntDestroyMenuObject(OldMenu, TRUE);
5450       }
5451    }
5452 
5453    OldMenu = MENU_GetSystemMenu(Window, Menu);
5454    if (OldMenu)
5455    {  // Use spmenuSys too!
5456       Window->SystemMenu = UserHMGetHandle(OldMenu);
5457    }
5458    else
5459       Window->SystemMenu = NULL;
5460 
5461    if (Menu && Window != Menu->spwndNotify)
5462    {
5463       Menu->spwndNotify = Window;
5464    }
5465 
5466    return TRUE;
5467 }
5468 
5469 BOOL FASTCALL
5470 IntSetMenu(
5471    PWND Wnd,
5472    HMENU Menu,
5473    BOOL *Changed)
5474 {
5475    PMENU OldMenu, NewMenu = NULL;
5476 
5477    if ((Wnd->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
5478    {
5479       ERR("SetMenu: Window is a Child 0x%p!\n",UserHMGetHandle(Wnd));
5480       EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
5481       return FALSE;
5482    }
5483 
5484    *Changed = (UlongToHandle(Wnd->IDMenu) != Menu);
5485    if (! *Changed)
5486    {
5487       return TRUE;
5488    }
5489 
5490    if (Wnd->IDMenu)
5491    {
5492       OldMenu = IntGetMenuObject(UlongToHandle(Wnd->IDMenu));
5493       ASSERT(NULL == OldMenu || OldMenu->hWnd == UserHMGetHandle(Wnd));
5494    }
5495    else
5496    {
5497       OldMenu = NULL;
5498    }
5499 
5500    if (NULL != Menu)
5501    {
5502       NewMenu = IntGetMenuObject(Menu);
5503       if (NULL == NewMenu)
5504       {
5505          if (NULL != OldMenu)
5506          {
5507             IntReleaseMenuObject(OldMenu);
5508          }
5509          EngSetLastError(ERROR_INVALID_MENU_HANDLE);
5510          return FALSE;
5511       }
5512       if (NULL != NewMenu->hWnd)
5513       {
5514          /* Can't use the same menu for two windows */
5515          if (NULL != OldMenu)
5516          {
5517             IntReleaseMenuObject(OldMenu);
5518          }
5519          EngSetLastError(ERROR_INVALID_MENU_HANDLE);
5520          return FALSE;
5521       }
5522 
5523    }
5524 
5525    Wnd->IDMenu = (UINT_PTR) Menu;
5526    if (NULL != NewMenu)
5527    {
5528       NewMenu->hWnd = UserHMGetHandle(Wnd);
5529       IntReleaseMenuObject(NewMenu);
5530    }
5531    if (NULL != OldMenu)
5532    {
5533       OldMenu->hWnd = NULL;
5534       IntReleaseMenuObject(OldMenu);
5535    }
5536 
5537    return TRUE;
5538 }
5539 
5540 
5541 /* FUNCTIONS *****************************************************************/
5542 
5543 /*
5544  * @implemented
5545  */
5546 /* http://www.cyber-ta.org/releases/malware-analysis/public/SOURCES/b47155634ccb2c30630da7e3666d3d07/b47155634ccb2c30630da7e3666d3d07.trace.html#NtUserGetIconSize */
5547 DWORD
5548 APIENTRY
5549 NtUserCalcMenuBar(
5550     HWND   hwnd,
5551     DWORD  leftBorder,
5552     DWORD  rightBorder,
5553     DWORD  top,
5554     LPRECT prc )
5555 {
5556     HDC hdc;
5557     PWND Window;
5558     RECT Rect;
5559     DWORD ret;
5560 
5561     UserEnterExclusive();
5562 
5563     if(!(Window = UserGetWindowObject(hwnd)))
5564     {
5565         EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
5566         UserLeave();
5567         return 0;
5568     }
5569 
5570     hdc = UserGetDCEx(NULL, NULL, DCX_CACHE);
5571     if (!hdc)
5572     {
5573         UserLeave();
5574         return 0;
5575     }
5576 
5577     Rect.left = leftBorder;
5578     Rect.right = Window->rcWindow.right - Window->rcWindow.left - rightBorder;
5579     Rect.top = top;
5580     Rect.bottom = 0;
5581 
5582     ret = MENU_DrawMenuBar(hdc, &Rect, Window, TRUE);
5583 
5584     UserReleaseDC( 0, hdc, FALSE );
5585 
5586     UserLeave();
5587 
5588     return ret;
5589 }
5590 
5591 /*
5592  * @implemented
5593  */
5594 DWORD APIENTRY
5595 NtUserCheckMenuItem(
5596    HMENU hMenu,
5597    UINT uIDCheckItem,
5598    UINT uCheck)
5599 {
5600    PMENU Menu;
5601    DWORD Ret = (DWORD)-1;
5602 
5603    TRACE("Enter NtUserCheckMenuItem\n");
5604    UserEnterExclusive();
5605 
5606    Menu = UserGetMenuObject(hMenu);
5607    if (Menu)
5608    {
5609       Ret = IntCheckMenuItem(Menu, uIDCheckItem, uCheck);
5610    }
5611 
5612    TRACE("Leave NtUserCheckMenuItem, ret=%lu\n", Ret);
5613    UserLeave();
5614    return Ret;
5615 }
5616 
5617 /*
5618  * @implemented
5619  */
5620 BOOL APIENTRY
5621 NtUserDeleteMenu(
5622    HMENU hMenu,
5623    UINT uPosition,
5624    UINT uFlags)
5625 {
5626    PMENU Menu;
5627    BOOL Ret = FALSE;
5628 
5629    TRACE("Enter NtUserDeleteMenu\n");
5630    UserEnterExclusive();
5631 
5632    Menu = UserGetMenuObject(hMenu);
5633    if (Menu)
5634    {
5635       Ret = IntRemoveMenuItem(Menu, uPosition, uFlags, TRUE);
5636    }
5637 
5638    TRACE("Leave NtUserDeleteMenu, ret=%i\n", Ret);
5639    UserLeave();
5640    return Ret;
5641 }
5642 
5643 /*
5644  * NtUserGetSystemMenu
5645  *
5646  * The NtUserGetSystemMenu function allows the application to access the
5647  * window menu (also known as the system menu or the control menu) for
5648  * copying and modifying.
5649  *
5650  * Parameters
5651  *    hWnd
5652  *       Handle to the window that will own a copy of the window menu.
5653  *    bRevert
5654  *       Specifies the action to be taken. If this parameter is FALSE,
5655  *       NtUserGetSystemMenu returns a handle to the copy of the window menu
5656  *       currently in use. The copy is initially identical to the window menu
5657  *       but it can be modified.
5658  *       If this parameter is TRUE, GetSystemMenu resets the window menu back
5659  *       to the default state. The previous window menu, if any, is destroyed.
5660  *
5661  * Return Value
5662  *    If the bRevert parameter is FALSE, the return value is a handle to a
5663  *    copy of the window menu. If the bRevert parameter is TRUE, the return
5664  *    value is NULL.
5665  *
5666  * Status
5667  *    @implemented
5668  */
5669 
5670 HMENU APIENTRY
5671 NtUserGetSystemMenu(HWND hWnd, BOOL bRevert)
5672 {
5673    PWND Window;
5674    PMENU Menu;
5675    HMENU Ret = NULL;
5676 
5677    TRACE("Enter NtUserGetSystemMenu\n");
5678    UserEnterExclusive();
5679 
5680    if (!(Window = UserGetWindowObject(hWnd)))
5681    {
5682       goto Exit; // Return NULL
5683    }
5684 
5685    if (!(Menu = IntGetSystemMenu(Window, bRevert)))
5686    {
5687       goto Exit; // Return NULL
5688    }
5689 
5690    Ret = UserHMGetHandle(Menu);
5691 
5692 Exit:
5693    TRACE("Leave NtUserGetSystemMenu, ret=%p\n", Ret);
5694    UserLeave();
5695    return Ret;
5696 }
5697 
5698 /*
5699  * NtUserSetSystemMenu
5700  *
5701  * Status
5702  *    @implemented
5703  */
5704 
5705 BOOL APIENTRY
5706 NtUserSetSystemMenu(HWND hWnd, HMENU hMenu)
5707 {
5708    BOOL Result = FALSE;
5709    PWND Window;
5710    PMENU Menu;
5711 
5712    TRACE("Enter NtUserSetSystemMenu\n");
5713    UserEnterExclusive();
5714 
5715    if (!(Window = UserGetWindowObject(hWnd)))
5716    {
5717       goto Exit; // Return FALSE
5718    }
5719 
5720    if (hMenu)
5721    {
5722       /*
5723        * Assign new menu handle and Up the Lock Count.
5724        */
5725       if (!(Menu = IntGetMenuObject(hMenu)))
5726       {
5727          goto Exit; // Return FALSE
5728       }
5729 
5730       Result = IntSetSystemMenu(Window, Menu);
5731    }
5732    else
5733       EngSetLastError(ERROR_INVALID_MENU_HANDLE);
5734 
5735 Exit:
5736    TRACE("Leave NtUserSetSystemMenu, ret=%i\n", Result);
5737    UserLeave();
5738    return Result;
5739 }
5740 
5741 /*
5742  * @implemented
5743  */
5744 BOOLEAN APIENTRY
5745 NtUserGetTitleBarInfo(
5746     HWND hwnd,
5747     PTITLEBARINFO bti)
5748 {
5749     PWND WindowObject;
5750     TITLEBARINFO bartitleinfo;
5751     BOOLEAN retValue = TRUE;
5752 
5753     TRACE("Enter NtUserGetTitleBarInfo\n");
5754     UserEnterExclusive();
5755 
5756     /* Vaildate the windows handle */
5757     if (!(WindowObject = UserGetWindowObject(hwnd)))
5758     {
5759         EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
5760         retValue = FALSE;
5761     }
5762 
5763     _SEH2_TRY
5764     {
5765         /* Copy our usermode buffer bti to local buffer bartitleinfo */
5766         ProbeForRead(bti, sizeof(TITLEBARINFO), 1);
5767         RtlCopyMemory(&bartitleinfo, bti, sizeof(TITLEBARINFO));
5768     }
5769     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5770     {
5771         /* Fail copy the data */
5772         EngSetLastError(ERROR_INVALID_PARAMETER);
5773         retValue = FALSE;
5774     }
5775     _SEH2_END
5776 
5777     /* Get the tile bar info */
5778     if (retValue)
5779     {
5780         retValue = intGetTitleBarInfo(WindowObject, &bartitleinfo);
5781         if (retValue)
5782         {
5783             _SEH2_TRY
5784             {
5785                 /* Copy our buffer to user mode buffer bti */
5786                 ProbeForWrite(bti, sizeof(TITLEBARINFO), 1);
5787                 RtlCopyMemory(bti, &bartitleinfo, sizeof(TITLEBARINFO));
5788             }
5789             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5790             {
5791                 /* Fail copy the data */
5792                 EngSetLastError(ERROR_INVALID_PARAMETER);
5793                 retValue = FALSE;
5794             }
5795             _SEH2_END
5796         }
5797     }
5798 
5799     TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n", retValue);
5800     UserLeave();
5801     return retValue;
5802 }
5803 
5804 /*
5805  * @implemented
5806  */
5807 BOOL FASTCALL UserDestroyMenu(HMENU hMenu)
5808 {
5809    PMENU Menu;
5810    PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
5811 
5812    if(!(Menu = UserGetMenuObject(hMenu)))
5813    {
5814       return FALSE;
5815    }
5816 
5817    if (Menu->head.rpdesk != pti->rpdesk)
5818    {
5819       EngSetLastError(ERROR_ACCESS_DENIED);
5820       return FALSE;
5821    }
5822    return IntDestroyMenuObject(Menu, FALSE);
5823 }
5824 
5825 /*
5826  * @implemented
5827  */
5828 BOOL APIENTRY
5829 NtUserDestroyMenu(
5830    HMENU hMenu)
5831 {
5832    PMENU Menu;
5833    BOOL Ret = FALSE;
5834 
5835    TRACE("Enter NtUserDestroyMenu\n");
5836    UserEnterExclusive();
5837 
5838    if(!(Menu = UserGetMenuObject(hMenu)))
5839    {
5840       goto Exit; // Return FALSE
5841    }
5842    if (Menu->head.rpdesk != gptiCurrent->rpdesk)
5843    {
5844       EngSetLastError(ERROR_ACCESS_DENIED);
5845       goto Exit; // Return FALSE
5846    }
5847    Ret = IntDestroyMenuObject(Menu, TRUE);
5848 
5849 Exit:
5850    TRACE("Leave NtUserDestroyMenu, ret=%i\n", Ret);
5851    UserLeave();
5852    return Ret;
5853 }
5854 
5855 /*
5856  * @implemented
5857  */
5858 UINT APIENTRY
5859 NtUserEnableMenuItem(
5860    HMENU hMenu,
5861    UINT uIDEnableItem,
5862    UINT uEnable)
5863 {
5864    PMENU Menu;
5865    UINT Ret = (UINT)-1;
5866 
5867    TRACE("Enter NtUserEnableMenuItem\n");
5868    UserEnterExclusive();
5869 
5870    Menu = UserGetMenuObject(hMenu);
5871    if (Menu)
5872    {
5873       Ret = IntEnableMenuItem(Menu, uIDEnableItem, uEnable);
5874    }
5875 
5876    TRACE("Leave NtUserEnableMenuItem, ret=%u\n", Ret);
5877    UserLeave();
5878    return Ret;
5879 }
5880 
5881 /*
5882  * @implemented
5883  */
5884 BOOL APIENTRY
5885 NtUserEndMenu(VOID)
5886 {
5887    //PWND pWnd;
5888    TRACE("Enter NtUserEndMenu\n");
5889    UserEnterExclusive();
5890  /*  if ( gptiCurrent->pMenuState &&
5891         gptiCurrent->pMenuState->pGlobalPopupMenu )
5892    {
5893        pWnd = IntGetMSWND(gptiCurrent->pMenuState);
5894        if (pWnd)
5895        {
5896           UserPostMessage( UserHMGetHandle(pWnd), WM_CANCELMODE, 0, 0);
5897        }
5898        else
5899           gptiCurrent->pMenuState->fInsideMenuLoop = FALSE;
5900    }*/
5901    if (fInsideMenuLoop && top_popup)
5902    {
5903       fInsideMenuLoop = FALSE;
5904       UserPostMessage( top_popup, WM_CANCELMODE, 0, 0);
5905    }
5906    UserLeave();
5907    TRACE("Leave NtUserEndMenu\n");
5908    return TRUE;
5909 }
5910 
5911 /*
5912  * @implemented
5913  */
5914 BOOL APIENTRY
5915 NtUserGetMenuBarInfo(
5916    HWND hwnd,
5917    LONG idObject,
5918    LONG idItem,
5919    PMENUBARINFO pmbi)
5920 {
5921    PWND pWnd;
5922    HMENU hMenu;
5923    MENUBARINFO kmbi;
5924    BOOL Ret = FALSE;
5925    PPOPUPMENU pPopupMenu;
5926    USER_REFERENCE_ENTRY Ref;
5927    NTSTATUS Status = STATUS_SUCCESS;
5928    PMENU Menu = NULL;
5929 
5930    TRACE("Enter NtUserGetMenuBarInfo\n");
5931    UserEnterShared();
5932 
5933    if (!(pWnd = UserGetWindowObject(hwnd)))
5934    {
5935         EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
5936         goto Cleanup; // Return FALSE
5937    }
5938 
5939    UserRefObjectCo(pWnd, &Ref);
5940 
5941    RECTL_vSetEmptyRect(&kmbi.rcBar);
5942    kmbi.hMenu = NULL;
5943    kmbi.hwndMenu = NULL;
5944    kmbi.fBarFocused = FALSE;
5945    kmbi.fFocused = FALSE;
5946 
5947    switch (idObject)
5948    {
5949     case OBJID_CLIENT:
5950         if (!pWnd->pcls->fnid)
5951             goto Cleanup; // Return FALSE
5952         if (pWnd->pcls->fnid != FNID_MENU)
5953         {
5954             WARN("called on invalid window: %u\n", pWnd->pcls->fnid);
5955             EngSetLastError(ERROR_INVALID_MENU_HANDLE);
5956             goto Cleanup; // Return FALSE
5957         }
5958         // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
5959         hMenu = (HMENU)co_IntSendMessage(hwnd, MN_GETHMENU, 0, 0);
5960         pPopupMenu = ((PMENUWND)pWnd)->ppopupmenu;
5961         if (pPopupMenu && pPopupMenu->spmenu)
5962         {
5963            if (UserHMGetHandle(pPopupMenu->spmenu) != hMenu)
5964            {
5965               ERR("Window Pop Up hMenu %p not the same as Get hMenu %p!\n", UserHMGetHandle(pPopupMenu->spmenu), hMenu);
5966            }
5967         }
5968         break;
5969     case OBJID_MENU:
5970         if (pWnd->style & WS_CHILD)
5971             goto Cleanup; // Return FALSE
5972         hMenu = UlongToHandle(pWnd->IDMenu);
5973         TRACE("GMBI: OBJID_MENU hMenu %p\n",hMenu);
5974         break;
5975     case OBJID_SYSMENU:
5976         if (!(pWnd->style & WS_SYSMENU))
5977             goto Cleanup; // Return FALSE
5978         Menu = IntGetSystemMenu(pWnd, FALSE);
5979         hMenu = UserHMGetHandle(Menu);
5980         break;
5981     default:
5982         goto Cleanup; // Return FALSE
5983    }
5984 
5985    if (!hMenu)
5986       goto Cleanup; // Return FALSE
5987 
5988    _SEH2_TRY
5989    {
5990        ProbeForRead(pmbi, sizeof(MENUBARINFO), 1);
5991        kmbi.cbSize = pmbi->cbSize;
5992    }
5993    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
5994    {
5995        kmbi.cbSize = 0;
5996    }
5997    _SEH2_END
5998 
5999    if (kmbi.cbSize != sizeof(MENUBARINFO))
6000    {
6001        EngSetLastError(ERROR_INVALID_PARAMETER);
6002        goto Cleanup; // Return FALSE
6003    }
6004 
6005    if (!Menu)
6006    {
6007        Menu = UserGetMenuObject(hMenu);
6008        if (!Menu)
6009           goto Cleanup; // Return FALSE
6010    }
6011 
6012    if ((idItem < 0) || ((ULONG)idItem > Menu->cItems))
6013        goto Cleanup; // Return FALSE
6014 
6015    if (idItem == 0)
6016    {
6017       Ret = IntGetMenuItemRect(pWnd, Menu, 0, &kmbi.rcBar);
6018       kmbi.rcBar.right = kmbi.rcBar.left + Menu->cxMenu;
6019       kmbi.rcBar.bottom = kmbi.rcBar.top + Menu->cyMenu;
6020       TRACE("idItem a 0 %d\n",Ret);
6021    }
6022    else
6023    {
6024       Ret = IntGetMenuItemRect(pWnd, Menu, idItem-1, &kmbi.rcBar);
6025       TRACE("idItem b %d %d\n", idItem-1, Ret);
6026    }
6027 
6028    kmbi.hMenu = hMenu;
6029    kmbi.fBarFocused = top_popup_hmenu == hMenu;
6030    TRACE("GMBI: top p hm %p hMenu %p\n",top_popup_hmenu, hMenu);
6031    if (idItem)
6032    {
6033        kmbi.fFocused = Menu->iItem == idItem-1;
6034        if (kmbi.fFocused && (Menu->rgItems[idItem - 1].spSubMenu))
6035        {
6036           kmbi.hwndMenu = Menu->rgItems[idItem - 1].spSubMenu->hWnd;
6037        }
6038    }
6039    else
6040    {
6041        kmbi.fFocused = kmbi.fBarFocused;
6042    }
6043 
6044    _SEH2_TRY
6045    {
6046       ProbeForWrite(pmbi, sizeof(MENUBARINFO), 1);
6047       RtlCopyMemory(pmbi, &kmbi, sizeof(MENUBARINFO));
6048    }
6049    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6050    {
6051       Status = _SEH2_GetExceptionCode();
6052    }
6053    _SEH2_END
6054 
6055    if (!NT_SUCCESS(Status))
6056    {
6057       SetLastNtError(Status);
6058       Ret = FALSE;
6059       goto Cleanup;
6060    }
6061 
6062    Ret = TRUE;
6063 
6064 Cleanup:
6065    if (pWnd) UserDerefObjectCo(pWnd);
6066    TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n", Ret);
6067    UserLeave();
6068    return Ret;
6069 }
6070 
6071 /*
6072  * @implemented
6073  */
6074 UINT APIENTRY
6075 NtUserGetMenuIndex(
6076    HMENU hMenu,
6077    HMENU hSubMenu)
6078 {
6079    PMENU Menu, SubMenu;
6080    PITEM MenuItem;
6081    UINT i;
6082    UINT Ret = 0xFFFFFFFF;
6083 
6084    TRACE("Enter NtUserGetMenuIndex\n");
6085    UserEnterShared();
6086 
6087    if ( !(Menu = UserGetMenuObject(hMenu)) ||
6088         !(SubMenu = UserGetMenuObject(hSubMenu)) )
6089       goto Exit; // Return 0xFFFFFFFF
6090 
6091    MenuItem = Menu->rgItems;
6092    for (i = 0; i < Menu->cItems; i++, MenuItem++)
6093    {
6094        if (MenuItem->spSubMenu == SubMenu)
6095        {
6096           Ret = MenuItem->wID;
6097           break;
6098        }
6099    }
6100 
6101 Exit:
6102    TRACE("Leave NtUserGetMenuIndex, ret=%u\n", Ret);
6103    UserLeave();
6104    return Ret;
6105 }
6106 
6107 /*
6108  * @implemented
6109  */
6110 BOOL APIENTRY
6111 NtUserGetMenuItemRect(
6112    HWND hWnd,
6113    HMENU hMenu,
6114    UINT uItem,
6115    PRECTL lprcItem)
6116 {
6117    PWND ReferenceWnd;
6118    LONG XMove, YMove;
6119    RECTL Rect;
6120    PMENU Menu;
6121    PITEM MenuItem;
6122    NTSTATUS Status = STATUS_SUCCESS;
6123    BOOL Ret = FALSE;
6124 
6125    TRACE("Enter NtUserGetMenuItemRect\n");
6126    UserEnterShared();
6127 
6128    if (!(Menu = UserGetMenuObject(hMenu)))
6129    {
6130       goto Exit; // Return FALSE
6131    }
6132 
6133    if ((MenuItem = MENU_FindItem (&Menu, &uItem, MF_BYPOSITION)))
6134    {
6135       Rect.left   = MenuItem->xItem;
6136       Rect.top    = MenuItem->yItem;
6137       Rect.right  = MenuItem->cxItem; // Do this for now......
6138       Rect.bottom = MenuItem->cyItem;
6139    }
6140    else
6141       goto Exit; // Return FALSE
6142 
6143    if(!hWnd)
6144    {
6145        hWnd = Menu->hWnd;
6146    }
6147 
6148    if (lprcItem == NULL)
6149        goto Exit; // Return FALSE
6150 
6151    if (!(ReferenceWnd = UserGetWindowObject(hWnd)))
6152        goto Exit; // Return FALSE
6153 
6154    if (Menu->fFlags & MNF_POPUP)
6155    {
6156      XMove = ReferenceWnd->rcClient.left;
6157      YMove = ReferenceWnd->rcClient.top;
6158    }
6159    else
6160    {
6161      XMove = ReferenceWnd->rcWindow.left;
6162      YMove = ReferenceWnd->rcWindow.top;
6163    }
6164 
6165    Rect.left   += XMove;
6166    Rect.top    += YMove;
6167    Rect.right  += XMove;
6168    Rect.bottom += YMove;
6169 
6170    _SEH2_TRY
6171    {
6172       RtlCopyMemory(lprcItem, &Rect, sizeof(RECTL));
6173    }
6174    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6175    {
6176       Status = _SEH2_GetExceptionCode();
6177    }
6178    _SEH2_END
6179 
6180    if (!NT_SUCCESS(Status))
6181    {
6182       SetLastNtError(Status);
6183       goto Exit; // Return FALSE
6184    }
6185    Ret = TRUE;
6186 
6187 Exit:
6188    TRACE("Leave NtUserGetMenuItemRect, ret=%i\n", Ret);
6189    UserLeave();
6190    return Ret;
6191 }
6192 
6193 /*
6194  * @implemented
6195  */
6196 BOOL APIENTRY
6197 NtUserHiliteMenuItem(
6198    HWND hWnd,
6199    HMENU hMenu,
6200    UINT uItemHilite,
6201    UINT uHilite)
6202 {
6203    PMENU Menu;
6204    PWND Window;
6205    BOOL Ret = FALSE;
6206 
6207    TRACE("Enter NtUserHiliteMenuItem\n");
6208    UserEnterExclusive();
6209 
6210    if(!(Window = UserGetWindowObject(hWnd)))
6211    {
6212       EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
6213       goto Exit; // Return FALSE
6214    }
6215 
6216    if(!(Menu = UserGetMenuObject(hMenu)))
6217    {
6218       EngSetLastError(ERROR_INVALID_MENU_HANDLE);
6219       goto Exit; // Return FALSE
6220    }
6221 
6222    Ret = IntHiliteMenuItem(Window, Menu, uItemHilite, uHilite);
6223 
6224 Exit:
6225    TRACE("Leave NtUserHiliteMenuItem, ret=%i\n", Ret);
6226    UserLeave();
6227    return Ret;
6228 }
6229 
6230 /*
6231  * @implemented
6232  */
6233 DWORD
6234 APIENTRY
6235 NtUserDrawMenuBarTemp(
6236    HWND hWnd,
6237    HDC hDC,
6238    PRECT pRect,
6239    HMENU hMenu,
6240    HFONT hFont)
6241 {
6242    PMENU Menu;
6243    PWND Window;
6244    RECT Rect;
6245    NTSTATUS Status = STATUS_SUCCESS;
6246    DWORD Ret = 0;
6247 
6248    ERR("Enter NtUserDrawMenuBarTemp\n");
6249    UserEnterExclusive();
6250 
6251    if(!(Window = UserGetWindowObject(hWnd)))
6252    {
6253       EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
6254       goto Exit; // Return 0
6255    }
6256 
6257    if(!(Menu = UserGetMenuObject(hMenu)))
6258    {
6259       EngSetLastError(ERROR_INVALID_MENU_HANDLE);
6260       goto Exit; // Return 0
6261    }
6262 
6263    _SEH2_TRY
6264    {
6265       ProbeForRead(pRect, sizeof(RECT), sizeof(ULONG));
6266       RtlCopyMemory(&Rect, pRect, sizeof(RECT));
6267    }
6268    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6269    {
6270       Status = _SEH2_GetExceptionCode();
6271    }
6272    _SEH2_END;
6273 
6274    if (Status != STATUS_SUCCESS)
6275    {
6276       SetLastNtError(Status);
6277       goto Exit; // Return 0
6278    }
6279 
6280    Ret = IntDrawMenuBarTemp(Window, hDC, &Rect, Menu, hFont);
6281 
6282 Exit:
6283    ERR("Leave NtUserDrawMenuBarTemp, ret=%lu\n", Ret);
6284    UserLeave();
6285    return Ret;
6286 }
6287 
6288 /*
6289  * @implemented
6290  */
6291 int APIENTRY
6292 NtUserMenuItemFromPoint(
6293    HWND hWnd,
6294    HMENU hMenu,
6295    DWORD X,
6296    DWORD Y)
6297 {
6298    PMENU Menu;
6299    PWND Window = NULL;
6300    PITEM mi;
6301    ULONG i;
6302    int Ret = -1;
6303 
6304    TRACE("Enter NtUserMenuItemFromPoint\n");
6305    UserEnterExclusive();
6306 
6307    if (!(Menu = UserGetMenuObject(hMenu)))
6308    {
6309       goto Exit; // Return -1
6310    }
6311 
6312    if (!(Window = UserGetWindowObject(Menu->hWnd)))
6313    {
6314       goto Exit; // Return -1
6315    }
6316 
6317    X -= Window->rcWindow.left;
6318    Y -= Window->rcWindow.top;
6319 
6320    mi = Menu->rgItems;
6321    for (i = 0; i < Menu->cItems; i++, mi++)
6322    {
6323       RECTL Rect;
6324 
6325       Rect.left   = mi->xItem;
6326       Rect.top    = mi->yItem;
6327       Rect.right  = mi->cxItem;
6328       Rect.bottom = mi->cyItem;
6329 
6330       MENU_AdjustMenuItemRect(Menu, &Rect);
6331 
6332       if (RECTL_bPointInRect(&Rect, X, Y))
6333       {
6334          break;
6335       }
6336    }
6337 
6338    Ret = (mi ? i : NO_SELECTED_ITEM);
6339 
6340 Exit:
6341    TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n", Ret);
6342    UserLeave();
6343    return Ret;
6344 }
6345 
6346 
6347 DWORD
6348 APIENTRY
6349 NtUserPaintMenuBar(
6350     HWND hWnd,
6351     HDC hDC,
6352     ULONG leftBorder,
6353     ULONG rightBorder,
6354     ULONG top,
6355     BOOL bActive)
6356 {
6357    PWND Window;
6358    RECT Rect;
6359    DWORD ret;
6360 
6361    UserEnterExclusive();
6362 
6363    if(!(Window = UserGetWindowObject(hWnd)))
6364    {
6365       EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
6366       UserLeave();
6367       return 0;
6368    }
6369 
6370    Rect.left = leftBorder;
6371    Rect.right = Window->rcWindow.right - Window->rcWindow.left - rightBorder;
6372    Rect.top = top;
6373    Rect.bottom = 0;
6374 
6375    ret = MENU_DrawMenuBar(hDC, &Rect, Window, FALSE);
6376 
6377    UserLeave();
6378 
6379    return ret;
6380 }
6381 
6382 /*
6383  * @implemented
6384  */
6385 BOOL APIENTRY
6386 NtUserRemoveMenu(
6387    HMENU hMenu,
6388    UINT uPosition,
6389    UINT uFlags)
6390 {
6391    PMENU Menu;
6392    BOOL Ret = FALSE;
6393 
6394    TRACE("Enter NtUserRemoveMenu\n");
6395    UserEnterExclusive();
6396 
6397    Menu = UserGetMenuObject(hMenu);
6398    if (Menu)
6399    {
6400       Ret = IntRemoveMenuItem(Menu, uPosition, uFlags, FALSE);
6401    }
6402 
6403    TRACE("Leave NtUserRemoveMenu, ret=%i\n", Ret);
6404    UserLeave();
6405    return Ret;
6406 }
6407 
6408 /*
6409  * @implemented
6410  */
6411 BOOL APIENTRY
6412 NtUserSetMenu(
6413    HWND hWnd,
6414    HMENU Menu,
6415    BOOL Repaint)
6416 {
6417    PWND Window;
6418    BOOL Changed;
6419    BOOL Ret = FALSE;
6420 
6421    TRACE("Enter NtUserSetMenu\n");
6422    UserEnterExclusive();
6423 
6424    if (!(Window = UserGetWindowObject(hWnd)))
6425    {
6426       goto Exit; // Return FALSE
6427    }
6428 
6429    if (!IntSetMenu(Window, Menu, &Changed))
6430    {
6431       goto Exit; // Return FALSE
6432    }
6433 
6434    // Not minimized and please repaint!!!
6435    if (!(Window->style & WS_MINIMIZE) && (Repaint || Changed))
6436    {
6437       USER_REFERENCE_ENTRY Ref;
6438       UserRefObjectCo(Window, &Ref);
6439       co_WinPosSetWindowPos(Window, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED);
6440       UserDerefObjectCo(Window);
6441    }
6442 
6443    Ret = TRUE;
6444 
6445 Exit:
6446    TRACE("Leave NtUserSetMenu, ret=%i\n", Ret);
6447    UserLeave();
6448    return Ret;
6449 }
6450 
6451 /*
6452  * @implemented
6453  */
6454 BOOL APIENTRY
6455 NtUserSetMenuContextHelpId(
6456    HMENU hMenu,
6457    DWORD dwContextHelpId)
6458 {
6459    PMENU Menu;
6460    BOOL Ret = FALSE;
6461 
6462    TRACE("Enter NtUserSetMenuContextHelpId\n");
6463    UserEnterExclusive();
6464 
6465    Menu = UserGetMenuObject(hMenu);
6466    if (Menu)
6467    {
6468       Ret = IntSetMenuContextHelpId(Menu, dwContextHelpId);
6469    }
6470 
6471    TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n", Ret);
6472    UserLeave();
6473    return Ret;
6474 }
6475 
6476 /*
6477  * @implemented
6478  */
6479 BOOL APIENTRY
6480 NtUserSetMenuDefaultItem(
6481    HMENU hMenu,
6482    UINT uItem,
6483    UINT fByPos)
6484 {
6485    PMENU Menu;
6486    BOOL Ret = FALSE;
6487 
6488    TRACE("Enter NtUserSetMenuDefaultItem\n");
6489    UserEnterExclusive();
6490 
6491    Menu = UserGetMenuObject(hMenu);
6492    if (Menu)
6493    {
6494       Ret = UserSetMenuDefaultItem(Menu, uItem, fByPos);
6495    }
6496 
6497    TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n", Ret);
6498    UserLeave();
6499    return Ret;
6500 }
6501 
6502 /*
6503  * @implemented
6504  */
6505 BOOL APIENTRY
6506 NtUserSetMenuFlagRtoL(
6507    HMENU hMenu)
6508 {
6509    PMENU Menu;
6510    BOOL Ret = FALSE;
6511 
6512    TRACE("Enter NtUserSetMenuFlagRtoL\n");
6513    UserEnterExclusive();
6514 
6515    Menu = UserGetMenuObject(hMenu);
6516    if (Menu)
6517    {
6518       Ret = IntSetMenuFlagRtoL(Menu);
6519    }
6520 
6521    TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n", Ret);
6522    UserLeave();
6523    return Ret;
6524 }
6525 
6526 /*
6527  * @implemented
6528  */
6529 BOOL APIENTRY
6530 NtUserThunkedMenuInfo(
6531    HMENU hMenu,
6532    LPCMENUINFO lpcmi)
6533 {
6534    PMENU Menu;
6535    BOOL Ret = FALSE;
6536 
6537    TRACE("Enter NtUserThunkedMenuInfo\n");
6538    UserEnterExclusive();
6539 
6540    Menu = UserGetMenuObject(hMenu);
6541    if (Menu)
6542    {
6543       Ret = UserMenuInfo(Menu, (PROSMENUINFO)lpcmi, TRUE);
6544    }
6545 
6546    TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n", Ret);
6547    UserLeave();
6548    return Ret;
6549 }
6550 
6551 /*
6552  * @implemented
6553  */
6554 BOOL APIENTRY
6555 NtUserThunkedMenuItemInfo(
6556    HMENU hMenu,
6557    UINT uItem,
6558    BOOL fByPosition,
6559    BOOL bInsert,
6560    LPMENUITEMINFOW lpmii,
6561    PUNICODE_STRING lpszCaption)
6562 {
6563    PMENU Menu;
6564    NTSTATUS Status;
6565    UNICODE_STRING lstrCaption;
6566    BOOL Ret = FALSE;
6567 
6568    TRACE("Enter NtUserThunkedMenuItemInfo\n");
6569    UserEnterExclusive();
6570 
6571    /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
6572       if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo()   */
6573 
6574    RtlInitEmptyUnicodeString(&lstrCaption, NULL, 0);
6575 
6576    if (!(Menu = UserGetMenuObject(hMenu)))
6577    {
6578       goto Cleanup; // Return FALSE
6579    }
6580 
6581    /* Check if we got a Caption */
6582    if (lpszCaption && lpszCaption->Buffer)
6583    {
6584       /* Copy the string to kernel mode */
6585       Status = ProbeAndCaptureUnicodeString( &lstrCaption,
6586                                                  UserMode,
6587                                               lpszCaption);
6588       if (!NT_SUCCESS(Status))
6589       {
6590          ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status);
6591          SetLastNtError(Status);
6592          goto Cleanup; // Return FALSE
6593       }
6594    }
6595 
6596    if (bInsert)
6597    {
6598       Ret = UserInsertMenuItem(Menu, uItem, fByPosition, lpmii, &lstrCaption);
6599       goto Cleanup;
6600    }
6601 
6602    Ret = UserMenuItemInfo(Menu, uItem, fByPosition, (PROSMENUITEMINFO)lpmii, TRUE, &lstrCaption);
6603 
6604 Cleanup:
6605    if (lstrCaption.Buffer)
6606    {
6607       ReleaseCapturedUnicodeString(&lstrCaption, UserMode);
6608    }
6609 
6610    TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n", Ret);
6611    UserLeave();
6612    return Ret;
6613 }
6614 
6615 /*
6616  * @implemented
6617  */
6618 BOOL APIENTRY
6619 NtUserTrackPopupMenuEx(
6620    HMENU hMenu,
6621    UINT fuFlags,
6622    int x,
6623    int y,
6624    HWND hWnd,
6625    LPTPMPARAMS lptpm)
6626 {
6627    PMENU menu;
6628    PWND pWnd;
6629    TPMPARAMS tpm;
6630    BOOL Ret = FALSE;
6631    USER_REFERENCE_ENTRY Ref;
6632 
6633    TRACE("Enter NtUserTrackPopupMenuEx\n");
6634    UserEnterExclusive();
6635    /* Parameter check */
6636    if (!(menu = UserGetMenuObject( hMenu )))
6637    {
6638       ERR("TPME : Invalid Menu handle.\n");
6639       EngSetLastError( ERROR_INVALID_MENU_HANDLE );
6640       goto Exit;
6641    }
6642 
6643    if (!(pWnd = UserGetWindowObject(hWnd)))
6644    {
6645       ERR("TPME : Invalid Window handle.\n");
6646       goto Exit;
6647    }
6648 
6649    if (lptpm)
6650    {
6651       _SEH2_TRY
6652       {
6653          ProbeForRead(lptpm, sizeof(TPMPARAMS), sizeof(ULONG));
6654          tpm = *lptpm;
6655       }
6656       _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
6657       {
6658          _SEH2_YIELD(goto Exit);
6659       }
6660       _SEH2_END
6661    }
6662    UserRefObjectCo(pWnd, &Ref);
6663    Ret = IntTrackPopupMenuEx(menu, fuFlags, x, y, pWnd, lptpm ? &tpm : NULL);
6664    UserDerefObjectCo(pWnd);
6665 
6666 Exit:
6667    TRACE("Leave NtUserTrackPopupMenuEx, ret=%i\n",Ret);
6668    UserLeave();
6669    return Ret;
6670 }
6671 
6672 /* EOF */
6673