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 ( (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
;
512 mii
.fType
|= MF_POPUP
;
514 else if (!mii
.dwTypeData
[0] && !(mii
.fType
& MF_SEPARATOR
))
516 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
518 mii
.fType
|= MF_SEPARATOR
;
520 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
521 } while (!(resinfo
& MF_END
));
526 /**********************************************************************
529 * Uses flags, id and text ptr, passed by InsertMenu() and
530 * ModifyMenu() to setup a MenuItemInfo structure.
532 static void MENU_mnu2mnuii( UINT flags
, UINT_PTR id
, LPCWSTR str
, LPMENUITEMINFOW pmii
, BOOL Unicode
)
534 RtlZeroMemory( pmii
, sizeof( MENUITEMINFOW
));
535 pmii
->cbSize
= sizeof( MENUITEMINFOW
);
536 pmii
->fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
537 /* setting bitmap clears text and vice versa */
538 if( IS_STRING_ITEM(flags
)) {
539 pmii
->fMask
|= MIIM_STRING
| MIIM_BITMAP
;
541 flags
|= MF_SEPARATOR
;
542 /* Item beginning with a backspace is a help item */
543 /* FIXME: wrong place, this is only true in win16 */
556 LPCSTR NewItemA
= (LPCSTR
) str
;
557 if (*NewItemA
== '\b')
561 str
= (LPCWSTR
) NewItemA
;
563 TRACE("A cch %d\n",strlen(NewItemA
));
566 pmii
->dwTypeData
= (LPWSTR
)str
;
567 } else if( flags
& MFT_BITMAP
){
568 pmii
->fMask
|= MIIM_BITMAP
| MIIM_STRING
;
569 pmii
->hbmpItem
= (HBITMAP
)str
;
571 if( flags
& MF_OWNERDRAW
){
572 pmii
->fMask
|= MIIM_DATA
;
573 pmii
->dwItemData
= (ULONG_PTR
) str
;
575 if( flags
& MF_POPUP
&& MENU_GetMenu((HMENU
)id
)) {
576 pmii
->fMask
|= MIIM_SUBMENU
;
577 pmii
->hSubMenu
= (HMENU
)id
;
579 if( flags
& MF_SEPARATOR
) flags
|= MF_GRAYED
| MF_DISABLED
;
580 pmii
->fState
= flags
& MENUITEMINFO_STATE_MASK
& ~MFS_DEFAULT
;
581 pmii
->fType
= flags
& MENUITEMINFO_TYPE_MASK
;
582 pmii
->wID
= (UINT
)id
;
585 /**********************************************************************
586 * MENU_NormalizeMenuItemInfoStruct
588 * Helper for SetMenuItemInfo and InsertMenuItemInfo:
589 * check, copy and extend the MENUITEMINFO struct from the version that the application
590 * supplied to the version used by wine source. */
591 static BOOL
MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW
*pmii_in
,
592 MENUITEMINFOW
*pmii_out
)
594 /* do we recognize the size? */
595 if( !pmii_in
|| (pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) &&
596 pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) - sizeof( pmii_in
->hbmpItem
)) ) {
597 SetLastError( ERROR_INVALID_PARAMETER
);
600 /* copy the fields that we have */
601 memcpy( pmii_out
, pmii_in
, pmii_in
->cbSize
);
602 /* if the hbmpItem member is missing then extend */
603 if( pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
)) {
604 pmii_out
->cbSize
= sizeof( MENUITEMINFOW
);
605 pmii_out
->hbmpItem
= NULL
;
607 /* test for invalid bit combinations */
608 if( (pmii_out
->fMask
& MIIM_TYPE
&&
609 pmii_out
->fMask
& (MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
)) ||
610 (pmii_out
->fMask
& MIIM_FTYPE
&& pmii_out
->fType
& MFT_BITMAP
)) {
611 ERR("invalid combination of fMask bits used\n");
612 /* this does not happen on Win9x/ME */
613 SetLastError( ERROR_INVALID_PARAMETER
);
616 /* convert old style (MIIM_TYPE) to the new and keep the old one too */
617 if( pmii_out
->fMask
& MIIM_TYPE
){
618 pmii_out
->fMask
|= MIIM_FTYPE
;
619 if( IS_STRING_ITEM(pmii_out
->fType
)){
620 pmii_out
->fMask
|= MIIM_STRING
;
621 } else if( (pmii_out
->fType
) & MFT_BITMAP
){
622 pmii_out
->fMask
|= MIIM_BITMAP
;
623 pmii_out
->hbmpItem
= UlongToHandle(LOWORD(pmii_out
->dwTypeData
));
626 if (pmii_out
->fMask
& MIIM_FTYPE
)
628 pmii_out
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
629 pmii_out
->fType
|= pmii_in
->fType
& MENUITEMINFO_TYPE_MASK
;
631 if (pmii_out
->fMask
& MIIM_STATE
)
632 /* Other menu items having MFS_DEFAULT are not converted
634 pmii_out
->fState
= pmii_in
->fState
& MENUITEMINFO_STATE_MASK
;
636 if (pmii_out
->fMask
& MIIM_SUBMENU
)
638 if ((pmii_out
->hSubMenu
!= NULL
) && !IsMenu(pmii_out
->hSubMenu
))
658 User32LoadSysMenuTemplateForKernel(PVOID Arguments
, ULONG ArgumentLength
)
662 // Use this for Menu Ole!!
664 return(ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
));
668 User32CallLoadMenuFromKernel(PVOID Arguments
, ULONG ArgumentLength
)
670 PLOADMENU_CALLBACK_ARGUMENTS Common
;
673 Common
= (PLOADMENU_CALLBACK_ARGUMENTS
) Arguments
;
675 Result
= (LRESULT
)LoadMenuW( Common
->hModule
, Common
->InterSource
? MAKEINTRESOURCE(Common
->InterSource
) : (LPCWSTR
)&Common
->MenuName
);
677 return ZwCallbackReturn(&Result
, sizeof(LRESULT
), STATUS_SUCCESS
);
681 /* FUNCTIONS *****************************************************************/
687 AppendMenuA(HMENU hMenu
,
693 UNICODE_STRING UnicodeString
;
696 RtlInitUnicodeString(&UnicodeString
, 0);
698 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
700 /* copy the text string, it will be one or the other */
701 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
703 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
705 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
708 mii
.dwTypeData
= UnicodeString
.Buffer
;
709 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
713 TRACE("AMA Handle bitmaps\n");
715 ////// Answer a question, why a -1? To hunt for the end of the item list. Get it, to Append?
716 res
= NtUserThunkedMenuItemInfo(hMenu
, -1, TRUE
, TRUE
, &mii
, &UnicodeString
);
717 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
725 AppendMenuW(HMENU hMenu
,
731 UNICODE_STRING MenuText
;
734 RtlInitUnicodeString(&MenuText
, 0);
736 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
738 /* copy the text string, it will be one or the other */
739 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
741 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
742 mii
.dwTypeData
= MenuText
.Buffer
;
743 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
745 res
= NtUserThunkedMenuItemInfo(hMenu
, -1, TRUE
, TRUE
, &mii
, &MenuText
);
753 CheckMenuItem(HMENU hmenu
,
759 UINT uID
= uIDCheckItem
;
761 if (!ValidateHandle(hmenu
, TYPE_MENU
))
764 if (!(item
= MENU_FindItem( &hmenu
, &uID
, uCheck
))) return -1;
766 Ret
= item
->fState
& MFS_CHECKED
;
767 if ( Ret
== (uCheck
& MFS_CHECKED
)) return Ret
; // Already Checked...
769 return NtUserCheckMenuItem(hmenu
, uIDCheckItem
, uCheck
);
776 CheckMenuRadioItem(HMENU hMenu
,
784 PITEM mi_first
= NULL
, mi_check
;
785 HMENU m_first
, m_check
;
787 mii
.cbSize
= sizeof( mii
);
789 for (i
= first
; i
<= last
; i
++)
796 mi_first
= MENU_FindItem(&m_first
, &pos
, bypos
);
797 if (!mi_first
) continue;
804 mi_check
= MENU_FindItem(&m_check
, &pos
, bypos
);
805 if (!mi_check
) continue;
808 if (m_first
!= m_check
) continue;
809 if (mi_check
->fType
== MFT_SEPARATOR
) continue;
813 if (!(mi_check
->fType
& MFT_RADIOCHECK
) || !(mi_check
->fState
& MFS_CHECKED
))
815 mii
.fMask
= MIIM_FTYPE
| MIIM_STATE
;
816 mii
.fType
= (mi_check
->fType
& MENUITEMINFO_TYPE_MASK
) | MFT_RADIOCHECK
;
817 mii
.fState
= (mi_check
->fState
& MII_STATE_MASK
) | MFS_CHECKED
;
818 NtUserThunkedMenuItemInfo(m_check
, i
, bypos
, FALSE
, &mii
, NULL
);
824 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
825 if (mi_check
->fState
& MFS_CHECKED
)
827 mii
.fMask
= MIIM_STATE
;
828 mii
.fState
= (mi_check
->fState
& MII_STATE_MASK
) & ~MFS_CHECKED
;
829 NtUserThunkedMenuItemInfo(m_check
, i
, bypos
, FALSE
, &mii
, NULL
);
842 return NtUserxCreateMenu();
849 CreatePopupMenu(VOID
)
851 return NtUserxCreatePopupMenu();
858 DrawMenuBar(HWND hWnd
)
860 return NtUserxDrawMenuBar(hWnd
);
867 EnableMenuItem(HMENU hMenu
,
871 return NtUserEnableMenuItem(hMenu
, uIDEnableItem
, uEnable
);
880 PWND Wnd
= ValidateHwnd(hWnd
);
885 return UlongToHandle(Wnd
->IDMenu
);
892 GetMenuCheckMarkDimensions(VOID
)
894 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK
),
895 GetSystemMetrics(SM_CYMENUCHECK
)));
903 GetMenuContextHelpId(HMENU hmenu
)
906 if ((pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
907 return pMenu
->dwContextHelpId
;
915 GetMenuDefaultItem(HMENU hMenu
,
921 if (!(pMenu
= ValidateHandle(hMenu
, TYPE_MENU
)))
924 return IntGetMenuDefaultItem( pMenu
, (BOOL
)fByPos
, gmdiFlags
, &gismc
);
931 GetMenuInfo(HMENU hmenu
,
936 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
938 SetLastError(ERROR_INVALID_PARAMETER
);
942 if (!(pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
945 if (lpcmi
->fMask
& MIM_BACKGROUND
)
946 lpcmi
->hbrBack
= pMenu
->hbrBack
;
948 if (lpcmi
->fMask
& MIM_HELPID
)
949 lpcmi
->dwContextHelpID
= pMenu
->dwContextHelpId
;
951 if (lpcmi
->fMask
& MIM_MAXHEIGHT
)
952 lpcmi
->cyMax
= pMenu
->cyMax
;
954 if (lpcmi
->fMask
& MIM_MENUDATA
)
955 lpcmi
->dwMenuData
= pMenu
->dwMenuData
;
957 if (lpcmi
->fMask
& MIM_STYLE
)
958 lpcmi
->dwStyle
= pMenu
->fFlags
& MNS_STYLE_MASK
;
967 GetMenuItemCount(HMENU hmenu
)
970 if ((pMenu
= ValidateHandle(hmenu
, TYPE_MENU
)))
971 return pMenu
->cItems
;
979 GetMenuItemID(HMENU hMenu
,
983 if (!(lpmi
= MENU_FindItem(&hMenu
,(UINT
*)&nPos
,MF_BYPOSITION
))) return -1;
984 if (lpmi
->spSubMenu
) return -1;
996 LPMENUITEMINFOA lpmii
)
1001 if( lpmii
->cbSize
!= sizeof( mii
) &&
1002 lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
))
1004 SetLastError( ERROR_INVALID_PARAMETER
);
1007 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
1008 mii
.cbSize
= sizeof( mii
);
1009 ret
= GetMenuItemInfo_common (hmenu
,
1012 (LPMENUITEMINFOW
)&mii
,
1014 mii
.cbSize
= lpmii
->cbSize
;
1015 memcpy( lpmii
, &mii
, mii
.cbSize
);
1027 LPMENUITEMINFOW lpmii
)
1031 if( lpmii
->cbSize
!= sizeof( mii
) && lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
))
1033 SetLastError( ERROR_INVALID_PARAMETER
);
1036 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
1037 mii
.cbSize
= sizeof( mii
);
1038 ret
= GetMenuItemInfo_common (hMenu
, Item
, bypos
, &mii
, TRUE
);
1039 mii
.cbSize
= lpmii
->cbSize
;
1040 memcpy( lpmii
, &mii
, mii
.cbSize
);
1056 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu
, uId
, uFlags
);
1057 if (!(pItem
= MENU_FindItem( &hMenu
, &uId
, uFlags
))) return -1;
1059 if (!pItem
->Xlpstr
&& pItem
->hbmp
) Type
= MFT_BITMAP
;
1061 if (pItem
->spSubMenu
)
1063 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
1064 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
1065 Type
|= MF_POPUP
; // Fix CORE-9269
1066 if (!IsMenu(hsubmenu
)) return (UINT
)-1;
1067 else return (pSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
|Type
) & 0xff);
1070 return (pItem
->fType
| pItem
->fState
| Type
);
1087 ////// wine Code, seems to be faster.
1088 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, uIDItem
, lpString
, nMaxCount
, uFlag
);
1090 if (lpString
&& nMaxCount
) lpString
[0] = '\0';
1092 if (!(item
= MENU_FindItem( &hMenu
, &uIDItem
, uFlag
)))
1094 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
1098 text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
1100 if (!text
) return 0;
1101 if (!lpString
|| !nMaxCount
) return WideCharToMultiByte( CP_ACP
, 0, text
, -1, NULL
, 0, NULL
, NULL
);
1102 if (!WideCharToMultiByte( CP_ACP
, 0, text
, -1, lpString
, nMaxCount
, NULL
, NULL
))
1103 lpString
[nMaxCount
-1] = 0;
1104 TRACE("A returning %s\n", lpString
);
1105 return strlen(lpString
);
1123 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu
, uIDItem
, lpString
, nMaxCount
, uFlag
);
1125 if (lpString
&& nMaxCount
) lpString
[0] = '\0';
1127 if (!(item
= MENU_FindItem( &hMenu
, &uIDItem
, uFlag
)))
1129 SetLastError( ERROR_MENU_ITEM_NOT_FOUND
);
1133 text
= item
->Xlpstr
? DesktopPtrToUser(item
->Xlpstr
) : NULL
;
1135 if (!lpString
|| !nMaxCount
) return text
? strlenW(text
) : 0;
1141 lstrcpynW( lpString
, text
, nMaxCount
);
1142 TRACE("W returning %S\n", lpString
);
1143 return strlenW(lpString
);
1156 if (!(pItem
= MENU_FindItem( &hMenu
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
1158 if (pItem
->spSubMenu
)
1160 PMENU pSubMenu
= DesktopPtrToUser(pItem
->spSubMenu
);
1161 HMENU hsubmenu
= UserHMGetHandle(pSubMenu
);
1162 if (IsMenu(hsubmenu
)) return hsubmenu
;
1172 GetSystemMenu(HWND hWnd
, BOOL bRevert
)
1174 return NtUserGetSystemMenu(hWnd
, bRevert
);
1186 UINT_PTR uIDNewItem
,
1190 UNICODE_STRING UnicodeString
;
1193 RtlInitUnicodeString(&UnicodeString
, 0);
1195 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
1197 /* copy the text string, it will be one or the other */
1198 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
1200 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
1202 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
1205 mii
.dwTypeData
= UnicodeString
.Buffer
;
1206 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
1210 TRACE("Handle bitmaps\n");
1212 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), TRUE
, &mii
, &UnicodeString
);
1213 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
1226 LPCMENUITEMINFOA lpmii
)
1229 UNICODE_STRING UnicodeString
;
1232 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
1234 RtlInitUnicodeString(&UnicodeString
, 0);
1236 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
1238 /* copy the text string */
1239 if (((mii
.fMask
& MIIM_STRING
) ||
1240 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
1241 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
1243 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
1245 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
1248 mii
.dwTypeData
= UnicodeString
.Buffer
;
1249 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
1253 TRACE("Handle bitmaps\n");
1255 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mii
, &UnicodeString
);
1256 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
1269 LPCMENUITEMINFOW lpmii
)
1272 UNICODE_STRING MenuText
;
1275 /* while we could just pass 'lpmii' to win32k, we make a copy so that
1276 if a bad user passes bad data, we crash his process instead of the
1279 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
1281 RtlInitUnicodeString(&MenuText
, 0);
1283 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
1285 /* copy the text string */
1286 if (((mii
.fMask
& MIIM_STRING
) ||
1287 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
1288 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
1290 RtlInitUnicodeString(&MenuText
, (PWSTR
)lpmii
->dwTypeData
);
1291 mii
.dwTypeData
= MenuText
.Buffer
;
1292 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
1294 res
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, TRUE
, &mii
, &MenuText
);
1307 UINT_PTR uIDNewItem
,
1311 UNICODE_STRING MenuText
;
1314 RtlInitUnicodeString(&MenuText
, 0);
1316 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
1318 /* copy the text string, it will be one or the other */
1319 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
1321 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
1322 mii
.dwTypeData
= MenuText
.Buffer
;
1323 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
1325 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), TRUE
, &mii
, &MenuText
);
1337 if (ValidateHandle(Menu
, TYPE_MENU
)) return TRUE
;
1345 LoadMenuA(HINSTANCE hInstance
,
1348 HANDLE Resource
= FindResourceA(hInstance
, lpMenuName
, MAKEINTRESOURCEA(4));
1349 if (Resource
== NULL
)
1353 return(LoadMenuIndirectA((PVOID
)LoadResource(hInstance
, Resource
)));
1360 LoadMenuIndirectA(CONST MENUTEMPLATE
*lpMenuTemplate
)
1362 return(LoadMenuIndirectW(lpMenuTemplate
));
1369 LoadMenuIndirectW(CONST MENUTEMPLATE
*lpMenuTemplate
)
1372 WORD version
, offset
;
1373 LPCSTR p
= (LPCSTR
)lpMenuTemplate
;
1375 version
= GET_WORD(p
);
1380 case 0: /* standard format is version of 0 */
1381 offset
= GET_WORD(p
);
1382 p
+= sizeof(WORD
) + offset
;
1383 if (!(hMenu
= CreateMenu())) return 0;
1384 if (!MENU_ParseResource(p
, hMenu
))
1390 case 1: /* extended format is version of 1 */
1391 offset
= GET_WORD(p
);
1392 p
+= sizeof(WORD
) + offset
;
1393 if (!(hMenu
= CreateMenu())) return 0;
1394 if (!MENUEX_ParseResource(p
, hMenu
))
1396 DestroyMenu( hMenu
);
1401 ERR("Menu template version %d not supported.\n", version
);
1410 LoadMenuW(HINSTANCE hInstance
,
1413 HANDLE Resource
= FindResourceW(hInstance
, lpMenuName
, RT_MENU
);
1414 if (Resource
== NULL
)
1418 return(LoadMenuIndirectW((PVOID
)LoadResource(hInstance
, Resource
)));
1430 UINT_PTR uIDNewItem
,
1434 UNICODE_STRING UnicodeString
;
1437 RtlInitUnicodeString(&UnicodeString
, 0);
1439 MENU_mnu2mnuii( uFlags
, uIDNewItem
, (LPCWSTR
)lpNewItem
, &mii
, FALSE
);
1441 /* copy the text string, it will be one or the other */
1442 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
1444 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
1446 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
1449 mii
.dwTypeData
= UnicodeString
.Buffer
;
1450 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
1454 TRACE("Handle bitmaps\n");
1456 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), FALSE
, &mii
, &UnicodeString
);
1457 if ( UnicodeString
.Buffer
) RtlFreeUnicodeString ( &UnicodeString
);
1470 UINT_PTR uIDNewItem
,
1474 UNICODE_STRING MenuText
;
1477 RtlInitUnicodeString(&MenuText
, 0);
1479 MENU_mnu2mnuii( uFlags
, uIDNewItem
, lpNewItem
, &mii
, TRUE
);
1481 /* copy the text string, it will be one or the other */
1482 if (lpNewItem
&& mii
.fMask
& MIIM_STRING
&& !mii
.hbmpItem
&& mii
.dwTypeData
)
1484 RtlInitUnicodeString(&MenuText
, (PWSTR
)mii
.dwTypeData
);
1485 mii
.dwTypeData
= MenuText
.Buffer
;
1486 mii
.cch
= MenuText
.Length
/ sizeof(WCHAR
);
1490 TRACE("Handle bitmaps\n");
1492 res
= NtUserThunkedMenuItemInfo(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), FALSE
, &mii
, &MenuText
);
1503 return NtUserSetMenu(hWnd
, hMenu
, TRUE
);
1518 if (!lpcmi
|| (lpcmi
->cbSize
!= sizeof(MENUINFO
)))
1520 SetLastError(ERROR_INVALID_PARAMETER
);
1524 memcpy(&mi
, lpcmi
, sizeof(MENUINFO
));
1525 return NtUserThunkedMenuInfo(hmenu
, (LPCMENUINFO
)&mi
);
1537 HBITMAP hBitmapUnchecked
,
1538 HBITMAP hBitmapChecked
)
1540 MENUITEMINFOW uItem
;
1541 memset ( &uItem
, 0, sizeof(uItem
) );
1542 uItem
.cbSize
= sizeof(MENUITEMINFOW
);
1543 uItem
.fMask
= MIIM_CHECKMARKS
;
1544 uItem
.hbmpUnchecked
= hBitmapUnchecked
;
1545 uItem
.hbmpChecked
= hBitmapChecked
;
1546 return SetMenuItemInfoW(hMenu
, uPosition
, (BOOL
)(uFlags
& MF_BYPOSITION
), &uItem
);
1558 LPCMENUITEMINFOA lpmii
)
1561 UNICODE_STRING UnicodeString
;
1564 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu
, item
, bypos
, lpmii
);
1566 RtlInitUnicodeString(&UnicodeString
, 0);
1568 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
1570 * MIIM_STRING == good
1571 * MIIM_TYPE & MFT_STRING == good
1572 * MIIM_STRING & MFT_STRING == good
1573 * MIIM_STRING & MFT_OWNERDRAW == good
1575 if (((mii
.fMask
& MIIM_STRING
) ||
1576 ((mii
.fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(mii
.fType
) == MF_STRING
)))
1577 && mii
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)mii
.dwTypeData
)) )
1579 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
1580 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString
, (LPSTR
)mii
.dwTypeData
))
1582 SetLastError (ERROR_NOT_ENOUGH_MEMORY
);
1585 mii
.dwTypeData
= UnicodeString
.Buffer
;
1586 mii
.cch
= UnicodeString
.Length
/ sizeof(WCHAR
);
1590 UnicodeString
.Buffer
= NULL
;
1592 Ret
= NtUserThunkedMenuItemInfo(hmenu
, item
, bypos
, FALSE
, &mii
, &UnicodeString
);
1593 if (UnicodeString
.Buffer
!= NULL
) RtlFreeUnicodeString(&UnicodeString
);
1606 LPCMENUITEMINFOW lpmii
)
1608 MENUITEMINFOW MenuItemInfoW
;
1609 UNICODE_STRING UnicodeString
;
1612 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hMenu
, uItem
, fByPosition
, lpmii
);
1614 RtlInitUnicodeString(&UnicodeString
, 0);
1616 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &MenuItemInfoW
)) return FALSE
;
1618 if (((MenuItemInfoW
.fMask
& MIIM_STRING
) ||
1619 ((MenuItemInfoW
.fMask
& MIIM_TYPE
) &&
1620 (MENU_ITEM_TYPE(MenuItemInfoW
.fType
) == MF_STRING
)))
1621 && MenuItemInfoW
.dwTypeData
&& !(GdiValidateHandle((HGDIOBJ
)MenuItemInfoW
.dwTypeData
)) )
1623 RtlInitUnicodeString(&UnicodeString
, (PCWSTR
)MenuItemInfoW
.dwTypeData
);
1624 MenuItemInfoW
.cch
= strlenW(MenuItemInfoW
.dwTypeData
);
1626 Ret
= NtUserThunkedMenuItemInfo(hMenu
, uItem
, fByPosition
, FALSE
, &MenuItemInfoW
, &UnicodeString
);
1642 SetLastError(ERROR_INVALID_WINDOW_HANDLE
);
1647 SetLastError(ERROR_INVALID_MENU_HANDLE
);
1650 return NtUserSetSystemMenu(hwnd
, hMenu
);
1664 return NtUserTrackPopupMenuEx( Menu
,
1669 NULL
); // LPTPMPARAMS is null
1687 return PopupMenuWndProcA(hWnd
, Msg
, wParam
, lParam
);
1689 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, TRUE
);
1707 return PopupMenuWndProcW(hWnd
, Msg
, wParam
, lParam
);
1709 return NtUserMessageCall(hWnd
, Msg
, wParam
, lParam
, Result
, FNID_MENU
, FALSE
);
1720 LPCWSTR lpszNewItem
,
1725 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
1726 for MF_DELETE. We should check the parameters for all others
1727 MF_* actions also (anybody got a doc on ChangeMenu?).
1730 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
1733 return AppendMenuW(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
1736 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
1739 return ModifyMenuW(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
1742 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
1743 flags
&~ MF_REMOVE
);
1745 default : /* MF_INSERT */
1746 return InsertMenuW(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);
1763 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
1764 for MF_DELETE. We should check the parameters for all others
1765 MF_* actions also (anybody got a doc on ChangeMenu?).
1768 switch(flags
& (MF_APPEND
| MF_DELETE
| MF_CHANGE
| MF_REMOVE
| MF_INSERT
))
1771 return AppendMenuA(hMenu
, flags
&~ MF_APPEND
, cmdInsert
, lpszNewItem
);
1774 return DeleteMenu(hMenu
, cmd
, flags
&~ MF_DELETE
);
1777 return ModifyMenuA(hMenu
, cmd
, flags
&~ MF_CHANGE
, cmdInsert
, lpszNewItem
);
1780 return RemoveMenu(hMenu
, flags
& MF_BYPOSITION
? cmd
: cmdInsert
,
1781 flags
&~ MF_REMOVE
);
1783 default : /* MF_INSERT */
1784 return InsertMenuA(hMenu
, cmd
, flags
, cmdInsert
, lpszNewItem
);