3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS user32.dll
5 * FILE: user32/windows/menu.c
8 * PROGRAMMERS: Casper S. Hornstrup
12 /* INCLUDES ******************************************************************/
16 #include <wine/debug.h>
17 WINE_DEFAULT_DEBUG_CHANNEL(user32
);
19 LRESULT
DefWndNCPaint(HWND hWnd
, HRGN hRgn
, BOOL Active
);
21 /* internal popup menu window messages */
22 #define MM_SETMENUHANDLE (WM_USER + 0)
23 #define MM_GETMENUHANDLE (WM_USER + 1)
25 /* Internal MenuTrackMenu() flags */
26 #define TPM_INTERNAL 0xF0000000
27 #define TPM_ENTERIDLEEX 0x80000000 /* set owner window for WM_ENTERIDLE */
28 #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */
29 #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */
31 /* TYPES *********************************************************************/
33 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
35 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
36 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
37 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
39 #define IS_SYSTEM_MENU(MenuInfo) \
40 (0 == ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
42 #define IS_SYSTEM_POPUP(MenuInfo) \
43 (0 != ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU))
45 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
47 #define MENU_ITEM_HBMP_SPACE (5)
48 #define MENU_BAR_ITEMS_SPACE (12)
49 #define SEPARATOR_HEIGHT (5)
50 #define MENU_TAB_SPACE (8)
55 #define MAKEINTATOMA(atom) ((LPCSTR)((ULONG_PTR)((WORD)(atom))))
56 #define MAKEINTATOMW(atom) ((LPCWSTR)((ULONG_PTR)((WORD)(atom))))
57 #define POPUPMENU_CLASS_ATOMA MAKEINTATOMA(32768) /* PopupMenu */
58 #define POPUPMENU_CLASS_ATOMW MAKEINTATOMW(32768) /* PopupMenu */
60 /* internal flags for menu tracking */
62 #define TF_ENDMENU 0x0001
63 #define TF_SUSPENDPOPUP 0x0002
64 #define TF_SKIPREMOVE 0x0004
69 HMENU CurrentMenu
; /* current submenu (can be equal to hTopMenu)*/
70 HMENU TopMenu
; /* initial menu */
71 HWND OwnerWnd
; /* where notifications are sent */
75 //static LRESULT WINAPI PopupMenuWndProcA(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam);
76 //static LRESULT WINAPI PopupMenuWndProcW(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
78 /*********************************************************************
79 * PopupMenu class descriptor
81 const struct builtin_class_descr POPUPMENU_builtin_class
=
83 POPUPMENU_CLASS_ATOMW
, /* name */
84 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
85 (WNDPROC
) NULL
, /* FIXME - procA */
86 (WNDPROC
) PopupMenuWndProcW
, /* FIXME - procW */
87 sizeof(MENUINFO
*), /* extra */
88 (LPCWSTR
) IDC_ARROW
, /* cursor */
89 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
93 /* INTERNAL FUNCTIONS ********************************************************/
95 /* Rip the fun and easy to use and fun WINE unicode string manipulation routines.
96 * Of course I didnt copy the ASM code because we want this to be portable
97 * and it needs to go away.
101 #define GET_WORD(ptr) (*(WORD *)(ptr))
104 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
107 HFONT hMenuFont
= NULL
;
108 HFONT hMenuFontBold
= NULL
;
110 /* Flag set by EndMenu() to force an exit from menu tracking */
111 static BOOL fEndMenu
= FALSE
;
113 /* Use global popup window because there's no way 2 menus can
114 * be tracked at the same time. */
115 static HWND TopPopup
;
117 /* Dimension of the menu bitmaps */
118 static HBITMAP BmpSysMenu
= NULL
;
120 static SIZE MenuCharSize
;
122 /***********************************************************************
125 * Get full information about menu
128 MenuGetRosMenuInfo(PROSMENUINFO MenuInfo
, HMENU Menu
)
130 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
131 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
133 return NtUserMenuInfo(Menu
, MenuInfo
, FALSE
);
136 /***********************************************************************
139 * Set full information about menu
142 MenuSetRosMenuInfo(PROSMENUINFO MenuInfo
)
144 MenuInfo
->cbSize
= sizeof(ROSMENUINFO
);
145 MenuInfo
->fMask
= MIM_BACKGROUND
| MIM_HELPID
| MIM_MAXHEIGHT
| MIM_MENUDATA
| MIM_STYLE
;
147 return NtUserMenuInfo(MenuInfo
->Self
, MenuInfo
, TRUE
);
150 /***********************************************************************
151 * MenuInitRosMenuItemInfo
153 * Initialize a buffer for use with MenuGet/SetRosMenuItemInfo
156 MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
158 ZeroMemory(ItemInfo
, sizeof(ROSMENUITEMINFO
));
159 ItemInfo
->cbSize
= sizeof(ROSMENUITEMINFO
);
162 /***********************************************************************
163 * MenuGetRosMenuItemInfo
165 * Get full information about a menu item
168 MenuGetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
170 UINT Save_Mask
= ItemInfo
->fMask
; /* Save the org mask bits. */
172 if (ItemInfo
->dwTypeData
!= NULL
)
174 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
178 ItemInfo
->fMask
= MIIM_BITMAP
| MIIM_CHECKMARKS
| MIIM_DATA
| MIIM_FTYPE
179 | MIIM_ID
| MIIM_STATE
| MIIM_STRING
| MIIM_SUBMENU
| MIIM_TYPE
;
180 ItemInfo
->dwTypeData
= NULL
;
182 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
188 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
)
191 ItemInfo
->dwTypeData
= HeapAlloc(GetProcessHeap(), 0,
192 ItemInfo
->cch
* sizeof(WCHAR
));
193 if (NULL
== ItemInfo
->dwTypeData
)
198 if (! NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, FALSE
))
203 ItemInfo
->dwTypeData
[ItemInfo
->cch
- 1] = UNICODE_NULL
;
205 ItemInfo
->fMask
= Save_Mask
;
209 /***********************************************************************
210 * MenuSetRosMenuItemInfo
212 * Set selected information about a menu item, need to set the mask bits.
215 MenuSetRosMenuItemInfo(HMENU Menu
, UINT Index
, PROSMENUITEMINFO ItemInfo
)
219 if (MENU_ITEM_TYPE(ItemInfo
->fType
) == MF_STRING
&&
220 ItemInfo
->dwTypeData
!= NULL
)
222 ItemInfo
->cch
= strlenW(ItemInfo
->dwTypeData
);
224 Ret
= NtUserMenuItemInfo(Menu
, Index
, TRUE
, ItemInfo
, TRUE
);
229 /***********************************************************************
230 * MenuCleanupRosMenuItemInfo
232 * Cleanup after use of MenuGet/SetRosMenuItemInfo
235 MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
237 if (ItemInfo
->dwTypeData
!= NULL
)
239 HeapFree(GetProcessHeap(), 0, ItemInfo
->dwTypeData
);
240 ItemInfo
->dwTypeData
= NULL
;
244 /***********************************************************************
245 * MenuGetAllRosMenuItemInfo
247 * Get full information about all menu items
250 MenuGetAllRosMenuItemInfo(HMENU Menu
, PROSMENUITEMINFO
*ItemInfo
)
254 BufSize
= NtUserBuildMenuItemList(Menu
, (VOID
*) 1, 0, 0);
255 if (BufSize
== (DWORD
) -1 || BufSize
== 0)
259 *ItemInfo
= HeapAlloc(GetProcessHeap(), 0, BufSize
);
260 if (NULL
== *ItemInfo
)
265 return NtUserBuildMenuItemList(Menu
, *ItemInfo
, BufSize
, 0);
268 /***********************************************************************
269 * MenuCleanupAllRosMenuItemInfo
271 * Cleanup after use of MenuGetAllRosMenuItemInfo
274 MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo
)
276 HeapFree(GetProcessHeap(), 0, ItemInfo
);
280 /***********************************************************************
283 * Load the arrow bitmap. We can't do this from MenuInit since user32
284 * can also be used (and thus initialized) from text-mode.
287 MenuLoadBitmaps(VOID
)
289 /* Load system buttons bitmaps */
290 if (NULL
== BmpSysMenu
)
292 BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
296 /***********************************************************************
297 * MenuGetBitmapItemSize
299 * Get the size of a bitmap item.
302 MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem
, SIZE
*Size
, HWND WndOwner
)
305 HBITMAP Bmp
= lpitem
->hbmpItem
;
307 Size
->cx
= Size
->cy
= 0;
309 /* check if there is a magic menu item associated with this item */
310 if (IS_MAGIC_BITMAP(Bmp
))
312 switch((INT_PTR
) Bmp
)
314 case (INT_PTR
)HBMMENU_CALLBACK
:
316 MEASUREITEMSTRUCT measItem
;
317 measItem
.CtlType
= ODT_MENU
;
319 measItem
.itemID
= lpitem
->wID
;
320 measItem
.itemWidth
= lpitem
->Rect
.right
- lpitem
->Rect
.left
;
321 measItem
.itemHeight
= lpitem
->Rect
.bottom
- lpitem
->Rect
.top
;
322 measItem
.itemData
= lpitem
->dwItemData
;
323 SendMessageW( WndOwner
, WM_MEASUREITEM
, lpitem
->wID
, (LPARAM
)&measItem
);
324 Size
->cx
= measItem
.itemWidth
;
325 Size
->cy
= measItem
.itemHeight
;
330 case (INT_PTR
) HBMMENU_SYSTEM
:
331 if (0 != lpitem
->dwItemData
)
333 Bmp
= (HBITMAP
)(ULONG_PTR
) lpitem
->dwItemData
;
337 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
338 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
339 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
340 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
341 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
342 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
343 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
344 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
345 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
346 /* FIXME: Why we need to subtract these magic values? */
347 /* to make them smaller than the menu bar? */
348 Size
->cx
= GetSystemMetrics(SM_CXSIZE
) - 2;
349 Size
->cy
= GetSystemMetrics(SM_CYSIZE
) - 4;
354 if (GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
356 Size
->cx
= Bm
.bmWidth
;
357 Size
->cy
= Bm
.bmHeight
;
361 /***********************************************************************
364 * Draws popup magic glyphs (can be found in system menu).
367 MenuDrawPopupGlyph(HDC dc
, LPRECT r
, INT_PTR popupMagic
, BOOL inactive
, BOOL hilite
)
370 HFONT hFont
, hOldFont
;
376 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
379 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
382 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
385 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
389 ERR("Invalid popup magic bitmap %d\n", (int)popupMagic
);
392 ZeroMemory(&lf
, sizeof(LOGFONTW
));
393 InflateRect(r
, -2, -2);
394 lf
.lfHeight
= r
->bottom
- r
->top
;
396 lf
.lfWeight
= FW_NORMAL
;
397 lf
.lfCharSet
= DEFAULT_CHARSET
;
398 lstrcpy(lf
.lfFaceName
, TEXT("Marlett"));
399 hFont
= CreateFontIndirect(&lf
);
400 /* save font and text color */
401 hOldFont
= SelectObject(dc
, hFont
);
402 clrsave
= GetTextColor(dc
);
403 bkmode
= GetBkMode(dc
);
404 /* set color and drawing mode */
405 SetBkMode(dc
, TRANSPARENT
);
411 SetTextColor(dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
412 TextOut(dc
, r
->left
+ 1, r
->top
+ 1, &symbol
, 1);
415 SetTextColor(dc
, GetSysColor(inactive
? COLOR_GRAYTEXT
: (hilite
? COLOR_HIGHLIGHTTEXT
: COLOR_MENUTEXT
)));
416 /* draw selected symbol */
417 TextOut(dc
, r
->left
, r
->top
, &symbol
, 1);
418 /* restore previous settings */
419 SetTextColor(dc
, clrsave
);
420 SelectObject(dc
, hOldFont
);
421 SetBkMode(dc
, bkmode
);
425 /***********************************************************************
428 * Draw a bitmap item.
431 MenuDrawBitmapItem(HDC Dc
, PROSMENUITEMINFO Item
, const RECT
*Rect
,
432 HMENU hmenu
, HWND WndOwner
, UINT odaction
, BOOL MenuBar
)
438 int w
= Rect
->right
- Rect
->left
;
439 int h
= Rect
->bottom
- Rect
->top
;
442 HBITMAP hbmpToDraw
= (HBITMAP
) Item
->hbmpItem
;
445 /* Check if there is a magic menu item associated with this item */
446 if (IS_MAGIC_BITMAP(hbmpToDraw
))
452 switch ((INT_PTR
)hbmpToDraw
)
454 case (INT_PTR
) HBMMENU_SYSTEM
:
455 if (NULL
!= Item
->dwTypeData
)
457 Bmp
= (HBITMAP
)Item
->dwTypeData
;
458 if (! GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
465 if (!BmpSysMenu
) BmpSysMenu
= LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE
));
467 if (! GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
471 /* only use right half of the bitmap */
472 BmpXoffset
= Bm
.bmWidth
/ 2;
473 Bm
.bmWidth
-= BmpXoffset
;
476 case (INT_PTR
) HBMMENU_MBAR_RESTORE
:
477 Flags
= DFCS_CAPTIONRESTORE
;
479 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE
:
481 Flags
= DFCS_CAPTIONMIN
;
483 case (INT_PTR
) HBMMENU_MBAR_MINIMIZE_D
:
485 Flags
= DFCS_CAPTIONMIN
| DFCS_INACTIVE
;
487 case (INT_PTR
) HBMMENU_MBAR_CLOSE
:
488 Flags
= DFCS_CAPTIONCLOSE
;
490 case (INT_PTR
) HBMMENU_MBAR_CLOSE_D
:
491 Flags
= DFCS_CAPTIONCLOSE
| DFCS_INACTIVE
;
493 case (INT_PTR
) HBMMENU_CALLBACK
:
495 DRAWITEMSTRUCT drawItem
;
497 drawItem
.CtlType
= ODT_MENU
;
499 drawItem
.itemID
= Item
->wID
;
500 drawItem
.itemAction
= odaction
;
501 drawItem
.itemState
= (Item
->fState
& MF_CHECKED
)?ODS_CHECKED
:0;
502 drawItem
.itemState
|= (Item
->fState
& MF_DEFAULT
)?ODS_DEFAULT
:0;
503 drawItem
.itemState
|= (Item
->fState
& MF_DISABLED
)?ODS_DISABLED
:0;
504 drawItem
.itemState
|= (Item
->fState
& MF_GRAYED
)?ODS_GRAYED
|ODS_DISABLED
:0;
505 drawItem
.itemState
|= (Item
->fState
& MF_HILITE
)?ODS_SELECTED
:0;
506 drawItem
.hwndItem
= (HWND
)hmenu
;
508 drawItem
.rcItem
= *Rect
;
509 drawItem
.itemData
= Item
->dwItemData
;
510 /* some applications make this assumption on the DC's origin */
511 SetViewportOrgEx( Dc
, Item
->Rect
.left
, Item
->Rect
.top
, &origorg
);
512 OffsetRect( &drawItem
.rcItem
, - Item
->Rect
.left
, - Item
->Rect
.top
);
513 SendMessageW( WndOwner
, WM_DRAWITEM
, 0, (LPARAM
)&drawItem
);
514 SetViewportOrgEx( Dc
, origorg
.x
, origorg
.y
, NULL
);
519 case (INT_PTR
) HBMMENU_POPUP_CLOSE
:
520 case (INT_PTR
) HBMMENU_POPUP_RESTORE
:
521 case (INT_PTR
) HBMMENU_POPUP_MAXIMIZE
:
522 case (INT_PTR
) HBMMENU_POPUP_MINIMIZE
:
523 MenuDrawPopupGlyph(Dc
, &r
, (INT_PTR
)hbmpToDraw
, Item
->fState
& MF_GRAYED
, Item
->fState
& MF_HILITE
);
526 InflateRect(&r
, -1, -1);
527 if (0 != (Item
->fState
& MF_HILITE
))
529 Flags
|= DFCS_PUSHED
;
531 DrawFrameControl(Dc
, &r
, DFC_CAPTION
, Flags
);
535 if (NULL
== Bmp
|| ! GetObjectW(Bmp
, sizeof(BITMAP
), &Bm
))
541 DcMem
= CreateCompatibleDC(Dc
);
542 SelectObject(DcMem
, Bmp
);
544 /* handle fontsize > bitmap_height */
545 Top
= (Bm
.bmHeight
< h
) ? Rect
->top
+ (h
- Bm
.bmHeight
) / 2 : Rect
->top
;
547 Rop
= ((Item
->fState
& MF_HILITE
) && !IS_MAGIC_BITMAP(hbmpToDraw
)) ? NOTSRCCOPY
: SRCCOPY
;
548 if ((Item
->fState
& MF_HILITE
) && Item
->hbmpItem
)
550 SetBkColor(Dc
, GetSysColor(COLOR_HIGHLIGHT
));
552 BitBlt(Dc
, Left
, Top
, w
, h
, DcMem
, BmpXoffset
, 0, Rop
);
556 /***********************************************************************
559 * Draw a single menu item.
562 MenuDrawMenuItem(HWND hWnd
, PROSMENUINFO MenuInfo
, HWND WndOwner
, HDC Dc
,
563 PROSMENUITEMINFO Item
, UINT Height
, BOOL MenuBar
, UINT Action
)
567 BOOL flat_menu
= FALSE
;
569 PWND Wnd
= ValidateHwnd(hWnd
);
574 if (0 != (Item
->fType
& MF_SYSMENU
))
576 if ( (Wnd
->style
& WS_MINIMIZE
))
578 UserGetInsideRectNC(Wnd
, &Rect
);
579 UserDrawSysMenuButton(hWnd
, Dc
, &Rect
,
580 Item
->fState
& (MF_HILITE
| MF_MOUSESELECT
));
585 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
586 bkgnd
= (MenuBar
&& flat_menu
) ? COLOR_MENUBAR
: COLOR_MENU
;
590 if (0 != (Item
->fState
& MF_HILITE
))
592 if (MenuBar
&& !flat_menu
)
594 SetTextColor(Dc
, GetSysColor(COLOR_MENUTEXT
));
595 SetBkColor(Dc
, GetSysColor(COLOR_MENU
));
599 if (0 != (Item
->fState
& MF_GRAYED
))
601 SetTextColor(Dc
, GetSysColor(COLOR_GRAYTEXT
));
605 SetTextColor(Dc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
607 SetBkColor(Dc
, GetSysColor(COLOR_HIGHLIGHT
));
612 if (0 != (Item
->fState
& MF_GRAYED
))
614 SetTextColor(Dc
, GetSysColor(COLOR_GRAYTEXT
));
618 SetTextColor(Dc
, GetSysColor(COLOR_MENUTEXT
));
620 SetBkColor(Dc
, GetSysColor(bkgnd
));
625 if (Item
->fType
& MF_OWNERDRAW
)
628 ** Experimentation under Windows reveals that an owner-drawn
629 ** menu is given the rectangle which includes the space it requested
630 ** in its response to WM_MEASUREITEM _plus_ width for a checkmark
631 ** and a popup-menu arrow. This is the value of lpitem->rect.
632 ** Windows will leave all drawing to the application except for
633 ** the popup-menu arrow. Windows always draws that itself, after
634 ** the menu owner has finished drawing.
638 dis
.CtlType
= ODT_MENU
;
640 dis
.itemID
= Item
->wID
;
641 dis
.itemData
= (DWORD
)Item
->dwItemData
;
643 if (0 != (Item
->fState
& MF_CHECKED
))
645 dis
.itemState
|= ODS_CHECKED
;
647 if (0 != (Item
->fState
& MF_GRAYED
))
649 dis
.itemState
|= ODS_GRAYED
| ODS_DISABLED
;
651 if (0 != (Item
->fState
& MF_HILITE
))
653 dis
.itemState
|= ODS_SELECTED
;
655 dis
.itemAction
= Action
; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */
656 dis
.hwndItem
= (HWND
) MenuInfo
->Self
;
659 TRACE("Ownerdraw: owner=%p itemID=%d, itemState=%d, itemAction=%d, "
660 "hwndItem=%p, hdc=%p, rcItem={%ld,%ld,%ld,%ld}\n", hWnd
,
661 dis
.itemID
, dis
.itemState
, dis
.itemAction
, dis
.hwndItem
,
662 dis
.hDC
, dis
.rcItem
.left
, dis
.rcItem
.top
, dis
.rcItem
.right
,
664 SendMessageW(WndOwner
, WM_DRAWITEM
, 0, (LPARAM
) &dis
);
665 /* Draw the popup-menu arrow */
666 if (0 != (Item
->fType
& MF_POPUP
))
669 CopyRect(&rectTemp
, &Rect
);
670 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
671 DrawFrameControl(Dc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
676 TRACE("rect={%ld,%ld,%ld,%ld}\n", Item
->Rect
.left
, Item
->Rect
.top
,
677 Item
->Rect
.right
, Item
->Rect
.bottom
);
679 if (MenuBar
&& 0 != (Item
->fType
& MF_SEPARATOR
))
684 if (Item
->fState
& MF_HILITE
)
688 InflateRect (&Rect
, -1, -1);
689 FillRect(Dc
, &Rect
, GetSysColorBrush(COLOR_MENUHILIGHT
));
690 InflateRect (&Rect
, 1, 1);
691 FrameRect(Dc
, &Rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
697 DrawEdge(Dc
, &Rect
, BDR_SUNKENOUTER
, BF_RECT
);
701 FillRect(Dc
, &Rect
, GetSysColorBrush(COLOR_HIGHLIGHT
));
707 FillRect(Dc
, &Rect
, GetSysColorBrush(bkgnd
));
710 SetBkMode(Dc
, TRANSPARENT
);
712 /* vertical separator */
713 if (! MenuBar
&& 0 != (Item
->fType
& MF_MENUBARBREAK
))
719 rc
.bottom
= Height
- 3;
722 oldPen
= SelectObject( Dc
, GetStockObject(DC_PEN
) );
723 SetDCPenColor(Dc
, GetSysColor(COLOR_BTNSHADOW
));
724 MoveToEx( Dc
, rc
.left
, rc
.top
, NULL
);
725 LineTo( Dc
, rc
.left
, rc
.bottom
);
726 SelectObject( Dc
, oldPen
);
729 DrawEdge(Dc
, &rc
, EDGE_ETCHED
, BF_LEFT
);
732 /* horizontal separator */
733 if (0 != (Item
->fType
& MF_SEPARATOR
))
739 rc
.top
+= SEPARATOR_HEIGHT
/ 2;
742 oldPen
= SelectObject( Dc
, GetStockObject(DC_PEN
) );
743 SetDCPenColor(Dc
, GetSysColor(COLOR_BTNSHADOW
));
744 MoveToEx( Dc
, rc
.left
, rc
.top
, NULL
);
745 LineTo( Dc
, rc
.right
, rc
.top
);
746 SelectObject( Dc
, oldPen
);
749 DrawEdge(Dc
, &rc
, EDGE_ETCHED
, BF_TOP
);
754 /* helper lines for debugging */
755 /* This is a very good test tool when hacking menus! (JT) 07/16/2006 */
756 FrameRect(Dc
, &Rect
, GetStockObject(BLACK_BRUSH
));
757 SelectObject(Dc
, GetStockObject(DC_PEN
));
758 SetDCPenColor(Dc
, GetSysColor(COLOR_WINDOWFRAME
));
759 MoveToEx(Dc
, Rect
.left
, (Rect
.top
+ Rect
.bottom
) / 2, NULL
);
760 LineTo(Dc
, Rect
.right
, (Rect
.top
+ Rect
.bottom
) / 2);
765 INT y
= Rect
.top
+ Rect
.bottom
;
767 UINT CheckBitmapWidth
= GetSystemMetrics(SM_CXMENUCHECK
);
768 UINT CheckBitmapHeight
= GetSystemMetrics(SM_CYMENUCHECK
);
770 /* Draw the check mark
773 * Custom checkmark bitmaps are monochrome but not always 1bpp.
775 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
777 HBITMAP bm
= 0 != (Item
->fState
& MF_CHECKED
) ? Item
->hbmpChecked
: Item
->hbmpUnchecked
;
778 if (NULL
!= bm
) /* we have a custom bitmap */
780 HDC DcMem
= CreateCompatibleDC(Dc
);
781 SelectObject(DcMem
, bm
);
782 BitBlt(Dc
, Rc
.left
, (y
- CheckBitmapHeight
) / 2,
783 CheckBitmapWidth
, CheckBitmapHeight
,
784 DcMem
, 0, 0, SRCCOPY
);
788 else if (0 != (Item
->fState
& MF_CHECKED
)) /* standard bitmaps */
791 CopyRect(&rectTemp
, &Rect
);
792 rectTemp
.right
= rectTemp
.left
+ GetSystemMetrics(SM_CXMENUCHECK
);
793 DrawFrameControl(Dc
, &rectTemp
, DFC_MENU
,
794 0 != (Item
->fType
& MFT_RADIOCHECK
) ?
795 DFCS_MENUBULLET
: DFCS_MENUCHECK
);
802 CopyRect(&bmpRect
, &Rect
);
803 if (!(MenuInfo
->dwStyle
& MNS_CHECKORBMP
) && !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
804 bmpRect
.left
+= CheckBitmapWidth
+ 2;
805 if (!(checked
&& (MenuInfo
->dwStyle
& MNS_CHECKORBMP
)))
807 bmpRect
.right
= bmpRect
.left
+ MenuInfo
->maxBmpSize
.cx
;
808 MenuDrawBitmapItem(Dc
, Item
, &bmpRect
, MenuInfo
->Self
, WndOwner
, Action
, MenuBar
);
811 /* Draw the popup-menu arrow */
812 if (0 != (Item
->fType
& MF_POPUP
))
815 CopyRect(&rectTemp
, &Rect
);
816 rectTemp
.left
= rectTemp
.right
- GetSystemMetrics(SM_CXMENUCHECK
);
817 DrawFrameControl(Dc
, &rectTemp
, DFC_MENU
, DFCS_MENUARROW
);
820 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
821 Rect
.left
+= CheckBitmapWidth
;
822 Rect
.right
-= CheckBitmapWidth
;
824 else if (Item
->hbmpItem
) /* Draw the bitmap */
826 MenuDrawBitmapItem(Dc
, Item
, &Rect
, MenuInfo
->Self
, WndOwner
, Action
, MenuBar
);
829 /* No bitmap - process text if present */
833 HFONT FontOld
= NULL
;
835 UINT uFormat
= MenuBar
? DT_CENTER
| DT_VCENTER
| DT_SINGLELINE
836 : DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
838 if(MenuInfo
->dwStyle
& MNS_CHECKORBMP
)
839 Rect
.left
+= max(0, MenuInfo
->maxBmpSize
.cx
- GetSystemMetrics(SM_CXMENUCHECK
));
841 Rect
.left
+= MenuInfo
->maxBmpSize
.cx
;
843 if (0 != (Item
->fState
& MFS_DEFAULT
))
845 FontOld
= SelectObject(Dc
, hMenuFontBold
);
850 Rect
.left
+= MENU_BAR_ITEMS_SPACE
/ 2;
851 Rect
.right
-= MENU_BAR_ITEMS_SPACE
/ 2;
854 Text
= (PWCHAR
) Item
->dwTypeData
;
857 for (i
= 0; L
'\0' != Text
[i
]; i
++)
859 if (L
'\t' == Text
[i
] || L
'\b' == Text
[i
])
866 if (0 != (Item
->fState
& MF_GRAYED
))
868 if (0 == (Item
->fState
& MF_HILITE
))
870 ++Rect
.left
; ++Rect
.top
; ++Rect
.right
; ++Rect
.bottom
;
871 SetTextColor(Dc
, RGB(0xff, 0xff, 0xff));
872 DrawTextW(Dc
, Text
, i
, &Rect
, uFormat
);
873 --Rect
.left
; --Rect
.top
; --Rect
.right
; --Rect
.bottom
;
875 SetTextColor(Dc
, RGB(0x80, 0x80, 0x80));
878 DrawTextW(Dc
, Text
, i
, &Rect
, uFormat
);
880 /* paint the shortcut text */
881 if (! MenuBar
&& L
'\0' != Text
[i
]) /* There's a tab or flush-right char */
883 if (L
'\t' == Text
[i
])
885 Rect
.left
= Item
->XTab
;
886 uFormat
= DT_LEFT
| DT_VCENTER
| DT_SINGLELINE
;
890 Rect
.right
= Item
->XTab
;
891 uFormat
= DT_RIGHT
| DT_VCENTER
| DT_SINGLELINE
;
894 if (0 != (Item
->fState
& MF_GRAYED
))
896 if (0 == (Item
->fState
& MF_HILITE
))
898 ++Rect
.left
; ++Rect
.top
; ++Rect
.right
; ++Rect
.bottom
;
899 SetTextColor(Dc
, RGB(0xff, 0xff, 0xff));
900 DrawTextW(Dc
, Text
+ i
+ 1, -1, &Rect
, uFormat
);
901 --Rect
.left
; --Rect
.top
; --Rect
.right
; --Rect
.bottom
;
903 SetTextColor(Dc
, RGB(0x80, 0x80, 0x80));
905 DrawTextW(Dc
, Text
+ i
+ 1, -1, &Rect
, uFormat
);
910 SelectObject(Dc
, FontOld
);
915 /***********************************************************************
918 * Paint a popup menu.
921 MenuDrawPopupMenu(HWND Wnd
, HDC Dc
, HMENU Menu
)
923 HBRUSH PrevBrush
= NULL
;
926 ROSMENUINFO MenuInfo
;
927 ROSMENUITEMINFO ItemInfo
;
930 TRACE("wnd=%x dc=%x menu=%x\n", Wnd
, Dc
, Menu
);
932 GetClientRect(Wnd
, &Rect
);
934 if (NULL
!= (PrevBrush
= SelectObject(Dc
, GetSysColorBrush(COLOR_MENU
)))
935 && NULL
!= SelectObject(Dc
, hMenuFont
))
937 Rectangle(Dc
, Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
939 PrevPen
= SelectObject(Dc
, GetStockObject(NULL_PEN
));
942 BOOL flat_menu
= FALSE
;
944 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
946 FrameRect(Dc
, &Rect
, GetSysColorBrush(COLOR_BTNSHADOW
));
948 DrawEdge(Dc
, &Rect
, EDGE_RAISED
, BF_RECT
);
950 /* draw menu items */
952 if (MenuGetRosMenuInfo(&MenuInfo
, Menu
) && 0 != MenuInfo
.MenuItemCount
)
954 MenuInitRosMenuItemInfo(&ItemInfo
);
956 for (u
= 0; u
< MenuInfo
.MenuItemCount
; u
++)
958 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, u
, &ItemInfo
))
960 MenuDrawMenuItem(Wnd
, &MenuInfo
, MenuInfo
.WndOwner
, Dc
, &ItemInfo
,
961 MenuInfo
.Height
, FALSE
, ODA_DRAWENTIRE
);
965 MenuCleanupRosMenuItemInfo(&ItemInfo
);
970 SelectObject(Dc
, PrevBrush
);
976 PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
978 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
984 CREATESTRUCTA
*cs
= (CREATESTRUCTA
*) lParam
;
985 SetWindowLongPtrA(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
989 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
990 return MA_NOACTIVATE
;
995 BeginPaint(Wnd
, &ps
);
996 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrA(Wnd
, 0));
1001 case WM_PRINTCLIENT
:
1003 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1004 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1012 /* zero out global pointer in case resident popup window was destroyed. */
1013 if (Wnd
== TopPopup
)
1022 if (0 == GetWindowLongPtrA(Wnd
, 0))
1024 OutputDebugStringA("no menu to display\n");
1029 SetWindowLongPtrA(Wnd
, 0, 0);
1033 case MM_SETMENUHANDLE
:
1034 SetWindowLongPtrA(Wnd
, 0, wParam
);
1037 case MM_GETMENUHANDLE
:
1039 return GetWindowLongPtrA(Wnd
, 0);
1042 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
1048 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
1050 TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
1056 CREATESTRUCTW
*cs
= (CREATESTRUCTW
*) lParam
;
1057 SetWindowLongPtrW(Wnd
, 0, (LONG_PTR
)cs
->lpCreateParams
);
1061 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
1062 return MA_NOACTIVATE
;
1067 BeginPaint(Wnd
, &ps
);
1068 MenuDrawPopupMenu(Wnd
, ps
.hdc
, (HMENU
)GetWindowLongPtrW(Wnd
, 0));
1073 case WM_PRINTCLIENT
:
1075 MenuDrawPopupMenu( Wnd
, (HDC
)wParam
,
1076 (HMENU
)GetWindowLongPtrW( Wnd
, 0 ) );
1084 /* zero out global pointer in case resident popup window was destroyed. */
1085 if (Wnd
== TopPopup
)
1094 if (0 == GetWindowLongPtrW(Wnd
, 0))
1096 OutputDebugStringA("no menu to display\n");
1101 SetWindowLongPtrW(Wnd
, 0, 0);
1105 case MM_SETMENUHANDLE
:
1106 SetWindowLongPtrW(Wnd
, 0, wParam
);
1109 case MM_GETMENUHANDLE
:
1111 return GetWindowLongPtrW(Wnd
, 0);
1114 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
1120 /**********************************************************************
1121 * MENUEX_ParseResource
1123 * Parse an extended menu resource and add items to the menu.
1124 * Return a pointer to the end of the resource.
1126 * FIXME - should we be passing an LPCSTR to a predominantly UNICODE function?
1128 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
1136 mii
.cbSize
= sizeof(mii
);
1137 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
1138 mii
.fType
= GET_DWORD(res
);
1139 res
+= sizeof(DWORD
);
1140 mii
.fState
= GET_DWORD(res
);
1141 res
+= sizeof(DWORD
);
1142 mii
.wID
= GET_DWORD(res
);
1143 res
+= sizeof(DWORD
);
1144 resinfo
= GET_WORD(res
);
1145 res
+= sizeof(WORD
);
1146 /* Align the text on a word boundary. */
1147 res
+= (~((UINT_PTR
)res
- 1)) & 1;
1148 mii
.dwTypeData
= (LPWSTR
) res
;
1149 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
1150 /* Align the following fields on a dword boundary. */
1151 res
+= (~((UINT_PTR
)res
- 1)) & 3;
1153 if (resinfo
& 1) /* Pop-up? */
1155 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
1156 res
+= sizeof(DWORD
);
1157 mii
.hSubMenu
= CreatePopupMenu();
1160 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
1162 DestroyMenu(mii
.hSubMenu
);
1165 mii
.fMask
|= MIIM_SUBMENU
;
1166 mii
.fType
|= MF_POPUP
;
1167 mii
.wID
= (UINT_PTR
) mii
.hSubMenu
;
1169 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
1171 mii
.fType
|= MF_SEPARATOR
;
1173 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
1175 while (!(resinfo
& MF_END
));
1180 /**********************************************************************
1181 * MENU_ParseResource
1183 * Parse a standard menu resource and add items to the menu.
1184 * Return a pointer to the end of the resource.
1186 * NOTE: flags is equivalent to the mtOption field
1188 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
, BOOL unicode
)
1197 flags
= GET_WORD(res
);
1199 /* remove MF_END flag before passing it to AppendMenu()! */
1200 end
= (flags
& MF_END
);
1201 if(end
) flags
^= MF_END
;
1203 res
+= sizeof(WORD
);
1204 if(!(flags
& MF_POPUP
))
1207 res
+= sizeof(WORD
);
1211 res
+= strlen(str
) + 1;
1213 res
+= (strlenW((LPCWSTR
)str
) + 1) * sizeof(WCHAR
);
1214 if (flags
& MF_POPUP
)
1216 hSubMenu
= CreatePopupMenu();
1217 if(!hSubMenu
) return NULL
;
1218 if(!(res
= MENU_ParseResource(res
, hSubMenu
, unicode
)))
1221 AppendMenuA(hMenu
, flags
, (UINT_PTR
)hSubMenu
, str
);
1223 AppendMenuW(hMenu
, flags
, (UINT_PTR
)hSubMenu
, (LPCWSTR
)str
);
1225 else /* Not a popup */
1230 flags
= MF_SEPARATOR
;
1234 if (*(LPCWSTR
)str
== 0)
1235 flags
= MF_SEPARATOR
;
1238 if (flags
& MF_SEPARATOR
)
1240 if (!(flags
& (MF_GRAYED
| MF_DISABLED
)))
1241 flags
|= MF_GRAYED
| MF_DISABLED
;
1245 AppendMenuA(hMenu
, flags
, id
, *str
? str
: NULL
);
1247 AppendMenuW(hMenu
, flags
, id
,
1248 *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
1257 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
1259 HMENU hmenu
= LoadMenuW(User32Instance
, L
"SYSMENU");
1260 LRESULT Result
= (LRESULT
)hmenu
;
1261 MENUINFO menuinfo
= {0};
1262 MENUITEMINFOW info
= {0};
1264 // removing space for checkboxes from menu
1265 menuinfo
.cbSize
= sizeof(menuinfo
);
1266 menuinfo
.fMask
= MIM_STYLE
;
1267 GetMenuInfo(hmenu
, &menuinfo
);
1268 menuinfo
.dwStyle
|= MNS_NOCHECK
;
1269 SetMenuInfo(hmenu
, &menuinfo
);
1271 // adding bitmaps to menu items
1272 info
.cbSize
= sizeof(info
);
1273 info
.fMask
|= MIIM_BITMAP
;
1274 info
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
1275 SetMenuItemInfoW(hmenu
, SC_MINIMIZE
, FALSE
, &info
);
1276 info
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
1277 SetMenuItemInfoW(hmenu
, SC_RESTORE
, FALSE
, &info
);
1278 info
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
1279 SetMenuItemInfoW(hmenu
, SC_MAXIMIZE
, FALSE
, &info
);
1280 info
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
1281 SetMenuItemInfoW(hmenu
, SC_CLOSE
, FALSE
, &info
);
1283 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
1290 NONCLIENTMETRICSW ncm
;
1292 /* get the menu font */
1293 if(!hMenuFont
|| !hMenuFontBold
)
1295 ncm
.cbSize
= sizeof(ncm
);
1296 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS
, sizeof(ncm
), &ncm
, 0))
1298 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
1302 hMenuFont
= CreateFontIndirectW(&ncm
.lfMenuFont
);
1303 if(hMenuFont
== NULL
)
1305 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
1309 ncm
.lfMenuFont
.lfWeight
= max(ncm
.lfMenuFont
.lfWeight
+ 300, 1000);
1310 hMenuFontBold
= CreateFontIndirectW(&ncm
.lfMenuFont
);
1311 if(hMenuFontBold
== NULL
)
1313 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
1314 DeleteObject(hMenuFont
);
1329 DeleteObject(hMenuFont
);
1335 DeleteObject(hMenuFontBold
);
1336 hMenuFontBold
= NULL
;
1342 /***********************************************************************
1345 * Calculate the size of the menu item and store it in ItemInfo->rect.
1347 static void FASTCALL
1348 MenuCalcItemSize(HDC Dc
, PROSMENUITEMINFO ItemInfo
, PROSMENUINFO MenuInfo
, HWND WndOwner
,
1349 INT OrgX
, INT OrgY
, BOOL MenuBar
)
1353 UINT CheckBitmapWidth
= GetSystemMetrics(SM_CXMENUCHECK
);
1355 TRACE("dc=%x owner=%x (%d,%d)\n", Dc
, WndOwner
, OrgX
, OrgY
);
1357 MenuCharSize
.cx
= GdiGetCharDimensions( Dc
, NULL
, &MenuCharSize
.cy
);
1359 SetRect(&ItemInfo
->Rect
, OrgX
, OrgY
, OrgX
, OrgY
);
1361 if (0 != (ItemInfo
->fType
& MF_OWNERDRAW
))
1364 ** Experimentation under Windows reveals that an owner-drawn
1365 ** menu is expected to return the size of the content part of
1366 ** the menu item, not including the checkmark nor the submenu
1367 ** arrow. Windows adds those values itself and returns the
1368 ** enlarged rectangle on subsequent WM_DRAWITEM messages.
1370 MEASUREITEMSTRUCT mis
;
1371 mis
.CtlType
= ODT_MENU
;
1373 mis
.itemID
= ItemInfo
->wID
;
1374 mis
.itemData
= (DWORD
)ItemInfo
->dwItemData
;
1375 mis
.itemHeight
= HIWORD( GetDialogBaseUnits());
1377 SendMessageW(WndOwner
, WM_MEASUREITEM
, 0, (LPARAM
) &mis
);
1378 /* Tests reveal that Windows ( Win95 thru WinXP) adds twice the average
1379 * width of a menufont character to the width of an owner-drawn menu.
1381 ItemInfo
->Rect
.right
+= mis
.itemWidth
+ 2 * MenuCharSize
.cx
;
1385 /* under at least win95 you seem to be given a standard
1386 height for the menu and the height value is ignored */
1387 ItemInfo
->Rect
.bottom
+= GetSystemMetrics(SM_CYMENUSIZE
);
1391 ItemInfo
->Rect
.bottom
+= mis
.itemHeight
;
1394 TRACE("id=%04x size=%dx%d\n", ItemInfo
->wID
, mis
.itemWidth
, mis
.itemHeight
);
1398 if (0 != (ItemInfo
->fType
& MF_SEPARATOR
))
1400 ItemInfo
->Rect
.bottom
+= SEPARATOR_HEIGHT
;
1402 ItemInfo
->Rect
.right
+= CheckBitmapWidth
+ MenuCharSize
.cx
;
1408 if (ItemInfo
->hbmpItem
)
1412 if (!MenuBar
) /* hbmpItem */
1414 MenuGetBitmapItemSize(ItemInfo
, &Size
, WndOwner
);
1415 /* Keep the size of the bitmap in callback mode to be able
1416 * to draw it correctly */
1417 ItemInfo
->Rect
.right
= ItemInfo
->Rect
.left
+ Size
.cx
;
1418 if (MenuInfo
->maxBmpSize
.cx
< abs(Size
.cx
) + MENU_ITEM_HBMP_SPACE
||
1419 MenuInfo
->maxBmpSize
.cy
< abs(Size
.cy
))
1421 MenuInfo
->maxBmpSize
.cx
= abs(Size
.cx
) + MENU_ITEM_HBMP_SPACE
;
1422 MenuInfo
->maxBmpSize
.cy
= abs(Size
.cy
);
1424 MenuSetRosMenuInfo(MenuInfo
);
1425 itemheight
= Size
.cy
+ 2;
1427 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1428 ItemInfo
->Rect
.right
+= 2 * CheckBitmapWidth
;
1429 ItemInfo
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1430 ItemInfo
->XTab
= ItemInfo
->Rect
.right
;
1431 ItemInfo
->Rect
.right
+= CheckBitmapWidth
;
1433 else /* hbmpItem & MenuBar */
1435 MenuGetBitmapItemSize(ItemInfo
, &Size
, WndOwner
);
1436 ItemInfo
->Rect
.right
+= Size
.cx
;
1437 if( ItemInfo
->Text
) ItemInfo
->Rect
.right
+= 2;
1438 itemheight
= Size
.cy
;
1440 /* Special case: Minimize button doesn't have a space behind it. */
1441 if (ItemInfo
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE
||
1442 ItemInfo
->hbmpItem
== (HBITMAP
)HBMMENU_MBAR_MINIMIZE_D
)
1443 ItemInfo
->Rect
.right
-= 1;
1448 if( !(MenuInfo
->dwStyle
& MNS_NOCHECK
))
1449 ItemInfo
->Rect
.right
+= CheckBitmapWidth
;
1450 ItemInfo
->Rect
.right
+= 4 + MenuCharSize
.cx
;
1451 ItemInfo
->XTab
= ItemInfo
->Rect
.right
;
1452 ItemInfo
->Rect
.right
+= CheckBitmapWidth
;
1455 /* it must be a text item - unless it's the system menu */
1456 if (0 == (ItemInfo
->fType
& MF_SYSMENU
) && ItemInfo
->Text
)
1458 HFONT hfontOld
= NULL
;
1459 RECT rc
= ItemInfo
->Rect
;
1460 LONG txtheight
, txtwidth
;
1462 if ( ItemInfo
->fState
& MFS_DEFAULT
)
1464 hfontOld
= SelectObject( Dc
, hMenuFontBold
);
1468 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, -1, &rc
,
1469 DT_SINGLELINE
|DT_CALCRECT
);
1470 ItemInfo
->Rect
.right
+= rc
.right
- rc
.left
;
1471 itemheight
= max( max( itemheight
, txtheight
),
1472 GetSystemMetrics( SM_CYMENU
) - 1);
1473 ItemInfo
->Rect
.right
+= 2 * MenuCharSize
.cx
;
1477 if ((p
= strchrW( ItemInfo
->dwTypeData
, '\t' )) != NULL
)
1481 int n
= (int)( p
- ItemInfo
->dwTypeData
);
1482 /* Item contains a tab (only meaningful in popup menus) */
1483 /* get text size before the tab */
1484 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, n
, &rc
,
1485 DT_SINGLELINE
|DT_CALCRECT
);
1486 txtwidth
= rc
.right
- rc
.left
;
1487 p
+= 1; /* advance past the Tab */
1488 /* get text size after the tab */
1489 tmpheight
= DrawTextW( Dc
, p
, -1, &tmprc
, DT_SINGLELINE
|DT_CALCRECT
);
1490 ItemInfo
->XTab
+= txtwidth
;
1491 txtheight
= max( txtheight
, tmpheight
);
1492 txtwidth
+= MenuCharSize
.cx
+ /* space for the tab */
1493 tmprc
.right
- tmprc
.left
; /* space for the short cut */
1497 txtheight
= DrawTextW( Dc
, ItemInfo
->dwTypeData
, -1, &rc
,
1498 DT_SINGLELINE
|DT_CALCRECT
);
1499 txtwidth
= rc
.right
- rc
.left
;
1500 ItemInfo
->XTab
+= txtwidth
;
1502 ItemInfo
->Rect
.right
+= 2 + txtwidth
;
1503 itemheight
= max( itemheight
, max( txtheight
+ 2, MenuCharSize
.cy
+ 4));
1505 if (hfontOld
) SelectObject (Dc
, hfontOld
);
1509 itemheight
= max( itemheight
, GetSystemMetrics(SM_CYMENU
)-1);
1511 ItemInfo
->Rect
.bottom
+= itemheight
;
1512 TRACE("(%ld,%ld)-(%ld,%ld)\n", ItemInfo
->Rect
.left
, ItemInfo
->Rect
.top
, ItemInfo
->Rect
.right
, ItemInfo
->Rect
.bottom
);
1515 /***********************************************************************
1516 * MenuPopupMenuCalcSize
1518 * Calculate the size of a popup menu.
1520 static void FASTCALL
1521 MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo
, HWND WndOwner
)
1523 ROSMENUITEMINFO ItemInfo
;
1526 int OrgX
, OrgY
, MaxX
, MaxTab
, MaxTabWidth
;
1528 MenuInfo
->Width
= MenuInfo
->Height
= 0;
1529 if (0 == MenuInfo
->MenuItemCount
)
1531 MenuSetRosMenuInfo(MenuInfo
);
1536 SelectObject(Dc
, hMenuFont
);
1541 MenuInfo
->maxBmpSize
.cx
= 0;
1542 MenuInfo
->maxBmpSize
.cy
= 0;
1544 MenuInitRosMenuItemInfo(&ItemInfo
);
1545 while (Start
< MenuInfo
->MenuItemCount
)
1550 MaxTab
= MaxTabWidth
= 0;
1552 /* Parse items until column break or end of menu */
1553 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1555 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1557 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1558 MenuSetRosMenuInfo(MenuInfo
);
1562 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1566 MenuCalcItemSize(Dc
, &ItemInfo
, MenuInfo
, WndOwner
, OrgX
, OrgY
, FALSE
);
1567 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1569 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1570 MenuSetRosMenuInfo(MenuInfo
);
1573 // Not sure here,, The patch from wine removes this.
1574 // if (0 != (ItemInfo.fType & MF_MENUBARBREAK))
1578 MaxX
= max(MaxX
, ItemInfo
.Rect
.right
);
1579 OrgY
= ItemInfo
.Rect
.bottom
;
1580 if ((ItemInfo
.Text
) && 0 != ItemInfo
.XTab
)
1582 MaxTab
= max(MaxTab
, ItemInfo
.XTab
);
1583 MaxTabWidth
= max(MaxTabWidth
, ItemInfo
.Rect
.right
- ItemInfo
.XTab
);
1587 /* Finish the column (set all items to the largest width found) */
1588 MaxX
= max(MaxX
, MaxTab
+ MaxTabWidth
);
1591 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1593 ItemInfo
.Rect
.right
= MaxX
;
1594 if ((ItemInfo
.Text
) && 0 != ItemInfo
.XTab
)
1596 ItemInfo
.XTab
= MaxTab
;
1598 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1602 MenuInfo
->Height
= max(MenuInfo
->Height
, OrgY
);
1605 MenuInfo
->Width
= MaxX
;
1607 /* space for 3d border */
1608 MenuInfo
->Height
+= 2;
1609 MenuInfo
->Width
+= 2;
1611 ReleaseDC(NULL
, Dc
);
1612 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1613 MenuSetRosMenuInfo(MenuInfo
);
1616 /***********************************************************************
1617 * MenuMenuBarCalcSize
1619 * FIXME: Word 6 implements its own MDI and its own 'close window' bitmap
1620 * height is off by 1 pixel which causes lengthy window relocations when
1621 * active document window is maximized/restored.
1623 * Calculate the size of the menu bar.
1625 static void FASTCALL
1626 MenuMenuBarCalcSize(HDC Dc
, LPRECT Rect
, PROSMENUINFO MenuInfo
, HWND WndOwner
)
1628 ROSMENUITEMINFO ItemInfo
;
1629 int Start
, i
, OrgX
, OrgY
, MaxY
, HelpPos
;
1631 if (NULL
== Rect
|| NULL
== MenuInfo
)
1635 if (0 == MenuInfo
->MenuItemCount
)
1640 TRACE("left=%ld top=%ld right=%ld bottom=%ld\n",
1641 Rect
->left
, Rect
->top
, Rect
->right
, Rect
->bottom
);
1642 MenuInfo
->Width
= Rect
->right
- Rect
->left
;
1643 MenuInfo
->Height
= 0;
1644 MaxY
= Rect
->top
+ 1;
1648 MenuInfo
->maxBmpSize
.cx
= 0;
1649 MenuInfo
->maxBmpSize
.cy
= 0;
1651 MenuInitRosMenuItemInfo(&ItemInfo
);
1652 while (Start
< MenuInfo
->MenuItemCount
)
1654 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1656 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1662 /* Parse items until line break or end of menu */
1663 for (i
= Start
; i
< MenuInfo
->MenuItemCount
; i
++)
1665 if (-1 == HelpPos
&& 0 != (ItemInfo
.fType
& MF_RIGHTJUSTIFY
))
1670 0 != (ItemInfo
.fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
1675 TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", OrgX
, OrgY
);
1676 MenuCalcItemSize(Dc
, &ItemInfo
, MenuInfo
, WndOwner
, OrgX
, OrgY
, TRUE
);
1677 if (! MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
))
1679 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1683 if (ItemInfo
.Rect
.right
> Rect
->right
)
1691 ItemInfo
.Rect
.right
= Rect
->right
;
1694 MaxY
= max(MaxY
, ItemInfo
.Rect
.bottom
);
1695 OrgX
= ItemInfo
.Rect
.right
;
1696 if (i
+ 1 < MenuInfo
->MenuItemCount
)
1698 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
+ 1, &ItemInfo
))
1700 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1706 /* FIXME: Is this really needed? */ /*NO! it is not needed, why make the
1707 HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */
1709 /* Finish the line (set all items to the largest height found) */
1712 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
))
1714 ItemInfo
.Rect
.bottom
= MaxY
;
1715 MenuSetRosMenuItemInfo(MenuInfo
->Self
, Start
, &ItemInfo
);
1720 Start
= i
; /* This works! */
1724 Rect
->bottom
= MaxY
;
1725 MenuInfo
->Height
= Rect
->bottom
- Rect
->top
;
1726 MenuSetRosMenuInfo(MenuInfo
);
1730 /* Flush right all items between the MF_RIGHTJUSTIFY and */
1731 /* the last item (if several lines, only move the last line) */
1732 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->MenuItemCount
- 1, &ItemInfo
))
1734 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1737 OrgY
= ItemInfo
.Rect
.top
;
1739 for (i
= MenuInfo
->MenuItemCount
- 1; HelpPos
<= i
; i
--)
1745 if (ItemInfo
.Rect
.top
!= OrgY
)
1747 break; /* Other line */
1749 if (OrgX
<= ItemInfo
.Rect
.right
)
1751 break; /* Too far right already */
1753 ItemInfo
.Rect
.left
+= OrgX
- ItemInfo
.Rect
.right
;
1754 ItemInfo
.Rect
.right
= OrgX
;
1755 OrgX
= ItemInfo
.Rect
.left
;
1756 MenuSetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
);
1757 if (HelpPos
+ 1 <= i
&&
1758 ! MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
- 1, &ItemInfo
))
1760 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1766 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1769 /***********************************************************************
1770 * DrawMenuBarTemp (USER32.@)
1774 * called by W98SE desk.cpl Control Panel Applet
1776 * Not 100% sure about the param names, but close.
1781 DrawMenuBarTemp(HWND Wnd
, HDC DC
, LPRECT Rect
, HMENU Menu
, HFONT Font
)
1783 ROSMENUINFO MenuInfo
;
1784 ROSMENUITEMINFO ItemInfo
;
1786 HFONT FontOld
= NULL
;
1787 BOOL flat_menu
= FALSE
;
1789 SystemParametersInfoW (SPI_GETFLATMENU
, 0, &flat_menu
, 0);
1793 Menu
= GetMenu(Wnd
);
1801 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1803 return GetSystemMetrics(SM_CYMENU
);
1806 TRACE("(%x, %x, %p, %x, %x)\n", Wnd
, DC
, Rect
, Menu
, Font
);
1808 FontOld
= SelectObject(DC
, Font
);
1810 if (0 == MenuInfo
.Height
)
1812 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
1815 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
1817 FillRect(DC
, Rect
, GetSysColorBrush(flat_menu
? COLOR_MENUBAR
: COLOR_MENU
));
1819 SelectObject(DC
, GetStockObject(DC_PEN
));
1820 SetDCPenColor(DC
, GetSysColor(COLOR_3DFACE
));
1821 MoveToEx(DC
, Rect
->left
, Rect
->bottom
, NULL
);
1822 LineTo(DC
, Rect
->right
, Rect
->bottom
);
1824 if (0 == MenuInfo
.MenuItemCount
)
1826 SelectObject(DC
, FontOld
);
1827 return GetSystemMetrics(SM_CYMENU
);
1830 MenuInitRosMenuItemInfo(&ItemInfo
);
1831 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
1833 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
1835 MenuDrawMenuItem(Wnd
, &MenuInfo
, Wnd
, DC
, &ItemInfo
,
1836 MenuInfo
.Height
, TRUE
, ODA_DRAWENTIRE
);
1839 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1841 SelectObject(DC
, FontOld
);
1843 return MenuInfo
.Height
;
1847 /***********************************************************************
1850 * Paint a menu bar. Returns the height of the menu bar.
1851 * called from [windows/nonclient.c]
1853 UINT
MenuDrawMenuBar(HDC DC
, LPRECT Rect
, HWND Wnd
, BOOL SuppressDraw
)
1855 ROSMENUINFO MenuInfo
;
1856 HFONT FontOld
= NULL
;
1857 HMENU Menu
= GetMenu(Wnd
);
1859 if (NULL
== Rect
|| ! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1861 return GetSystemMetrics(SM_CYMENU
);
1866 FontOld
= SelectObject(DC
, hMenuFont
);
1868 MenuMenuBarCalcSize(DC
, Rect
, &MenuInfo
, Wnd
);
1870 Rect
->bottom
= Rect
->top
+ MenuInfo
.Height
;
1872 if (NULL
!= FontOld
)
1874 SelectObject(DC
, FontOld
);
1876 return MenuInfo
.Height
;
1880 return DrawMenuBarTemp(Wnd
, DC
, Rect
, Menu
, NULL
);
1884 /***********************************************************************
1887 static BOOL FASTCALL
1888 MenuInitTracking(HWND Wnd
, HMENU Menu
, BOOL Popup
, UINT Flags
)
1890 TRACE("Wnd=%p Menu=%p\n", Wnd
, Menu
);
1894 /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */
1895 if (0 == (Flags
& TPM_NONOTIFY
))
1897 SendMessageW(Wnd
, WM_ENTERMENULOOP
, Popup
, 0);
1900 SendMessageW(Wnd
, WM_SETCURSOR
, (WPARAM
) Wnd
, HTCAPTION
);
1902 if (0 == (Flags
& TPM_NONOTIFY
))
1904 ROSMENUINFO MenuInfo
;
1906 SendMessageW(Wnd
, WM_INITMENU
, (WPARAM
)Menu
, 0);
1908 MenuGetRosMenuInfo(&MenuInfo
, Menu
);
1910 if (0 == MenuInfo
.Height
)
1912 /* app changed/recreated menu bar entries in WM_INITMENU
1913 Recalculate menu sizes else clicks will not work */
1914 SetWindowPos(Wnd
, 0, 0, 0, 0, 0, SWP_NOSIZE
| SWP_NOMOVE
|
1915 SWP_NOACTIVATE
| SWP_NOZORDER
| SWP_FRAMECHANGED
);
1918 /* This makes the menus of applications built with Delphi work.
1919 * It also enables menus to be displayed in more than one window,
1920 * but there are some bugs left that need to be fixed in this case.
1922 if(MenuInfo
.Self
== Menu
)
1925 MenuSetRosMenuInfo(&MenuInfo
);
1933 /***********************************************************************
1936 * Display a popup menu.
1938 static BOOL FASTCALL
1939 MenuShowPopup(HWND WndOwner
, HMENU Menu
, UINT Id
, UINT flags
,
1940 INT X
, INT Y
, INT XAnchor
, INT YAnchor
)
1942 ROSMENUINFO MenuInfo
;
1943 ROSMENUITEMINFO ItemInfo
;
1949 TRACE("owner=%x hmenu=%x id=0x%04x x=0x%04x y=0x%04x xa=0x%04x ya=0x%04x\n",
1950 WndOwner
, Menu
, Id
, X
, Y
, XAnchor
, YAnchor
);
1952 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
1957 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
1959 MenuInitRosMenuItemInfo(&ItemInfo
);
1960 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
1962 ItemInfo
.fMask
|= MIIM_STATE
;
1963 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
1964 MenuSetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
);
1966 MenuCleanupRosMenuItemInfo(&ItemInfo
);
1967 MenuInfo
.FocusedItem
= NO_SELECTED_ITEM
;
1970 /* store the owner for DrawItem */
1971 MenuInfo
.WndOwner
= WndOwner
;
1972 MenuSetRosMenuInfo(&MenuInfo
);
1974 MenuPopupMenuCalcSize(&MenuInfo
, WndOwner
);
1976 /* adjust popup menu pos so that it fits within the desktop */
1978 Width
= MenuInfo
.Width
+ GetSystemMetrics(SM_CXBORDER
);
1979 Height
= MenuInfo
.Height
+ GetSystemMetrics(SM_CYBORDER
);
1981 /* FIXME: should use item rect */
1984 monitor
= MonitorFromPoint( pt
, MONITOR_DEFAULTTONEAREST
);
1985 info
.cbSize
= sizeof(info
);
1986 GetMonitorInfoW( monitor
, &info
);
1988 if( flags
& TPM_RIGHTALIGN
) X
-= Width
;
1989 if( flags
& TPM_CENTERALIGN
) X
-= Width
/ 2;
1991 if( flags
& TPM_BOTTOMALIGN
) Y
-= Height
;
1992 if( flags
& TPM_VCENTERALIGN
) Y
-= Height
/ 2;
1994 if (X
+ Width
> info
.rcWork
.right
)
1996 if ( XAnchor
&& X
>= Width
- XAnchor
)
1997 X
-= Width
- XAnchor
;
1999 if ( X
+ Width
> info
.rcWork
.right
)
2000 X
= info
.rcWork
.right
- Width
;
2003 if ( X
< info
.rcWork
.left
) X
= info
.rcWork
.left
;
2005 if (Y
+ Height
> info
.rcWork
.bottom
)
2007 if ( YAnchor
&& Y
>= Height
+ YAnchor
)
2008 Y
-= Height
+ YAnchor
;
2010 if ( Y
+ Height
> info
.rcWork
.bottom
)
2011 Y
= info
.rcWork
.bottom
- Height
;
2014 if ( Y
< info
.rcWork
.top
) Y
= info
.rcWork
.top
;
2016 /* NOTE: In Windows, top menu popup is not owned. */
2017 MenuInfo
.Wnd
= CreateWindowExW(0, POPUPMENU_CLASS_ATOMW
, NULL
,
2018 WS_POPUP
, X
, Y
, Width
, Height
,
2019 WndOwner
, 0, (HINSTANCE
) GetWindowLongPtrW(WndOwner
, GWLP_HINSTANCE
),
2020 (LPVOID
) MenuInfo
.Self
);
2021 if (NULL
== MenuInfo
.Wnd
|| ! MenuSetRosMenuInfo(&MenuInfo
))
2025 if (NULL
== TopPopup
)
2027 TopPopup
= MenuInfo
.Wnd
;
2030 /* Display the window */
2031 SetWindowPos(MenuInfo
.Wnd
, HWND_TOPMOST
, 0, 0, 0, 0,
2032 SWP_SHOWWINDOW
| SWP_NOSIZE
| SWP_NOMOVE
| SWP_NOACTIVATE
);
2033 UpdateWindow(MenuInfo
.Wnd
);
2038 /***********************************************************************
2041 * Find a Sub menu. Return the position of the submenu, and modifies
2042 * *hmenu in case it is found in another sub-menu.
2043 * If the submenu cannot be found, NO_SELECTED_ITEM is returned.
2045 static UINT FASTCALL
2046 MenuFindSubMenu(HMENU
*Menu
, HMENU SubTarget
)
2048 ROSMENUINFO MenuInfo
;
2049 ROSMENUITEMINFO ItemInfo
;
2054 if ((HMENU
) 0xffff == *Menu
2055 || ! MenuGetRosMenuInfo(&MenuInfo
, *Menu
))
2057 return NO_SELECTED_ITEM
;
2060 MenuInitRosMenuItemInfo(&ItemInfo
);
2061 for (i
= 0; i
< MenuInfo
.MenuItemCount
; i
++)
2063 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, i
, &ItemInfo
))
2065 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2066 return NO_SELECTED_ITEM
;
2068 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2072 if (ItemInfo
.hSubMenu
== SubTarget
)
2074 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2077 SubMenu
= ItemInfo
.hSubMenu
;
2078 Pos
= MenuFindSubMenu(&SubMenu
, SubTarget
);
2079 if (NO_SELECTED_ITEM
!= Pos
)
2085 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2087 return NO_SELECTED_ITEM
;
2090 /***********************************************************************
2093 static void FASTCALL
2094 MenuSelectItem(HWND WndOwner
, PROSMENUINFO MenuInfo
, UINT Index
,
2095 BOOL SendMenuSelect
, HMENU TopMenu
)
2098 ROSMENUITEMINFO ItemInfo
;
2099 ROSMENUINFO TopMenuInfo
;
2102 TRACE("owner=%x menu=%p index=0x%04x select=0x%04x\n", WndOwner
, MenuInfo
, Index
, SendMenuSelect
);
2104 if (NULL
== MenuInfo
|| 0 == MenuInfo
->MenuItemCount
|| NULL
== MenuInfo
->Wnd
)
2109 if (MenuInfo
->FocusedItem
== Index
)
2114 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2116 Dc
= GetDC(MenuInfo
->Wnd
);
2120 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2123 if (NULL
== TopPopup
)
2125 TopPopup
= MenuInfo
->Wnd
;
2128 SelectObject(Dc
, hMenuFont
);
2129 MenuInitRosMenuItemInfo(&ItemInfo
);
2130 /* Clear previous highlighted item */
2131 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2133 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2135 ItemInfo
.fMask
|= MIIM_STATE
;
2136 ItemInfo
.fState
&= ~(MF_HILITE
|MF_MOUSESELECT
);
2137 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2139 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
,
2140 MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
2144 /* Highlight new item (if any) */
2145 MenuInfo
->FocusedItem
= Index
;
2146 MenuSetRosMenuInfo(MenuInfo
);
2147 if (NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2149 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2151 if (0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2153 ItemInfo
.fMask
|= MIIM_STATE
;
2154 ItemInfo
.fState
|= MF_HILITE
;
2155 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2156 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
,
2157 &ItemInfo
, MenuInfo
->Height
, ! (MenuInfo
->Flags
& MF_POPUP
),
2162 SendMessageW(WndOwner
, WM_MENUSELECT
,
2163 MAKELONG(ItemInfo
.fType
& MF_POPUP
? Index
: ItemInfo
.wID
,
2164 ItemInfo
.fType
| ItemInfo
.fState
| MF_MOUSESELECT
|
2165 (MenuInfo
->Flags
& MF_SYSMENU
)), (LPARAM
) MenuInfo
->Self
);
2169 else if (SendMenuSelect
)
2171 if (NULL
!= TopMenu
)
2173 Pos
= MenuFindSubMenu(&TopMenu
, MenuInfo
->Self
);
2174 if (NO_SELECTED_ITEM
!= Pos
)
2176 if (MenuGetRosMenuInfo(&TopMenuInfo
, TopMenu
)
2177 && MenuGetRosMenuItemInfo(TopMenu
, Pos
, &ItemInfo
))
2179 SendMessageW(WndOwner
, WM_MENUSELECT
,
2180 MAKELONG(Pos
, ItemInfo
.fType
| ItemInfo
.fState
2182 | (TopMenuInfo
.Flags
& MF_SYSMENU
)),
2188 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2189 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2192 /***********************************************************************
2195 * Moves currently selected item according to the Offset parameter.
2196 * If there is no selection then it should select the last item if
2197 * Offset is ITEM_PREV or the first item if Offset is ITEM_NEXT.
2199 static void FASTCALL
2200 MenuMoveSelection(HWND WndOwner
, PROSMENUINFO MenuInfo
, INT Offset
)
2203 ROSMENUITEMINFO ItemInfo
;
2206 TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner
, MenuInfo
, Offset
);
2208 /* Prevent looping */
2209 if (0 == MenuInfo
->MenuItemCount
|| 0 == Offset
)
2211 else if (Offset
< -1)
2213 else if (Offset
> 1)
2216 MenuInitRosMenuItemInfo(&ItemInfo
);
2218 OrigPos
= MenuInfo
->FocusedItem
;
2219 if (OrigPos
== NO_SELECTED_ITEM
) /* NO_SELECTED_ITEM is not -1 ! */
2226 i
= MenuInfo
->FocusedItem
;
2233 /* Clip and wrap around */
2236 i
= MenuInfo
->MenuItemCount
- 1;
2238 else if (i
>= MenuInfo
->MenuItemCount
)
2242 /* If this is a good candidate; */
2243 if (MenuGetRosMenuItemInfo(MenuInfo
->Self
, i
, &ItemInfo
) &&
2244 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2246 MenuSelectItem(WndOwner
, MenuInfo
, i
, TRUE
, NULL
);
2247 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2250 } while (i
!= OrigPos
);
2253 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2256 /***********************************************************************
2257 * MenuInitSysMenuPopup
2259 * Grey the appropriate items in System menu.
2262 MenuInitSysMenuPopup(HMENU Menu
, DWORD Style
, DWORD ClsStyle
, LONG HitTest
)
2270 Gray
= 0 == (Style
& WS_THICKFRAME
) || 0 != (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2271 EnableMenuItem(Menu
, SC_SIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2272 Gray
= 0 != (Style
& WS_MAXIMIZE
);
2273 EnableMenuItem(Menu
, SC_MOVE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2274 Gray
= 0 == (Style
& WS_MINIMIZEBOX
) || 0 != (Style
& WS_MINIMIZE
);
2275 EnableMenuItem(Menu
, SC_MINIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2276 Gray
= 0 == (Style
& WS_MAXIMIZEBOX
) || 0 != (Style
& WS_MAXIMIZE
);
2277 EnableMenuItem(Menu
, SC_MAXIMIZE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2278 Gray
= 0 == (Style
& (WS_MAXIMIZE
| WS_MINIMIZE
));
2279 EnableMenuItem(Menu
, SC_RESTORE
, (Gray
? MF_GRAYED
: MF_ENABLED
));
2280 Gray
= 0 != (ClsStyle
& CS_NOCLOSE
);
2282 /* The menu item must keep its state if it's disabled */
2285 EnableMenuItem(Menu
, SC_CLOSE
, MF_GRAYED
);
2288 /* Set default menu item */
2289 if(Style
& WS_MINIMIZE
)
2291 DefItem
= SC_RESTORE
;
2295 if(HitTest
== HTCAPTION
)
2297 DefItem
= ((Style
& (WS_MAXIMIZE
| WS_MINIMIZE
)) ? SC_RESTORE
: SC_MAXIMIZE
);
2305 mii
.cbSize
= sizeof(MENUITEMINFOW
);
2306 mii
.fMask
|= MIIM_STATE
;
2307 if((DefItem
!= SC_CLOSE
) && GetMenuItemInfoW(Menu
, DefItem
, FALSE
, &mii
) &&
2308 (mii
.fState
& (MFS_GRAYED
| MFS_DISABLED
)))
2313 SetMenuDefaultItem(Menu
, DefItem
, MF_BYCOMMAND
);
2316 /***********************************************************************
2319 * Display the sub-menu of the selected item of this menu.
2320 * Return the handle of the submenu, or menu if no submenu to display.
2322 static HMENU FASTCALL
2323 MenuShowSubPopup(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SelectFirst
, UINT Flags
)
2325 extern void FASTCALL
NcGetSysPopupPos(HWND Wnd
, RECT
*Rect
);
2327 ROSMENUITEMINFO ItemInfo
;
2328 ROSMENUINFO SubMenuInfo
;
2332 TRACE("owner=%x menu=%p 0x%04x\n", WndOwner
, MenuInfo
, SelectFirst
);
2334 if (NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2336 return MenuInfo
->Self
;
2339 MenuInitRosMenuItemInfo(&ItemInfo
);
2340 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2342 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2343 return MenuInfo
->Self
;
2345 if (0 == (ItemInfo
.fType
& MF_POPUP
) || 0 != (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
)))
2347 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2348 return MenuInfo
->Self
;
2351 /* message must be sent before using item,
2352 because nearly everything may be changed by the application ! */
2354 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
2355 if (0 == (Flags
& TPM_NONOTIFY
))
2357 SendMessageW(WndOwner
, WM_INITMENUPOPUP
, (WPARAM
) ItemInfo
.hSubMenu
,
2358 MAKELONG(MenuInfo
->FocusedItem
, IS_SYSTEM_MENU(MenuInfo
)));
2361 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2363 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2364 return MenuInfo
->Self
;
2366 Rect
= ItemInfo
.Rect
;
2368 /* correct item if modified as a reaction to WM_INITMENUPOPUP message */
2369 if (0 == (ItemInfo
.fState
& MF_HILITE
))
2371 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2373 Dc
= GetDC(MenuInfo
->Wnd
);
2377 Dc
= GetDCEx(MenuInfo
->Wnd
, 0, DCX_CACHE
| DCX_WINDOW
);
2380 SelectObject(Dc
, hMenuFont
);
2381 ItemInfo
.fMask
|= MIIM_STATE
;
2382 ItemInfo
.fState
|= MF_HILITE
;
2383 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2384 MenuDrawMenuItem(MenuInfo
->Wnd
, MenuInfo
, WndOwner
, Dc
, &ItemInfo
, MenuInfo
->Height
,
2385 ! (MenuInfo
->Flags
& MF_POPUP
), ODA_DRAWENTIRE
);
2386 ReleaseDC(MenuInfo
->Wnd
, Dc
);
2389 if (0 == ItemInfo
.Rect
.top
&& 0 == ItemInfo
.Rect
.left
2390 && 0 == ItemInfo
.Rect
.bottom
&& 0 == ItemInfo
.Rect
.right
)
2392 ItemInfo
.Rect
= Rect
;
2395 ItemInfo
.fMask
|= MIIM_STATE
;
2396 ItemInfo
.fState
|= MF_MOUSESELECT
;
2397 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2399 if (IS_SYSTEM_MENU(MenuInfo
))
2401 MenuInitSysMenuPopup(ItemInfo
.hSubMenu
, GetWindowLongPtrW(MenuInfo
->Wnd
, GWL_STYLE
),
2402 GetClassLongPtrW(MenuInfo
->Wnd
, GCL_STYLE
), HTSYSMENU
);
2404 NcGetSysPopupPos(MenuInfo
->Wnd
, &Rect
);
2405 Rect
.top
= Rect
.bottom
;
2406 Rect
.right
= GetSystemMetrics(SM_CXSIZE
);
2407 Rect
.bottom
= GetSystemMetrics(SM_CYSIZE
);
2411 GetWindowRect(MenuInfo
->Wnd
, &Rect
);
2412 if (0 != (MenuInfo
->Flags
& MF_POPUP
))
2414 Rect
.left
+= ItemInfo
.Rect
.right
- GetSystemMetrics(SM_CXBORDER
);
2415 Rect
.top
+= ItemInfo
.Rect
.top
- 3;
2416 Rect
.right
= ItemInfo
.Rect
.left
- ItemInfo
.Rect
.right
+ GetSystemMetrics(SM_CXBORDER
);
2417 Rect
.bottom
= ItemInfo
.Rect
.top
- ItemInfo
.Rect
.bottom
- 3 - 2
2418 - GetSystemMetrics(SM_CYBORDER
);
2422 Rect
.left
+= ItemInfo
.Rect
.left
;
2423 Rect
.top
+= ItemInfo
.Rect
.bottom
;
2424 Rect
.right
= ItemInfo
.Rect
.right
- ItemInfo
.Rect
.left
;
2425 Rect
.bottom
= ItemInfo
.Rect
.bottom
- ItemInfo
.Rect
.top
;
2429 MenuShowPopup(WndOwner
, ItemInfo
.hSubMenu
, MenuInfo
->FocusedItem
, Flags
,
2430 Rect
.left
, Rect
.top
, Rect
.right
, Rect
.bottom
);
2431 if (SelectFirst
&& MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2433 MenuMoveSelection(WndOwner
, &SubMenuInfo
, ITEM_NEXT
);
2436 Ret
= ItemInfo
.hSubMenu
;
2437 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2442 /***********************************************************************
2445 * Hide the sub-popup menus of this menu.
2447 static void FASTCALL
2448 MenuHideSubPopups(HWND WndOwner
, PROSMENUINFO MenuInfo
, BOOL SendMenuSelect
)
2450 ROSMENUINFO SubMenuInfo
;
2451 ROSMENUITEMINFO ItemInfo
;
2453 TRACE("owner=%x menu=%x 0x%04x\n", WndOwner
, MenuInfo
, SendMenuSelect
);
2455 if (NULL
!= MenuInfo
&& NULL
!= TopPopup
&& NO_SELECTED_ITEM
!= MenuInfo
->FocusedItem
)
2457 MenuInitRosMenuItemInfo(&ItemInfo
);
2458 ItemInfo
.fMask
|= MIIM_FTYPE
| MIIM_STATE
;
2459 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
)
2460 || 0 == (ItemInfo
.fType
& MF_POPUP
)
2461 || 0 == (ItemInfo
.fState
& MF_MOUSESELECT
))
2463 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2466 ItemInfo
.fState
&= ~MF_MOUSESELECT
;
2467 ItemInfo
.fMask
|= MIIM_STATE
;
2468 MenuSetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
);
2469 if (MenuGetRosMenuInfo(&SubMenuInfo
, ItemInfo
.hSubMenu
))
2471 MenuHideSubPopups(WndOwner
, &SubMenuInfo
, FALSE
);
2472 MenuSelectItem(WndOwner
, &SubMenuInfo
, NO_SELECTED_ITEM
, SendMenuSelect
, NULL
);
2473 DestroyWindow(SubMenuInfo
.Wnd
);
2474 SubMenuInfo
.Wnd
= NULL
;
2475 MenuSetRosMenuInfo(&SubMenuInfo
);
2480 /***********************************************************************
2481 * MenuSwitchTracking
2483 * Helper function for menu navigation routines.
2485 static void FASTCALL
2486 MenuSwitchTracking(MTRACKER
* Mt
, PROSMENUINFO PtMenuInfo
, UINT Index
)
2488 ROSMENUINFO TopMenuInfo
;
2490 TRACE("%x menu=%x 0x%04x\n", Mt
, PtMenuInfo
->Self
, Index
);
2492 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
) &&
2493 Mt
->TopMenu
!= PtMenuInfo
->Self
&&
2494 0 == ((PtMenuInfo
->Flags
| TopMenuInfo
.Flags
) & MF_POPUP
))
2496 /* both are top level menus (system and menu-bar) */
2497 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
2498 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
2499 Mt
->TopMenu
= PtMenuInfo
->Self
;
2503 MenuHideSubPopups(Mt
->OwnerWnd
, PtMenuInfo
, FALSE
);
2506 MenuSelectItem(Mt
->OwnerWnd
, PtMenuInfo
, Index
, TRUE
, NULL
);
2509 /***********************************************************************
2510 * MenuExecFocusedItem
2512 * Execute a menu item (for instance when user pressed Enter).
2513 * Return the wID of the executed item. Otherwise, -1 indicating
2514 * that no menu item was executed, -2 if a popup is shown;
2515 * Have to receive the flags for the TrackPopupMenu options to avoid
2516 * sending unwanted message.
2520 MenuExecFocusedItem(MTRACKER
*Mt
, PROSMENUINFO MenuInfo
, UINT Flags
)
2522 ROSMENUITEMINFO ItemInfo
;
2525 TRACE("%p menu=%p\n", Mt
, MenuInfo
);
2527 if (0 == MenuInfo
->MenuItemCount
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2532 MenuInitRosMenuItemInfo(&ItemInfo
);
2533 if (! MenuGetRosMenuItemInfo(MenuInfo
->Self
, MenuInfo
->FocusedItem
, &ItemInfo
))
2535 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2539 TRACE("%p %08x %p\n", MenuInfo
, ItemInfo
.wID
, ItemInfo
.hSubMenu
);
2541 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2543 if (0 == (ItemInfo
.fState
& (MF_GRAYED
| MF_DISABLED
))
2544 && 0 == (ItemInfo
.fType
& MF_SEPARATOR
))
2546 /* If TPM_RETURNCMD is set you return the id, but
2547 do not send a message to the owner */
2548 if (0 == (Flags
& TPM_RETURNCMD
))
2550 if (0 != (MenuInfo
->Flags
& MF_SYSMENU
))
2552 PostMessageW(Mt
->OwnerWnd
, WM_SYSCOMMAND
, ItemInfo
.wID
,
2553 MAKELPARAM((SHORT
) Mt
->Pt
.x
, (SHORT
) Mt
->Pt
.y
));
2557 if (MenuInfo
->dwStyle
& MNS_NOTIFYBYPOS
)
2558 PostMessageW(Mt
->OwnerWnd
, WM_MENUCOMMAND
,
2559 MenuInfo
->FocusedItem
,
2560 (LPARAM
)MenuInfo
->Self
);
2562 PostMessageW(Mt
->OwnerWnd
, WM_COMMAND
, ItemInfo
.wID
, 0);
2566 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2572 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, MenuInfo
, TRUE
, Flags
);
2579 /***********************************************************************
2582 * Return TRUE if we can go on with menu tracking.
2584 static BOOL FASTCALL
2585 MenuButtonDown(MTRACKER
* Mt
, HMENU PtMenu
, UINT Flags
)
2588 ROSMENUINFO MenuInfo
;
2589 ROSMENUITEMINFO Item
;
2591 TRACE("%x PtMenu=%p\n", Mt
, PtMenu
);
2595 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2599 if (IS_SYSTEM_MENU(&MenuInfo
))
2605 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2607 MenuInitRosMenuItemInfo(&Item
);
2608 if (NO_SELECTED_ITEM
== Index
|| ! MenuGetRosMenuItemInfo(PtMenu
, Index
, &Item
))
2610 MenuCleanupRosMenuItemInfo(&Item
);
2614 if (!(Item
.fType
& MF_SEPARATOR
) &&
2615 !(Item
.fState
& (MFS_DISABLED
| MFS_GRAYED
)) )
2617 if (MenuInfo
.FocusedItem
!= Index
)
2619 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2622 /* If the popup menu is not already "popped" */
2623 if (0 == (Item
.fState
& MF_MOUSESELECT
))
2625 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2629 MenuCleanupRosMenuItemInfo(&Item
);
2634 /* else the click was on the menu bar, finish the tracking */
2639 /***********************************************************************
2642 * Return the value of MenuExecFocusedItem if
2643 * the selected item was not a popup. Else open the popup.
2644 * A -1 return value indicates that we go on with menu tracking.
2648 MenuButtonUp(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2651 ROSMENUINFO MenuInfo
;
2652 ROSMENUITEMINFO ItemInfo
;
2654 TRACE("%p hmenu=%x\n", Mt
, PtMenu
);
2659 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2664 if (! IS_SYSTEM_MENU(&MenuInfo
))
2666 Id
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, MenuInfo
.Self
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2668 MenuInitRosMenuItemInfo(&ItemInfo
);
2669 if (0 <= Id
&& MenuGetRosMenuItemInfo(MenuInfo
.Self
, Id
, &ItemInfo
) &&
2670 MenuInfo
.FocusedItem
== Id
)
2672 if (0 == (ItemInfo
.fType
& MF_POPUP
))
2674 INT ExecutedMenuId
= MenuExecFocusedItem(Mt
, &MenuInfo
, Flags
);
2675 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2676 return (ExecutedMenuId
< 0) ? -1 : ExecutedMenuId
;
2678 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2680 /* If we are dealing with the top-level menu */
2681 /* and this is a click on an already "popped" item: */
2682 /* Stop the menu tracking and close the opened submenus */
2683 if (Mt
->TopMenu
== MenuInfo
.Self
&& MenuInfo
.TimeToHide
)
2685 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2689 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2690 MenuInfo
.TimeToHide
= TRUE
;
2691 MenuSetRosMenuInfo(&MenuInfo
);
2697 /***********************************************************************
2700 * Walks menu chain trying to find a menu pt maps to.
2702 static HMENU FASTCALL
2703 MenuPtMenu(HMENU Menu
, POINT Pt
)
2705 extern LRESULT
DefWndNCHitTest(HWND hWnd
, POINT Point
);
2706 ROSMENUINFO MenuInfo
;
2707 ROSMENUITEMINFO ItemInfo
;
2711 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
2716 /* try subpopup first (if any) */
2717 if (NO_SELECTED_ITEM
!= MenuInfo
.FocusedItem
)
2719 MenuInitRosMenuItemInfo(&ItemInfo
);
2720 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
) &&
2721 0 != (ItemInfo
.fType
& MF_POPUP
) &&
2722 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2724 Ret
= MenuPtMenu(ItemInfo
.hSubMenu
, Pt
);
2727 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2731 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2734 /* check the current window (avoiding WM_HITTEST) */
2735 Ht
= DefWndNCHitTest(MenuInfo
.Wnd
, Pt
);
2736 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
2738 if (HTNOWHERE
!= Ht
&& HTERROR
!= Ht
)
2743 else if (HTSYSMENU
== Ht
)
2745 Ret
= NtUserGetSystemMenu(MenuInfo
.Wnd
, FALSE
);
2747 else if (HTMENU
== Ht
)
2749 Ret
= GetMenu(MenuInfo
.Wnd
);
2755 /***********************************************************************
2758 * Return TRUE if we can go on with menu tracking.
2760 static BOOL FASTCALL
2761 MenuMouseMove(MTRACKER
*Mt
, HMENU PtMenu
, UINT Flags
)
2764 ROSMENUINFO MenuInfo
;
2765 ROSMENUITEMINFO ItemInfo
;
2769 if (! MenuGetRosMenuInfo(&MenuInfo
, PtMenu
))
2773 if (IS_SYSTEM_MENU(&MenuInfo
))
2779 Index
= NtUserMenuItemFromPoint(Mt
->OwnerWnd
, PtMenu
, Mt
->Pt
.x
, Mt
->Pt
.y
);
2784 Index
= NO_SELECTED_ITEM
;
2787 if (NO_SELECTED_ITEM
== Index
)
2789 if (Mt
->CurrentMenu
== MenuInfo
.Self
||
2790 MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
2792 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
2796 else if (MenuInfo
.FocusedItem
!= Index
)
2798 MenuInitRosMenuItemInfo(&ItemInfo
);
2799 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
, Index
, &ItemInfo
) &&
2800 !(ItemInfo
.fType
& MF_SEPARATOR
))
2802 MenuSwitchTracking(Mt
, &MenuInfo
, Index
);
2803 if (!(ItemInfo
.fState
& (MFS_DISABLED
| MFS_GRAYED
)))
2804 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
, FALSE
, Flags
);
2806 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2812 /******************************************************************************
2814 * UINT MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo)
2816 static UINT
MenuGetStartOfNextColumn(PROSMENUINFO MenuInfo
)
2819 PROSMENUITEMINFO MenuItems
;
2821 i
= MenuInfo
->FocusedItem
;
2822 if (NO_SELECTED_ITEM
== i
)
2827 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2829 return NO_SELECTED_ITEM
;
2832 for (i
++ ; i
< MenuInfo
->MenuItemCount
; i
++)
2834 if (0 != (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
)))
2840 return NO_SELECTED_ITEM
;
2843 /******************************************************************************
2845 * UINT MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo)
2847 static UINT FASTCALL
2848 MenuGetStartOfPrevColumn(PROSMENUINFO MenuInfo
)
2851 PROSMENUITEMINFO MenuItems
;
2853 if (0 == MenuInfo
->FocusedItem
|| NO_SELECTED_ITEM
== MenuInfo
->FocusedItem
)
2855 return NO_SELECTED_ITEM
;
2858 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &MenuItems
) <= 0)
2860 return NO_SELECTED_ITEM
;
2863 /* Find the start of the column */
2865 for (i
= MenuInfo
->FocusedItem
;
2866 0 != i
&& 0 == (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
));
2874 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2875 return NO_SELECTED_ITEM
;
2878 for (--i
; 0 != i
; --i
)
2880 if (MenuItems
[i
].fType
& (MF_MENUBREAK
| MF_MENUBARBREAK
))
2886 MenuCleanupAllRosMenuItemInfo(MenuItems
);
2887 TRACE("ret %d.\n", i
);
2892 /***********************************************************************
2895 * Return the handle of the selected sub-popup menu (if any).
2897 static HMENU FASTCALL
2898 MenuGetSubPopup(HMENU Menu
)
2900 ROSMENUINFO MenuInfo
;
2901 ROSMENUITEMINFO ItemInfo
;
2903 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
)
2904 || NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
2909 MenuInitRosMenuItemInfo(&ItemInfo
);
2910 if (! MenuGetRosMenuItemInfo(MenuInfo
.Self
, MenuInfo
.FocusedItem
, &ItemInfo
))
2912 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2915 if (0 != (ItemInfo
.fType
& MF_POPUP
) && 0 != (ItemInfo
.fState
& MF_MOUSESELECT
))
2917 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2918 return ItemInfo
.hSubMenu
;
2921 MenuCleanupRosMenuItemInfo(&ItemInfo
);
2925 /***********************************************************************
2928 * NOTE: WM_NEXTMENU documented in Win32 is a bit different.
2930 static LRESULT FASTCALL
2931 MenuDoNextMenu(MTRACKER
* Mt
, UINT Vk
)
2933 ROSMENUINFO TopMenuInfo
;
2934 ROSMENUINFO MenuInfo
;
2936 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
2938 return (LRESULT
) FALSE
;
2941 if ((VK_LEFT
== Vk
&& 0 == TopMenuInfo
.FocusedItem
)
2942 || (VK_RIGHT
== Vk
&& TopMenuInfo
.FocusedItem
== TopMenuInfo
.MenuItemCount
- 1))
2944 MDINEXTMENU NextMenu
;
2949 NextMenu
.hmenuIn
= (IS_SYSTEM_MENU(&TopMenuInfo
)) ? GetSubMenu(Mt
->TopMenu
, 0) : Mt
->TopMenu
;
2950 NextMenu
.hmenuNext
= NULL
;
2951 NextMenu
.hwndNext
= NULL
;
2952 SendMessageW(Mt
->OwnerWnd
, WM_NEXTMENU
, Vk
, (LPARAM
) &NextMenu
);
2954 TRACE("%p [%p] -> %p [%p]\n",
2955 Mt
->CurrentMenu
, Mt
->OwnerWnd
, NextMenu
.hmenuNext
, NextMenu
.hwndNext
);
2957 if (NULL
== NextMenu
.hmenuNext
|| NULL
== NextMenu
.hwndNext
)
2959 DWORD Style
= GetWindowLongPtrW(Mt
->OwnerWnd
, GWL_STYLE
);
2960 NewWnd
= Mt
->OwnerWnd
;
2961 if (IS_SYSTEM_MENU(&TopMenuInfo
))
2963 /* switch to the menu bar */
2965 if (0 != (Style
& WS_CHILD
)
2966 || NULL
== (NewMenu
= GetMenu(NewWnd
)))
2973 if (! MenuGetRosMenuInfo(&MenuInfo
, NewMenu
))
2977 Id
= MenuInfo
.MenuItemCount
- 1;
2980 else if (0 != (Style
& WS_SYSMENU
))
2982 /* switch to the system menu */
2983 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
2990 else /* application returned a new menu to switch to */
2992 NewMenu
= NextMenu
.hmenuNext
;
2993 NewWnd
= NextMenu
.hwndNext
;
2995 if (IsMenu(NewMenu
) && IsWindow(NewWnd
))
2997 DWORD Style
= GetWindowLongPtrW(NewWnd
, GWL_STYLE
);
2999 if (0 != (Style
& WS_SYSMENU
)
3000 && GetSystemMenu(NewWnd
, FALSE
) == NewMenu
)
3002 /* get the real system menu */
3003 NewMenu
= NtUserGetSystemMenu(NewWnd
, FALSE
);
3005 else if (0 != (Style
& WS_CHILD
) || GetMenu(NewWnd
) != NewMenu
)
3007 /* FIXME: Not sure what to do here;
3008 * perhaps try to track NewMenu as a popup? */
3010 WARN(" -- got confused.\n");
3020 if (NewMenu
!= Mt
->TopMenu
)
3022 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, NO_SELECTED_ITEM
,
3024 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3026 MenuHideSubPopups(Mt
->OwnerWnd
, &TopMenuInfo
, FALSE
);
3030 if (NewWnd
!= Mt
->OwnerWnd
)
3032 Mt
->OwnerWnd
= NewWnd
;
3033 SetCapture(Mt
->OwnerWnd
);
3034 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
->OwnerWnd
);
3037 Mt
->TopMenu
= Mt
->CurrentMenu
= NewMenu
; /* all subpopups are hidden */
3038 if (MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3040 MenuSelectItem(Mt
->OwnerWnd
, &TopMenuInfo
, Id
, TRUE
, 0);
3049 /***********************************************************************
3052 * The idea is not to show the popup if the next input message is
3053 * going to hide it anyway.
3055 static BOOL FASTCALL
3056 MenuSuspendPopup(MTRACKER
* Mt
, UINT Message
)
3060 Msg
.hwnd
= Mt
->OwnerWnd
;
3062 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
3063 Mt
->TrackFlags
|= TF_SKIPREMOVE
;
3068 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3069 if (WM_KEYUP
== Msg
.message
|| WM_PAINT
== Msg
.message
)
3071 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_REMOVE
);
3072 PeekMessageW(&Msg
, 0, 0, 0, PM_NOYIELD
| PM_NOREMOVE
);
3073 if (WM_KEYDOWN
== Msg
.message
3074 && (VK_LEFT
== Msg
.wParam
|| VK_RIGHT
== Msg
.wParam
))
3076 Mt
->TrackFlags
|= TF_SUSPENDPOPUP
;
3083 /* failures go through this */
3084 Mt
->TrackFlags
&= ~TF_SUSPENDPOPUP
;
3089 /***********************************************************************
3092 * Handle a VK_ESCAPE key event in a menu.
3094 static BOOL FASTCALL
3095 MenuKeyEscape(MTRACKER
*Mt
, UINT Flags
)
3097 BOOL EndMenu
= TRUE
;
3098 ROSMENUINFO MenuInfo
;
3099 HMENU MenuTmp
, MenuPrev
;
3101 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3103 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
)
3104 && 0 != (MenuInfo
.Flags
& MF_POPUP
))
3106 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3108 /* close topmost popup */
3109 while (MenuTmp
!= Mt
->CurrentMenu
)
3112 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3115 if (MenuGetRosMenuInfo(&MenuInfo
, MenuPrev
))
3117 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, TRUE
);
3119 Mt
->CurrentMenu
= MenuPrev
;
3127 /***********************************************************************
3130 * Handle a VK_LEFT key event in a menu.
3132 static void FASTCALL
3133 MenuKeyLeft(MTRACKER
* Mt
, UINT Flags
)
3135 ROSMENUINFO MenuInfo
;
3136 ROSMENUINFO TopMenuInfo
;
3137 ROSMENUINFO PrevMenuInfo
;
3138 HMENU MenuTmp
, MenuPrev
;
3141 MenuPrev
= MenuTmp
= Mt
->TopMenu
;
3143 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3148 /* Try to move 1 column left (if possible) */
3149 if (NO_SELECTED_ITEM
!= (PrevCol
= MenuGetStartOfPrevColumn(&MenuInfo
)))
3151 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3153 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, PrevCol
, TRUE
, 0);
3158 /* close topmost popup */
3159 while (MenuTmp
!= Mt
->CurrentMenu
)
3162 MenuTmp
= MenuGetSubPopup(MenuPrev
);
3165 if (! MenuGetRosMenuInfo(&PrevMenuInfo
, MenuPrev
))
3169 MenuHideSubPopups(Mt
->OwnerWnd
, &PrevMenuInfo
, TRUE
);
3170 Mt
->CurrentMenu
= MenuPrev
;
3172 if (! MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3176 if ((MenuPrev
== Mt
->TopMenu
) && 0 == (TopMenuInfo
.Flags
& MF_POPUP
))
3178 /* move menu bar selection if no more popups are left */
3180 if (! MenuDoNextMenu(Mt
, VK_LEFT
))
3182 MenuMoveSelection(Mt
->OwnerWnd
, &TopMenuInfo
, ITEM_PREV
);
3185 if (MenuPrev
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3187 /* A sublevel menu was displayed - display the next one
3188 * unless there is another displacement coming up */
3190 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3191 && MenuGetRosMenuInfo(&TopMenuInfo
, Mt
->TopMenu
))
3193 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &TopMenuInfo
,
3200 /***********************************************************************
3203 * Handle a VK_RIGHT key event in a menu.
3205 static void FASTCALL
3206 MenuKeyRight(MTRACKER
*Mt
, UINT Flags
)
3209 ROSMENUINFO MenuInfo
;
3210 ROSMENUINFO CurrentMenuInfo
;
3213 TRACE("MenuKeyRight called, cur %p, top %p.\n",
3214 Mt
->CurrentMenu
, Mt
->TopMenu
);
3216 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3220 if (0 != (MenuInfo
.Flags
& MF_POPUP
) || (Mt
->CurrentMenu
!= Mt
->TopMenu
))
3222 /* If already displaying a popup, try to display sub-popup */
3224 MenuTmp
= Mt
->CurrentMenu
;
3225 if (MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3227 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &CurrentMenuInfo
, TRUE
, Flags
);
3230 /* if subpopup was displayed then we are done */
3231 if (MenuTmp
!= Mt
->CurrentMenu
)
3237 if (! MenuGetRosMenuInfo(&CurrentMenuInfo
, Mt
->CurrentMenu
))
3242 /* Check to see if there's another column */
3243 if (NO_SELECTED_ITEM
!= (NextCol
= MenuGetStartOfNextColumn(&CurrentMenuInfo
)))
3245 TRACE("Going to %d.\n", NextCol
);
3246 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
->CurrentMenu
))
3248 MenuSelectItem(Mt
->OwnerWnd
, &MenuInfo
, NextCol
, TRUE
, 0);
3253 if (0 == (MenuInfo
.Flags
& MF_POPUP
)) /* menu bar tracking */
3255 if (Mt
->CurrentMenu
!= Mt
->TopMenu
)
3257 MenuHideSubPopups(Mt
->OwnerWnd
, &MenuInfo
, FALSE
);
3258 MenuTmp
= Mt
->CurrentMenu
= Mt
->TopMenu
;
3265 /* try to move to the next item */
3266 if (! MenuDoNextMenu(Mt
, VK_RIGHT
))
3268 MenuMoveSelection(Mt
->OwnerWnd
, &MenuInfo
, ITEM_NEXT
);
3271 if (NULL
!= MenuTmp
|| 0 != (Mt
->TrackFlags
& TF_SUSPENDPOPUP
))
3273 if (! MenuSuspendPopup(Mt
, WM_KEYDOWN
)
3274 && MenuGetRosMenuInfo(&MenuInfo
, Mt
->TopMenu
))
3276 Mt
->CurrentMenu
= MenuShowSubPopup(Mt
->OwnerWnd
, &MenuInfo
,
3283 /***********************************************************************
3286 * Find the menu item selected by a key press.
3287 * Return item id, -1 if none, -2 if we should close the menu.
3289 static UINT FASTCALL
3290 MenuFindItemByKey(HWND WndOwner
, PROSMENUINFO MenuInfo
,
3291 WCHAR Key
, BOOL ForceMenuChar
)
3293 ROSMENUINFO SysMenuInfo
;
3294 PROSMENUITEMINFO Items
, ItemInfo
;
3298 TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key
, Key
, MenuInfo
);
3300 if (NULL
== MenuInfo
|| ! IsMenu(MenuInfo
->Self
))
3302 if (MenuGetRosMenuInfo(&SysMenuInfo
, GetSystemMenu(WndOwner
, FALSE
)))
3304 MenuInfo
= &SysMenuInfo
;
3312 if (NULL
!= MenuInfo
)
3314 if (MenuGetAllRosMenuItemInfo(MenuInfo
->Self
, &Items
) <= 0)
3318 if (! ForceMenuChar
)
3320 Key
= toupperW(Key
);
3322 for (i
= 0; i
< MenuInfo
->MenuItemCount
; i
++, ItemInfo
++)
3324 if ((ItemInfo
->Text
) && NULL
!= ItemInfo
->dwTypeData
)
3326 WCHAR
*p
= (WCHAR
*) ItemInfo
->dwTypeData
- 2;
3329 p
= strchrW(p
+ 2, '&');
3331 while (NULL
!= p
&& L
'&' == p
[1]);
3332 if (NULL
!= p
&& (toupperW(p
[1]) == Key
))
3340 MenuChar
= SendMessageW(WndOwner
, WM_MENUCHAR
,
3341 MAKEWPARAM(Key
, MenuInfo
->Flags
), (LPARAM
) MenuInfo
->Self
);
3342 if (2 == HIWORD(MenuChar
))
3344 return LOWORD(MenuChar
);
3346 if (1 == HIWORD(MenuChar
))
3355 /***********************************************************************
3358 * Menu tracking code.
3361 MenuTrackMenu(HMENU Menu
, UINT Flags
, INT x
, INT y
,
3362 HWND Wnd
, const RECT
*Rect
)
3365 ROSMENUINFO MenuInfo
;
3366 ROSMENUITEMINFO ItemInfo
;
3368 INT ExecutedMenuId
= -1;
3370 BOOL EnterIdleSent
= FALSE
;
3373 Mt
.CurrentMenu
= Menu
;
3379 TRACE("Menu=%x Flags=0x%08x (%d,%d) Wnd=%x (%ld,%ld)-(%ld,%ld)\n",
3380 Menu
, Flags
, x
, y
, Wnd
, Rect
? Rect
->left
: 0, Rect
? Rect
->top
: 0,
3381 Rect
? Rect
->right
: 0, Rect
? Rect
->bottom
: 0);
3385 SetLastError( ERROR_INVALID_MENU_HANDLE
);
3390 if (! MenuGetRosMenuInfo(&MenuInfo
, Menu
))
3395 if (0 != (Flags
& TPM_BUTTONDOWN
))
3397 /* Get the result in order to start the tracking or not */
3398 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3399 fEndMenu
= ! fRemove
;
3402 SetCapture(Mt
.OwnerWnd
);
3403 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, Mt
.OwnerWnd
);
3405 ERR("MenuTrackMenu 1\n");
3408 PVOID menu
= ValidateHandle(Mt
.CurrentMenu
, VALIDATE_TYPE_MENU
);
3409 if (!menu
) /* sometimes happens if I do a window manager close */
3412 /* we have to keep the message in the queue until it's
3413 * clear that menu loop is not over yet. */
3417 if (PeekMessageW(&Msg
, 0, 0, 0, PM_NOREMOVE
))
3419 if (! CallMsgFilterW(&Msg
, MSGF_MENU
))
3423 /* remove the message from the queue */
3424 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3428 if (! EnterIdleSent
)
3430 HWND Win
= (0 != (Flags
& TPM_ENTERIDLEEX
)
3431 && 0 != (MenuInfo
.Flags
& MF_POPUP
)) ? MenuInfo
.Wnd
: NULL
;
3432 EnterIdleSent
= TRUE
;
3433 SendMessageW(Mt
.OwnerWnd
, WM_ENTERIDLE
, MSGF_MENU
, (LPARAM
) Win
);
3439 /* check if EndMenu() tried to cancel us, by posting this message */
3440 if (WM_CANCELMODE
== Msg
.message
)
3442 /* we are now out of the loop */
3445 /* remove the message from the queue */
3446 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3448 /* break out of internal loop, ala ESCAPE */
3452 TranslateMessage(&Msg
);
3455 if (Msg
.hwnd
== MenuInfo
.Wnd
|| WM_TIMER
!= Msg
.message
)
3457 EnterIdleSent
= FALSE
;
3461 if (WM_MOUSEFIRST
<= Msg
.message
&& Msg
.message
<= WM_MOUSELAST
)
3464 * Use the mouse coordinates in lParam instead of those in the MSG
3465 * struct to properly handle synthetic messages. They are already
3466 * in screen coordinates.
3468 Mt
.Pt
.x
= (short) LOWORD(Msg
.lParam
);
3469 Mt
.Pt
.y
= (short) HIWORD(Msg
.lParam
);
3471 /* Find a menu for this mouse event */
3472 Menu
= MenuPtMenu(Mt
.TopMenu
, Mt
.Pt
);
3476 /* no WM_NC... messages in captured state */
3478 case WM_RBUTTONDBLCLK
:
3479 case WM_RBUTTONDOWN
:
3480 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3485 case WM_LBUTTONDBLCLK
:
3486 case WM_LBUTTONDOWN
:
3487 /* If the message belongs to the menu, removes it from the queue */
3488 /* Else, end menu tracking */
3489 fRemove
= MenuButtonDown(&Mt
, Menu
, Flags
);
3490 fEndMenu
= ! fRemove
;
3494 if (0 == (Flags
& TPM_RIGHTBUTTON
))
3500 /* Check if a menu was selected by the mouse */
3503 ExecutedMenuId
= MenuButtonUp(&Mt
, Menu
, Flags
);
3505 /* End the loop if ExecutedMenuId is an item ID */
3506 /* or if the job was done (ExecutedMenuId = 0). */
3507 fEndMenu
= fRemove
= (-1 != ExecutedMenuId
);
3511 /* No menu was selected by the mouse */
3512 /* if the function was called by TrackPopupMenu, continue
3513 with the menu tracking. If not, stop it */
3514 fEndMenu
= (0 != (Flags
& TPM_POPUPMENU
) ? FALSE
: TRUE
);
3521 fEndMenu
|= ! MenuMouseMove(&Mt
, Menu
, Flags
);
3525 } /* switch(Msg.message) - mouse */
3527 else if (WM_KEYFIRST
<= Msg
.message
&& Msg
.message
<= WM_KEYLAST
)
3529 fRemove
= TRUE
; /* Keyboard messages are always removed */
3541 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3543 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
,
3545 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
,
3546 VK_HOME
== Msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3551 case VK_DOWN
: /* If on menu bar, pull-down the menu */
3552 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3554 if (0 == (MenuInfo
.Flags
& MF_POPUP
))
3556 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3558 Mt
.CurrentMenu
= MenuShowSubPopup(Mt
.OwnerWnd
, &MenuInfo
,
3562 else /* otherwise try to move selection */
3564 MenuMoveSelection(Mt
.OwnerWnd
, &MenuInfo
,
3565 VK_DOWN
== Msg
.wParam
? ITEM_NEXT
: ITEM_PREV
);
3571 MenuKeyLeft(&Mt
, Flags
);
3575 MenuKeyRight(&Mt
, Flags
);
3579 fEndMenu
= MenuKeyEscape(&Mt
, Flags
);
3585 hi
.cbSize
= sizeof(HELPINFO
);
3586 hi
.iContextType
= HELPINFO_MENUITEM
;
3587 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3589 if (NO_SELECTED_ITEM
== MenuInfo
.FocusedItem
)
3595 MenuInitRosMenuItemInfo(&ItemInfo
);
3596 if (MenuGetRosMenuItemInfo(MenuInfo
.Self
,
3597 MenuInfo
.FocusedItem
,
3600 hi
.iCtrlId
= ItemInfo
.wID
;
3606 MenuCleanupRosMenuItemInfo(&ItemInfo
);
3609 hi
.hItemHandle
= Menu
;
3610 hi
.dwContextId
= MenuInfo
.dwContextHelpID
;
3611 hi
.MousePos
= Msg
.pt
;
3612 SendMessageW(Wnd
, WM_HELP
, 0, (LPARAM
) &hi
);
3619 break; /* WM_KEYDOWN */
3626 if (! MenuGetRosMenuInfo(&MenuInfo
, Mt
.CurrentMenu
))
3630 if (L
'\r' == Msg
.wParam
|| L
' ' == Msg
.wParam
)
3632 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3633 fEndMenu
= (ExecutedMenuId
!= -2);
3637 /* Hack to avoid control chars. */
3638 /* We will find a better way real soon... */
3639 if (Msg
.wParam
< 32)
3644 Pos
= MenuFindItemByKey(Mt
.OwnerWnd
, &MenuInfo
,
3645 LOWORD(Msg
.wParam
), FALSE
);
3646 if ((UINT
) -2 == Pos
)
3650 else if ((UINT
) -1 == Pos
)
3656 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, Pos
, TRUE
, 0);
3657 ExecutedMenuId
= MenuExecFocusedItem(&Mt
, &MenuInfo
, Flags
);
3658 fEndMenu
= (-2 != ExecutedMenuId
);
3662 } /* switch(msg.message) - kbd */
3666 PeekMessageW( &Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3667 DispatchMessageW(&Msg
);
3676 /* finally remove message from the queue */
3678 if (fRemove
&& 0 == (Mt
.TrackFlags
& TF_SKIPREMOVE
))
3680 PeekMessageW(&Msg
, 0, Msg
.message
, Msg
.message
, PM_REMOVE
);
3684 Mt
.TrackFlags
&= ~TF_SKIPREMOVE
;
3687 ERR("MenuTrackMenu 2\n");
3689 (void)NtUserSetGUIThreadHandle(MSQ_STATE_MENUOWNER
, NULL
);
3690 SetCapture(NULL
); /* release the capture */
3692 /* If dropdown is still painted and the close box is clicked on
3693 then the menu will be destroyed as part of the DispatchMessage above.
3694 This will then invalidate the menu handle in Mt.hTopMenu. We should
3695 check for this first. */
3696 if (IsMenu(Mt
.TopMenu
))
3698 if (IsWindow(Mt
.OwnerWnd
))
3700 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3702 MenuHideSubPopups(Mt
.OwnerWnd
, &MenuInfo
, FALSE
);
3704 if (0 != (MenuInfo
.Flags
& MF_POPUP
))
3706 DestroyWindow(MenuInfo
.Wnd
);
3707 MenuInfo
.Wnd
= NULL
;
3709 if (!(MenuInfo
.Flags
& TPM_NONOTIFY
))
3710 SendMessageW( Mt
.OwnerWnd
, WM_UNINITMENUPOPUP
, (WPARAM
)Mt
.TopMenu
,
3711 MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo
)) );
3714 MenuSelectItem(Mt
.OwnerWnd
, &MenuInfo
, NO_SELECTED_ITEM
, FALSE
, NULL
);
3717 SendMessageW(Mt
.OwnerWnd
, WM_MENUSELECT
, MAKELONG(0, 0xffff), 0);
3720 if (MenuGetRosMenuInfo(&MenuInfo
, Mt
.TopMenu
))
3722 /* Reset the variable for hiding menu */
3723 MenuInfo
.TimeToHide
= FALSE
;
3724 MenuSetRosMenuInfo(&MenuInfo
);
3728 /* The return value is only used by TrackPopupMenu */
3729 if (!(Flags
& TPM_RETURNCMD
)) return TRUE
;
3730 if (ExecutedMenuId
< 0) ExecutedMenuId
= 0;
3731 return ExecutedMenuId
;
3734 /***********************************************************************
3737 static BOOL FASTCALL
3738 MenuExitTracking(HWND Wnd
)
3740 TRACE("hwnd=%p\n", Wnd
);
3742 SendMessageW(Wnd
, WM_EXITMENULOOP
, 0, 0);
3749 MenuTrackMouseMenuBar(HWND Wnd
, ULONG Ht
, POINT Pt
)
3751 HMENU Menu
= (HTSYSMENU
== Ht
) ? NtUserGetSystemMenu(Wnd
, FALSE
) : GetMenu(Wnd
);
3752 UINT Flags
= TPM_ENTERIDLEEX
| TPM_BUTTONDOWN
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3754 TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", Wnd
, Ht
, Pt
.x
, Pt
.y
);
3758 /* map point to parent client coordinates */
3759 HWND Parent
= GetAncestor(Wnd
, GA_PARENT
);
3760 if (Parent
!= GetDesktopWindow())
3762 ScreenToClient(Parent
, &Pt
);
3765 MenuInitTracking(Wnd
, Menu
, FALSE
, Flags
);
3766 MenuTrackMenu(Menu
, Flags
, Pt
.x
, Pt
.y
, Wnd
, NULL
);
3767 MenuExitTracking(Wnd
);
3773 MenuTrackKbdMenuBar(HWND hWnd
, UINT wParam
, WCHAR wChar
)
3775 UINT uItem
= NO_SELECTED_ITEM
;
3777 ROSMENUINFO MenuInfo
;
3778 UINT wFlags
= TPM_ENTERIDLEEX
| TPM_LEFTALIGN
| TPM_LEFTBUTTON
;
3780 TRACE("hwnd %p wParam 0x%04x wChar 0x%04x\n", hWnd
, wParam
, wChar
);
3782 /* find window that has a menu */
3784 while (!((GetWindowLongPtrW( hWnd
, GWL_STYLE
) &
3785 (WS_CHILD
| WS_POPUP
)) != WS_CHILD
))
3786 if (!(hWnd
= GetAncestor( hWnd
, GA_PARENT
))) return;
3788 /* check if we have to track a system menu */
3790 hTrackMenu
= GetMenu( hWnd
);
3791 if (!hTrackMenu
|| IsIconic(hWnd
) || wChar
== ' ' )
3793 if (!(GetWindowLongPtrW( hWnd
, GWL_STYLE
) & WS_SYSMENU
)) return;
3794 hTrackMenu
= NtUserGetSystemMenu(hWnd
, FALSE
);
3796 wParam
|= HTSYSMENU
; /* prevent item lookup */
3799 if (!IsMenu( hTrackMenu
)) return;
3801 MenuInitTracking( hWnd
, hTrackMenu
, FALSE
, wFlags
);
3803 if (! MenuGetRosMenuInfo(&MenuInfo
, hTrackMenu
))
3808 if( wChar
&& wChar
!= ' ' )
3810 uItem
= MenuFindItemByKey( hWnd
, &MenuInfo
, wChar
, (wParam
& HTSYSMENU
) );
3811 if ( uItem
>= (UINT
)(-2) )
3813 if( uItem
== (UINT
)(-1) ) MessageBeep(0);
3814 /* schedule end of menu tracking */
3815 wFlags
|= TF_ENDMENU
;
3820 MenuSelectItem( hWnd
, &MenuInfo
, uItem
, TRUE
, 0 );
3822 if (wParam
& HTSYSMENU
)
3824 /* prevent sysmenu activation for managed windows on Alt down/up */
3825 // if (GetPropA( hwnd, "__wine_x11_managed" ))
3826 wFlags
|= TF_ENDMENU
; /* schedule end of menu tracking */
3830 if( uItem
== NO_SELECTED_ITEM
)
3831 MenuMoveSelection( hWnd
, &MenuInfo
, ITEM_NEXT
);
3833 PostMessageW( hWnd
, WM_KEYDOWN
, VK_DOWN
, 0L );
3837 MenuTrackMenu( hTrackMenu
, wFlags
, 0, 0, hWnd
, NULL
);
3838 MenuExitTracking( hWnd
);
3844 * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined
3845 * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType.
3847 * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE.
3849 * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows
3850 * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING.
3851 * MFT_STRING is replaced by MIIM_STRING.
3852 * (So, I guess we should use MIIM_STRING only for strings?)
3854 * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member.
3856 * Based on wine, SetMenuItemInfo_common:
3857 * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE,
3858 * it will result in a error.
3859 * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error.
3860 * These conditions are addressed in Win32k IntSetMenuItemInfo.
3867 LPMENUITEMINFOW mii
,
3874 * Let us assume MIIM_FTYPE is set and building a new menu item structure.
3876 if(Flags
& MF_BITMAP
)
3878 mii
->fMask
|= MIIM_BITMAP
; /* Use the new way of seting hbmpItem.*/
3879 mii
->hbmpItem
= (HBITMAP
) NewItem
;
3881 if (Flags
& MF_HELP
)
3883 /* increase ident */
3884 mii
->fType
|= MF_HELP
;
3887 else if(Flags
& MF_OWNERDRAW
)
3889 mii
->fType
|= MFT_OWNERDRAW
;
3890 mii
->fMask
|= MIIM_DATA
;
3891 mii
->dwItemData
= (DWORD_PTR
) NewItem
;
3893 else if (Flags
& MF_SEPARATOR
)
3895 mii
->fType
|= MFT_SEPARATOR
;
3896 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3897 Flags
|= MF_GRAYED
|MF_DISABLED
;
3899 else /* Default action MF_STRING. */
3901 /* Item beginning with a backspace is a help item */
3902 if (NewItem
!= NULL
)
3906 if (*NewItem
== '\b')
3908 mii
->fType
|= MF_HELP
;
3914 LPCSTR NewItemA
= (LPCSTR
) NewItem
;
3915 if (*NewItemA
== '\b')
3917 mii
->fType
|= MF_HELP
;
3919 NewItem
= (LPCWSTR
) NewItemA
;
3923 if (Flags
& MF_HELP
)
3924 mii
->fType
|= MF_HELP
;
3925 mii
->fMask
|= MIIM_STRING
;
3926 mii
->fType
|= MFT_STRING
; /* Zero */
3927 mii
->dwTypeData
= (LPWSTR
)NewItem
;
3929 mii
->cch
= (NULL
== NewItem
? 0 : strlenW(NewItem
));
3931 mii
->cch
= (NULL
== NewItem
? 0 : strlen((LPCSTR
)NewItem
));
3935 mii
->fType
|= MFT_SEPARATOR
;
3936 if (!(Flags
& (MF_GRAYED
|MF_DISABLED
)))
3937 Flags
|= MF_GRAYED
|MF_DISABLED
;
3941 if(Flags
& MF_RIGHTJUSTIFY
) /* Same as MF_HELP */
3943 mii
->fType
|= MFT_RIGHTJUSTIFY
;
3946 if(Flags
& MF_MENUBREAK
)
3948 mii
->fType
|= MFT_MENUBREAK
;
3950 else if(Flags
& MF_MENUBARBREAK
)
3952 mii
->fType
|= MFT_MENUBARBREAK
;
3955 if(Flags
& MF_GRAYED
|| Flags
& MF_DISABLED
)
3957 if (Flags
& MF_GRAYED
)
3958 mii
->fState
|= MF_GRAYED
;
3960 if (Flags
& MF_DISABLED
)
3961 mii
->fState
|= MF_DISABLED
;
3963 mii
->fMask
|= MIIM_STATE
;
3965 else if (Flags
& MF_HILITE
)
3967 mii
->fState
|= MF_HILITE
;
3968 mii
->fMask
|= MIIM_STATE
;
3970 else /* default state */
3972 mii
->fState
|= MFS_ENABLED
;
3973 mii
->fMask
|= MIIM_STATE
;
3976 if(Flags
& MF_POPUP
)
3978 mii
->fType
|= MF_POPUP
;
3979 mii
->fMask
|= MIIM_SUBMENU
;
3980 mii
->hSubMenu
= (HMENU
)IDNewItem
;
3984 mii
->fMask
|= MIIM_ID
;
3985 mii
->wID
= (UINT
)IDNewItem
;
3991 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
3993 PLOADMENU_CALLBACK_ARGUMENTS Common
;
3996 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
3998 Result
= (LRESULT
)LoadMenuW( Common
->hModule
,
3999 IS_INTRESOURCE(Common
->MenuName
[0]) ?
4000 MAKEINTRESOURCE(Common
->MenuName
[0]) :
4001 (LPCWSTR
)&Common
->MenuName
);
4003 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
4007 /* FUNCTIONS *****************************************************************/
4010 MenuIsStringItem(ULONG TypeData)
4012 return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType));
4020 AppendMenuA(HMENU hMenu
,
4022 UINT_PTR uIDNewItem
,
4025 return(InsertMenuA(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
4034 AppendMenuW(HMENU hMenu
,
4036 UINT_PTR uIDNewItem
,
4039 return(InsertMenuW(hMenu
, -1, uFlags
| MF_BYPOSITION
, uIDNewItem
,
4048 CheckMenuItem(HMENU hmenu
,
4052 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
4057 MenuCheckMenuRadioItem(HMENU hMenu
, UINT idFirst
, UINT idLast
, UINT idCheck
, UINT uFlags
, BOOL bCheck
, PUINT pChecked
, PUINT pUnchecked
, PUINT pMenuChanged
)
4060 PROSMENUITEMINFO Items
= NULL
;
4061 UINT cChecked
, cUnchecked
;
4065 if(idFirst
> idLast
)
4068 ItemCount
= GetMenuItemCount(hMenu
);
4070 //mi.cbSize = sizeof(ROSMENUINFO);
4071 //if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret;
4074 if(MenuGetAllRosMenuItemInfo(hMenu
, &Items
) <= 0)
4076 ERR("MenuGetAllRosMenuItemInfo failed\n");
4080 cChecked
= cUnchecked
= 0;
4082 for (i
= 0 ; i
< ItemCount
; i
++)
4085 if (0 != (Items
[i
].fType
& MF_MENUBARBREAK
)) continue;
4086 if (0 != (Items
[i
].fType
& MF_SEPARATOR
)) continue;
4088 if ((Items
[i
].fType
& MF_POPUP
) && (uFlags
== MF_BYCOMMAND
))
4090 MenuCheckMenuRadioItem(Items
[i
].hSubMenu
, idFirst
, idLast
, idCheck
, uFlags
, bCheck
, pChecked
, pUnchecked
, pMenuChanged
);
4093 if (uFlags
& MF_BYPOSITION
)
4095 if (i
< idFirst
|| i
> idLast
)
4110 if (Items
[i
].wID
< idFirst
|| Items
[i
].wID
> idLast
)
4113 if (Items
[i
].wID
== idCheck
)
4127 Items
[i
].fMask
= MIIM_STATE
| MIIM_FTYPE
;
4130 Items
[i
].fType
|= MFT_RADIOCHECK
;
4131 Items
[i
].fState
|= MFS_CHECKED
;
4135 Items
[i
].fState
&= ~MFS_CHECKED
;
4138 if(!MenuSetRosMenuItemInfo(hMenu
, i
,&Items
[i
]))
4140 ERR("MenuSetRosMenuItemInfo failed\n");
4145 HeapFree(GetProcessHeap(), 0, Items
);
4147 *pChecked
+= cChecked
;
4148 *pUnchecked
+= cUnchecked
;
4150 if (cChecked
|| cUnchecked
)
4160 CheckMenuRadioItem(HMENU hmenu
,
4167 UINT cUnchecked
= 0;
4168 UINT cMenuChanged
= 0;
4170 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, FALSE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4173 if (cMenuChanged
> 1)
4180 if (!MenuCheckMenuRadioItem(hmenu
, idFirst
, idLast
, idCheck
, uFlags
, TRUE
, &cChecked
, &cUnchecked
, &cMenuChanged
))
4183 return (cChecked
!= 0);
4194 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENU
);
4202 CreatePopupMenu(VOID
)
4205 return (HMENU
)NtUserCallNoParam(NOPARAM_ROUTINE_CREATEMENUPOPUP
);
4213 DrawMenuBar(HWND hWnd
)
4215 // return (BOOL)NtUserCallHwndLock(hWnd, HWNDLOCK_ROUTINE_DRAWMENUBAR);
4216 ROSMENUINFO MenuInfo
;
4218 hMenu
= GetMenu(hWnd
);
4221 MenuGetRosMenuInfo(&MenuInfo
, hMenu
);
4222 MenuInfo
.Height
= 0; // make sure to recalc size
4223 MenuSetRosMenuInfo(&MenuInfo
);
4224 /* The wine method doesn't work and I suspect it's more effort
4225 then hackfix solution
4226 SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE |
4227 SWP_NOZORDER | SWP_FRAMECHANGED );
4230 DefWndNCPaint(hWnd
,(HRGN
)-1,-1);
4239 EnableMenuItem(HMENU hMenu
,
4243 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
4253 guii
.cbSize
= sizeof(GUITHREADINFO
);
4254 if(GetGUIThreadInfo(GetCurrentThreadId(), &guii
) && guii
.hwndMenuOwner
)
4256 PostMessageW(guii
.hwndMenuOwner
, WM_CANCELMODE
, 0, 0);
4268 HMENU retvalue
= (HMENU
)GetWindowLongPtrW( hWnd
, GWLP_ID
);
4269 TRACE("for %p returning %p\n", hWnd
, retvalue
);
4278 GetMenuCheckMarkDimensions(VOID
)
4280 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
4281 GetSystemMetrics(SM_CYMENUCHECK
)));
4289 GetMenuDefaultItem(HMENU hMenu
,
4293 return NtUserGetMenuDefaultItem(hMenu
, fByPos
, gmdiFlags
);
4301 GetMenuInfo(HMENU hmenu
,
4307 if(!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
4310 RtlZeroMemory(&mi
, sizeof(MENUINFO
));
4311 mi
.cbSize
= sizeof(MENUINFO
);
4312 mi
.fMask
= lpcmi
->fMask
;
4314 res
= NtUserMenuInfo(hmenu
, &mi
, FALSE
);
4316 memcpy(lpcmi
, &mi
, sizeof(MENUINFO
));
4325 GetMenuItemCount(HMENU Menu
)
4327 ROSMENUINFO MenuInfo
;
4329 return MenuGetRosMenuInfo(&MenuInfo
, Menu
) ? MenuInfo
.MenuItemCount
: 0;
4337 GetMenuItemID(HMENU hMenu
,
4340 ROSMENUITEMINFO mii
;
4342 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4343 mii
.fMask
= MIIM_ID
| MIIM_SUBMENU
;
4345 if (! NtUserMenuItemInfo(hMenu
, nPos
, MF_BYPOSITION
, &mii
, FALSE
))
4350 if (NULL
!= mii
.hSubMenu
)
4371 LPMENUITEMINFOA mii
)
4377 if (mii
->cbSize
!= sizeof(MENUITEMINFOA
) &&
4378 mii
->cbSize
!= sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
))
4380 SetLastError(ERROR_INVALID_PARAMETER
);
4384 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4386 /* No text requested, just pass on */
4387 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4390 AnsiBuffer
= mii
->dwTypeData
;
4391 Count
= miiW
.cch
= mii
->cch
;
4392 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4393 miiW
.dwTypeData
= 0;
4397 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4398 miiW
.cch
* sizeof(WCHAR
));
4399 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4400 miiW
.dwTypeData
[0] = 0;
4403 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
)&miiW
, FALSE
))
4405 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4409 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
);
4411 if (!AnsiBuffer
|| !Count
)
4413 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4414 mii
->dwTypeData
= AnsiBuffer
;
4415 mii
->cch
= miiW
.cch
;
4419 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4423 if (!WideCharToMultiByte(CP_ACP
, 0, miiW
.dwTypeData
, miiW
.cch
, AnsiBuffer
, mii
->cch
, NULL
, NULL
))
4427 if (Count
> miiW
.cch
)
4429 AnsiBuffer
[miiW
.cch
] = 0;
4431 mii
->cch
= mii
->cch
;
4439 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4440 mii
->dwTypeData
= AnsiBuffer
;
4454 LPMENUITEMINFOW mii
)
4460 if (mii
->cbSize
!= sizeof(MENUITEMINFOW
) &&
4461 mii
->cbSize
!= sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
))
4463 SetLastError(ERROR_INVALID_PARAMETER
);
4467 if(!(mii
->fMask
& (MIIM_TYPE
| MIIM_STRING
)))
4469 /* No text requested, just pass on */
4470 return NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) mii
, FALSE
);
4473 String
= mii
->dwTypeData
;
4475 RtlCopyMemory(&miiW
, mii
, mii
->cbSize
);
4476 miiW
.dwTypeData
= 0;
4480 miiW
.dwTypeData
= RtlAllocateHeap(GetProcessHeap(), 0,
4481 miiW
.cch
* sizeof(WCHAR
));
4482 if (miiW
.dwTypeData
== NULL
) return FALSE
;
4483 miiW
.dwTypeData
[0] = 0;
4486 if (!NtUserMenuItemInfo(Menu
, Item
, ByPosition
, (PROSMENUITEMINFO
) &miiW
, FALSE
))
4488 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4492 RtlCopyMemory(mii
, &miiW
, miiW
.cbSize
); // Okay to over write user data.
4494 if (!String
|| !Count
)
4496 if (miiW
.dwTypeData
) RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4497 mii
->dwTypeData
= String
; // may not be zero.
4498 mii
->cch
= miiW
.cch
;
4502 if ((miiW
.fMask
& MIIM_STRING
) || (IS_STRING_ITEM(miiW
.fType
)))
4504 lstrcpynW( String
, miiW
.dwTypeData
, Count
);
4507 RtlFreeHeap(GetProcessHeap(), 0, miiW
.dwTypeData
);
4508 mii
->dwTypeData
= String
;
4509 mii
->cch
= strlenW(String
);
4524 ROSMENUINFO MenuInfo
;
4525 ROSMENUITEMINFO mii
;
4526 memset( &mii
, 0, sizeof(mii
) );
4527 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4528 mii
.fMask
= MIIM_STATE
| MIIM_FTYPE
| MIIM_SUBMENU
;
4531 if(NtUserMenuItemInfo(hMenu
, uId
, uFlags
, &mii
, FALSE
))
4536 if (! MenuGetRosMenuInfo(&MenuInfo
, mii
.hSubMenu
))
4540 nSubItems
= MenuInfo
.MenuItemCount
;
4542 /* FIXME - ported from wine, does that work (0xff)? */
4543 if(GetLastError() != ERROR_INVALID_MENU_HANDLE
)
4544 return (nSubItems
<< 8) | ((mii
.fState
| mii
.fType
) & 0xff);
4546 return (UINT
)-1; /* Invalid submenu */
4549 /* FIXME - ported from wine, does that work? */
4550 return (mii
.fType
| mii
.fState
);
4570 memset( &mii
, 0, sizeof(mii
) );
4571 mii
.dwTypeData
= lpString
;
4572 mii
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4573 mii
.fType
= MFT_STRING
;
4574 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4575 mii
.cch
= nMaxCount
;
4577 if(!(GetMenuItemInfoA( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&mii
)))
4597 memset( &miiW
, 0, sizeof(miiW
) );
4598 miiW
.dwTypeData
= lpString
;
4599 miiW
.fMask
= MIIM_STRING
| MIIM_FTYPE
;
4600 miiW
.fType
= MFT_STRING
;
4601 miiW
.cbSize
= sizeof(MENUITEMINFOW
);
4602 miiW
.cch
= nMaxCount
;
4604 if(!(GetMenuItemInfoW( hMenu
, uIDItem
, (BOOL
)(MF_BYPOSITION
& uFlag
),&miiW
)))
4622 mi
.cbSize
= sizeof(MENUITEMINFOW
);
4623 mi
.fMask
= MIIM_SUBMENU
;
4625 if (NtUserMenuItemInfo(hMenu
, (UINT
)nPos
, MF_BYPOSITION
, &mi
, FALSE
))
4627 return IsMenu(mi
.hSubMenu
) ? mi
.hSubMenu
: NULL
;
4644 TopMenu
= NtUserGetSystemMenu(hWnd
, bRevert
);
4646 return NULL
== TopMenu
? NULL
: GetSubMenu(TopMenu
, 0);
4659 UINT_PTR uIDNewItem
,
4663 memset( &mii
, 0, sizeof(mii
) );
4664 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4665 mii
.fMask
= MIIM_FTYPE
;
4667 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4670 (LPCWSTR
) lpNewItem
,
4673 return InsertMenuItemA(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4687 LPCMENUITEMINFOA lpmii
)
4690 UNICODE_STRING MenuText
;
4692 BOOL CleanHeap
= FALSE
;
4695 if((lpmii
->cbSize
== sizeof(MENUITEMINFOA
)) ||
4696 (lpmii
->cbSize
== sizeof(MENUITEMINFOA
) - sizeof(HBITMAP
)))
4698 RtlCopyMemory ( &mi
, lpmii
, lpmii
->cbSize
);
4700 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4702 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4705 /* copy the text string */
4706 if (((mi
.fMask
& MIIM_STRING
) ||
4707 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4708 && mi
.dwTypeData
!= NULL
)
4710 Status
= RtlCreateUnicodeStringFromAsciiz(&MenuText
, (LPSTR
)mi
.dwTypeData
);
4711 if (!NT_SUCCESS (Status
))
4713 SetLastError (RtlNtStatusToDosError(Status
));
4716 mi
.dwTypeData
= MenuText
.Buffer
;
4717 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4720 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4722 if ( CleanHeap
) RtlFreeUnicodeString ( &MenuText
);
4737 LPCMENUITEMINFOW lpmii
)
4740 UNICODE_STRING MenuText
;
4743 /* while we could just pass 'lpmii' to win32k, we make a copy so that
4744 if a bad user passes bad data, we crash his process instead of the
4747 if((lpmii
->cbSize
== sizeof(MENUITEMINFOW
)) ||
4748 (lpmii
->cbSize
== sizeof(MENUITEMINFOW
) - sizeof(HBITMAP
)))
4750 RtlCopyMemory(&mi
, lpmii
, lpmii
->cbSize
);
4752 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
4754 mi
.cbSize
= sizeof( MENUITEMINFOW
);
4757 /* copy the text string */
4758 if (((mi
.fMask
& MIIM_STRING
) ||
4759 ((mi
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mi
.fType
) == MF_STRING
)))
4760 && mi
.dwTypeData
!= NULL
)
4762 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
4763 mi
.dwTypeData
= MenuText
.Buffer
;
4764 mi
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
4766 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mi
, NULL
);
4781 UINT_PTR uIDNewItem
,
4785 memset( &mii
, 0, sizeof(mii
) );
4786 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4787 mii
.fMask
= MIIM_FTYPE
;
4789 MenuSetItemData( &mii
,
4795 return InsertMenuItemW(hMenu
, uPosition
, (BOOL
)((MF_BYPOSITION
& uFlags
) > 0), &mii
);
4807 if (ValidateHandle(Menu
, VALIDATE_TYPE_MENU
)) return TRUE
;
4816 LoadMenuA(HINSTANCE hInstance
,
4819 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
4820 if (Resource
== NULL
)
4824 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
4832 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
4834 return(LoadMenuIndirectW(lpMenuTemplate
));
4842 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
4845 WORD version
, offset
;
4846 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
4848 version
= GET_WORD(p
);
4853 case 0: /* standard format is version of 0 */
4854 offset
= GET_WORD(p
);
4855 p
+= sizeof(WORD
) + offset
;
4856 if (!(hMenu
= CreateMenu())) return 0;
4857 if (!MENU_ParseResource(p
, hMenu
, TRUE
))
4863 case 1: /* extended format is version of 1 */
4864 offset
= GET_WORD(p
);
4865 p
+= sizeof(WORD
) + offset
;
4866 if (!(hMenu
= CreateMenu())) return 0;
4867 if (!MENUEX_ParseResource(p
, hMenu
))
4869 DestroyMenu( hMenu
);
4874 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version
);
4884 LoadMenuW(HINSTANCE hInstance
,
4887 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
4888 if (Resource
== NULL
)
4892 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
4906 return NtUserMenuItemFromPoint(hWnd
, hMenu
, ptScreen
.x
, ptScreen
.y
);
4919 UINT_PTR uIDNewItem
,
4923 ROSMENUITEMINFO rmii
;
4925 memset( &mii
, 0, sizeof(mii
) );
4926 mii
.cbSize
= sizeof(MENUITEMINFOA
);
4927 mii
.fMask
= MIIM_FTYPE
;
4929 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4933 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4935 MenuInitRosMenuItemInfo( &rmii
);
4937 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4939 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4940 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4942 MenuCleanupRosMenuItemInfo( &rmii
);
4944 MenuSetItemData((LPMENUITEMINFOW
) &mii
,
4947 (LPCWSTR
) lpNewItem
,
4950 return SetMenuItemInfoA( hMnu
,
4952 (BOOL
)(MF_BYPOSITION
& uFlags
),
4966 UINT_PTR uIDNewItem
,
4970 ROSMENUITEMINFO rmii
;
4972 memset ( &mii
, 0, sizeof(mii
) );
4973 mii
.cbSize
= sizeof(MENUITEMINFOW
);
4974 mii
.fMask
= MIIM_FTYPE
;
4976 if (!MenuGetRosMenuInfo( &mi
, hMnu
)) return FALSE
;
4978 mi
.Height
= 0; // Force size recalculation.
4980 if (!MenuSetRosMenuInfo( &mi
)) return FALSE
;
4982 MenuInitRosMenuItemInfo( &rmii
);
4984 if(!MenuGetRosMenuItemInfo( hMnu
, uPosition
, &rmii
)) return FALSE
;
4986 if ((rmii
.fType
& MF_POPUP
) && (uFlags
& MF_POPUP
) && (rmii
.hSubMenu
!= (HMENU
)uIDNewItem
))
4987 NtUserDestroyMenu( rmii
.hSubMenu
); /* ModifyMenu() spec */
4989 MenuCleanupRosMenuItemInfo( &rmii
);
4991 /* Init new data for this menu item */
4992 MenuSetItemData( &mii
,
4998 /* Now, make Win32k IntSetMenuItemInfo handle the changes to this menu item. */
4999 return SetMenuItemInfoW( hMnu
,
5001 (BOOL
)(MF_BYPOSITION
& uFlags
),
5013 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
5029 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
5031 SetLastError(ERROR_INVALID_PARAMETER
);
5035 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
5036 return NtUserMenuInfo(hmenu
, &mi
, TRUE
);
5049 HBITMAP hBitmapUnchecked
,
5050 HBITMAP hBitmapChecked
)
5052 ROSMENUITEMINFO uItem
;
5053 memset ( &uItem
, 0, sizeof(uItem
) );
5054 uItem
.fMask
= MIIM_STATE
| MIIM_BITMAP
;
5056 if(!(NtUserMenuItemInfo(hMenu
, uPosition
,
5057 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, FALSE
))) return FALSE
;
5059 if (!hBitmapChecked
&& !hBitmapUnchecked
)
5061 uItem
.fState
&= ~MF_USECHECKBITMAPS
;
5063 else /* Install new bitmaps */
5065 uItem
.hbmpChecked
= hBitmapChecked
;
5066 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
5067 uItem
.fState
|= MF_USECHECKBITMAPS
;
5069 return NtUserMenuItemInfo(hMenu
, uPosition
,
5070 (BOOL
)(MF_BYPOSITION
& uFlags
), &uItem
, TRUE
);
5083 LPCMENUITEMINFOA lpmii
)
5085 MENUITEMINFOW MenuItemInfoW
;
5086 UNICODE_STRING UnicodeString
;
5088 ULONG Result
= FALSE
;
5090 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5092 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5094 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5095 MenuItemInfoW
.hbmpItem
= NULL
;
5098 * MIIM_STRING == good
5099 * MIIM_TYPE & MFT_STRING == good
5100 * MIIM_STRING & MFT_STRING == good
5101 * MIIM_STRING & MFT_OWNERSRAW == good
5103 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5104 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5105 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5106 && MenuItemInfoW
.dwTypeData
!= NULL
)
5108 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
5109 Status
= RtlCreateUnicodeStringFromAsciiz(&UnicodeString
,
5110 (LPSTR
)MenuItemInfoW
.dwTypeData
);
5111 if (!NT_SUCCESS (Status
))
5113 SetLastError (RtlNtStatusToDosError(Status
));
5116 MenuItemInfoW
.dwTypeData
= UnicodeString
.Buffer
;
5117 MenuItemInfoW
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
5121 UnicodeString
.Buffer
= NULL
;
5124 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5125 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5127 if (UnicodeString
.Buffer
!= NULL
)
5129 RtlFreeUnicodeString(&UnicodeString
);
5145 LPCMENUITEMINFOW lpmii
)
5147 MENUITEMINFOW MenuItemInfoW
;
5150 RtlCopyMemory(&MenuItemInfoW
, lpmii
, min(lpmii
->cbSize
, sizeof(MENUITEMINFOW
)));
5152 if( lpmii
->cbSize
!= sizeof( MENUITEMINFOW
))
5154 MenuItemInfoW
.cbSize
= sizeof( MENUITEMINFOW
);
5155 MenuItemInfoW
.hbmpItem
= NULL
;
5158 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
5159 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
5160 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
5161 && MenuItemInfoW
.dwTypeData
!= NULL
)
5163 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
5165 Result
= NtUserMenuItemInfo(hMenu
, uItem
, fByPosition
,
5166 (PROSMENUITEMINFO
)&MenuItemInfoW
, TRUE
);
5182 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
5187 SetLastError(ERROR_INVALID_MENU_HANDLE
);
5190 return NtUserSetSystemMenu(hwnd
, hMenu
);
5212 SetLastError( ERROR_INVALID_MENU_HANDLE
);
5216 MenuInitTracking(Wnd
, Menu
, TRUE
, Flags
);
5218 /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */
5219 if (0 == (Flags
& TPM_NONOTIFY
))
5221 SendMessageW(Wnd
, WM_INITMENUPOPUP
, (WPARAM
) Menu
, 0);
5224 if (MenuShowPopup(Wnd
, Menu
, 0, Flags
, x
, y
, 0, 0 ))
5226 ret
= MenuTrackMenu(Menu
, Flags
| TPM_POPUPMENU
, 0, 0, Wnd
, Rect
);
5228 MenuExitTracking(Wnd
);
5246 /* Not fully implemented */
5247 return TrackPopupMenu(Menu
, Flags
, x
, y
, 0, Wnd
,
5248 NULL
!= Tpm
? &Tpm
->rcExclude
: NULL
);
5252 // Example for the Win32/User32 rewrite.
5253 // Def = TrackPopupMenuEx@24=NtUserTrackPopupMenuEx@24
5267 return NtUserTrackPopupMenuEx( Menu
,
5272 NULL
); // LPTPMPARAMS is null
5281 GetMenuContextHelpId(HMENU hmenu
)
5284 mi
.cbSize
= sizeof(ROSMENUINFO
);
5285 mi
.fMask
= MIM_HELPID
;
5287 if(NtUserMenuInfo(hmenu
, &mi
, FALSE
))
5289 return mi
.dwContextHelpID
;
5310 lResult
= PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
5313 Result
= (ULONG_PTR
)lResult
;
5318 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
5338 lResult
= PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
5341 Result
= (ULONG_PTR
)lResult
;
5346 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
5357 LPCWSTR lpszNewItem
,
5362 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5363 for MF_DELETE. We should check the parameters for all others
5364 MF_* actions also (anybody got a doc on ChangeMenu?).
5367 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5370 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5373 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5376 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5379 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5380 flags
&~ MF_REMOVE
);
5382 default : /* MF_INSERT */
5383 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
5400 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
5401 for MF_DELETE. We should check the parameters for all others
5402 MF_* actions also (anybody got a doc on ChangeMenu?).
5405 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
5408 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
5411 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
5414 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
5417 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
5418 flags
&~ MF_REMOVE
);
5420 default : /* MF_INSERT */
5421 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);