2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS user32.dll
4 * FILE: win32ss/user/user32/windows/menu.c
7 * PROGRAMMERS: Casper S. Hornstrup
11 /* INCLUDES ******************************************************************/
14 #include <wine/debug.h>
16 BOOL WINAPI
GdiValidateHandle(HGDIOBJ hobj
);
18 WINE_DEFAULT_DEBUG_CHANNEL(menu
);
20 /* internal popup menu window messages */
22 #define MM_SETMENUHANDLE (WM_USER + 0)
23 #define MM_GETMENUHANDLE (WM_USER + 1)
25 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
27 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
29 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
31 #define MENUITEMINFO_TYPE_MASK \
32 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
33 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
34 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
36 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
38 #define STATE_MASK (~TYPE_MASK)
40 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
42 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
44 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
45 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
46 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
48 #define IS_SYSTEM_MENU(MenuInfo) \
49 (0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
51 #define IS_SYSTEM_POPUP(MenuInfo) \
52 (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
54 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
56 /*********************************************************************
57 * PopupMenu class descriptor
59 const struct builtin_class_descr POPUPMENU_builtin_class
=
62 CS_SAVEBITS
| CS_DBLCLKS
, /* style */
63 NULL
, /* FIXME - procA */
64 PopupMenuWndProcW
, /* FIXME - procW */
65 sizeof(MENUINFO
*), /* extra */
66 (LPCWSTR
) IDC_ARROW
, /* cursor */
67 (HBRUSH
)(COLOR_MENU
+ 1) /* brush */
71 #define GET_WORD(ptr) (*(WORD *)(ptr))
74 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
78 /***********************************************************************
81 * Validate the given menu handle and returns the menu structure pointer.
83 FORCEINLINE PMENU
MENU_GetMenu(HMENU hMenu
)
85 return ValidateHandleNoErr(hMenu
, TYPE_MENU
);
88 /***********************************************************************
91 * Find a menu item. Return a pointer on the item, and modifies *hmenu
92 * in case the item was in a sub-menu.
94 ITEM
*MENU_FindItem( HMENU
*hmenu
, UINT
*nPos
, UINT wFlags
)
97 ITEM
*fallback
= NULL
;
98 UINT fallback_pos
= 0;
102 if ((*hmenu
== (HMENU
)0xffff) || (!(menu
= MENU_GetMenu(*hmenu
)))) return NULL
;
103 if (wFlags
& MF_BYPOSITION
)
105 if (*nPos
>= menu
->cItems
) return NULL
;
106 pItem
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
107 if (pItem
) pItem
= &pItem
[*nPos
];
112 PITEM item
= menu
->rgItems
? DesktopPtrToUser(menu
->rgItems
) : NULL
;
113 for (i
= 0; item
&& (i
< menu
->cItems
); i
++, item
++)
117 PMENU pSubMenu
= DesktopPtrToUser(item
->spSubMenu
);
118 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
119 ITEM
*subitem
= MENU_FindItem( &hsubmenu
, nPos
, wFlags
);
125 else if (item
->wID
== *nPos
)
127 /* fallback to this item if nothing else found */
132 else if (item
->wID
== *nPos
)
141 *nPos
= fallback_pos
;
147 IntGetMenuDefaultItem(PMENU Menu
, BOOL fByPos
, UINT gmdiFlags
, DWORD
*gismc
)
150 PITEM Item
= Menu
->rgItems
? DesktopPtrToUser(Menu
->rgItems
) : NULL
;
153 if (!Item
) return -1;
155 while ( !( Item
->fState
& MFS_DEFAULT
) )
158 if (i
>= Menu
->cItems
) return -1;
161 /* default: don't return disabled items */
162 if ( (!(GMDI_USEDISABLED
& gmdiFlags
)) && (Item
->fState
& MFS_DISABLED
)) return -1;
164 /* search rekursiv when needed */
165 if ( (Item
->fType
& MF_POPUP
) && (gmdiFlags
& GMDI_GOINTOPOPUPS
) && Item
->spSubMenu
)
169 ret
= IntGetMenuDefaultItem( DesktopPtrToUser(Item
->spSubMenu
), fByPos
, gmdiFlags
, gismc
);
171 if ( -1 != ret
) return ret
;
173 /* when item not found in submenu, return the popup item */
175 return ( fByPos
) ? i
: Item
->wID
;
178 static BOOL
GetMenuItemInfo_common ( HMENU hmenu
,
181 LPMENUITEMINFOW lpmii
,
184 ITEM
*pItem
= MENU_FindItem (&hmenu
, &item
, bypos
? MF_BYPOSITION
: 0);
186 //debug_print_menuitem("GetMenuItemInfo_common: ", pItem, "");
190 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
194 if( lpmii
->fMask
& MIIM_TYPE
)
196 if( lpmii
->fMask
& ( MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
))
198 ERR("invalid combination of fMask bits used\n");
199 /* this does not happen on Win9x/ME */
200 SetLastError( ERROR_INVALID_PARAMETER
);
203 lpmii
->fType
= pItem
->fType
& MENUITEMINFO_TYPE_MASK
;
204 if( pItem
->hbmp
) lpmii
->fType
|= MFT_BITMAP
;
205 lpmii
->hbmpItem
= pItem
->hbmp
; /* not on Win9x/ME */
206 if( lpmii
->fType
& MFT_BITMAP
)
208 lpmii
->dwTypeData
= (LPWSTR
) pItem
->hbmp
;
211 else if( lpmii
->fType
& (MFT_OWNERDRAW
| MFT_SEPARATOR
))
213 /* this does not happen on Win9x/ME */
214 lpmii
->dwTypeData
= 0;
219 /* copy the text string */
220 if ((lpmii
->fMask
& (MIIM_TYPE
|MIIM_STRING
)))
223 { // Very strange this fixes a wine test with a crash.
224 if(lpmii
->dwTypeData
&& lpmii
->cch
&& !(GdiValidateHandle((HGDIOBJ
)lpmii
->dwTypeData
)) )
227 *((WCHAR
*)lpmii
->dwTypeData
) = 0;
229 *((CHAR
*)lpmii
->dwTypeData
) = 0;
236 LPWSTR text
= DesktopPtrToUser(pItem
->Xlpstr
);
240 if(lpmii
->dwTypeData
&& lpmii
->cch
)
241 lstrcpynW(lpmii
->dwTypeData
, text
, lpmii
->cch
);
245 len
= WideCharToMultiByte( CP_ACP
, 0, text
, -1, NULL
, 0, NULL
, NULL
) - 1;
246 if(lpmii
->dwTypeData
&& lpmii
->cch
)
247 if (!WideCharToMultiByte( CP_ACP
, 0, text
, -1,
248 (LPSTR
)lpmii
->dwTypeData
, lpmii
->cch
, NULL
, NULL
))
249 ((LPSTR
)lpmii
->dwTypeData
)[lpmii
->cch
- 1] = 0;
251 /* if we've copied a substring we return its length */
252 if(lpmii
->dwTypeData
&& lpmii
->cch
)
253 if (lpmii
->cch
<= len
+ 1)
259 /* return length of string */
260 /* not on Win9x/ME if fType & MFT_BITMAP */
266 if (lpmii
->fMask
& MIIM_FTYPE
)
267 lpmii
->fType
= pItem
->fType
& MENUITEMINFO_TYPE_MASK
;
269 if (lpmii
->fMask
& MIIM_BITMAP
)
270 lpmii
->hbmpItem
= pItem
->hbmp
;
272 if (lpmii
->fMask
& MIIM_STATE
)
273 lpmii
->fState
= pItem
->fState
& MENUITEMINFO_STATE_MASK
;
275 if (lpmii
->fMask
& MIIM_ID
)
276 lpmii
->wID
= pItem
->wID
;
278 if (lpmii
->fMask
& MIIM_SUBMENU
&& pItem
->spSubMenu
)
280 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
281 HMENU hSubMenu
= UserHMGetHandle(pSubMenu
);
282 lpmii
->hSubMenu
= hSubMenu
;
286 /* hSubMenu is always cleared
287 * (not on Win9x/ME ) */
291 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
293 lpmii
->hbmpChecked
= pItem
->hbmpChecked
;
294 lpmii
->hbmpUnchecked
= pItem
->hbmpUnchecked
;
296 if (lpmii
->fMask
& MIIM_DATA
)
297 lpmii
->dwItemData
= pItem
->dwItemData
;
304 // User side Menu Class Proc.
307 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
312 TRACE("PMWPW : hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
314 pWnd
= ValidateHwnd(Wnd
);
319 if (Message
!= WM_NCCREATE
)
321 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
326 if (pWnd
->fnid
!= FNID_MENU
)
328 ERR("Wrong window class for Menu!\n");
340 case MM_SETMENUHANDLE
:
341 case MM_GETMENUHANDLE
:
347 TRACE("Menu Class ProcW\n");
348 NtUserMessageCall( Wnd
, Message
, wParam
, lParam
, (ULONG_PTR
)&lResult
, FNID_MENU
, FALSE
);
351 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
352 return MA_NOACTIVATE
;
357 case WM_SHOWWINDOW
: // Not sure what this does....
360 if (0 == GetWindowLongPtrW(Wnd
, 0))
362 OutputDebugStringA("no menu to display\n");
367 //SetWindowLongPtrW(Wnd, 0, 0);
372 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
378 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
382 pWnd
= ValidateHwnd(Wnd
);
383 if (pWnd
&& !pWnd
->fnid
&& Message
!= WM_NCCREATE
)
385 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
387 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
393 case WM_MOUSEACTIVATE
:
400 case MM_SETMENUHANDLE
:
401 case MM_GETMENUHANDLE
:
404 return PopupMenuWndProcW(Wnd
, Message
, wParam
, lParam
);
407 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
412 /**********************************************************************
415 * Parse a standard menu resource and add items to the menu.
416 * Return a pointer to the end of the resource.
418 * NOTE: flags is equivalent to the mtOption field
420 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
)
429 flags
= GET_WORD(res
);
431 /* remove MF_END flag before passing it to AppendMenu()! */
432 end
= (flags
& MF_END
);
433 if(end
) flags
^= MF_END
;
436 if(!(flags
& MF_POPUP
))
442 res
+= (strlenW(str
) + 1) * sizeof(WCHAR
);
444 if (flags
& MF_POPUP
)
446 hSubMenu
= CreatePopupMenu();
447 if(!hSubMenu
) return NULL
;
448 if(!(res
= MENU_ParseResource(res
, hSubMenu
))) return NULL
;
449 AppendMenuW(hMenu
, flags
, (UINT_PTR
)hSubMenu
, (LPCWSTR
)str
);
451 else /* Not a popup */
453 AppendMenuW(hMenu
, flags
, id
, *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
459 /**********************************************************************
460 * MENUEX_ParseResource
462 * Parse an extended menu resource and add items to the menu.
463 * Return a pointer to the end of the resource.
465 static LPCSTR
MENUEX_ParseResource(LPCSTR res
, HMENU hMenu
)
472 mii
.cbSize
= sizeof(mii
);
473 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
474 mii
.fType
= GET_DWORD(res
);
475 res
+= sizeof(DWORD
);
476 mii
.fState
= GET_DWORD(res
);
477 res
+= sizeof(DWORD
);
478 mii
.wID
= GET_DWORD(res
);
479 res
+= sizeof(DWORD
);
480 resinfo
= GET_WORD(res
);
482 /* Align the text on a word boundary. */
483 res
+= (~((UINT_PTR
)res
- 1)) & 1;
484 mii
.dwTypeData
= (LPWSTR
)res
;
485 mii
.cch
= strlenW(mii
.dwTypeData
);
486 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
487 /* Align the following fields on a dword boundary. */
488 res
+= (~((UINT_PTR
)res
- 1)) & 3;
490 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
491 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
493 if (resinfo
& 1) /* Pop-up? */
495 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
496 res
+= sizeof(DWORD
);
497 mii
.hSubMenu
= CreatePopupMenu();
500 ERR("CreatePopupMenu failed\n");
504 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
506 ERR("MENUEX_ParseResource failed\n");
507 DestroyMenu(mii
.hSubMenu
);
510 mii
.fMask
|= MIIM_SUBMENU
;
512 else if (!mii
.dwTypeData
[0] && !(mii
.fType
& MF_SEPARATOR
))
514 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
516 mii
.fType
|= MF_SEPARATOR
;
518 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
519 } while (!(resinfo
& MF_END
));
524 /**********************************************************************
527 * Uses flags, id and text ptr, passed by InsertMenu() and
528 * ModifyMenu() to setup a MenuItemInfo structure.
530 static void MENU_mnu2mnuii( UINT flags
, UINT_PTR id
, LPCWSTR str
, LPMENUITEMINFOW pmii
, BOOL Unicode
)
532 RtlZeroMemory( pmii
, sizeof( MENUITEMINFOW
));
533 pmii
->cbSize
= sizeof( MENUITEMINFOW
);
534 pmii
->fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
535 /* setting bitmap clears text and vice versa */
536 if( IS_STRING_ITEM(flags
)) {
537 pmii
->fMask
|= MIIM_STRING
| MIIM_BITMAP
;
539 flags
|= MF_SEPARATOR
;
540 /* Item beginning with a backspace is a help item */
541 /* FIXME: wrong place, this is only true in win16 */
554 LPCSTR NewItemA
= (LPCSTR
) str
;
555 if (*NewItemA
== '\b')
559 str
= (LPCWSTR
) NewItemA
;
561 TRACE("A cch %d\n",strlen(NewItemA
));
564 pmii
->dwTypeData
= (LPWSTR
)str
;
565 } else if( flags
& MFT_BITMAP
){
566 pmii
->fMask
|= MIIM_BITMAP
| MIIM_STRING
;
567 pmii
->hbmpItem
= (HBITMAP
)str
;
569 if( flags
& MF_OWNERDRAW
){
570 pmii
->fMask
|= MIIM_DATA
;
571 pmii
->dwItemData
= (ULONG_PTR
) str
;
573 if( flags
& MF_POPUP
&& MENU_GetMenu((HMENU
)id
)) {
574 pmii
->fMask
|= MIIM_SUBMENU
;
575 pmii
->hSubMenu
= (HMENU
)id
;
577 if( flags
& MF_SEPARATOR
) flags
|= MF_GRAYED
| MF_DISABLED
;
578 pmii
->fState
= flags
& MENUITEMINFO_STATE_MASK
& ~MFS_DEFAULT
;
579 pmii
->fType
= flags
& MENUITEMINFO_TYPE_MASK
;
580 pmii
->wID
= (UINT
)id
;
583 /**********************************************************************
584 * MENU_NormalizeMenuItemInfoStruct
586 * Helper for SetMenuItemInfo and InsertMenuItemInfo:
587 * check, copy and extend the MENUITEMINFO struct from the version that the application
588 * supplied to the version used by wine source. */
589 static BOOL
MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW
*pmii_in
,
590 MENUITEMINFOW
*pmii_out
)
592 /* do we recognize the size? */
593 if( !pmii_in
|| (pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) &&
594 pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) - sizeof( pmii_in
->hbmpItem
)) ) {
595 SetLastError( ERROR_INVALID_PARAMETER
);
598 /* copy the fields that we have */
599 memcpy( pmii_out
, pmii_in
, pmii_in
->cbSize
);
600 /* if the hbmpItem member is missing then extend */
601 if( pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
)) {
602 pmii_out
->cbSize
= sizeof( MENUITEMINFOW
);
603 pmii_out
->hbmpItem
= NULL
;
605 /* test for invalid bit combinations */
606 if( (pmii_out
->fMask
& MIIM_TYPE
&&
607 pmii_out
->fMask
& (MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
)) ||
608 (pmii_out
->fMask
& MIIM_FTYPE
&& pmii_out
->fType
& MFT_BITMAP
)) {
609 ERR("invalid combination of fMask bits used\n");
610 /* this does not happen on Win9x/ME */
611 SetLastError( ERROR_INVALID_PARAMETER
);
614 /* convert old style (MIIM_TYPE) to the new and keep the old one too */
615 if( pmii_out
->fMask
& MIIM_TYPE
){
616 pmii_out
->fMask
|= MIIM_FTYPE
;
617 if( IS_STRING_ITEM(pmii_out
->fType
)){
618 pmii_out
->fMask
|= MIIM_STRING
;
619 } else if( (pmii_out
->fType
) & MFT_BITMAP
){
620 pmii_out
->fMask
|= MIIM_BITMAP
;
621 pmii_out
->hbmpItem
= UlongToHandle(LOWORD(pmii_out
->dwTypeData
));
624 if (pmii_out
->fMask
& MIIM_FTYPE
)
626 pmii_out
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
627 pmii_out
->fType
|= pmii_in
->fType
& MENUITEMINFO_TYPE_MASK
;
629 if (pmii_out
->fMask
& MIIM_STATE
)
630 /* Other menu items having MFS_DEFAULT are not converted
632 pmii_out
->fState
= pmii_in
->fState
& MENUITEMINFO_STATE_MASK
;
634 if (pmii_out
->fMask
& MIIM_SUBMENU
)
636 if ((pmii_out
->hSubMenu
!= NULL
) && !IsMenu(pmii_out
->hSubMenu
))
656 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
660 // Use this for Menu Ole!!
662 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
666 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
668 PLOADMENU_CALLBACK_ARGUMENTS Common
;
671 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
673 Result
= (LRESULT
)LoadMenuW( Common
->hModule
, Common
->InterSource
? MAKEINTRESOURCE(Common
->InterSource
) : (LPCWSTR
)&Common
->MenuName
);
675 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
679 /* FUNCTIONS *****************************************************************/
685 AppendMenuA(HMENU hMenu
,
691 UNICODE_STRING UnicodeString
;
694 RtlInitUnicodeString(&UnicodeString
, 0);
696 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
698 /* copy the text string, it will be one or the other */
699 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
701 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
703 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
706 mii
.dwTypeData
= UnicodeString
.Buffer
;
707 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
711 TRACE("AMA Handle bitmaps\n");
713 ////// Answer a question, why a -1? To hunt for the end of the item list. Get it, to Append?
714 res
= NtUserThunkedMenuItemInfo(hMenu
, -1, TRUE
, TRUE
, &mii
, &UnicodeString
);
715 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
723 AppendMenuW(HMENU hMenu
,
729 UNICODE_STRING MenuText
;
732 RtlInitUnicodeString(&MenuText
, 0);
734 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
736 /* copy the text string, it will be one or the other */
737 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
739 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
740 mii
.dwTypeData
= MenuText
.Buffer
;
741 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
743 res
= NtUserThunkedMenuItemInfo(hMenu
, -1, TRUE
, TRUE
, &mii
, &MenuText
);
751 CheckMenuItem(HMENU hmenu
,
757 UINT uID
= uIDCheckItem
;
759 if (!ValidateHandle(hmenu
, TYPE_MENU
))
762 if (!(item
= MENU_FindItem( &hmenu
, &uID
, uCheck
))) return -1;
764 Ret
= item
->fState
& MFS_CHECKED
;
765 if ( Ret
== (uCheck
& MFS_CHECKED
)) return Ret
; // Already Checked...
767 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
774 CheckMenuRadioItem(HMENU hMenu
,
782 PITEM mi_first
= NULL
, mi_check
;
783 HMENU m_first
, m_check
;
785 mii
.cbSize
= sizeof( mii
);
787 for (i
= first
; i
<= last
; i
++)
794 mi_first
= MENU_FindItem(&m_first
, &pos
, bypos
);
795 if (!mi_first
) continue;
802 mi_check
= MENU_FindItem(&m_check
, &pos
, bypos
);
803 if (!mi_check
) continue;
806 if (m_first
!= m_check
) continue;
807 if (mi_check
->fType
== MFT_SEPARATOR
) continue;
811 if (!(mi_check
->fType
& MFT_RADIOCHECK
) || !(mi_check
->fState
& MFS_CHECKED
))
813 mii
.fMask
= MIIM_FTYPE
| MIIM_STATE
;
814 mii
.fType
= (mi_check
->fType
& MENUITEMINFO_TYPE_MASK
) | MFT_RADIOCHECK
;
815 mii
.fState
= (mi_check
->fState
& MII_STATE_MASK
) | MFS_CHECKED
;
816 NtUserThunkedMenuItemInfo(m_check
, i
, bypos
, FALSE
, &mii
, NULL
);
822 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
823 if (mi_check
->fState
& MFS_CHECKED
)
825 mii
.fMask
= MIIM_STATE
;
826 mii
.fState
= (mi_check
->fState
& MII_STATE_MASK
) & ~MFS_CHECKED
;
827 NtUserThunkedMenuItemInfo(m_check
, i
, bypos
, FALSE
, &mii
, NULL
);
840 return NtUserxCreateMenu();
847 CreatePopupMenu(VOID
)
849 return NtUserxCreatePopupMenu();
856 DrawMenuBar(HWND hWnd
)
858 return NtUserxDrawMenuBar(hWnd
);
865 EnableMenuItem(HMENU hMenu
,
869 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
878 PWND Wnd
= ValidateHwnd(hWnd
);
883 return UlongToHandle(Wnd
->IDMenu
);
890 GetMenuCheckMarkDimensions(VOID
)
892 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
893 GetSystemMetrics(SM_CYMENUCHECK
)));
901 GetMenuContextHelpId(HMENU hmenu
)
904 if ((pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
905 return pMenu
->dwContextHelpId
;
913 GetMenuDefaultItem(HMENU hMenu
,
919 if (!(pMenu
= ValidateHandle(hMenu
, TYPE_MENU
)))
922 return IntGetMenuDefaultItem( pMenu
, (BOOL
)fByPos
, gmdiFlags
, &gismc
);
929 GetMenuInfo(HMENU hmenu
,
934 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
936 SetLastError(ERROR_INVALID_PARAMETER
);
940 if (!(pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
943 if (lpcmi
->fMask
& MIM_BACKGROUND
)
944 lpcmi
->hbrBack
= pMenu
->hbrBack
;
946 if (lpcmi
->fMask
& MIM_HELPID
)
947 lpcmi
->dwContextHelpID
= pMenu
->dwContextHelpId
;
949 if (lpcmi
->fMask
& MIM_MAXHEIGHT
)
950 lpcmi
->cyMax
= pMenu
->cyMax
;
952 if (lpcmi
->fMask
& MIM_MENUDATA
)
953 lpcmi
->dwMenuData
= pMenu
->dwMenuData
;
955 if (lpcmi
->fMask
& MIM_STYLE
)
956 lpcmi
->dwStyle
= pMenu
->fFlags
& MNS_STYLE_MASK
;
965 GetMenuItemCount(HMENU hmenu
)
968 if ((pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
969 return pMenu
->cItems
;
977 GetMenuItemID(HMENU hMenu
,
981 if (!(lpmi
= MENU_FindItem(&hMenu
,(UINT
*)&nPos
,MF_BYPOSITION
))) return -1;
982 if (lpmi
->spSubMenu
) return -1;
994 LPMENUITEMINFOA lpmii
)
999 if( lpmii
->cbSize
!= sizeof( mii
) &&
1000 lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
))
1002 SetLastError( ERROR_INVALID_PARAMETER
);
1005 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
1006 mii
.cbSize
= sizeof( mii
);
1007 ret
= GetMenuItemInfo_common (hmenu
,
1010 (LPMENUITEMINFOW
)&mii
,
1012 mii
.cbSize
= lpmii
->cbSize
;
1013 memcpy( lpmii
, &mii
, mii
.cbSize
);
1025 LPMENUITEMINFOW lpmii
)
1029 if( lpmii
->cbSize
!= sizeof( mii
) && lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
))
1031 SetLastError( ERROR_INVALID_PARAMETER
);
1034 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
1035 mii
.cbSize
= sizeof( mii
);
1036 ret
= GetMenuItemInfo_common (hMenu
, Item
, bypos
, &mii
, TRUE
);
1037 mii
.cbSize
= lpmii
->cbSize
;
1038 memcpy( lpmii
, &mii
, mii
.cbSize
);
1054 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu
, uId
, uFlags
);
1055 if (!(pItem
= MENU_FindItem( &hMenu
, &uId
, uFlags
))) return -1;
1057 if (!pItem
->Xlpstr
&& pItem
->hbmp
) Type
= MFT_BITMAP
;
1059 if (pItem
->spSubMenu
)
1061 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
1062 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
1063 if (!IsMenu(hsubmenu
)) return (UINT
)-1;
1064 else return (pSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|Type
) & 0xff);
1067 return (pItem
->fType
| pItem
->fState
| Type
);
1084 ////// wine Code, seems to be faster.
1085 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, uIDItem
, lpString
, nMaxCount
, uFlag
);
1087 if (lpString
&& nMaxCount
) lpString
[0] = '\0';
1089 if (!(item
= MENU_FindItem( &hMenu
, &uIDItem
, uFlag
)))
1091 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
1095 text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
1097 if (!text
) return 0;
1098 if (!lpString
|| !nMaxCount
) return WideCharToMultiByte( CP_ACP
, 0, text
, -1, NULL
, 0, NULL
, NULL
);
1099 if (!WideCharToMultiByte( CP_ACP
, 0, text
, -1, lpString
, nMaxCount
, NULL
, NULL
))
1100 lpString
[nMaxCount
-1] = 0;
1101 TRACE("A returning %s\n", lpString
);
1102 return strlen(lpString
);
1120 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, uIDItem
, lpString
, nMaxCount
, uFlag
);
1122 if (lpString
&& nMaxCount
) lpString
[0] = '\0';
1124 if (!(item
= MENU_FindItem( &hMenu
, &uIDItem
, uFlag
)))
1126 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
1130 text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
1132 if (!lpString
|| !nMaxCount
) return text
? strlenW(text
) : 0;
1138 lstrcpynW( lpString
, text
, nMaxCount
);
1139 TRACE("W returning %S\n", lpString
);
1140 return strlenW(lpString
);
1153 if (!(pItem
= MENU_FindItem( &hMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
1155 if (pItem
->spSubMenu
)
1157 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
1158 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
1159 if (IsMenu(hsubmenu
)) return hsubmenu
;
1169 GetSystemMenu(HWND hWnd
, BOOL bRevert
)
1171 return NtUserGetSystemMenu(hWnd
, bRevert
);
1183 UINT_PTR uIDNewItem
,
1187 UNICODE_STRING UnicodeString
;
1190 RtlInitUnicodeString(&UnicodeString
, 0);
1192 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
1194 /* copy the text string, it will be one or the other */
1195 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
1197 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
1199 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
1202 mii
.dwTypeData
= UnicodeString
.Buffer
;
1203 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
1207 TRACE("Handle bitmaps\n");
1209 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), TRUE
, &mii
, &UnicodeString
);
1210 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
1223 LPCMENUITEMINFOA lpmii
)
1226 UNICODE_STRING UnicodeString
;
1229 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
1231 RtlInitUnicodeString(&UnicodeString
, 0);
1233 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
1235 /* copy the text string */
1236 if (((mii
.fMask
& MIIM_STRING
) ||
1237 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
1238 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
1240 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
1242 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
1245 mii
.dwTypeData
= UnicodeString
.Buffer
;
1246 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
1250 TRACE("Handle bitmaps\n");
1252 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mii
, &UnicodeString
);
1253 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
1266 LPCMENUITEMINFOW lpmii
)
1269 UNICODE_STRING MenuText
;
1272 /* while we could just pass 'lpmii' to win32k, we make a copy so that
1273 if a bad user passes bad data, we crash his process instead of the
1276 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
1278 RtlInitUnicodeString(&MenuText
, 0);
1280 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
1282 /* copy the text string */
1283 if (((mii
.fMask
& MIIM_STRING
) ||
1284 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
1285 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
1287 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
1288 mii
.dwTypeData
= MenuText
.Buffer
;
1289 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
1291 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mii
, &MenuText
);
1304 UINT_PTR uIDNewItem
,
1308 UNICODE_STRING MenuText
;
1311 RtlInitUnicodeString(&MenuText
, 0);
1313 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
1315 /* copy the text string, it will be one or the other */
1316 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
1318 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
1319 mii
.dwTypeData
= MenuText
.Buffer
;
1320 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
1322 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), TRUE
, &mii
, &MenuText
);
1334 if (ValidateHandle(Menu
, TYPE_MENU
)) return TRUE
;
1342 LoadMenuA(HINSTANCE hInstance
,
1345 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
1346 if (Resource
== NULL
)
1350 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
1357 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
1359 return(LoadMenuIndirectW(lpMenuTemplate
));
1366 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
1369 WORD version
, offset
;
1370 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
1372 version
= GET_WORD(p
);
1377 case 0: /* standard format is version of 0 */
1378 offset
= GET_WORD(p
);
1379 p
+= sizeof(WORD
) + offset
;
1380 if (!(hMenu
= CreateMenu())) return 0;
1381 if (!MENU_ParseResource(p
, hMenu
))
1387 case 1: /* extended format is version of 1 */
1388 offset
= GET_WORD(p
);
1389 p
+= sizeof(WORD
) + offset
;
1390 if (!(hMenu
= CreateMenu())) return 0;
1391 if (!MENUEX_ParseResource(p
, hMenu
))
1393 DestroyMenu( hMenu
);
1398 ERR("Menu template version %d not supported.\n", version
);
1407 LoadMenuW(HINSTANCE hInstance
,
1410 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
1411 if (Resource
== NULL
)
1415 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
1427 UINT_PTR uIDNewItem
,
1431 UNICODE_STRING UnicodeString
;
1434 RtlInitUnicodeString(&UnicodeString
, 0);
1436 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
1438 /* copy the text string, it will be one or the other */
1439 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
1441 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
1443 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
1446 mii
.dwTypeData
= UnicodeString
.Buffer
;
1447 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
1451 TRACE("Handle bitmaps\n");
1453 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), FALSE
, &mii
, &UnicodeString
);
1454 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
1467 UINT_PTR uIDNewItem
,
1471 UNICODE_STRING MenuText
;
1474 RtlInitUnicodeString(&MenuText
, 0);
1476 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
1478 /* copy the text string, it will be one or the other */
1479 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
1481 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
1482 mii
.dwTypeData
= MenuText
.Buffer
;
1483 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
1487 TRACE("Handle bitmaps\n");
1489 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), FALSE
, &mii
, &MenuText
);
1500 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
1515 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
1517 SetLastError(ERROR_INVALID_PARAMETER
);
1521 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
1522 return NtUserThunkedMenuInfo(hmenu
, (LPCMENUINFO
)&mi
);
1534 HBITMAP hBitmapUnchecked
,
1535 HBITMAP hBitmapChecked
)
1537 MENUITEMINFOW uItem
;
1538 memset ( &uItem
, 0, sizeof(uItem
) );
1539 uItem
.cbSize
= sizeof(MENUITEMINFOW
);
1540 uItem
.fMask
= MIIM_CHECKMARKS
;
1541 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
1542 uItem
.hbmpChecked
= hBitmapChecked
;
1543 return SetMenuItemInfoW(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), &uItem
);
1555 LPCMENUITEMINFOA lpmii
)
1558 UNICODE_STRING UnicodeString
;
1561 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu
, item
, bypos
, lpmii
);
1563 RtlInitUnicodeString(&UnicodeString
, 0);
1565 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
1567 * MIIM_STRING == good
1568 * MIIM_TYPE & MFT_STRING == good
1569 * MIIM_STRING & MFT_STRING == good
1570 * MIIM_STRING & MFT_OWNERDRAW == good
1572 if (((mii
.fMask
& MIIM_STRING
) ||
1573 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
1574 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
1576 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
1577 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
1579 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
1582 mii
.dwTypeData
= UnicodeString
.Buffer
;
1583 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
1587 UnicodeString
.Buffer
= NULL
;
1589 Ret
= NtUserThunkedMenuItemInfo(hmenu
, item
, bypos
, FALSE
, &mii
, &UnicodeString
);
1590 if (UnicodeString
.Buffer
!= NULL
) RtlFreeUnicodeString(&UnicodeString
);
1603 LPCMENUITEMINFOW lpmii
)
1605 MENUITEMINFOW MenuItemInfoW
;
1606 UNICODE_STRING UnicodeString
;
1609 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
1611 RtlInitUnicodeString(&UnicodeString
, 0);
1613 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &MenuItemInfoW
)) return FALSE
;
1615 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
1616 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
1617 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
1618 && MenuItemInfoW
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)MenuItemInfoW
.dwTypeData
)) )
1620 RtlInitUnicodeString(&UnicodeString
, (PCWSTR
)MenuItemInfoW
.dwTypeData
);
1621 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
1623 Ret
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, FALSE
, &MenuItemInfoW
, &UnicodeString
);
1639 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
1644 SetLastError(ERROR_INVALID_MENU_HANDLE
);
1647 return NtUserSetSystemMenu(hwnd
, hMenu
);
1661 return NtUserTrackPopupMenuEx( Menu
,
1666 NULL
); // LPTPMPARAMS is null
1684 return PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
1686 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
1704 return PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
1706 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
1717 LPCWSTR lpszNewItem
,
1722 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
1723 for MF_DELETE. We should check the parameters for all others
1724 MF_* actions also (anybody got a doc on ChangeMenu?).
1727 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
1730 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
1733 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
1736 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
1739 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
1740 flags
&~ MF_REMOVE
);
1742 default : /* MF_INSERT */
1743 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
1760 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
1761 for MF_DELETE. We should check the parameters for all others
1762 MF_* actions also (anybody got a doc on ChangeMenu?).
1765 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
1768 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
1771 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
1774 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
1777 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
1778 flags
&~ MF_REMOVE
);
1780 default : /* MF_INSERT */
1781 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);