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