widl: Add support for protected attribute.
[wine.git] / dlls / user32 / menu.c
blob4ba6fa710288677b59419c441cdca44b88e20f81
1 /*
2 * Menu functions
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.
35 * TODO:
36 * implements styles :
37 * - MNS_AUTODISMISS
38 * - MNS_DRAGDROP
39 * - MNS_MODELESS
42 #include <stdarg.h>
43 #include <string.h>
45 #include "windef.h"
46 #include "winbase.h"
47 #include "wingdi.h"
48 #include "winnls.h"
49 #include "controls.h"
50 #include "user_private.h"
51 #include "wine/debug.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(menu);
56 #define MENU_ITEM_TYPE(flags) \
57 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
59 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
60 #define IS_STRING_ITEM(flags) (MENU_ITEM_TYPE ((flags)) == MF_STRING)
61 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
63 #define MENUITEMINFO_TYPE_MASK \
64 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
65 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
66 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
67 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
68 #define STATE_MASK (~TYPE_MASK)
69 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
72 /**********************************************************************
73 * MENU_ParseResource
75 * Parse a standard menu resource and add items to the menu.
76 * Return a pointer to the end of the resource.
78 * NOTE: flags is equivalent to the mtOption field
80 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu )
82 WORD flags, id = 0;
83 LPCWSTR str;
84 BOOL end_flag;
88 flags = GET_WORD(res);
89 end_flag = flags & MF_END;
90 /* Remove MF_END because it has the same value as MF_HILITE */
91 flags &= ~MF_END;
92 res += sizeof(WORD);
93 if (!(flags & MF_POPUP))
95 id = GET_WORD(res);
96 res += sizeof(WORD);
98 str = (LPCWSTR)res;
99 res += (lstrlenW(str) + 1) * sizeof(WCHAR);
100 if (flags & MF_POPUP)
102 HMENU hSubMenu = CreatePopupMenu();
103 if (!hSubMenu) return NULL;
104 if (!(res = MENU_ParseResource( res, hSubMenu ))) return NULL;
105 AppendMenuW( hMenu, flags, (UINT_PTR)hSubMenu, str );
107 else /* Not a popup */
109 AppendMenuW( hMenu, flags, id, *str ? str : NULL );
111 } while (!end_flag);
112 return res;
116 /**********************************************************************
117 * MENUEX_ParseResource
119 * Parse an extended menu resource and add items to the menu.
120 * Return a pointer to the end of the resource.
122 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
124 WORD resinfo;
125 do {
126 MENUITEMINFOW mii;
128 mii.cbSize = sizeof(mii);
129 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
130 mii.fType = GET_DWORD(res);
131 res += sizeof(DWORD);
132 mii.fState = GET_DWORD(res);
133 res += sizeof(DWORD);
134 mii.wID = GET_DWORD(res);
135 res += sizeof(DWORD);
136 resinfo = GET_WORD(res); /* FIXME: for 16-bit apps this is a byte. */
137 res += sizeof(WORD);
138 /* Align the text on a word boundary. */
139 res += (~((UINT_PTR)res - 1)) & 1;
140 mii.dwTypeData = (LPWSTR) res;
141 res += (1 + lstrlenW(mii.dwTypeData)) * sizeof(WCHAR);
142 /* Align the following fields on a dword boundary. */
143 res += (~((UINT_PTR)res - 1)) & 3;
145 TRACE("Menu item: [%08x,%08x,%04x,%04x,%s]\n",
146 mii.fType, mii.fState, mii.wID, resinfo, debugstr_w(mii.dwTypeData));
148 if (resinfo & 1) { /* Pop-up? */
149 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
150 res += sizeof(DWORD);
151 mii.hSubMenu = CreatePopupMenu();
152 if (!mii.hSubMenu)
153 return NULL;
154 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) {
155 NtUserDestroyMenu( mii.hSubMenu );
156 return NULL;
158 mii.fMask |= MIIM_SUBMENU;
159 mii.fType |= MF_POPUP;
161 else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR))
163 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
164 mii.wID, mii.fType);
165 mii.fType |= MF_SEPARATOR;
167 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
168 } while (!(resinfo & MF_END));
169 return res;
173 /**********************************************************************
174 * TrackPopupMenu (USER32.@)
176 * Like the win32 API, the function return the command ID only if the
177 * flag TPM_RETURNCMD is on.
180 BOOL WINAPI TrackPopupMenu( HMENU hMenu, UINT wFlags, INT x, INT y,
181 INT nReserved, HWND hWnd, const RECT *lpRect )
183 return NtUserTrackPopupMenuEx( hMenu, wFlags, x, y, hWnd, NULL );
186 /***********************************************************************
187 * PopupMenuWndProc
189 * NOTE: Windows has totally different (and undocumented) popup wndproc.
191 LRESULT WINAPI PopupMenuWndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
193 switch(message)
195 case WM_DESTROY:
196 case WM_CREATE:
197 case WM_MOUSEACTIVATE:
198 case WM_PAINT:
199 case WM_PRINTCLIENT:
200 case WM_ERASEBKGND:
201 case WM_SHOWWINDOW:
202 case MN_GETHMENU:
203 return NtUserMessageCall( hwnd, message, wParam, lParam,
204 NULL, NtUserPopupMenuWndProc, FALSE );
206 default:
207 return DefWindowProcW( hwnd, message, wParam, lParam );
209 return 0;
213 /*******************************************************************
214 * ChangeMenuA (USER32.@)
216 BOOL WINAPI ChangeMenuA( HMENU hMenu, UINT pos, LPCSTR data,
217 UINT id, UINT flags )
219 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu, pos, data, id, flags );
220 if (flags & MF_APPEND) return AppendMenuA( hMenu, flags & ~MF_APPEND,
221 id, data );
222 if (flags & MF_DELETE) return NtUserDeleteMenu( hMenu, pos, flags & ~MF_DELETE );
223 if (flags & MF_CHANGE) return ModifyMenuA(hMenu, pos, flags & ~MF_CHANGE,
224 id, data );
225 if (flags & MF_REMOVE) return NtUserRemoveMenu( hMenu,
226 flags & MF_BYPOSITION ? pos : id,
227 flags & ~MF_REMOVE );
228 /* Default: MF_INSERT */
229 return InsertMenuA( hMenu, pos, flags, id, data );
233 /*******************************************************************
234 * ChangeMenuW (USER32.@)
236 BOOL WINAPI ChangeMenuW( HMENU hMenu, UINT pos, LPCWSTR data,
237 UINT id, UINT flags )
239 TRACE("menu=%p pos=%d data=%p id=%08x flags=%08x\n", hMenu, pos, data, id, flags );
240 if (flags & MF_APPEND) return AppendMenuW( hMenu, flags & ~MF_APPEND,
241 id, data );
242 if (flags & MF_DELETE) return NtUserDeleteMenu( hMenu, pos, flags & ~MF_DELETE );
243 if (flags & MF_CHANGE) return ModifyMenuW(hMenu, pos, flags & ~MF_CHANGE,
244 id, data );
245 if (flags & MF_REMOVE) return NtUserRemoveMenu( hMenu,
246 flags & MF_BYPOSITION ? pos : id,
247 flags & ~MF_REMOVE );
248 /* Default: MF_INSERT */
249 return InsertMenuW( hMenu, pos, flags, id, data );
253 /*******************************************************************
254 * GetMenuStringA (USER32.@)
256 INT WINAPI GetMenuStringA( HMENU menu, UINT item, char *str, INT count, UINT flags )
258 MENUITEMINFOA info;
259 int ret;
261 TRACE( "menu=%p item=%04x ptr=%p len=%d flags=%04x\n", menu, item, str, count, flags );
263 info.cbSize = sizeof(info);
264 info.fMask = MIIM_STRING;
265 info.dwTypeData = str;
266 info.cch = count;
267 ret = NtUserThunkedMenuItemInfo( menu, item, flags, NtUserGetMenuItemInfoA,
268 (MENUITEMINFOW *)&info, NULL );
269 if (ret) ret = info.cch;
270 TRACE( "returning %s %d\n", debugstr_a( str ), ret );
271 return ret;
275 /*******************************************************************
276 * GetMenuStringW (USER32.@)
278 INT WINAPI GetMenuStringW( HMENU menu, UINT item, WCHAR *str, INT count, UINT flags )
280 MENUITEMINFOW info;
281 int ret;
283 TRACE( "menu=%p item=%04x ptr=%p len=%d flags=%04x\n", menu, item, str, count, flags );
285 info.cbSize = sizeof(info);
286 info.fMask = MIIM_STRING;
287 info.dwTypeData = str;
288 info.cch = count;
289 ret = NtUserThunkedMenuItemInfo( menu, item, flags, NtUserGetMenuItemInfoW, &info, NULL );
290 if (ret) ret = info.cch;
291 TRACE( "returning %s %d\n", debugstr_w( str ), ret );
292 return ret;
296 /**********************************************************************
297 * GetMenuState (USER32.@)
299 UINT WINAPI GetMenuState( HMENU menu, UINT item, UINT flags )
301 return NtUserThunkedMenuItemInfo( menu, item, flags, NtUserGetMenuState, NULL, NULL );
305 /**********************************************************************
306 * GetMenuItemCount (USER32.@)
308 INT WINAPI GetMenuItemCount( HMENU menu )
310 return NtUserGetMenuItemCount( menu );
314 /**********************************************************************
315 * GetMenuItemID (USER32.@)
317 UINT WINAPI GetMenuItemID( HMENU menu, INT pos )
319 return NtUserThunkedMenuItemInfo( menu, pos, MF_BYPOSITION, NtUserGetMenuItemID, NULL, NULL );
323 /**********************************************************************
324 * MENU_mnu2mnuii
326 * Uses flags, id and text ptr, passed by InsertMenu() and
327 * ModifyMenu() to setup a MenuItemInfo structure.
329 static void MENU_mnu2mnuii( UINT flags, UINT_PTR id, LPCWSTR str,
330 LPMENUITEMINFOW pmii)
332 ZeroMemory( pmii, sizeof( MENUITEMINFOW));
333 pmii->cbSize = sizeof( MENUITEMINFOW);
334 pmii->fMask = MIIM_STATE | MIIM_ID | MIIM_FTYPE;
335 /* setting bitmap clears text and vice versa */
336 if( IS_STRING_ITEM(flags)) {
337 pmii->fMask |= MIIM_STRING | MIIM_BITMAP;
338 if( !str)
339 flags |= MF_SEPARATOR;
340 /* Item beginning with a backspace is a help item */
341 /* FIXME: wrong place, this is only true in win16 */
342 else if( *str == '\b') {
343 flags |= MF_HELP;
344 str++;
346 pmii->dwTypeData = (LPWSTR)str;
347 } else if( flags & MFT_BITMAP){
348 pmii->fMask |= MIIM_BITMAP | MIIM_STRING;
349 pmii->hbmpItem = (HBITMAP)str;
351 if( flags & MF_OWNERDRAW){
352 pmii->fMask |= MIIM_DATA;
353 pmii->dwItemData = (ULONG_PTR) str;
355 if ((flags & MF_POPUP) && IsMenu( UlongToHandle( id )))
357 pmii->fMask |= MIIM_SUBMENU;
358 pmii->hSubMenu = (HMENU)id;
360 if( flags & MF_SEPARATOR) flags |= MF_GRAYED | MF_DISABLED;
361 pmii->fState = flags & MENUITEMINFO_STATE_MASK & ~MFS_DEFAULT;
362 pmii->fType = flags & MENUITEMINFO_TYPE_MASK;
363 pmii->wID = (UINT)id;
367 /*******************************************************************
368 * InsertMenuW (USER32.@)
370 BOOL WINAPI InsertMenuW( HMENU hMenu, UINT pos, UINT flags,
371 UINT_PTR id, LPCWSTR str )
373 MENUITEMINFOW mii;
375 if (IS_STRING_ITEM(flags) && str)
376 TRACE("hMenu %p, pos %d, flags %08x, id %04Ix, str %s\n",
377 hMenu, pos, flags, id, debugstr_w(str) );
378 else TRACE("hMenu %p, pos %d, flags %08x, id %04Ix, str %p (not a string)\n",
379 hMenu, pos, flags, id, str );
381 MENU_mnu2mnuii( flags, id, str, &mii);
382 mii.fMask |= MIIM_CHECKMARKS;
383 return NtUserThunkedMenuItemInfo( hMenu, pos, flags, NtUserInsertMenuItem, &mii, NULL );
387 /*******************************************************************
388 * InsertMenuA (USER32.@)
390 BOOL WINAPI InsertMenuA( HMENU hMenu, UINT pos, UINT flags,
391 UINT_PTR id, LPCSTR str )
393 BOOL ret = FALSE;
395 if (IS_STRING_ITEM(flags) && str)
397 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
398 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
399 if (newstr)
401 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
402 ret = InsertMenuW( hMenu, pos, flags, id, newstr );
403 HeapFree( GetProcessHeap(), 0, newstr );
405 return ret;
407 else return InsertMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
411 /*******************************************************************
412 * AppendMenuA (USER32.@)
414 BOOL WINAPI AppendMenuA( HMENU hMenu, UINT flags,
415 UINT_PTR id, LPCSTR data )
417 return InsertMenuA( hMenu, -1, flags | MF_BYPOSITION, id, data );
421 /*******************************************************************
422 * AppendMenuW (USER32.@)
424 BOOL WINAPI AppendMenuW( HMENU hMenu, UINT flags,
425 UINT_PTR id, LPCWSTR data )
427 return InsertMenuW( hMenu, -1, flags | MF_BYPOSITION, id, data );
431 /*******************************************************************
432 * ModifyMenuW (USER32.@)
434 BOOL WINAPI ModifyMenuW( HMENU hMenu, UINT pos, UINT flags,
435 UINT_PTR id, LPCWSTR str )
437 MENUITEMINFOW mii;
439 if (IS_STRING_ITEM(flags))
440 TRACE("%p %d %04x %04Ix %s\n", hMenu, pos, flags, id, debugstr_w(str) );
441 else
442 TRACE("%p %d %04x %04Ix %p\n", hMenu, pos, flags, id, str );
444 MENU_mnu2mnuii( flags, id, str, &mii);
445 return NtUserThunkedMenuItemInfo( hMenu, pos, flags, NtUserSetMenuItemInfo, &mii, NULL );
449 /*******************************************************************
450 * ModifyMenuA (USER32.@)
452 BOOL WINAPI ModifyMenuA( HMENU hMenu, UINT pos, UINT flags,
453 UINT_PTR id, LPCSTR str )
455 BOOL ret = FALSE;
457 if (IS_STRING_ITEM(flags) && str)
459 INT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
460 LPWSTR newstr = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
461 if (newstr)
463 MultiByteToWideChar( CP_ACP, 0, str, -1, newstr, len );
464 ret = ModifyMenuW( hMenu, pos, flags, id, newstr );
465 HeapFree( GetProcessHeap(), 0, newstr );
467 return ret;
469 else return ModifyMenuW( hMenu, pos, flags, id, (LPCWSTR)str );
473 /**********************************************************************
474 * CreatePopupMenu (USER32.@)
476 HMENU WINAPI CreatePopupMenu(void)
478 return NtUserCreateMenu( TRUE );
482 /**********************************************************************
483 * GetMenuCheckMarkDimensions (USER.417)
484 * GetMenuCheckMarkDimensions (USER32.@)
486 DWORD WINAPI GetMenuCheckMarkDimensions(void)
488 return MAKELONG( GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK) );
492 /**********************************************************************
493 * SetMenuItemBitmaps (USER32.@)
495 BOOL WINAPI SetMenuItemBitmaps( HMENU menu, UINT pos, UINT flags, HBITMAP uncheck, HBITMAP check )
497 MENUITEMINFOW info;
499 info.cbSize = sizeof(info);
500 info.fMask = MIIM_STATE;
501 if (!NtUserThunkedMenuItemInfo( menu, pos, flags, NtUserGetMenuItemInfoW, &info, NULL ))
502 return FALSE;
504 info.fMask = MIIM_STATE | MIIM_CHECKMARKS;
505 info.hbmpChecked = check;
506 info.hbmpUnchecked = uncheck;
507 if (check || uncheck) info.fState |= MF_USECHECKBITMAPS;
508 else info.fState &= ~MF_USECHECKBITMAPS;
509 return NtUserThunkedMenuItemInfo( menu, pos, flags, NtUserSetMenuItemInfo, &info, NULL );
513 /**********************************************************************
514 * CreateMenu (USER32.@)
516 HMENU WINAPI CreateMenu(void)
518 return NtUserCreateMenu( FALSE );
522 /**********************************************************************
523 * GetMenu (USER32.@)
525 HMENU WINAPI GetMenu( HWND hWnd )
527 HMENU retvalue = (HMENU)GetWindowLongPtrW( hWnd, GWLP_ID );
528 TRACE("for %p returning %p\n", hWnd, retvalue);
529 return retvalue;
533 /**********************************************************************
534 * GetSubMenu (USER32.@)
536 HMENU WINAPI GetSubMenu( HMENU menu, INT pos )
538 UINT ret = NtUserThunkedMenuItemInfo( menu, pos, MF_BYPOSITION, NtUserGetSubMenu, NULL, NULL );
539 return UlongToHandle( ret );
543 /**********************************************************************
544 * DrawMenuBar (USER32.@)
546 BOOL WINAPI DrawMenuBar( HWND hwnd )
548 return NtUserDrawMenuBar( hwnd );
552 /*****************************************************************
553 * LoadMenuA (USER32.@)
555 HMENU WINAPI LoadMenuA( HINSTANCE instance, LPCSTR name )
557 HRSRC hrsrc = FindResourceA( instance, name, (LPSTR)RT_MENU );
558 if (!hrsrc) return 0;
559 return LoadMenuIndirectA( LoadResource( instance, hrsrc ));
563 /*****************************************************************
564 * LoadMenuW (USER32.@)
566 HMENU WINAPI LoadMenuW( HINSTANCE instance, LPCWSTR name )
568 HRSRC hrsrc = FindResourceW( instance, name, (LPWSTR)RT_MENU );
569 if (!hrsrc) return 0;
570 return LoadMenuIndirectW( LoadResource( instance, hrsrc ));
574 /**********************************************************************
575 * LoadMenuIndirectW (USER32.@)
577 HMENU WINAPI LoadMenuIndirectW( LPCVOID template )
579 HMENU hMenu;
580 WORD version, offset;
581 LPCSTR p = template;
583 version = GET_WORD(p);
584 p += sizeof(WORD);
585 TRACE("%p, ver %d\n", template, version );
586 switch (version)
588 case 0: /* standard format is version of 0 */
589 offset = GET_WORD(p);
590 p += sizeof(WORD) + offset;
591 if (!(hMenu = CreateMenu())) return 0;
592 if (!MENU_ParseResource( p, hMenu ))
594 NtUserDestroyMenu( hMenu );
595 return 0;
597 return hMenu;
598 case 1: /* extended format is version of 1 */
599 offset = GET_WORD(p);
600 p += sizeof(WORD) + offset;
601 if (!(hMenu = CreateMenu())) return 0;
602 if (!MENUEX_ParseResource( p, hMenu))
604 NtUserDestroyMenu( hMenu );
605 return 0;
607 return hMenu;
608 default:
609 ERR("version %d not supported.\n", version);
610 return 0;
615 /**********************************************************************
616 * LoadMenuIndirectA (USER32.@)
618 HMENU WINAPI LoadMenuIndirectA( LPCVOID template )
620 return LoadMenuIndirectW( template );
624 /**********************************************************************
625 * IsMenu (USER32.@)
627 BOOL WINAPI IsMenu( HMENU menu )
629 MENUINFO info;
631 info.cbSize = sizeof(info);
632 info.fMask = 0;
633 if (GetMenuInfo( menu, &info )) return TRUE;
635 SetLastError(ERROR_INVALID_MENU_HANDLE);
636 return FALSE;
640 /**********************************************************************
641 * GetMenuItemInfoA (USER32.@)
643 BOOL WINAPI GetMenuItemInfoA( HMENU hmenu, UINT item, BOOL bypos,
644 LPMENUITEMINFOA lpmii)
646 BOOL ret;
647 MENUITEMINFOA mii;
648 if( lpmii->cbSize != sizeof( mii) &&
649 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
650 SetLastError( ERROR_INVALID_PARAMETER);
651 return FALSE;
653 memcpy( &mii, lpmii, lpmii->cbSize);
654 mii.cbSize = sizeof( mii);
655 ret = NtUserThunkedMenuItemInfo( hmenu, item, bypos ? MF_BYPOSITION : 0,
656 NtUserGetMenuItemInfoA, (MENUITEMINFOW *)&mii, NULL );
657 mii.cbSize = lpmii->cbSize;
658 memcpy( lpmii, &mii, mii.cbSize );
659 return ret;
662 /**********************************************************************
663 * GetMenuItemInfoW (USER32.@)
665 BOOL WINAPI GetMenuItemInfoW( HMENU hmenu, UINT item, BOOL bypos,
666 LPMENUITEMINFOW lpmii)
668 BOOL ret;
669 MENUITEMINFOW mii;
670 if( lpmii->cbSize != sizeof( mii) &&
671 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) {
672 SetLastError( ERROR_INVALID_PARAMETER);
673 return FALSE;
675 memcpy( &mii, lpmii, lpmii->cbSize);
676 mii.cbSize = sizeof( mii);
677 ret = NtUserThunkedMenuItemInfo( hmenu, item, bypos ? MF_BYPOSITION : 0,
678 NtUserGetMenuItemInfoW, &mii, NULL );
679 mii.cbSize = lpmii->cbSize;
680 memcpy( lpmii, &mii, mii.cbSize );
681 return ret;
685 /**********************************************************************
686 * MENU_NormalizeMenuItemInfoStruct
688 * Helper for SetMenuItemInfo and InsertMenuItemInfo:
689 * check, copy and extend the MENUITEMINFO struct from the version that the application
690 * supplied to the version used by wine source. */
691 static BOOL MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW *pmii_in,
692 MENUITEMINFOW *pmii_out )
694 /* do we recognize the size? */
695 if( !pmii_in || (pmii_in->cbSize != sizeof( MENUITEMINFOW) &&
696 pmii_in->cbSize != sizeof( MENUITEMINFOW) - sizeof( pmii_in->hbmpItem)) ) {
697 SetLastError( ERROR_INVALID_PARAMETER);
698 return FALSE;
700 /* copy the fields that we have */
701 memcpy( pmii_out, pmii_in, pmii_in->cbSize);
702 /* if the hbmpItem member is missing then extend */
703 if( pmii_in->cbSize != sizeof( MENUITEMINFOW)) {
704 pmii_out->cbSize = sizeof( MENUITEMINFOW);
705 pmii_out->hbmpItem = NULL;
707 /* test for invalid bit combinations */
708 if( (pmii_out->fMask & MIIM_TYPE &&
709 pmii_out->fMask & (MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) ||
710 (pmii_out->fMask & MIIM_FTYPE && pmii_out->fType & MFT_BITMAP)) {
711 WARN("invalid combination of fMask bits used\n");
712 /* this does not happen on Win9x/ME */
713 SetLastError( ERROR_INVALID_PARAMETER);
714 return FALSE;
716 /* convert old style (MIIM_TYPE) to the new */
717 if( pmii_out->fMask & MIIM_TYPE){
718 pmii_out->fMask |= MIIM_FTYPE;
719 if( IS_STRING_ITEM(pmii_out->fType)){
720 pmii_out->fMask |= MIIM_STRING;
721 } else if( (pmii_out->fType) & MFT_BITMAP){
722 pmii_out->fMask |= MIIM_BITMAP;
723 pmii_out->hbmpItem = UlongToHandle(LOWORD(pmii_out->dwTypeData));
726 return TRUE;
729 /**********************************************************************
730 * SetMenuItemInfoA (USER32.@)
732 BOOL WINAPI SetMenuItemInfoA(HMENU hmenu, UINT item, BOOL bypos,
733 const MENUITEMINFOA *lpmii)
735 WCHAR *strW = NULL;
736 MENUITEMINFOW mii;
737 BOOL ret;
739 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu, item, bypos, lpmii);
741 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
743 if ((mii.fMask & MIIM_STRING) && mii.dwTypeData)
745 const char *str = (const char *)mii.dwTypeData;
746 UINT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
747 if (!(strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
748 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
749 mii.dwTypeData = strW;
752 ret = NtUserThunkedMenuItemInfo( hmenu, item, bypos ? MF_BYPOSITION : 0,
753 NtUserSetMenuItemInfo, &mii, NULL );
755 HeapFree( GetProcessHeap(), 0, strW );
756 return ret;
759 /**********************************************************************
760 * SetMenuItemInfoW (USER32.@)
762 BOOL WINAPI SetMenuItemInfoW(HMENU hmenu, UINT item, BOOL bypos,
763 const MENUITEMINFOW *lpmii)
765 MENUITEMINFOW mii;
767 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu, item, bypos, lpmii);
769 if (!MENU_NormalizeMenuItemInfoStruct( lpmii, &mii )) return FALSE;
771 return NtUserThunkedMenuItemInfo( hmenu, item, bypos ? MF_BYPOSITION : 0,
772 NtUserSetMenuItemInfo, &mii, NULL );
775 /**********************************************************************
776 * GetMenuDefaultItem (USER32.@)
778 UINT WINAPI GetMenuDefaultItem( HMENU menu, UINT bypos, UINT flags )
780 return NtUserThunkedMenuItemInfo( menu, bypos, flags, NtUserGetMenuDefaultItem, NULL, NULL );
784 /**********************************************************************
785 * InsertMenuItemA (USER32.@)
787 BOOL WINAPI InsertMenuItemA(HMENU hMenu, UINT uItem, BOOL bypos,
788 const MENUITEMINFOA *lpmii)
790 WCHAR *strW = NULL;
791 MENUITEMINFOW mii;
792 BOOL ret;
794 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, bypos, lpmii);
796 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
798 if ((mii.fMask & MIIM_STRING) && mii.dwTypeData)
800 const char *str = (const char *)mii.dwTypeData;
801 UINT len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
802 if (!(strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
803 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
804 mii.dwTypeData = strW;
807 ret = NtUserThunkedMenuItemInfo( hMenu, uItem, bypos ? MF_BYPOSITION : 0,
808 NtUserInsertMenuItem, &mii, NULL );
810 HeapFree( GetProcessHeap(), 0, strW );
811 return ret;
815 /**********************************************************************
816 * InsertMenuItemW (USER32.@)
818 BOOL WINAPI InsertMenuItemW(HMENU hMenu, UINT uItem, BOOL bypos,
819 const MENUITEMINFOW *lpmii)
821 MENUITEMINFOW mii;
823 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, bypos, lpmii);
825 if (!MENU_NormalizeMenuItemInfoStruct( lpmii, &mii )) return FALSE;
827 return NtUserThunkedMenuItemInfo( hMenu, uItem, bypos ? MF_BYPOSITION : 0,
828 NtUserInsertMenuItem, &mii, NULL );
831 /**********************************************************************
832 * CheckMenuRadioItem (USER32.@)
834 BOOL WINAPI CheckMenuRadioItem( HMENU menu, UINT first, UINT last, UINT check, UINT flags )
836 MENUITEMINFOW info; /* abuse to pass last and check */
837 info.cch = last;
838 info.fMask = check;
839 return NtUserThunkedMenuItemInfo( menu, first, flags, NtUserCheckMenuRadioItem, &info, NULL );
843 /**********************************************************************
844 * SetMenuInfo (USER32.@)
846 BOOL WINAPI SetMenuInfo( HMENU menu, const MENUINFO *info )
848 TRACE( "(%p %p)\n", menu, info );
850 if (!info || info->cbSize != sizeof(*info))
852 SetLastError( ERROR_INVALID_PARAMETER);
853 return FALSE;
856 return NtUserThunkedMenuInfo( menu, info );
859 /**********************************************************************
860 * GetMenuInfo (USER32.@)
862 BOOL WINAPI GetMenuInfo( HMENU menu, MENUINFO *info )
864 return NtUserGetMenuInfo( menu, info );
868 /**********************************************************************
869 * GetMenuContextHelpId (USER32.@)
871 DWORD WINAPI GetMenuContextHelpId( HMENU menu )
873 MENUINFO info;
874 TRACE( "(%p)\n", menu );
875 info.cbSize = sizeof(info);
876 info.fMask = MIM_HELPID;
877 return GetMenuInfo( menu, &info ) ? info.dwContextHelpID : 0;
880 /**********************************************************************
881 * MenuItemFromPoint (USER32.@)
883 INT WINAPI MenuItemFromPoint( HWND hwnd, HMENU menu, POINT pt )
885 return NtUserMenuItemFromPoint( hwnd, menu, pt.x, pt.y );
889 /**********************************************************************
890 * CalcMenuBar (USER32.@)
892 DWORD WINAPI CalcMenuBar(HWND hwnd, DWORD left, DWORD right, DWORD top, RECT *rect)
894 FIXME("(%p, %ld, %ld, %ld, %p): stub\n", hwnd, left, right, top, rect);
895 return 0;
899 /**********************************************************************
900 * TranslateAcceleratorA (USER32.@)
901 * TranslateAccelerator (USER32.@)
903 INT WINAPI TranslateAcceleratorA( HWND hWnd, HACCEL hAccel, LPMSG msg )
905 switch (msg->message)
907 case WM_KEYDOWN:
908 case WM_SYSKEYDOWN:
909 return NtUserTranslateAccelerator( hWnd, hAccel, msg );
911 case WM_CHAR:
912 case WM_SYSCHAR:
914 MSG msgW = *msg;
915 char ch = LOWORD(msg->wParam);
916 WCHAR wch;
917 MultiByteToWideChar(CP_ACP, 0, &ch, 1, &wch, 1);
918 msgW.wParam = MAKEWPARAM(wch, HIWORD(msg->wParam));
919 return NtUserTranslateAccelerator( hWnd, hAccel, &msgW );
922 default:
923 return 0;