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