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
&& !IS_MAGIC_BITMAP(pItem
->hbmp
))
205 lpmii
->fType
|= MFT_BITMAP
;
206 lpmii
->hbmpItem
= pItem
->hbmp
; /* not on Win9x/ME */
207 if( lpmii
->fType
& MFT_BITMAP
)
209 lpmii
->dwTypeData
= (LPWSTR
) pItem
->hbmp
;
212 else if( lpmii
->fType
& (MFT_OWNERDRAW
| MFT_SEPARATOR
))
214 /* this does not happen on Win9x/ME */
215 lpmii
->dwTypeData
= 0;
220 /* copy the text string */
221 if ((lpmii
->fMask
& (MIIM_TYPE
|MIIM_STRING
)))
224 { // Very strange this fixes a wine test with a crash.
225 if(lpmii
->dwTypeData
&& lpmii
->cch
&& !(GdiValidateHandle((HGDIOBJ
)lpmii
->dwTypeData
)) )
228 *((WCHAR
*)lpmii
->dwTypeData
) = 0;
230 *((CHAR
*)lpmii
->dwTypeData
) = 0;
237 LPWSTR text
= DesktopPtrToUser(pItem
->Xlpstr
);
241 if(lpmii
->dwTypeData
&& lpmii
->cch
)
242 lstrcpynW(lpmii
->dwTypeData
, text
, lpmii
->cch
);
246 len
= WideCharToMultiByte( CP_ACP
, 0, text
, -1, NULL
, 0, NULL
, NULL
) - 1;
247 if(lpmii
->dwTypeData
&& lpmii
->cch
)
248 if (!WideCharToMultiByte( CP_ACP
, 0, text
, -1,
249 (LPSTR
)lpmii
->dwTypeData
, lpmii
->cch
, NULL
, NULL
))
250 ((LPSTR
)lpmii
->dwTypeData
)[lpmii
->cch
- 1] = 0;
252 /* if we've copied a substring we return its length */
253 if(lpmii
->dwTypeData
&& lpmii
->cch
)
254 if (lpmii
->cch
<= len
+ 1)
260 /* return length of string */
261 /* not on Win9x/ME if fType & MFT_BITMAP */
267 if (lpmii
->fMask
& MIIM_FTYPE
)
268 lpmii
->fType
= pItem
->fType
& MENUITEMINFO_TYPE_MASK
;
270 if (lpmii
->fMask
& MIIM_BITMAP
)
271 lpmii
->hbmpItem
= pItem
->hbmp
;
273 if (lpmii
->fMask
& MIIM_STATE
)
274 lpmii
->fState
= pItem
->fState
& MENUITEMINFO_STATE_MASK
;
276 if (lpmii
->fMask
& MIIM_ID
)
277 lpmii
->wID
= pItem
->wID
;
279 if (lpmii
->fMask
& MIIM_SUBMENU
&& pItem
->spSubMenu
)
281 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
282 HMENU hSubMenu
= UserHMGetHandle(pSubMenu
);
283 lpmii
->hSubMenu
= hSubMenu
;
287 /* hSubMenu is always cleared
288 * (not on Win9x/ME ) */
292 if (lpmii
->fMask
& MIIM_CHECKMARKS
)
294 lpmii
->hbmpChecked
= pItem
->hbmpChecked
;
295 lpmii
->hbmpUnchecked
= pItem
->hbmpUnchecked
;
297 if (lpmii
->fMask
& MIIM_DATA
)
298 lpmii
->dwItemData
= pItem
->dwItemData
;
305 // User side Menu Class Proc.
308 PopupMenuWndProcW(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
313 TRACE("PMWPW : hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
315 pWnd
= ValidateHwnd(Wnd
);
320 if (Message
!= WM_NCCREATE
)
322 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
327 if (pWnd
->fnid
!= FNID_MENU
)
329 ERR("Wrong window class for Menu!\n");
341 case MM_SETMENUHANDLE
:
342 case MM_GETMENUHANDLE
:
348 TRACE("Menu Class ProcW\n");
349 NtUserMessageCall( Wnd
, Message
, wParam
, lParam
, (ULONG_PTR
)&lResult
, FNID_MENU
, FALSE
);
352 case WM_MOUSEACTIVATE
: /* We don't want to be activated */
353 return MA_NOACTIVATE
;
358 case WM_SHOWWINDOW
: // Not sure what this does....
361 if (0 == GetWindowLongPtrW(Wnd
, 0))
363 OutputDebugStringA("no menu to display\n");
368 //SetWindowLongPtrW(Wnd, 0, 0);
373 return DefWindowProcW(Wnd
, Message
, wParam
, lParam
);
379 LRESULT WINAPI
PopupMenuWndProcA(HWND Wnd
, UINT Message
, WPARAM wParam
, LPARAM lParam
)
383 pWnd
= ValidateHwnd(Wnd
);
384 if (pWnd
&& !pWnd
->fnid
&& Message
!= WM_NCCREATE
)
386 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
388 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd
, Message
, wParam
, lParam
);
394 case WM_MOUSEACTIVATE
:
401 case MM_SETMENUHANDLE
:
402 case MM_GETMENUHANDLE
:
405 return PopupMenuWndProcW(Wnd
, Message
, wParam
, lParam
);
408 return DefWindowProcA(Wnd
, Message
, wParam
, lParam
);
413 /**********************************************************************
416 * Parse a standard menu resource and add items to the menu.
417 * Return a pointer to the end of the resource.
419 * NOTE: flags is equivalent to the mtOption field
421 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
)
430 flags
= GET_WORD(res
);
432 /* remove MF_END flag before passing it to AppendMenu()! */
433 end
= (flags
& MF_END
);
434 if(end
) flags
^= MF_END
;
437 if(!(flags
& MF_POPUP
))
443 res
+= (strlenW(str
) + 1) * sizeof(WCHAR
);
445 if (flags
& MF_POPUP
)
447 hSubMenu
= CreatePopupMenu();
448 if(!hSubMenu
) return NULL
;
449 if(!(res
= MENU_ParseResource(res
, hSubMenu
))) return NULL
;
450 AppendMenuW(hMenu
, flags
, (UINT_PTR
)hSubMenu
, (LPCWSTR
)str
);
452 else /* Not a popup */
454 AppendMenuW(hMenu
, flags
, id
, *(LPCWSTR
)str
? (LPCWSTR
)str
: NULL
);
460 /**********************************************************************
461 * MENUEX_ParseResource
463 * Parse an extended menu resource and add items to the menu.
464 * Return a pointer to the end of the resource.
466 static LPCSTR
MENUEX_ParseResource(LPCSTR res
, HMENU hMenu
)
473 mii
.cbSize
= sizeof(mii
);
474 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
475 mii
.fType
= GET_DWORD(res
);
476 res
+= sizeof(DWORD
);
477 mii
.fState
= GET_DWORD(res
);
478 res
+= sizeof(DWORD
);
479 mii
.wID
= GET_DWORD(res
);
480 res
+= sizeof(DWORD
);
481 resinfo
= GET_WORD(res
);
483 /* Align the text on a word boundary. */
484 res
+= (~((UINT_PTR
)res
- 1)) & 1;
485 mii
.dwTypeData
= (LPWSTR
)res
;
486 mii
.cch
= strlenW(mii
.dwTypeData
);
487 res
+= (1 + strlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
488 /* Align the following fields on a dword boundary. */
489 res
+= (~((UINT_PTR
)res
- 1)) & 3;
491 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
492 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, mii
.dwTypeData
);
494 if (resinfo
& 1) /* Pop-up? */
496 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
497 res
+= sizeof(DWORD
);
498 mii
.hSubMenu
= CreatePopupMenu();
501 ERR("CreatePopupMenu failed\n");
505 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
)))
507 ERR("MENUEX_ParseResource failed\n");
508 DestroyMenu(mii
.hSubMenu
);
511 mii
.fMask
|= MIIM_SUBMENU
;
513 else if (!mii
.dwTypeData
[0] && !(mii
.fType
& MF_SEPARATOR
))
515 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
517 mii
.fType
|= MF_SEPARATOR
;
519 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
520 } while (!(resinfo
& MF_END
));
525 /**********************************************************************
528 * Uses flags, id and text ptr, passed by InsertMenu() and
529 * ModifyMenu() to setup a MenuItemInfo structure.
531 static void MENU_mnu2mnuii( UINT flags
, UINT_PTR id
, LPCWSTR str
, LPMENUITEMINFOW pmii
, BOOL Unicode
)
533 RtlZeroMemory( pmii
, sizeof( MENUITEMINFOW
));
534 pmii
->cbSize
= sizeof( MENUITEMINFOW
);
535 pmii
->fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
536 /* setting bitmap clears text and vice versa */
537 if( IS_STRING_ITEM(flags
)) {
538 pmii
->fMask
|= MIIM_STRING
| MIIM_BITMAP
;
540 flags
|= MF_SEPARATOR
;
541 /* Item beginning with a backspace is a help item */
542 /* FIXME: wrong place, this is only true in win16 */
555 LPCSTR NewItemA
= (LPCSTR
) str
;
556 if (*NewItemA
== '\b')
560 str
= (LPCWSTR
) NewItemA
;
562 TRACE("A cch %d\n",strlen(NewItemA
));
565 pmii
->dwTypeData
= (LPWSTR
)str
;
566 } else if( flags
& MFT_BITMAP
){
567 pmii
->fMask
|= MIIM_BITMAP
| MIIM_STRING
;
568 pmii
->hbmpItem
= (HBITMAP
)str
;
570 if( flags
& MF_OWNERDRAW
){
571 pmii
->fMask
|= MIIM_DATA
;
572 pmii
->dwItemData
= (ULONG_PTR
) str
;
574 if( flags
& MF_POPUP
&& MENU_GetMenu((HMENU
)id
)) {
575 pmii
->fMask
|= MIIM_SUBMENU
;
576 pmii
->hSubMenu
= (HMENU
)id
;
578 if( flags
& MF_SEPARATOR
) flags
|= MF_GRAYED
| MF_DISABLED
;
579 pmii
->fState
= flags
& MENUITEMINFO_STATE_MASK
& ~MFS_DEFAULT
;
580 pmii
->fType
= flags
& MENUITEMINFO_TYPE_MASK
;
581 pmii
->wID
= (UINT
)id
;
584 /**********************************************************************
585 * MENU_NormalizeMenuItemInfoStruct
587 * Helper for SetMenuItemInfo and InsertMenuItemInfo:
588 * check, copy and extend the MENUITEMINFO struct from the version that the application
589 * supplied to the version used by wine source. */
590 static BOOL
MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW
*pmii_in
,
591 MENUITEMINFOW
*pmii_out
)
593 /* do we recognize the size? */
594 if( !pmii_in
|| (pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) &&
595 pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) - sizeof( pmii_in
->hbmpItem
)) ) {
596 SetLastError( ERROR_INVALID_PARAMETER
);
599 /* copy the fields that we have */
600 memcpy( pmii_out
, pmii_in
, pmii_in
->cbSize
);
601 /* if the hbmpItem member is missing then extend */
602 if( pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
)) {
603 pmii_out
->cbSize
= sizeof( MENUITEMINFOW
);
604 pmii_out
->hbmpItem
= NULL
;
606 /* test for invalid bit combinations */
607 if( (pmii_out
->fMask
& MIIM_TYPE
&&
608 pmii_out
->fMask
& (MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
)) ||
609 (pmii_out
->fMask
& MIIM_FTYPE
&& pmii_out
->fType
& MFT_BITMAP
)) {
610 ERR("invalid combination of fMask bits used\n");
611 /* this does not happen on Win9x/ME */
612 SetLastError( ERROR_INVALID_PARAMETER
);
615 /* convert old style (MIIM_TYPE) to the new and keep the old one too */
616 if( pmii_out
->fMask
& MIIM_TYPE
){
617 pmii_out
->fMask
|= MIIM_FTYPE
;
618 if( IS_STRING_ITEM(pmii_out
->fType
)){
619 pmii_out
->fMask
|= MIIM_STRING
;
620 } else if( (pmii_out
->fType
) & MFT_BITMAP
){
621 pmii_out
->fMask
|= MIIM_BITMAP
;
622 pmii_out
->hbmpItem
= UlongToHandle(LOWORD(pmii_out
->dwTypeData
));
625 if (pmii_out
->fMask
& MIIM_FTYPE
)
627 pmii_out
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
628 pmii_out
->fType
|= pmii_in
->fType
& MENUITEMINFO_TYPE_MASK
;
630 if (pmii_out
->fMask
& MIIM_STATE
)
631 /* Other menu items having MFS_DEFAULT are not converted
633 pmii_out
->fState
= pmii_in
->fState
& MENUITEMINFO_STATE_MASK
;
635 if (pmii_out
->fMask
& MIIM_SUBMENU
)
637 if ((pmii_out
->hSubMenu
!= NULL
) && !IsMenu(pmii_out
->hSubMenu
))
657 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
661 // Use this for Menu Ole!!
663 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
667 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
669 PLOADMENU_CALLBACK_ARGUMENTS Common
;
672 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
674 Result
= (LRESULT
)LoadMenuW( Common
->hModule
, Common
->InterSource
? MAKEINTRESOURCE(Common
->InterSource
) : (LPCWSTR
)&Common
->MenuName
);
676 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
680 /* FUNCTIONS *****************************************************************/
686 AppendMenuA(HMENU hMenu
,
692 UNICODE_STRING UnicodeString
;
695 RtlInitUnicodeString(&UnicodeString
, 0);
697 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
699 /* copy the text string, it will be one or the other */
700 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
702 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
704 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
707 mii
.dwTypeData
= UnicodeString
.Buffer
;
708 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
712 TRACE("AMA Handle bitmaps\n");
714 ////// Answer a question, why a -1? To hunt for the end of the item list. Get it, to Append?
715 res
= NtUserThunkedMenuItemInfo(hMenu
, -1, TRUE
, TRUE
, &mii
, &UnicodeString
);
716 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
724 AppendMenuW(HMENU hMenu
,
730 UNICODE_STRING MenuText
;
733 RtlInitUnicodeString(&MenuText
, 0);
735 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
737 /* copy the text string, it will be one or the other */
738 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
740 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
741 mii
.dwTypeData
= MenuText
.Buffer
;
742 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
744 res
= NtUserThunkedMenuItemInfo(hMenu
, -1, TRUE
, TRUE
, &mii
, &MenuText
);
752 CheckMenuItem(HMENU hmenu
,
758 UINT uID
= uIDCheckItem
;
760 if (!ValidateHandle(hmenu
, TYPE_MENU
))
763 if (!(item
= MENU_FindItem( &hmenu
, &uID
, uCheck
))) return -1;
765 Ret
= item
->fState
& MFS_CHECKED
;
766 if ( Ret
== (uCheck
& MFS_CHECKED
)) return Ret
; // Already Checked...
768 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
775 CheckMenuRadioItem(HMENU hMenu
,
783 PITEM mi_first
= NULL
, mi_check
;
784 HMENU m_first
, m_check
;
786 mii
.cbSize
= sizeof( mii
);
788 for (i
= first
; i
<= last
; i
++)
795 mi_first
= MENU_FindItem(&m_first
, &pos
, bypos
);
796 if (!mi_first
) continue;
803 mi_check
= MENU_FindItem(&m_check
, &pos
, bypos
);
804 if (!mi_check
) continue;
807 if (m_first
!= m_check
) continue;
808 if (mi_check
->fType
== MFT_SEPARATOR
) continue;
812 if (!(mi_check
->fType
& MFT_RADIOCHECK
) || !(mi_check
->fState
& MFS_CHECKED
))
814 mii
.fMask
= MIIM_FTYPE
| MIIM_STATE
;
815 mii
.fType
= (mi_check
->fType
& MENUITEMINFO_TYPE_MASK
) | MFT_RADIOCHECK
;
816 mii
.fState
= (mi_check
->fState
& MII_STATE_MASK
) | MFS_CHECKED
;
817 NtUserThunkedMenuItemInfo(m_check
, i
, bypos
, FALSE
, &mii
, NULL
);
823 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
824 if (mi_check
->fState
& MFS_CHECKED
)
826 mii
.fMask
= MIIM_STATE
;
827 mii
.fState
= (mi_check
->fState
& MII_STATE_MASK
) & ~MFS_CHECKED
;
828 NtUserThunkedMenuItemInfo(m_check
, i
, bypos
, FALSE
, &mii
, NULL
);
841 return NtUserxCreateMenu();
848 CreatePopupMenu(VOID
)
850 return NtUserxCreatePopupMenu();
857 DrawMenuBar(HWND hWnd
)
859 return NtUserxDrawMenuBar(hWnd
);
866 EnableMenuItem(HMENU hMenu
,
870 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
879 PWND Wnd
= ValidateHwnd(hWnd
);
884 return UlongToHandle(Wnd
->IDMenu
);
891 GetMenuCheckMarkDimensions(VOID
)
893 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
894 GetSystemMetrics(SM_CYMENUCHECK
)));
902 GetMenuContextHelpId(HMENU hmenu
)
905 if ((pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
906 return pMenu
->dwContextHelpId
;
914 GetMenuDefaultItem(HMENU hMenu
,
920 if (!(pMenu
= ValidateHandle(hMenu
, TYPE_MENU
)))
923 return IntGetMenuDefaultItem( pMenu
, (BOOL
)fByPos
, gmdiFlags
, &gismc
);
930 GetMenuInfo(HMENU hmenu
,
935 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
937 SetLastError(ERROR_INVALID_PARAMETER
);
941 if (!(pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
944 if (lpcmi
->fMask
& MIM_BACKGROUND
)
945 lpcmi
->hbrBack
= pMenu
->hbrBack
;
947 if (lpcmi
->fMask
& MIM_HELPID
)
948 lpcmi
->dwContextHelpID
= pMenu
->dwContextHelpId
;
950 if (lpcmi
->fMask
& MIM_MAXHEIGHT
)
951 lpcmi
->cyMax
= pMenu
->cyMax
;
953 if (lpcmi
->fMask
& MIM_MENUDATA
)
954 lpcmi
->dwMenuData
= pMenu
->dwMenuData
;
956 if (lpcmi
->fMask
& MIM_STYLE
)
957 lpcmi
->dwStyle
= pMenu
->fFlags
& MNS_STYLE_MASK
;
966 GetMenuItemCount(HMENU hmenu
)
969 if ((pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
970 return pMenu
->cItems
;
978 GetMenuItemID(HMENU hMenu
,
982 if (!(lpmi
= MENU_FindItem(&hMenu
,(UINT
*)&nPos
,MF_BYPOSITION
))) return -1;
983 if (lpmi
->spSubMenu
) return -1;
995 LPMENUITEMINFOA lpmii
)
1000 if( lpmii
->cbSize
!= sizeof( mii
) &&
1001 lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
))
1003 SetLastError( ERROR_INVALID_PARAMETER
);
1006 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
1007 mii
.cbSize
= sizeof( mii
);
1008 ret
= GetMenuItemInfo_common (hmenu
,
1011 (LPMENUITEMINFOW
)&mii
,
1013 mii
.cbSize
= lpmii
->cbSize
;
1014 memcpy( lpmii
, &mii
, mii
.cbSize
);
1026 LPMENUITEMINFOW lpmii
)
1030 if( lpmii
->cbSize
!= sizeof( mii
) && lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
))
1032 SetLastError( ERROR_INVALID_PARAMETER
);
1035 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
1036 mii
.cbSize
= sizeof( mii
);
1037 ret
= GetMenuItemInfo_common (hMenu
, Item
, bypos
, &mii
, TRUE
);
1038 mii
.cbSize
= lpmii
->cbSize
;
1039 memcpy( lpmii
, &mii
, mii
.cbSize
);
1055 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu
, uId
, uFlags
);
1056 if (!(pItem
= MENU_FindItem( &hMenu
, &uId
, uFlags
))) return -1;
1058 if (!pItem
->Xlpstr
&& pItem
->hbmp
) Type
= MFT_BITMAP
;
1060 if (pItem
->spSubMenu
)
1062 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
1063 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
1064 if (!IsMenu(hsubmenu
)) return (UINT
)-1;
1065 else return (pSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|Type
) & 0xff);
1068 return (pItem
->fType
| pItem
->fState
| Type
);
1085 ////// wine Code, seems to be faster.
1086 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, uIDItem
, lpString
, nMaxCount
, uFlag
);
1088 if (lpString
&& nMaxCount
) lpString
[0] = '\0';
1090 if (!(item
= MENU_FindItem( &hMenu
, &uIDItem
, uFlag
)))
1092 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
1096 text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
1098 if (!text
) return 0;
1099 if (!lpString
|| !nMaxCount
) return WideCharToMultiByte( CP_ACP
, 0, text
, -1, NULL
, 0, NULL
, NULL
);
1100 if (!WideCharToMultiByte( CP_ACP
, 0, text
, -1, lpString
, nMaxCount
, NULL
, NULL
))
1101 lpString
[nMaxCount
-1] = 0;
1102 TRACE("A returning %s\n", lpString
);
1103 return strlen(lpString
);
1121 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, uIDItem
, lpString
, nMaxCount
, uFlag
);
1123 if (lpString
&& nMaxCount
) lpString
[0] = '\0';
1125 if (!(item
= MENU_FindItem( &hMenu
, &uIDItem
, uFlag
)))
1127 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
1131 text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
1133 if (!lpString
|| !nMaxCount
) return text
? strlenW(text
) : 0;
1139 lstrcpynW( lpString
, text
, nMaxCount
);
1140 TRACE("W returning %S\n", lpString
);
1141 return strlenW(lpString
);
1154 if (!(pItem
= MENU_FindItem( &hMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
1156 if (pItem
->spSubMenu
)
1158 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
1159 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
1160 if (IsMenu(hsubmenu
)) return hsubmenu
;
1170 GetSystemMenu(HWND hWnd
, BOOL bRevert
)
1172 return NtUserGetSystemMenu(hWnd
, bRevert
);
1184 UINT_PTR uIDNewItem
,
1188 UNICODE_STRING UnicodeString
;
1191 RtlInitUnicodeString(&UnicodeString
, 0);
1193 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
1195 /* copy the text string, it will be one or the other */
1196 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
1198 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
1200 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
1203 mii
.dwTypeData
= UnicodeString
.Buffer
;
1204 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
1208 TRACE("Handle bitmaps\n");
1210 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), TRUE
, &mii
, &UnicodeString
);
1211 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
1224 LPCMENUITEMINFOA lpmii
)
1227 UNICODE_STRING UnicodeString
;
1230 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
1232 RtlInitUnicodeString(&UnicodeString
, 0);
1234 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
1236 /* copy the text string */
1237 if (((mii
.fMask
& MIIM_STRING
) ||
1238 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
1239 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
1241 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
1243 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
1246 mii
.dwTypeData
= UnicodeString
.Buffer
;
1247 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
1251 TRACE("Handle bitmaps\n");
1253 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mii
, &UnicodeString
);
1254 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
1267 LPCMENUITEMINFOW lpmii
)
1270 UNICODE_STRING MenuText
;
1273 /* while we could just pass 'lpmii' to win32k, we make a copy so that
1274 if a bad user passes bad data, we crash his process instead of the
1277 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
1279 RtlInitUnicodeString(&MenuText
, 0);
1281 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
1283 /* copy the text string */
1284 if (((mii
.fMask
& MIIM_STRING
) ||
1285 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
1286 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
1288 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
1289 mii
.dwTypeData
= MenuText
.Buffer
;
1290 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
1292 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mii
, &MenuText
);
1305 UINT_PTR uIDNewItem
,
1309 UNICODE_STRING MenuText
;
1312 RtlInitUnicodeString(&MenuText
, 0);
1314 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
1316 /* copy the text string, it will be one or the other */
1317 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
1319 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
1320 mii
.dwTypeData
= MenuText
.Buffer
;
1321 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
1323 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), TRUE
, &mii
, &MenuText
);
1335 if (ValidateHandle(Menu
, TYPE_MENU
)) return TRUE
;
1343 LoadMenuA(HINSTANCE hInstance
,
1346 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
1347 if (Resource
== NULL
)
1351 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
1358 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
1360 return(LoadMenuIndirectW(lpMenuTemplate
));
1367 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
1370 WORD version
, offset
;
1371 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
1373 version
= GET_WORD(p
);
1378 case 0: /* standard format is version of 0 */
1379 offset
= GET_WORD(p
);
1380 p
+= sizeof(WORD
) + offset
;
1381 if (!(hMenu
= CreateMenu())) return 0;
1382 if (!MENU_ParseResource(p
, hMenu
))
1388 case 1: /* extended format is version of 1 */
1389 offset
= GET_WORD(p
);
1390 p
+= sizeof(WORD
) + offset
;
1391 if (!(hMenu
= CreateMenu())) return 0;
1392 if (!MENUEX_ParseResource(p
, hMenu
))
1394 DestroyMenu( hMenu
);
1399 ERR("Menu template version %d not supported.\n", version
);
1408 LoadMenuW(HINSTANCE hInstance
,
1411 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
1412 if (Resource
== NULL
)
1416 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
1428 UINT_PTR uIDNewItem
,
1432 UNICODE_STRING UnicodeString
;
1435 RtlInitUnicodeString(&UnicodeString
, 0);
1437 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
1439 /* copy the text string, it will be one or the other */
1440 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
1442 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
1444 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
1447 mii
.dwTypeData
= UnicodeString
.Buffer
;
1448 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
1452 TRACE("Handle bitmaps\n");
1454 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), FALSE
, &mii
, &UnicodeString
);
1455 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
1468 UINT_PTR uIDNewItem
,
1472 UNICODE_STRING MenuText
;
1475 RtlInitUnicodeString(&MenuText
, 0);
1477 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
1479 /* copy the text string, it will be one or the other */
1480 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
1482 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
1483 mii
.dwTypeData
= MenuText
.Buffer
;
1484 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
1488 TRACE("Handle bitmaps\n");
1490 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), FALSE
, &mii
, &MenuText
);
1501 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
1516 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
1518 SetLastError(ERROR_INVALID_PARAMETER
);
1522 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
1523 return NtUserThunkedMenuInfo(hmenu
, (LPCMENUINFO
)&mi
);
1535 HBITMAP hBitmapUnchecked
,
1536 HBITMAP hBitmapChecked
)
1538 MENUITEMINFOW uItem
;
1539 memset ( &uItem
, 0, sizeof(uItem
) );
1540 uItem
.cbSize
= sizeof(MENUITEMINFOW
);
1541 uItem
.fMask
= MIIM_CHECKMARKS
;
1542 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
1543 uItem
.hbmpChecked
= hBitmapChecked
;
1544 return SetMenuItemInfoW(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), &uItem
);
1556 LPCMENUITEMINFOA lpmii
)
1559 UNICODE_STRING UnicodeString
;
1562 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu
, item
, bypos
, lpmii
);
1564 RtlInitUnicodeString(&UnicodeString
, 0);
1566 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
1568 * MIIM_STRING == good
1569 * MIIM_TYPE & MFT_STRING == good
1570 * MIIM_STRING & MFT_STRING == good
1571 * MIIM_STRING & MFT_OWNERDRAW == good
1573 if (((mii
.fMask
& MIIM_STRING
) ||
1574 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
1575 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
1577 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
1578 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
1580 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
1583 mii
.dwTypeData
= UnicodeString
.Buffer
;
1584 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
1588 UnicodeString
.Buffer
= NULL
;
1590 Ret
= NtUserThunkedMenuItemInfo(hmenu
, item
, bypos
, FALSE
, &mii
, &UnicodeString
);
1591 if (UnicodeString
.Buffer
!= NULL
) RtlFreeUnicodeString(&UnicodeString
);
1604 LPCMENUITEMINFOW lpmii
)
1606 MENUITEMINFOW MenuItemInfoW
;
1607 UNICODE_STRING UnicodeString
;
1610 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
1612 RtlInitUnicodeString(&UnicodeString
, 0);
1614 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &MenuItemInfoW
)) return FALSE
;
1616 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
1617 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
1618 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
1619 && MenuItemInfoW
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)MenuItemInfoW
.dwTypeData
)) )
1621 RtlInitUnicodeString(&UnicodeString
, (PCWSTR
)MenuItemInfoW
.dwTypeData
);
1622 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
1624 Ret
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, FALSE
, &MenuItemInfoW
, &UnicodeString
);
1640 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
1645 SetLastError(ERROR_INVALID_MENU_HANDLE
);
1648 return NtUserSetSystemMenu(hwnd
, hMenu
);
1662 return NtUserTrackPopupMenuEx( Menu
,
1667 NULL
); // LPTPMPARAMS is null
1685 return PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
1687 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
1705 return PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
1707 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
1718 LPCWSTR lpszNewItem
,
1723 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
1724 for MF_DELETE. We should check the parameters for all others
1725 MF_* actions also (anybody got a doc on ChangeMenu?).
1728 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
1731 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
1734 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
1737 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
1740 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
1741 flags
&~ MF_REMOVE
);
1743 default : /* MF_INSERT */
1744 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
1761 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
1762 for MF_DELETE. We should check the parameters for all others
1763 MF_* actions also (anybody got a doc on ChangeMenu?).
1766 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
1769 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
1772 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
1775 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
1778 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
1779 flags
&~ MF_REMOVE
);
1781 default : /* MF_INSERT */
1782 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);