4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994 Alexandre Julliard
6 * Copyright 1997 Morten Welinder
7 * Copyright 2005 Maxime Bellengé
8 * Copyright 2006 Phil Krylov
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 * Note: the style MF_MOUSESELECT is used to mark popup items that
27 * have been selected, i.e. their popup menu is currently displayed.
28 * This is probably not the meaning this style has in MS-Windows.
30 * Note 2: where there is a difference, these menu API's are according
31 * the behavior of Windows 2k and Windows XP. Known differences with
32 * Windows 9x/ME are documented in the comments, in case an application
33 * is found to depend on the old behavior.
51 #include "wine/server.h"
52 #include "wine/exception.h"
55 #include "user_private.h"
56 #include "wine/debug.h"
58 WINE_DEFAULT_DEBUG_CHANNEL(menu
);
61 /* Space between 2 columns */
62 #define MENU_COL_SPACE 4
64 /* Margins for popup menus */
67 /* (other menu->FocusedItem values give the position of the focused item) */
68 #define NO_SELECTED_ITEM 0xffff
70 #define MENU_ITEM_TYPE(flags) \
71 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
73 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
74 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
75 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
77 #define MENUITEMINFO_TYPE_MASK \
78 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
79 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
80 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
81 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
82 #define STATE_MASK (~TYPE_MASK)
83 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
85 /*********************************************************************
86 * menu class descriptor
88 const struct builtin_class_descr MENU_builtin_class
=
90 (LPCWSTR
)POPUPMENU_CLASS_ATOM
, /* name */
91 CS_DROPSHADOW
| CS_SAVEBITS
| CS_DBLCLKS
, /* style */
92 WINPROC_MENU
, /* proc */
93 sizeof(HMENU
), /* extra */
94 IDC_ARROW
, /* cursor */
95 (HBRUSH
)(COLOR_MENU
+1) /* brush */
99 /***********************************************************************
102 * Validate the given menu handle and returns the menu structure pointer.
104 static POPUPMENU
*MENU_GetMenu(HMENU hMenu
)
106 POPUPMENU
*menu
= get_user_handle_ptr( hMenu
, NTUSER_OBJ_MENU
);
108 if (menu
== OBJ_OTHER_PROCESS
)
110 WARN( "other process menu %p?\n", hMenu
);
113 if (menu
) release_user_handle_ptr( menu
); /* FIXME! */
114 else WARN("invalid menu handle=%p\n", hMenu
);
118 static POPUPMENU
*grab_menu_ptr(HMENU hMenu
)
120 POPUPMENU
*menu
= get_user_handle_ptr( hMenu
, NTUSER_OBJ_MENU
);
122 if (menu
== OBJ_OTHER_PROCESS
)
124 WARN("other process menu %p?\n", hMenu
);
131 WARN("invalid menu handle=%p\n", hMenu
);
135 static void release_menu_ptr(POPUPMENU
*menu
)
140 release_user_handle_ptr(menu
);
144 /***********************************************************************
147 * Return the default system menu.
149 static HMENU
MENU_CopySysPopup(BOOL mdi
)
151 HMENU hMenu
= LoadMenuW(user32_module
, mdi
? L
"SYSMENUMDI" : L
"SYSMENU");
155 MENUITEMINFOW miteminfo
;
156 POPUPMENU
* menu
= MENU_GetMenu(hMenu
);
157 menu
->wFlags
|= MF_SYSMENU
| MF_POPUP
;
158 /* decorate the menu with bitmaps */
159 minfo
.cbSize
= sizeof( MENUINFO
);
160 minfo
.dwStyle
= MNS_CHECKORBMP
;
161 minfo
.fMask
= MIM_STYLE
;
162 SetMenuInfo( hMenu
, &minfo
);
163 miteminfo
.cbSize
= sizeof( MENUITEMINFOW
);
164 miteminfo
.fMask
= MIIM_BITMAP
;
165 miteminfo
.hbmpItem
= HBMMENU_POPUP_CLOSE
;
166 SetMenuItemInfoW( hMenu
, SC_CLOSE
, FALSE
, &miteminfo
);
167 miteminfo
.hbmpItem
= HBMMENU_POPUP_RESTORE
;
168 SetMenuItemInfoW( hMenu
, SC_RESTORE
, FALSE
, &miteminfo
);
169 miteminfo
.hbmpItem
= HBMMENU_POPUP_MAXIMIZE
;
170 SetMenuItemInfoW( hMenu
, SC_MAXIMIZE
, FALSE
, &miteminfo
);
171 miteminfo
.hbmpItem
= HBMMENU_POPUP_MINIMIZE
;
172 SetMenuItemInfoW( hMenu
, SC_MINIMIZE
, FALSE
, &miteminfo
);
173 NtUserSetMenuDefaultItem( hMenu
, SC_CLOSE
, FALSE
);
176 ERR("Unable to load default system menu\n" );
178 TRACE("returning %p (mdi=%d).\n", hMenu
, mdi
);
184 /**********************************************************************
187 * Create a copy of the system menu. System menu in Windows is
188 * a special menu bar with the single entry - system menu popup.
189 * This popup is presented to the outside world as a "system menu".
190 * However, the real system menu handle is sometimes seen in the
191 * WM_MENUSELECT parameters (and Word 6 likes it this way).
193 HMENU
MENU_GetSysMenu( HWND hWnd
, HMENU hPopupMenu
)
197 TRACE("loading system menu, hWnd %p, hPopupMenu %p\n", hWnd
, hPopupMenu
);
198 if ((hMenu
= CreateMenu()))
200 POPUPMENU
*menu
= MENU_GetMenu(hMenu
);
201 menu
->wFlags
= MF_SYSMENU
;
202 menu
->hWnd
= WIN_GetFullHandle( hWnd
);
203 TRACE("hWnd %p (hMenu %p)\n", menu
->hWnd
, hMenu
);
207 if (GetWindowLongW(hWnd
, GWL_EXSTYLE
) & WS_EX_MDICHILD
)
208 hPopupMenu
= MENU_CopySysPopup(TRUE
);
210 hPopupMenu
= MENU_CopySysPopup(FALSE
);
215 if (GetClassLongW(hWnd
, GCL_STYLE
) & CS_NOCLOSE
)
216 NtUserDeleteMenu( hPopupMenu
, SC_CLOSE
, MF_BYCOMMAND
);
218 InsertMenuW( hMenu
, -1, MF_SYSMENU
| MF_POPUP
| MF_BYPOSITION
,
219 (UINT_PTR
)hPopupMenu
, NULL
);
221 menu
->items
[0].fType
= MF_SYSMENU
| MF_POPUP
;
222 menu
->items
[0].fState
= 0;
223 if ((menu
= MENU_GetMenu(hPopupMenu
))) menu
->wFlags
|= MF_SYSMENU
;
225 TRACE("hMenu=%p (hPopup %p)\n", hMenu
, hPopupMenu
);
228 NtUserDestroyMenu( hMenu
);
230 ERR("failed to load system menu!\n");
235 static POPUPMENU
*find_menu_item(HMENU hmenu
, UINT id
, UINT flags
, UINT
*pos
)
237 UINT fallback_pos
= ~0u, i
;
240 menu
= grab_menu_ptr(hmenu
);
244 if (flags
& MF_BYPOSITION
)
246 if (id
>= menu
->nItems
)
248 release_menu_ptr(menu
);
257 MENUITEM
*item
= menu
->items
;
258 for (i
= 0; i
< menu
->nItems
; i
++, item
++)
260 if (item
->fType
& MF_POPUP
)
262 POPUPMENU
*submenu
= find_menu_item(item
->hSubMenu
, id
, flags
, pos
);
266 release_menu_ptr(menu
);
269 else if (item
->wID
== id
)
271 /* fallback to this item if nothing else found */
275 else if (item
->wID
== id
)
283 if (fallback_pos
!= ~0u)
287 release_menu_ptr(menu
);
295 /**********************************************************************
298 * Parse a standard menu resource and add items to the menu.
299 * Return a pointer to the end of the resource.
301 * NOTE: flags is equivalent to the mtOption field
303 static LPCSTR
MENU_ParseResource( LPCSTR res
, HMENU hMenu
)
311 flags
= GET_WORD(res
);
312 end_flag
= flags
& MF_END
;
313 /* Remove MF_END because it has the same value as MF_HILITE */
316 if (!(flags
& MF_POPUP
))
322 res
+= (lstrlenW(str
) + 1) * sizeof(WCHAR
);
323 if (flags
& MF_POPUP
)
325 HMENU hSubMenu
= CreatePopupMenu();
326 if (!hSubMenu
) return NULL
;
327 if (!(res
= MENU_ParseResource( res
, hSubMenu
))) return NULL
;
328 AppendMenuW( hMenu
, flags
, (UINT_PTR
)hSubMenu
, str
);
330 else /* Not a popup */
332 AppendMenuW( hMenu
, flags
, id
, *str
? str
: NULL
);
339 /**********************************************************************
340 * MENUEX_ParseResource
342 * Parse an extended menu resource and add items to the menu.
343 * Return a pointer to the end of the resource.
345 static LPCSTR
MENUEX_ParseResource( LPCSTR res
, HMENU hMenu
)
351 mii
.cbSize
= sizeof(mii
);
352 mii
.fMask
= MIIM_STATE
| MIIM_ID
| MIIM_TYPE
;
353 mii
.fType
= GET_DWORD(res
);
354 res
+= sizeof(DWORD
);
355 mii
.fState
= GET_DWORD(res
);
356 res
+= sizeof(DWORD
);
357 mii
.wID
= GET_DWORD(res
);
358 res
+= sizeof(DWORD
);
359 resinfo
= GET_WORD(res
); /* FIXME: for 16-bit apps this is a byte. */
361 /* Align the text on a word boundary. */
362 res
+= (~((UINT_PTR
)res
- 1)) & 1;
363 mii
.dwTypeData
= (LPWSTR
) res
;
364 res
+= (1 + lstrlenW(mii
.dwTypeData
)) * sizeof(WCHAR
);
365 /* Align the following fields on a dword boundary. */
366 res
+= (~((UINT_PTR
)res
- 1)) & 3;
368 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
369 mii
.fType
, mii
.fState
, mii
.wID
, resinfo
, debugstr_w(mii
.dwTypeData
));
371 if (resinfo
& 1) { /* Pop-up? */
372 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
373 res
+= sizeof(DWORD
);
374 mii
.hSubMenu
= CreatePopupMenu();
377 if (!(res
= MENUEX_ParseResource(res
, mii
.hSubMenu
))) {
378 NtUserDestroyMenu( mii
.hSubMenu
);
381 mii
.fMask
|= MIIM_SUBMENU
;
382 mii
.fType
|= MF_POPUP
;
384 else if(!*mii
.dwTypeData
&& !(mii
.fType
& MF_SEPARATOR
))
386 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
388 mii
.fType
|= MF_SEPARATOR
;
390 InsertMenuItemW(hMenu
, -1, MF_BYPOSITION
, &mii
);
391 } while (!(resinfo
& MF_END
));
396 /**********************************************************************
397 * TrackPopupMenu (USER32.@)
399 * Like the win32 API, the function return the command ID only if the
400 * flag TPM_RETURNCMD is on.
403 BOOL WINAPI
TrackPopupMenu( HMENU hMenu
, UINT wFlags
, INT x
, INT y
,
404 INT nReserved
, HWND hWnd
, const RECT
*lpRect
)
406 return NtUserTrackPopupMenuEx( hMenu
, wFlags
, x
, y
, hWnd
, NULL
);
409 /***********************************************************************
412 * NOTE: Windows has totally different (and undocumented) popup wndproc.
414 LRESULT WINAPI
PopupMenuWndProc( HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
420 case WM_MOUSEACTIVATE
:
426 return NtUserMessageCall( hwnd
, message
, wParam
, lParam
,
427 NULL
, NtUserPopupMenuWndProc
, FALSE
);
430 return DefWindowProcW( hwnd
, message
, wParam
, lParam
);
436 /*******************************************************************
437 * ChangeMenuA (USER32.@)
439 BOOL WINAPI
ChangeMenuA( HMENU hMenu
, UINT pos
, LPCSTR data
,
440 UINT id
, UINT flags
)
442 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu
, pos
, data
, id
, flags
);
443 if (flags
& MF_APPEND
) return AppendMenuA( hMenu
, flags
& ~MF_APPEND
,
445 if (flags
& MF_DELETE
) return NtUserDeleteMenu( hMenu
, pos
, flags
& ~MF_DELETE
);
446 if (flags
& MF_CHANGE
) return ModifyMenuA(hMenu
, pos
, flags
& ~MF_CHANGE
,
448 if (flags
& MF_REMOVE
) return NtUserRemoveMenu( hMenu
,
449 flags
& MF_BYPOSITION
? pos
: id
,
450 flags
& ~MF_REMOVE
);
451 /* Default: MF_INSERT */
452 return InsertMenuA( hMenu
, pos
, flags
, id
, data
);
456 /*******************************************************************
457 * ChangeMenuW (USER32.@)
459 BOOL WINAPI
ChangeMenuW( HMENU hMenu
, UINT pos
, LPCWSTR data
,
460 UINT id
, UINT flags
)
462 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu
, pos
, data
, id
, flags
);
463 if (flags
& MF_APPEND
) return AppendMenuW( hMenu
, flags
& ~MF_APPEND
,
465 if (flags
& MF_DELETE
) return NtUserDeleteMenu( hMenu
, pos
, flags
& ~MF_DELETE
);
466 if (flags
& MF_CHANGE
) return ModifyMenuW(hMenu
, pos
, flags
& ~MF_CHANGE
,
468 if (flags
& MF_REMOVE
) return NtUserRemoveMenu( hMenu
,
469 flags
& MF_BYPOSITION
? pos
: id
,
470 flags
& ~MF_REMOVE
);
471 /* Default: MF_INSERT */
472 return InsertMenuW( hMenu
, pos
, flags
, id
, data
);
476 /*******************************************************************
477 * GetMenuStringA (USER32.@)
479 INT WINAPI
GetMenuStringA( HMENU menu
, UINT item
, char *str
, INT count
, UINT flags
)
484 TRACE( "menu=%p item=%04x ptr=%p len=%d flags=%04x\n", menu
, item
, str
, count
, flags
);
486 info
.cbSize
= sizeof(info
);
487 info
.fMask
= MIIM_STRING
;
488 info
.dwTypeData
= str
;
490 ret
= NtUserThunkedMenuItemInfo( menu
, item
, flags
, NtUserGetMenuItemInfoA
,
491 (MENUITEMINFOW
*)&info
, NULL
);
492 if (ret
) ret
= info
.cch
;
493 TRACE( "returning %s %d\n", debugstr_a( str
), ret
);
498 /*******************************************************************
499 * GetMenuStringW (USER32.@)
501 INT WINAPI
GetMenuStringW( HMENU menu
, UINT item
, WCHAR
*str
, INT count
, UINT flags
)
506 TRACE( "menu=%p item=%04x ptr=%p len=%d flags=%04x\n", menu
, item
, str
, count
, flags
);
508 info
.cbSize
= sizeof(info
);
509 info
.fMask
= MIIM_STRING
;
510 info
.dwTypeData
= str
;
512 ret
= NtUserThunkedMenuItemInfo( menu
, item
, flags
, NtUserGetMenuItemInfoW
, &info
, NULL
);
513 if (ret
) ret
= info
.cch
;
514 TRACE( "returning %s %d\n", debugstr_w( str
), ret
);
519 /**********************************************************************
520 * GetMenuState (USER32.@)
522 UINT WINAPI
GetMenuState( HMENU menu
, UINT item
, UINT flags
)
524 return NtUserThunkedMenuItemInfo( menu
, item
, flags
, NtUserGetMenuState
, NULL
, NULL
);
528 /**********************************************************************
529 * GetMenuItemCount (USER32.@)
531 INT WINAPI
GetMenuItemCount( HMENU menu
)
533 return NtUserGetMenuItemCount( menu
);
537 /**********************************************************************
538 * GetMenuItemID (USER32.@)
540 UINT WINAPI
GetMenuItemID( HMENU hMenu
, INT nPos
)
545 if (!(menu
= find_menu_item(hMenu
, nPos
, MF_BYPOSITION
, &pos
)))
548 id
= menu
->items
[pos
].fType
& MF_POPUP
? -1 : menu
->items
[pos
].wID
;
549 release_menu_ptr(menu
);
554 /**********************************************************************
557 * Uses flags, id and text ptr, passed by InsertMenu() and
558 * ModifyMenu() to setup a MenuItemInfo structure.
560 static void MENU_mnu2mnuii( UINT flags
, UINT_PTR id
, LPCWSTR str
,
561 LPMENUITEMINFOW pmii
)
563 ZeroMemory( pmii
, sizeof( MENUITEMINFOW
));
564 pmii
->cbSize
= sizeof( MENUITEMINFOW
);
565 pmii
->fMask
= MIIM_STATE
| MIIM_ID
| MIIM_FTYPE
;
566 /* setting bitmap clears text and vice versa */
567 if( IS_STRING_ITEM(flags
)) {
568 pmii
->fMask
|= MIIM_STRING
| MIIM_BITMAP
;
570 flags
|= MF_SEPARATOR
;
571 /* Item beginning with a backspace is a help item */
572 /* FIXME: wrong place, this is only true in win16 */
573 else if( *str
== '\b') {
577 pmii
->dwTypeData
= (LPWSTR
)str
;
578 } else if( flags
& MFT_BITMAP
){
579 pmii
->fMask
|= MIIM_BITMAP
| MIIM_STRING
;
580 pmii
->hbmpItem
= (HBITMAP
)str
;
582 if( flags
& MF_OWNERDRAW
){
583 pmii
->fMask
|= MIIM_DATA
;
584 pmii
->dwItemData
= (ULONG_PTR
) str
;
586 if( flags
& MF_POPUP
&& MENU_GetMenu((HMENU
)id
)) {
587 pmii
->fMask
|= MIIM_SUBMENU
;
588 pmii
->hSubMenu
= (HMENU
)id
;
590 if( flags
& MF_SEPARATOR
) flags
|= MF_GRAYED
| MF_DISABLED
;
591 pmii
->fState
= flags
& MENUITEMINFO_STATE_MASK
& ~MFS_DEFAULT
;
592 pmii
->fType
= flags
& MENUITEMINFO_TYPE_MASK
;
593 pmii
->wID
= (UINT
)id
;
597 /*******************************************************************
598 * InsertMenuW (USER32.@)
600 BOOL WINAPI
InsertMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
601 UINT_PTR id
, LPCWSTR str
)
605 if (IS_STRING_ITEM(flags
) && str
)
606 TRACE("hMenu %p, pos %d, flags %08x, id %04Ix, str %s\n",
607 hMenu
, pos
, flags
, id
, debugstr_w(str
) );
608 else TRACE("hMenu %p, pos %d, flags %08x, id %04Ix, str %p (not a string)\n",
609 hMenu
, pos
, flags
, id
, str
);
611 MENU_mnu2mnuii( flags
, id
, str
, &mii
);
612 mii
.fMask
|= MIIM_CHECKMARKS
;
613 return NtUserThunkedMenuItemInfo( hMenu
, pos
, flags
, NtUserInsertMenuItem
, &mii
, NULL
);
617 /*******************************************************************
618 * InsertMenuA (USER32.@)
620 BOOL WINAPI
InsertMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
621 UINT_PTR id
, LPCSTR str
)
625 if (IS_STRING_ITEM(flags
) && str
)
627 INT len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
628 LPWSTR newstr
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
631 MultiByteToWideChar( CP_ACP
, 0, str
, -1, newstr
, len
);
632 ret
= InsertMenuW( hMenu
, pos
, flags
, id
, newstr
);
633 HeapFree( GetProcessHeap(), 0, newstr
);
637 else return InsertMenuW( hMenu
, pos
, flags
, id
, (LPCWSTR
)str
);
641 /*******************************************************************
642 * AppendMenuA (USER32.@)
644 BOOL WINAPI
AppendMenuA( HMENU hMenu
, UINT flags
,
645 UINT_PTR id
, LPCSTR data
)
647 return InsertMenuA( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
651 /*******************************************************************
652 * AppendMenuW (USER32.@)
654 BOOL WINAPI
AppendMenuW( HMENU hMenu
, UINT flags
,
655 UINT_PTR id
, LPCWSTR data
)
657 return InsertMenuW( hMenu
, -1, flags
| MF_BYPOSITION
, id
, data
);
661 /*******************************************************************
662 * ModifyMenuW (USER32.@)
664 BOOL WINAPI
ModifyMenuW( HMENU hMenu
, UINT pos
, UINT flags
,
665 UINT_PTR id
, LPCWSTR str
)
669 if (IS_STRING_ITEM(flags
))
670 TRACE("%p %d %04x %04Ix %s\n", hMenu
, pos
, flags
, id
, debugstr_w(str
) );
672 TRACE("%p %d %04x %04Ix %p\n", hMenu
, pos
, flags
, id
, str
);
674 MENU_mnu2mnuii( flags
, id
, str
, &mii
);
675 return NtUserThunkedMenuItemInfo( hMenu
, pos
, flags
, NtUserSetMenuItemInfo
, &mii
, NULL
);
679 /*******************************************************************
680 * ModifyMenuA (USER32.@)
682 BOOL WINAPI
ModifyMenuA( HMENU hMenu
, UINT pos
, UINT flags
,
683 UINT_PTR id
, LPCSTR str
)
687 if (IS_STRING_ITEM(flags
) && str
)
689 INT len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
690 LPWSTR newstr
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) );
693 MultiByteToWideChar( CP_ACP
, 0, str
, -1, newstr
, len
);
694 ret
= ModifyMenuW( hMenu
, pos
, flags
, id
, newstr
);
695 HeapFree( GetProcessHeap(), 0, newstr
);
699 else return ModifyMenuW( hMenu
, pos
, flags
, id
, (LPCWSTR
)str
);
703 /**********************************************************************
704 * CreatePopupMenu (USER32.@)
706 HMENU WINAPI
CreatePopupMenu(void)
708 return NtUserCreateMenu( TRUE
);
712 /**********************************************************************
713 * GetMenuCheckMarkDimensions (USER.417)
714 * GetMenuCheckMarkDimensions (USER32.@)
716 DWORD WINAPI
GetMenuCheckMarkDimensions(void)
718 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK
), GetSystemMetrics(SM_CYMENUCHECK
) );
722 /**********************************************************************
723 * SetMenuItemBitmaps (USER32.@)
725 BOOL WINAPI
SetMenuItemBitmaps( HMENU hMenu
, UINT nPos
, UINT wFlags
,
726 HBITMAP hNewUnCheck
, HBITMAP hNewCheck
)
732 if (!(menu
= find_menu_item(hMenu
, nPos
, wFlags
, &pos
)))
735 item
= &menu
->items
[pos
];
736 if (!hNewCheck
&& !hNewUnCheck
)
738 item
->fState
&= ~MF_USECHECKBITMAPS
;
740 else /* Install new bitmaps */
742 item
->hCheckBit
= hNewCheck
;
743 item
->hUnCheckBit
= hNewUnCheck
;
744 item
->fState
|= MF_USECHECKBITMAPS
;
746 release_menu_ptr(menu
);
752 /**********************************************************************
753 * CreateMenu (USER32.@)
755 HMENU WINAPI
CreateMenu(void)
757 return NtUserCreateMenu( FALSE
);
761 /**********************************************************************
764 HMENU WINAPI
GetMenu( HWND hWnd
)
766 HMENU retvalue
= (HMENU
)GetWindowLongPtrW( hWnd
, GWLP_ID
);
767 TRACE("for %p returning %p\n", hWnd
, retvalue
);
772 /**********************************************************************
773 * GetSubMenu (USER32.@)
775 HMENU WINAPI
GetSubMenu( HMENU hMenu
, INT nPos
)
781 if (!(menu
= find_menu_item(hMenu
, nPos
, MF_BYPOSITION
, &pos
)))
784 if (menu
->items
[pos
].fType
& MF_POPUP
)
785 submenu
= menu
->items
[pos
].hSubMenu
;
789 release_menu_ptr(menu
);
794 /**********************************************************************
795 * DrawMenuBar (USER32.@)
797 BOOL WINAPI
DrawMenuBar( HWND hwnd
)
799 return NtUserDrawMenuBar( hwnd
);
803 /*****************************************************************
804 * LoadMenuA (USER32.@)
806 HMENU WINAPI
LoadMenuA( HINSTANCE instance
, LPCSTR name
)
808 HRSRC hrsrc
= FindResourceA( instance
, name
, (LPSTR
)RT_MENU
);
809 if (!hrsrc
) return 0;
810 return LoadMenuIndirectA( LoadResource( instance
, hrsrc
));
814 /*****************************************************************
815 * LoadMenuW (USER32.@)
817 HMENU WINAPI
LoadMenuW( HINSTANCE instance
, LPCWSTR name
)
819 HRSRC hrsrc
= FindResourceW( instance
, name
, (LPWSTR
)RT_MENU
);
820 if (!hrsrc
) return 0;
821 return LoadMenuIndirectW( LoadResource( instance
, hrsrc
));
825 /**********************************************************************
826 * LoadMenuIndirectW (USER32.@)
828 HMENU WINAPI
LoadMenuIndirectW( LPCVOID
template )
831 WORD version
, offset
;
834 version
= GET_WORD(p
);
836 TRACE("%p, ver %d\n", template, version
);
839 case 0: /* standard format is version of 0 */
840 offset
= GET_WORD(p
);
841 p
+= sizeof(WORD
) + offset
;
842 if (!(hMenu
= CreateMenu())) return 0;
843 if (!MENU_ParseResource( p
, hMenu
))
845 NtUserDestroyMenu( hMenu
);
849 case 1: /* extended format is version of 1 */
850 offset
= GET_WORD(p
);
851 p
+= sizeof(WORD
) + offset
;
852 if (!(hMenu
= CreateMenu())) return 0;
853 if (!MENUEX_ParseResource( p
, hMenu
))
855 NtUserDestroyMenu( hMenu
);
860 ERR("version %d not supported.\n", version
);
866 /**********************************************************************
867 * LoadMenuIndirectA (USER32.@)
869 HMENU WINAPI
LoadMenuIndirectA( LPCVOID
template )
871 return LoadMenuIndirectW( template );
875 /**********************************************************************
878 BOOL WINAPI
IsMenu( HMENU menu
)
882 info
.cbSize
= sizeof(info
);
884 if (GetMenuInfo( menu
, &info
)) return TRUE
;
886 SetLastError(ERROR_INVALID_MENU_HANDLE
);
891 /**********************************************************************
892 * GetMenuItemInfoA (USER32.@)
894 BOOL WINAPI
GetMenuItemInfoA( HMENU hmenu
, UINT item
, BOOL bypos
,
895 LPMENUITEMINFOA lpmii
)
899 if( lpmii
->cbSize
!= sizeof( mii
) &&
900 lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
)) {
901 SetLastError( ERROR_INVALID_PARAMETER
);
904 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
905 mii
.cbSize
= sizeof( mii
);
906 ret
= NtUserThunkedMenuItemInfo( hmenu
, item
, bypos
? MF_BYPOSITION
: 0,
907 NtUserGetMenuItemInfoA
, (MENUITEMINFOW
*)&mii
, NULL
);
908 mii
.cbSize
= lpmii
->cbSize
;
909 memcpy( lpmii
, &mii
, mii
.cbSize
);
913 /**********************************************************************
914 * GetMenuItemInfoW (USER32.@)
916 BOOL WINAPI
GetMenuItemInfoW( HMENU hmenu
, UINT item
, BOOL bypos
,
917 LPMENUITEMINFOW lpmii
)
921 if( lpmii
->cbSize
!= sizeof( mii
) &&
922 lpmii
->cbSize
!= sizeof( mii
) - sizeof ( mii
.hbmpItem
)) {
923 SetLastError( ERROR_INVALID_PARAMETER
);
926 memcpy( &mii
, lpmii
, lpmii
->cbSize
);
927 mii
.cbSize
= sizeof( mii
);
928 ret
= NtUserThunkedMenuItemInfo( hmenu
, item
, bypos
? MF_BYPOSITION
: 0,
929 NtUserGetMenuItemInfoW
, &mii
, NULL
);
930 mii
.cbSize
= lpmii
->cbSize
;
931 memcpy( lpmii
, &mii
, mii
.cbSize
);
936 /**********************************************************************
937 * MENU_NormalizeMenuItemInfoStruct
939 * Helper for SetMenuItemInfo and InsertMenuItemInfo:
940 * check, copy and extend the MENUITEMINFO struct from the version that the application
941 * supplied to the version used by wine source. */
942 static BOOL
MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW
*pmii_in
,
943 MENUITEMINFOW
*pmii_out
)
945 /* do we recognize the size? */
946 if( !pmii_in
|| (pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) &&
947 pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
) - sizeof( pmii_in
->hbmpItem
)) ) {
948 SetLastError( ERROR_INVALID_PARAMETER
);
951 /* copy the fields that we have */
952 memcpy( pmii_out
, pmii_in
, pmii_in
->cbSize
);
953 /* if the hbmpItem member is missing then extend */
954 if( pmii_in
->cbSize
!= sizeof( MENUITEMINFOW
)) {
955 pmii_out
->cbSize
= sizeof( MENUITEMINFOW
);
956 pmii_out
->hbmpItem
= NULL
;
958 /* test for invalid bit combinations */
959 if( (pmii_out
->fMask
& MIIM_TYPE
&&
960 pmii_out
->fMask
& (MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
)) ||
961 (pmii_out
->fMask
& MIIM_FTYPE
&& pmii_out
->fType
& MFT_BITMAP
)) {
962 WARN("invalid combination of fMask bits used\n");
963 /* this does not happen on Win9x/ME */
964 SetLastError( ERROR_INVALID_PARAMETER
);
967 /* convert old style (MIIM_TYPE) to the new */
968 if( pmii_out
->fMask
& MIIM_TYPE
){
969 pmii_out
->fMask
|= MIIM_FTYPE
;
970 if( IS_STRING_ITEM(pmii_out
->fType
)){
971 pmii_out
->fMask
|= MIIM_STRING
;
972 } else if( (pmii_out
->fType
) & MFT_BITMAP
){
973 pmii_out
->fMask
|= MIIM_BITMAP
;
974 pmii_out
->hbmpItem
= UlongToHandle(LOWORD(pmii_out
->dwTypeData
));
980 /**********************************************************************
981 * SetMenuItemInfoA (USER32.@)
983 BOOL WINAPI
SetMenuItemInfoA(HMENU hmenu
, UINT item
, BOOL bypos
,
984 const MENUITEMINFOA
*lpmii
)
990 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu
, item
, bypos
, lpmii
);
992 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
994 if ((mii
.fMask
& MIIM_STRING
) && mii
.dwTypeData
)
996 const char *str
= (const char *)mii
.dwTypeData
;
997 UINT len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
998 if (!(strW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return FALSE
;
999 MultiByteToWideChar( CP_ACP
, 0, str
, -1, strW
, len
);
1000 mii
.dwTypeData
= strW
;
1003 ret
= NtUserThunkedMenuItemInfo( hmenu
, item
, bypos
? MF_BYPOSITION
: 0,
1004 NtUserSetMenuItemInfo
, &mii
, NULL
);
1006 HeapFree( GetProcessHeap(), 0, strW
);
1010 /**********************************************************************
1011 * SetMenuItemInfoW (USER32.@)
1013 BOOL WINAPI
SetMenuItemInfoW(HMENU hmenu
, UINT item
, BOOL bypos
,
1014 const MENUITEMINFOW
*lpmii
)
1018 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu
, item
, bypos
, lpmii
);
1020 if (!MENU_NormalizeMenuItemInfoStruct( lpmii
, &mii
)) return FALSE
;
1022 return NtUserThunkedMenuItemInfo( hmenu
, item
, bypos
? MF_BYPOSITION
: 0,
1023 NtUserSetMenuItemInfo
, &mii
, NULL
);
1026 /**********************************************************************
1027 * GetMenuDefaultItem (USER32.@)
1029 UINT WINAPI
GetMenuDefaultItem(HMENU hmenu
, UINT bypos
, UINT flags
)
1035 TRACE("(%p,%d,%d)\n", hmenu
, bypos
, flags
);
1037 if (!(menu
= MENU_GetMenu(hmenu
))) return -1;
1039 /* find default item */
1043 if (! item
) return -1;
1045 while ( !( item
->fState
& MFS_DEFAULT
) )
1048 if (i
>= menu
->nItems
) return -1;
1051 /* default: don't return disabled items */
1052 if ( (!(GMDI_USEDISABLED
& flags
)) && (item
->fState
& MFS_DISABLED
)) return -1;
1054 /* search rekursiv when needed */
1055 if ( (item
->fType
& MF_POPUP
) && (flags
& GMDI_GOINTOPOPUPS
) )
1058 ret
= GetMenuDefaultItem( item
->hSubMenu
, bypos
, flags
);
1059 if ( -1 != ret
) return ret
;
1061 /* when item not found in submenu, return the popup item */
1063 return ( bypos
) ? i
: item
->wID
;
1068 /**********************************************************************
1069 * InsertMenuItemA (USER32.@)
1071 BOOL WINAPI
InsertMenuItemA(HMENU hMenu
, UINT uItem
, BOOL bypos
,
1072 const MENUITEMINFOA
*lpmii
)
1078 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, bypos
, lpmii
);
1080 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW
*)lpmii
, &mii
)) return FALSE
;
1082 if ((mii
.fMask
& MIIM_STRING
) && mii
.dwTypeData
)
1084 const char *str
= (const char *)mii
.dwTypeData
;
1085 UINT len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
1086 if (!(strW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return FALSE
;
1087 MultiByteToWideChar( CP_ACP
, 0, str
, -1, strW
, len
);
1088 mii
.dwTypeData
= strW
;
1091 ret
= NtUserThunkedMenuItemInfo( hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0,
1092 NtUserInsertMenuItem
, &mii
, NULL
);
1094 HeapFree( GetProcessHeap(), 0, strW
);
1099 /**********************************************************************
1100 * InsertMenuItemW (USER32.@)
1102 BOOL WINAPI
InsertMenuItemW(HMENU hMenu
, UINT uItem
, BOOL bypos
,
1103 const MENUITEMINFOW
*lpmii
)
1107 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu
, uItem
, bypos
, lpmii
);
1109 if (!MENU_NormalizeMenuItemInfoStruct( lpmii
, &mii
)) return FALSE
;
1111 return NtUserThunkedMenuItemInfo( hMenu
, uItem
, bypos
? MF_BYPOSITION
: 0,
1112 NtUserInsertMenuItem
, &mii
, NULL
);
1115 /**********************************************************************
1116 * CheckMenuRadioItem (USER32.@)
1119 BOOL WINAPI
CheckMenuRadioItem(HMENU hMenu
, UINT first
, UINT last
,
1120 UINT check
, UINT flags
)
1122 POPUPMENU
*first_menu
= NULL
, *check_menu
;
1126 for (i
= first
; i
<= last
; i
++)
1130 if (!(check_menu
= find_menu_item(hMenu
, i
, flags
, &check_pos
)))
1134 first_menu
= grab_menu_ptr(check_menu
->obj
.handle
);
1136 if (first_menu
!= check_menu
)
1138 release_menu_ptr(check_menu
);
1142 item
= &check_menu
->items
[check_pos
];
1143 if (item
->fType
!= MFT_SEPARATOR
)
1147 item
->fType
|= MFT_RADIOCHECK
;
1148 item
->fState
|= MFS_CHECKED
;
1153 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
1154 item
->fState
&= ~MFS_CHECKED
;
1158 release_menu_ptr(check_menu
);
1160 release_menu_ptr(first_menu
);
1166 /**********************************************************************
1167 * SetMenuInfo (USER32.@)
1169 BOOL WINAPI
SetMenuInfo( HMENU menu
, const MENUINFO
*info
)
1171 TRACE( "(%p %p)\n", menu
, info
);
1173 if (!info
|| info
->cbSize
!= sizeof(*info
))
1175 SetLastError( ERROR_INVALID_PARAMETER
);
1179 return NtUserThunkedMenuInfo( menu
, info
);
1182 /**********************************************************************
1183 * GetMenuInfo (USER32.@)
1185 BOOL WINAPI
GetMenuInfo( HMENU menu
, MENUINFO
*info
)
1187 return NtUserGetMenuInfo( menu
, info
);
1191 /**********************************************************************
1192 * GetMenuContextHelpId (USER32.@)
1194 DWORD WINAPI
GetMenuContextHelpId( HMENU menu
)
1197 TRACE( "(%p)\n", menu
);
1198 info
.cbSize
= sizeof(info
);
1199 info
.fMask
= MIM_HELPID
;
1200 return GetMenuInfo( menu
, &info
) ? info
.dwContextHelpID
: 0;
1203 /**********************************************************************
1204 * MenuItemFromPoint (USER32.@)
1206 INT WINAPI
MenuItemFromPoint( HWND hwnd
, HMENU menu
, POINT pt
)
1208 return NtUserMenuItemFromPoint( hwnd
, menu
, pt
.x
, pt
.y
);
1212 /**********************************************************************
1213 * CalcMenuBar (USER32.@)
1215 DWORD WINAPI
CalcMenuBar(HWND hwnd
, DWORD left
, DWORD right
, DWORD top
, RECT
*rect
)
1217 FIXME("(%p, %ld, %ld, %ld, %p): stub\n", hwnd
, left
, right
, top
, rect
);
1222 /**********************************************************************
1223 * TranslateAcceleratorA (USER32.@)
1224 * TranslateAccelerator (USER32.@)
1226 INT WINAPI
TranslateAcceleratorA( HWND hWnd
, HACCEL hAccel
, LPMSG msg
)
1228 switch (msg
->message
)
1232 return NtUserTranslateAccelerator( hWnd
, hAccel
, msg
);
1238 char ch
= LOWORD(msg
->wParam
);
1240 MultiByteToWideChar(CP_ACP
, 0, &ch
, 1, &wch
, 1);
1241 msgW
.wParam
= MAKEWPARAM(wch
, HIWORD(msg
->wParam
));
1242 return NtUserTranslateAccelerator( hWnd
, hAccel
, &msgW
);