[BROWSEUI][USER32] Explicitly use MAKEINTRESOURCEW() for consistency (#3192)
[reactos.git] / win32ss / user / user32 / windows / menu.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS user32.dll
4 * FILE: win32ss/user/user32/windows/menu.c
5 * PURPOSE: Menus
6 *
7 * PROGRAMMERS: Casper S. Hornstrup
8 * James Tabor
9 */
10
11 #include <user32.h>
12
13 BOOL WINAPI GdiValidateHandle(HGDIOBJ hobj);
14
15 WINE_DEFAULT_DEBUG_CHANNEL(menu);
16
17 /* internal popup menu window messages */
18
19 #define MM_SETMENUHANDLE (WM_USER + 0)
20 #define MM_GETMENUHANDLE (WM_USER + 1)
21
22 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
23
24 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
25
26 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
27
28 #define MENUITEMINFO_TYPE_MASK \
29 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
30 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
31 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
32
33 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
34
35 #define STATE_MASK (~TYPE_MASK)
36
37 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
38
39 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
40
41 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */
42 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
43 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
44
45 #define IS_SYSTEM_MENU(MenuInfo) \
46 (0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
47
48 #define IS_SYSTEM_POPUP(MenuInfo) \
49 (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
50
51 #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
52
53 /*********************************************************************
54 * PopupMenu class descriptor
55 */
56 const struct builtin_class_descr POPUPMENU_builtin_class =
57 {
58 WC_MENU, /* name */
59 CS_SAVEBITS | CS_DBLCLKS, /* style */
60 NULL, /* FIXME - procA */
61 PopupMenuWndProcW, /* FIXME - procW */
62 sizeof(MENUINFO *), /* extra */
63 (LPCWSTR) IDC_ARROW, /* cursor */
64 (HBRUSH)(COLOR_MENU + 1) /* brush */
65 };
66
67 #ifndef GET_WORD
68 #define GET_WORD(ptr) (*(WORD *)(ptr))
69 #endif
70 #ifndef GET_DWORD
71 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
72 #endif
73
74
75 /***********************************************************************
76 * MENU_GetMenu
77 *
78 * Validate the given menu handle and returns the menu structure pointer.
79 */
80 FORCEINLINE PMENU MENU_GetMenu(HMENU hMenu)
81 {
82 return ValidateHandleNoErr(hMenu, TYPE_MENU);
83 }
84
85 /***********************************************************************
86 * MENU_FindItem
87 *
88 * Find a menu item. Return a pointer on the item, and modifies *hmenu
89 * in case the item was in a sub-menu.
90 */
91 ITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
92 {
93 MENU *menu;
94 ITEM *fallback = NULL;
95 UINT fallback_pos = 0;
96 UINT i;
97 PITEM pItem;
98
99 if ((*hmenu == (HMENU)0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
100 if (wFlags & MF_BYPOSITION)
101 {
102 if (*nPos >= menu->cItems) return NULL;
103 pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
104 if (pItem) pItem = &pItem[*nPos];
105 return pItem;
106 }
107 else
108 {
109 PITEM item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
110 for (i = 0; item && (i < menu->cItems); i++, item++)
111 {
112 if (item->spSubMenu)
113 {
114 PMENU pSubMenu = DesktopPtrToUser(item->spSubMenu);
115 HMENU hsubmenu = UserHMGetHandle(pSubMenu);
116 ITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
117 if (subitem)
118 {
119 *hmenu = hsubmenu;
120 return subitem;
121 }
122 else if (item->wID == *nPos)
123 {
124 /* fallback to this item if nothing else found */
125 fallback_pos = i;
126 fallback = item;
127 }
128 }
129 else if (item->wID == *nPos)
130 {
131 *nPos = i;
132 return item;
133 }
134 }
135 }
136
137 if (fallback)
138 *nPos = fallback_pos;
139
140 return fallback;
141 }
142
143 UINT FASTCALL
144 IntGetMenuDefaultItem(PMENU Menu, BOOL fByPos, UINT gmdiFlags, DWORD *gismc)
145 {
146 UINT i = 0;
147 PITEM Item = Menu->rgItems ? DesktopPtrToUser(Menu->rgItems) : NULL;
148
149 /* empty menu */
150 if (!Item) return -1;
151
152 while ( !( Item->fState & MFS_DEFAULT ) )
153 {
154 i++; Item++;
155 if (i >= Menu->cItems ) return -1;
156 }
157
158 /* default: don't return disabled items */
159 if ( (!(GMDI_USEDISABLED & gmdiFlags)) && (Item->fState & MFS_DISABLED )) return -1;
160
161 /* search rekursiv when needed */
162 if ( (gmdiFlags & GMDI_GOINTOPOPUPS) && Item->spSubMenu )
163 {
164 UINT ret;
165 (*gismc)++;
166 ret = IntGetMenuDefaultItem( DesktopPtrToUser(Item->spSubMenu), fByPos, gmdiFlags, gismc );
167 (*gismc)--;
168 if ( -1 != ret ) return ret;
169
170 /* when item not found in submenu, return the popup item */
171 }
172 return ( fByPos ) ? i : Item->wID;
173 }
174
175 static BOOL GetMenuItemInfo_common ( HMENU hmenu,
176 UINT item,
177 BOOL bypos,
178 LPMENUITEMINFOW lpmii,
179 BOOL unicode)
180 {
181 ITEM *pItem = MENU_FindItem (&hmenu, &item, bypos ? MF_BYPOSITION : 0);
182
183 //debug_print_menuitem("GetMenuItemInfo_common: ", pItem, "");
184
185 if (!pItem)
186 {
187 SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
188 return FALSE;
189 }
190
191 if( lpmii->fMask & MIIM_TYPE)
192 {
193 if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP))
194 {
195 ERR("invalid combination of fMask bits used\n");
196 /* this does not happen on Win9x/ME */
197 SetLastError( ERROR_INVALID_PARAMETER);
198 return FALSE;
199 }
200 lpmii->fType = pItem->fType & MENUITEMINFO_TYPE_MASK;
201 if (pItem->hbmp && !IS_MAGIC_BITMAP(pItem->hbmp))
202 lpmii->fType |= MFT_BITMAP;
203 lpmii->hbmpItem = pItem->hbmp; /* not on Win9x/ME */
204 if( lpmii->fType & MFT_BITMAP)
205 {
206 lpmii->dwTypeData = (LPWSTR) pItem->hbmp;
207 lpmii->cch = 0;
208 }
209 else if( lpmii->fType & (MFT_OWNERDRAW | MFT_SEPARATOR))
210 {
211 /* this does not happen on Win9x/ME */
212 lpmii->dwTypeData = 0;
213 lpmii->cch = 0;
214 }
215 }
216
217 /* copy the text string */
218 if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)))
219 {
220 if( !pItem->Xlpstr )
221 { // Very strange this fixes a wine test with a crash.
222 if(lpmii->dwTypeData && lpmii->cch && !(GdiValidateHandle((HGDIOBJ)lpmii->dwTypeData)) )
223 {
224 if( unicode)
225 *((WCHAR *)lpmii->dwTypeData) = 0;
226 else
227 *((CHAR *)lpmii->dwTypeData) = 0;
228 }
229 lpmii->cch = 0;
230 }
231 else
232 {
233 int len;
234 LPWSTR text = DesktopPtrToUser(pItem->Xlpstr);
235 if (unicode)
236 {
237 len = strlenW(text);
238 if(lpmii->dwTypeData && lpmii->cch)
239 lstrcpynW(lpmii->dwTypeData, text, lpmii->cch);
240 }
241 else
242 {
243 len = WideCharToMultiByte( CP_ACP, 0, text, -1, NULL, 0, NULL, NULL ) - 1;
244 if(lpmii->dwTypeData && lpmii->cch)
245 if (!WideCharToMultiByte( CP_ACP, 0, text, -1,
246 (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
247 ((LPSTR)lpmii->dwTypeData)[lpmii->cch - 1] = 0;
248 }
249 /* if we've copied a substring we return its length */
250 if(lpmii->dwTypeData && lpmii->cch)
251 if (lpmii->cch <= len + 1)
252 lpmii->cch--;
253 else
254 lpmii->cch = len;
255 else
256 {
257 /* return length of string */
258 /* not on Win9x/ME if fType & MFT_BITMAP */
259 lpmii->cch = len;
260 }
261 }
262 }
263
264 if (lpmii->fMask & MIIM_FTYPE)
265 lpmii->fType = pItem->fType & MENUITEMINFO_TYPE_MASK;
266
267 if (lpmii->fMask & MIIM_BITMAP)
268 lpmii->hbmpItem = pItem->hbmp;
269
270 if (lpmii->fMask & MIIM_STATE)
271 lpmii->fState = pItem->fState & MENUITEMINFO_STATE_MASK;
272
273 if (lpmii->fMask & MIIM_ID)
274 lpmii->wID = pItem->wID;
275
276 if (lpmii->fMask & MIIM_SUBMENU && pItem->spSubMenu )
277 {
278 PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
279 HMENU hSubMenu = UserHMGetHandle(pSubMenu);
280 lpmii->hSubMenu = hSubMenu;
281 }
282 else
283 {
284 /* hSubMenu is always cleared
285 * (not on Win9x/ME ) */
286 lpmii->hSubMenu = 0;
287 }
288
289 if (lpmii->fMask & MIIM_CHECKMARKS)
290 {
291 lpmii->hbmpChecked = pItem->hbmpChecked;
292 lpmii->hbmpUnchecked = pItem->hbmpUnchecked;
293 }
294 if (lpmii->fMask & MIIM_DATA)
295 lpmii->dwItemData = pItem->dwItemData;
296
297 return TRUE;
298 }
299
300
301 //
302 // User side Menu Class Proc.
303 //
304 LRESULT WINAPI
305 PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
306 {
307 LRESULT lResult;
308 PWND pWnd;
309
310 TRACE("PMWPW : hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
311
312 pWnd = ValidateHwnd(Wnd);
313 if (pWnd)
314 {
315 if (!pWnd->fnid)
316 {
317 if (Message != WM_NCCREATE)
318 {
319 return DefWindowProcW(Wnd, Message, wParam, lParam);
320 }
321 }
322 else
323 {
324 if (pWnd->fnid != FNID_MENU)
325 {
326 ERR("Wrong window class for Menu!\n");
327 return 0;
328 }
329 }
330 }
331
332 switch(Message)
333 {
334 case WM_DESTROY:
335 case WM_NCDESTROY:
336 case WM_NCCREATE:
337 case WM_CREATE:
338 case MM_SETMENUHANDLE:
339 case MM_GETMENUHANDLE:
340 case MN_SETHMENU:
341 case MN_GETHMENU:
342 case WM_PAINT:
343 case WM_PRINTCLIENT:
344 {
345 TRACE("Menu Class ProcW\n");
346 NtUserMessageCall( Wnd, Message, wParam, lParam, (ULONG_PTR)&lResult, FNID_MENU, FALSE);
347 return lResult;
348 }
349 case WM_MOUSEACTIVATE: /* We don't want to be activated */
350 return MA_NOACTIVATE;
351
352 case WM_ERASEBKGND:
353 return 1;
354
355 case WM_SHOWWINDOW: // Not sure what this does....
356 if (0 != wParam)
357 {
358 if (0 == GetWindowLongPtrW(Wnd, 0))
359 {
360 OutputDebugStringA("no menu to display\n");
361 }
362 }
363 else
364 {
365 //SetWindowLongPtrW(Wnd, 0, 0);
366 }
367 break;
368
369 default:
370 return DefWindowProcW(Wnd, Message, wParam, lParam);
371 }
372
373 return 0;
374 }
375
376 LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
377 {
378 PWND pWnd;
379
380 pWnd = ValidateHwnd(Wnd);
381 if (pWnd && !pWnd->fnid && Message != WM_NCCREATE)
382 {
383 return DefWindowProcA(Wnd, Message, wParam, lParam);
384 }
385 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
386
387 switch(Message)
388 {
389 case WM_NCCREATE:
390 case WM_CREATE:
391 case WM_MOUSEACTIVATE:
392 case WM_PAINT:
393 case WM_PRINTCLIENT:
394 case WM_ERASEBKGND:
395 case WM_DESTROY:
396 case WM_NCDESTROY:
397 case WM_SHOWWINDOW:
398 case MM_SETMENUHANDLE:
399 case MM_GETMENUHANDLE:
400 case MN_SETHMENU:
401 case MN_GETHMENU:
402 return PopupMenuWndProcW(Wnd, Message, wParam, lParam);
403
404 default:
405 return DefWindowProcA(Wnd, Message, wParam, lParam);
406 }
407 return 0;
408 }
409
410 /**********************************************************************
411 * MENU_ParseResource
412 *
413 * Parse a standard menu resource and add items to the menu.
414 * Return a pointer to the end of the resource.
415 *
416 * NOTE: flags is equivalent to the mtOption field
417 */
418 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu)
419 {
420 WORD flags, id = 0;
421 HMENU hSubMenu;
422 LPCWSTR str;
423 BOOL end = FALSE;
424
425 do
426 {
427 flags = GET_WORD(res);
428
429 /* remove MF_END flag before passing it to AppendMenu()! */
430 end = (flags & MF_END);
431 if(end) flags ^= MF_END;
432
433 res += sizeof(WORD);
434 if(!(flags & MF_POPUP))
435 {
436 id = GET_WORD(res);
437 res += sizeof(WORD);
438 }
439 str = (LPCWSTR)res;
440 res += (strlenW(str) + 1) * sizeof(WCHAR);
441
442 if (flags & MF_POPUP)
443 {
444 hSubMenu = CreatePopupMenu();
445 if(!hSubMenu) return NULL;
446 if(!(res = MENU_ParseResource(res, hSubMenu))) return NULL;
447 AppendMenuW(hMenu, flags, (UINT_PTR)hSubMenu, (LPCWSTR)str);
448 }
449 else /* Not a popup */
450 {
451 AppendMenuW(hMenu, flags, id, *(LPCWSTR)str ? (LPCWSTR)str : NULL);
452 }
453 } while(!end);
454 return res;
455 }
456
457 /**********************************************************************
458 * MENUEX_ParseResource
459 *
460 * Parse an extended menu resource and add items to the menu.
461 * Return a pointer to the end of the resource.
462 */
463 static LPCSTR MENUEX_ParseResource(LPCSTR res, HMENU hMenu)
464 {
465 WORD resinfo;
466 do
467 {
468 MENUITEMINFOW mii;
469
470 mii.cbSize = sizeof(mii);
471 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
472 mii.fType = GET_DWORD(res);
473 res += sizeof(DWORD);
474 mii.fState = GET_DWORD(res);
475 res += sizeof(DWORD);
476 mii.wID = GET_DWORD(res);
477 res += sizeof(DWORD);
478 resinfo = GET_WORD(res);
479 res += sizeof(WORD);
480 /* Align the text on a word boundary. */
481 res += (~((UINT_PTR)res - 1)) & 1;
482 mii.dwTypeData = (LPWSTR)res;
483 mii.cch = strlenW(mii.dwTypeData);
484 res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
485 /* Align the following fields on a dword boundary. */
486 res += (~((UINT_PTR)res - 1)) & 3;
487
488 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
489 mii.fType, mii.fState, mii.wID, resinfo, mii.dwTypeData);
490
491 if (resinfo & 1) /* Pop-up? */
492 {
493 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
494 res += sizeof(DWORD);
495 mii.hSubMenu = CreatePopupMenu();
496 if (!mii.hSubMenu)
497 {
498 ERR("CreatePopupMenu failed\n");
499 return NULL;
500 }
501
502 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu)))
503 {
504 ERR("MENUEX_ParseResource failed\n");
505 DestroyMenu(mii.hSubMenu);
506 return NULL;
507 }
508 mii.fMask |= MIIM_SUBMENU;
509 mii.fType |= MF_POPUP;
510 }
511 else if (!mii.dwTypeData[0] && !(mii.fType & MF_SEPARATOR))
512 {
513 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
514 mii.wID, mii.fType);
515 mii.fType |= MF_SEPARATOR;
516 }
517 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
518 } while (!(resinfo & MF_END));
519 return res;
520 }
521
522
523 /**********************************************************************
524 * MENU_mnu2mnuii
525 *
526 * Uses flags, id and text ptr, passed by InsertMenu() and
527 * ModifyMenu() to setup a MenuItemInfo structure.
528 */
529 static void MENU_mnu2mnuii( UINT flags, UINT_PTR id, LPCWSTR str, LPMENUITEMINFOW pmii, BOOL Unicode)
530 {
531 RtlZeroMemory( pmii, sizeof( MENUITEMINFOW));
532 pmii->cbSize = sizeof( MENUITEMINFOW);
533 pmii->fMask = MIIM_STATE | MIIM_ID | MIIM_FTYPE;
534 /* setting bitmap clears text and vice versa */
535 if( IS_STRING_ITEM(flags)) {
536 pmii->fMask |= MIIM_STRING | MIIM_BITMAP;
537 if( !str)
538 flags |= MF_SEPARATOR;
539 /* Item beginning with a backspace is a help item */
540 /* FIXME: wrong place, this is only true in win16 */
541 else
542 {
543 if (Unicode)
544 {
545 if (*str == '\b')
546 {
547 flags |= MF_HELP;
548 str++;
549 }
550 }
551 else
552 {
553 LPCSTR NewItemA = (LPCSTR) str;
554 if (*NewItemA == '\b')
555 {
556 flags |= MF_HELP;
557 NewItemA++;
558 str = (LPCWSTR) NewItemA;
559 }
560 TRACE("A cch %d\n",strlen(NewItemA));
561 }
562 }
563 pmii->dwTypeData = (LPWSTR)str;
564 } else if( flags & MFT_BITMAP){
565 pmii->fMask |= MIIM_BITMAP | MIIM_STRING;
566 pmii->hbmpItem = (HBITMAP)str;
567 }
568 if( flags & MF_OWNERDRAW){
569 pmii->fMask |= MIIM_DATA;
570 pmii->dwItemData = (ULONG_PTR) str;
571 }
572 if( flags & MF_POPUP && MENU_GetMenu((HMENU)id)) {
573 pmii->fMask |= MIIM_SUBMENU;
574 pmii->hSubMenu = (HMENU)id;
575 }
576 if( flags & MF_SEPARATOR) flags |= MF_GRAYED | MF_DISABLED;
577 pmii->fState = flags & MENUITEMINFO_STATE_MASK & ~MFS_DEFAULT;
578 pmii->fType = flags & MENUITEMINFO_TYPE_MASK;
579 pmii->wID = (UINT)id;
580 }
581
582 /**********************************************************************
583 * MENU_NormalizeMenuItemInfoStruct
584 *
585 * Helper for SetMenuItemInfo and InsertMenuItemInfo:
586 * check, copy and extend the MENUITEMINFO struct from the version that the application
587 * supplied to the version used by wine source. */
588 static BOOL MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW *pmii_in,
589 MENUITEMINFOW *pmii_out )
590 {
591 /* do we recognize the size? */
592 if( !pmii_in || (pmii_in->cbSize != sizeof( MENUITEMINFOW) &&
593 pmii_in->cbSize != sizeof( MENUITEMINFOW) - sizeof( pmii_in->hbmpItem)) ) {
594 SetLastError( ERROR_INVALID_PARAMETER);
595 return FALSE;
596 }
597 /* copy the fields that we have */
598 memcpy( pmii_out, pmii_in, pmii_in->cbSize);
599 /* if the hbmpItem member is missing then extend */
600 if( pmii_in->cbSize != sizeof( MENUITEMINFOW)) {
601 pmii_out->cbSize = sizeof( MENUITEMINFOW);
602 pmii_out->hbmpItem = NULL;
603 }
604 /* test for invalid bit combinations */
605 if( (pmii_out->fMask & MIIM_TYPE &&
606 pmii_out->fMask & (MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) ||
607 (pmii_out->fMask & MIIM_FTYPE && pmii_out->fType & MFT_BITMAP)) {
608 ERR("invalid combination of fMask bits used\n");
609 /* this does not happen on Win9x/ME */
610 SetLastError( ERROR_INVALID_PARAMETER);
611 return FALSE;
612 }
613 /* convert old style (MIIM_TYPE) to the new and keep the old one too */
614 if( pmii_out->fMask & MIIM_TYPE){
615 pmii_out->fMask |= MIIM_FTYPE;
616 if( IS_STRING_ITEM(pmii_out->fType)){
617 pmii_out->fMask |= MIIM_STRING;
618 } else if( (pmii_out->fType) & MFT_BITMAP){
619 pmii_out->fMask |= MIIM_BITMAP;
620 pmii_out->hbmpItem = UlongToHandle(LOWORD(pmii_out->dwTypeData));
621 }
622 }
623 if (pmii_out->fMask & MIIM_FTYPE )
624 {
625 pmii_out->fType &= ~MENUITEMINFO_TYPE_MASK;
626 pmii_out->fType |= pmii_in->fType & MENUITEMINFO_TYPE_MASK;
627 }
628 if (pmii_out->fMask & MIIM_STATE)
629 /* Other menu items having MFS_DEFAULT are not converted
630 to normal items */
631 pmii_out->fState = pmii_in->fState & MENUITEMINFO_STATE_MASK;
632
633 if (pmii_out->fMask & MIIM_SUBMENU)
634 {
635 if ((pmii_out->hSubMenu != NULL) && !IsMenu(pmii_out->hSubMenu))
636 return FALSE;
637 }
638
639 return TRUE;
640 }
641
642 BOOL
643 MenuInit(VOID)
644 {
645 return TRUE;
646 }
647
648 VOID
649 MenuCleanup(VOID)
650 {
651 }
652
653
654 NTSTATUS WINAPI
655 User32LoadSysMenuTemplateForKernel(PVOID Arguments, ULONG ArgumentLength)
656 {
657 LRESULT Result = 0;
658
659 // Use this for Menu Ole!!
660
661 return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
662 }
663
664 NTSTATUS WINAPI
665 User32CallLoadMenuFromKernel(PVOID Arguments, ULONG ArgumentLength)
666 {
667 PLOADMENU_CALLBACK_ARGUMENTS Common;
668 LRESULT Result;
669
670 Common = (PLOADMENU_CALLBACK_ARGUMENTS) Arguments;
671
672 Result = (LRESULT)LoadMenuW(Common->hModule, Common->InterSource ? MAKEINTRESOURCEW(Common->InterSource) : (LPCWSTR)&Common->MenuName);
673
674 return ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS);
675 }
676
677
678 /* FUNCTIONS *****************************************************************/
679
680 /*
681 * @implemented
682 */
683 BOOL WINAPI
684 AppendMenuA(HMENU hMenu,
685 UINT uFlags,
686 UINT_PTR uIDNewItem,
687 LPCSTR lpNewItem)
688 {
689 MENUITEMINFOW mii;
690 UNICODE_STRING UnicodeString;
691 BOOL res;
692
693 RtlInitUnicodeString(&UnicodeString, 0);
694
695 MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE);
696
697 /* copy the text string, it will be one or the other */
698 if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
699 {
700 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
701 {
702 SetLastError (ERROR_NOT_ENOUGH_MEMORY);
703 return FALSE;
704 }
705 mii.dwTypeData = UnicodeString.Buffer;
706 mii.cch = UnicodeString.Length / sizeof(WCHAR);
707 }
708 else
709 {
710 TRACE("AMA Handle bitmaps\n");
711 }
712 ////// Answer a question, why a -1? To hunt for the end of the item list. Get it, to Append?
713 res = NtUserThunkedMenuItemInfo(hMenu, -1, TRUE, TRUE, &mii, &UnicodeString);
714 if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
715 return res;
716 }
717
718 /*
719 * @implemented
720 */
721 BOOL WINAPI
722 AppendMenuW(HMENU hMenu,
723 UINT uFlags,
724 UINT_PTR uIDNewItem,
725 LPCWSTR lpNewItem)
726 {
727 MENUITEMINFOW mii;
728 UNICODE_STRING MenuText;
729 BOOL res;
730
731 RtlInitUnicodeString(&MenuText, 0);
732
733 MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE);
734
735 /* copy the text string, it will be one or the other */
736 if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
737 {
738 RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData);
739 mii.dwTypeData = MenuText.Buffer;
740 mii.cch = MenuText.Length / sizeof(WCHAR);
741 }
742 res = NtUserThunkedMenuItemInfo(hMenu, -1, TRUE, TRUE, &mii, &MenuText);
743 return res;
744 }
745
746 /*
747 * @implemented
748 */
749 DWORD WINAPI
750 CheckMenuItem(HMENU hmenu,
751 UINT uIDCheckItem,
752 UINT uCheck)
753 {
754 PITEM item;
755 DWORD Ret;
756 UINT uID = uIDCheckItem;
757
758 if (!ValidateHandle(hmenu, TYPE_MENU))
759 return -1;
760
761 if (!(item = MENU_FindItem( &hmenu, &uID, uCheck ))) return -1;
762
763 Ret = item->fState & MFS_CHECKED;
764 if ( Ret == (uCheck & MFS_CHECKED)) return Ret; // Already Checked...
765
766 return NtUserCheckMenuItem(hmenu, uIDCheckItem, uCheck);
767 }
768
769 /*
770 * @implemented
771 */
772 BOOL WINAPI
773 CheckMenuRadioItem(HMENU hMenu,
774 UINT first,
775 UINT last,
776 UINT check,
777 UINT bypos)
778 {
779 BOOL done = FALSE;
780 UINT i;
781 PITEM mi_first = NULL, mi_check;
782 HMENU m_first, m_check;
783 MENUITEMINFOW mii;
784 mii.cbSize = sizeof( mii);
785
786 for (i = first; i <= last; i++)
787 {
788 UINT pos = i;
789
790 if (!mi_first)
791 {
792 m_first = hMenu;
793 mi_first = MENU_FindItem(&m_first, &pos, bypos);
794 if (!mi_first) continue;
795 mi_check = mi_first;
796 m_check = m_first;
797 }
798 else
799 {
800 m_check = hMenu;
801 mi_check = MENU_FindItem(&m_check, &pos, bypos);
802 if (!mi_check) continue;
803 }
804
805 if (m_first != m_check) continue;
806 if (mi_check->fType == MFT_SEPARATOR) continue;
807
808 if (i == check)
809 {
810 if (!(mi_check->fType & MFT_RADIOCHECK) || !(mi_check->fState & MFS_CHECKED))
811 {
812 mii.fMask = MIIM_FTYPE | MIIM_STATE;
813 mii.fType = (mi_check->fType & MENUITEMINFO_TYPE_MASK) | MFT_RADIOCHECK;
814 mii.fState = (mi_check->fState & MII_STATE_MASK) | MFS_CHECKED;
815 NtUserThunkedMenuItemInfo(m_check, i, bypos, FALSE, &mii, NULL);
816 }
817 done = TRUE;
818 }
819 else
820 {
821 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
822 if (mi_check->fState & MFS_CHECKED)
823 {
824 mii.fMask = MIIM_STATE;
825 mii.fState = (mi_check->fState & MII_STATE_MASK) & ~MFS_CHECKED;
826 NtUserThunkedMenuItemInfo(m_check, i, bypos, FALSE, &mii, NULL);
827 }
828 }
829 }
830 return done;
831 }
832
833 /*
834 * @implemented
835 */
836 HMENU WINAPI
837 CreateMenu(VOID)
838 {
839 return NtUserxCreateMenu();
840 }
841
842 /*
843 * @implemented
844 */
845 HMENU WINAPI
846 CreatePopupMenu(VOID)
847 {
848 return NtUserxCreatePopupMenu();
849 }
850
851 /*
852 * @implemented
853 */
854 BOOL WINAPI
855 DrawMenuBar(HWND hWnd)
856 {
857 return NtUserxDrawMenuBar(hWnd);
858 }
859
860 /*
861 * @implemented
862 */
863 BOOL WINAPI
864 EnableMenuItem(HMENU hMenu,
865 UINT uIDEnableItem,
866 UINT uEnable)
867 {
868 return NtUserEnableMenuItem(hMenu, uIDEnableItem, uEnable);
869 }
870
871 /*
872 * @implemented
873 */
874 HMENU WINAPI
875 GetMenu(HWND hWnd)
876 {
877 PWND Wnd = ValidateHwnd(hWnd);
878
879 if (!Wnd)
880 return NULL;
881
882 return UlongToHandle(Wnd->IDMenu);
883 }
884
885 /*
886 * @implemented
887 */
888 LONG WINAPI
889 GetMenuCheckMarkDimensions(VOID)
890 {
891 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK),
892 GetSystemMetrics(SM_CYMENUCHECK)));
893 }
894
895 /*
896 * @implemented
897 */
898 DWORD
899 WINAPI
900 GetMenuContextHelpId(HMENU hmenu)
901 {
902 PMENU pMenu;
903 if ((pMenu = ValidateHandle(hmenu, TYPE_MENU)))
904 return pMenu->dwContextHelpId;
905 return 0;
906 }
907
908 /*
909 * @implemented
910 */
911 UINT WINAPI
912 GetMenuDefaultItem(HMENU hMenu,
913 UINT fByPos,
914 UINT gmdiFlags)
915 {
916 PMENU pMenu;
917 DWORD gismc = 0;
918 if (!(pMenu = ValidateHandle(hMenu, TYPE_MENU)))
919 return (UINT)-1;
920
921 return IntGetMenuDefaultItem( pMenu, (BOOL)fByPos, gmdiFlags, &gismc);
922 }
923
924 /*
925 * @implemented
926 */
927 BOOL WINAPI
928 GetMenuInfo(HMENU hmenu,
929 LPMENUINFO lpcmi)
930 {
931 PMENU pMenu;
932
933 if (!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO)))
934 {
935 SetLastError(ERROR_INVALID_PARAMETER);
936 return FALSE;
937 }
938
939 if (!(pMenu = ValidateHandle(hmenu, TYPE_MENU)))
940 return FALSE;
941
942 if (lpcmi->fMask & MIM_BACKGROUND)
943 lpcmi->hbrBack = pMenu->hbrBack;
944
945 if (lpcmi->fMask & MIM_HELPID)
946 lpcmi->dwContextHelpID = pMenu->dwContextHelpId;
947
948 if (lpcmi->fMask & MIM_MAXHEIGHT)
949 lpcmi->cyMax = pMenu->cyMax;
950
951 if (lpcmi->fMask & MIM_MENUDATA)
952 lpcmi->dwMenuData = pMenu->dwMenuData;
953
954 if (lpcmi->fMask & MIM_STYLE)
955 lpcmi->dwStyle = pMenu->fFlags & MNS_STYLE_MASK;
956
957 return TRUE;
958 }
959
960 /*
961 * @implemented
962 */
963 int WINAPI
964 GetMenuItemCount(HMENU hmenu)
965 {
966 PMENU pMenu;
967 if ((pMenu = ValidateHandle(hmenu, TYPE_MENU)))
968 return pMenu->cItems;
969 return -1;
970 }
971
972 /*
973 * @implemented
974 */
975 UINT WINAPI
976 GetMenuItemID(HMENU hMenu,
977 int nPos)
978 {
979 ITEM * lpmi;
980 if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) return -1;
981 if (lpmi->spSubMenu) return -1;
982 return lpmi->wID;
983 }
984
985 /*
986 * @implemented
987 */
988 BOOL WINAPI
989 GetMenuItemInfoA(
990 HMENU hmenu,
991 UINT item,
992 BOOL bypos,
993 LPMENUITEMINFOA lpmii)
994 {
995 BOOL ret;
996 MENUITEMINFOA mii;
997
998 if( lpmii->cbSize != sizeof( mii) &&
999 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem))
1000 {
1001 SetLastError( ERROR_INVALID_PARAMETER);
1002 return FALSE;
1003 }
1004 memcpy( &mii, lpmii, lpmii->cbSize);
1005 mii.cbSize = sizeof( mii);
1006 ret = GetMenuItemInfo_common (hmenu,
1007 item,
1008 bypos,
1009 (LPMENUITEMINFOW)&mii,
1010 FALSE);
1011 mii.cbSize = lpmii->cbSize;
1012 memcpy( lpmii, &mii, mii.cbSize);
1013 return ret;
1014 }
1015
1016 /*
1017 * @implemented
1018 */
1019 BOOL WINAPI
1020 GetMenuItemInfoW(
1021 HMENU hMenu,
1022 UINT Item,
1023 BOOL bypos,
1024 LPMENUITEMINFOW lpmii)
1025 {
1026 BOOL ret;
1027 MENUITEMINFOW mii;
1028 if( lpmii->cbSize != sizeof( mii) && lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem))
1029 {
1030 SetLastError( ERROR_INVALID_PARAMETER);
1031 return FALSE;
1032 }
1033 memcpy( &mii, lpmii, lpmii->cbSize);
1034 mii.cbSize = sizeof( mii);
1035 ret = GetMenuItemInfo_common (hMenu, Item, bypos, &mii, TRUE);
1036 mii.cbSize = lpmii->cbSize;
1037 memcpy( lpmii, &mii, mii.cbSize);
1038 return ret;
1039 }
1040
1041 /*
1042 * @implemented
1043 */
1044 UINT
1045 WINAPI
1046 GetMenuState(
1047 HMENU hMenu,
1048 UINT uId,
1049 UINT uFlags)
1050 {
1051 PITEM pItem;
1052 UINT Type = 0;
1053 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu, uId, uFlags);
1054 if (!(pItem = MENU_FindItem( &hMenu, &uId, uFlags ))) return -1;
1055
1056 if (!pItem->Xlpstr && pItem->hbmp) Type = MFT_BITMAP;
1057
1058 if (pItem->spSubMenu)
1059 {
1060 PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
1061 HMENU hsubmenu = UserHMGetHandle(pSubMenu);
1062 Type |= MF_POPUP; // Fix CORE-9269
1063 if (!IsMenu(hsubmenu)) return (UINT)-1;
1064 else return (pSubMenu->cItems << 8) | ((pItem->fState|pItem->fType|Type) & 0xff);
1065 }
1066 else
1067 return (pItem->fType | pItem->fState | Type);
1068 }
1069
1070 /*
1071 * @implemented
1072 */
1073 int
1074 WINAPI
1075 GetMenuStringA(
1076 HMENU hMenu,
1077 UINT uIDItem,
1078 LPSTR lpString,
1079 int nMaxCount,
1080 UINT uFlag)
1081 {
1082 ITEM *item;
1083 LPWSTR text;
1084 ////// wine Code, seems to be faster.
1085 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, uIDItem, lpString, nMaxCount, uFlag );
1086
1087 if (lpString && nMaxCount) lpString[0] = '\0';
1088
1089 if (!(item = MENU_FindItem( &hMenu, &uIDItem, uFlag )))
1090 {
1091 SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
1092 return 0;
1093 }
1094
1095 text = item->Xlpstr ? DesktopPtrToUser(item->Xlpstr) : NULL;
1096
1097 if (!text) return 0;
1098 if (!lpString || !nMaxCount) return WideCharToMultiByte( CP_ACP, 0, text, -1, NULL, 0, NULL, NULL );
1099 if (!WideCharToMultiByte( CP_ACP, 0, text, -1, lpString, nMaxCount, NULL, NULL ))
1100 lpString[nMaxCount-1] = 0;
1101 TRACE("A returning %s\n", lpString);
1102 return strlen(lpString);
1103 }
1104
1105 /*
1106 * @implemented
1107 */
1108 int
1109 WINAPI
1110 GetMenuStringW(
1111 HMENU hMenu,
1112 UINT uIDItem,
1113 LPWSTR lpString,
1114 int nMaxCount,
1115 UINT uFlag)
1116 {
1117 ITEM *item;
1118 LPWSTR text;
1119
1120 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, uIDItem, lpString, nMaxCount, uFlag );
1121
1122 if (lpString && nMaxCount) lpString[0] = '\0';
1123
1124 if (!(item = MENU_FindItem( &hMenu, &uIDItem, uFlag )))
1125 {
1126 SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
1127 return 0;
1128 }
1129
1130 text = item->Xlpstr ? DesktopPtrToUser(item->Xlpstr) : NULL;
1131
1132 if (!lpString || !nMaxCount) return text ? strlenW(text) : 0;
1133 if( !(text))
1134 {
1135 lpString[0] = 0;
1136 return 0;
1137 }
1138 lstrcpynW( lpString, text, nMaxCount );
1139 TRACE("W returning %S\n", lpString);
1140 return strlenW(lpString);
1141 }
1142
1143 /*
1144 * @implemented
1145 */
1146 HMENU
1147 WINAPI
1148 GetSubMenu(
1149 HMENU hMenu,
1150 int nPos)
1151 {
1152 PITEM pItem;
1153 if (!(pItem = MENU_FindItem( &hMenu, (UINT*)&nPos, MF_BYPOSITION ))) return NULL;
1154
1155 if (pItem->spSubMenu)
1156 {
1157 PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
1158 HMENU hsubmenu = UserHMGetHandle(pSubMenu);
1159 if (IsMenu(hsubmenu)) return hsubmenu;
1160 }
1161 return NULL;
1162 }
1163
1164 /*
1165 * @implemented
1166 */
1167 HMENU
1168 WINAPI
1169 GetSystemMenu(HWND hWnd, BOOL bRevert)
1170 {
1171 return NtUserGetSystemMenu(hWnd, bRevert);
1172 }
1173
1174 /*
1175 * @implemented
1176 */
1177 BOOL
1178 WINAPI
1179 InsertMenuA(
1180 HMENU hMenu,
1181 UINT uPosition,
1182 UINT uFlags,
1183 UINT_PTR uIDNewItem,
1184 LPCSTR lpNewItem)
1185 {
1186 MENUITEMINFOW mii;
1187 UNICODE_STRING UnicodeString;
1188 BOOL res;
1189
1190 RtlInitUnicodeString(&UnicodeString, 0);
1191
1192 MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE);
1193
1194 /* copy the text string, it will be one or the other */
1195 if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
1196 {
1197 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
1198 {
1199 SetLastError (ERROR_NOT_ENOUGH_MEMORY);
1200 return FALSE;
1201 }
1202 mii.dwTypeData = UnicodeString.Buffer;
1203 mii.cch = UnicodeString.Length / sizeof(WCHAR);
1204 }
1205 else
1206 {
1207 TRACE("Handle bitmaps\n");
1208 }
1209 res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), TRUE, &mii, &UnicodeString);
1210 if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
1211 return res;
1212 }
1213
1214 /*
1215 * @implemented
1216 */
1217 BOOL
1218 WINAPI
1219 InsertMenuItemA(
1220 HMENU hMenu,
1221 UINT uItem,
1222 BOOL fByPosition,
1223 LPCMENUITEMINFOA lpmii)
1224 {
1225 MENUITEMINFOW mii;
1226 UNICODE_STRING UnicodeString;
1227 BOOL res;
1228
1229 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii);
1230
1231 RtlInitUnicodeString(&UnicodeString, 0);
1232
1233 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
1234
1235 /* copy the text string */
1236 if (((mii.fMask & MIIM_STRING) ||
1237 ((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING)))
1238 && mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) )
1239 {
1240 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
1241 {
1242 SetLastError (ERROR_NOT_ENOUGH_MEMORY);
1243 return FALSE;
1244 }
1245 mii.dwTypeData = UnicodeString.Buffer;
1246 mii.cch = UnicodeString.Length / sizeof(WCHAR);
1247 }
1248 else
1249 {
1250 TRACE("Handle bitmaps\n");
1251 }
1252 res = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, TRUE, &mii, &UnicodeString);
1253 if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
1254 return res;
1255 }
1256
1257 /*
1258 * @implemented
1259 */
1260 BOOL
1261 WINAPI
1262 InsertMenuItemW(
1263 HMENU hMenu,
1264 UINT uItem,
1265 BOOL fByPosition,
1266 LPCMENUITEMINFOW lpmii)
1267 {
1268 MENUITEMINFOW mii;
1269 UNICODE_STRING MenuText;
1270 BOOL res = FALSE;
1271
1272 /* while we could just pass 'lpmii' to win32k, we make a copy so that
1273 if a bad user passes bad data, we crash his process instead of the
1274 entire kernel */
1275
1276 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii);
1277
1278 RtlInitUnicodeString(&MenuText, 0);
1279
1280 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
1281
1282 /* copy the text string */
1283 if (((mii.fMask & MIIM_STRING) ||
1284 ((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING)))
1285 && mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) )
1286 {
1287 RtlInitUnicodeString(&MenuText, (PWSTR)lpmii->dwTypeData);
1288 mii.dwTypeData = MenuText.Buffer;
1289 mii.cch = MenuText.Length / sizeof(WCHAR);
1290 }
1291 res = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, TRUE, &mii, &MenuText);
1292 return res;
1293 }
1294
1295 /*
1296 * @implemented
1297 */
1298 BOOL
1299 WINAPI
1300 InsertMenuW(
1301 HMENU hMenu,
1302 UINT uPosition,
1303 UINT uFlags,
1304 UINT_PTR uIDNewItem,
1305 LPCWSTR lpNewItem)
1306 {
1307 MENUITEMINFOW mii;
1308 UNICODE_STRING MenuText;
1309 BOOL res;
1310
1311 RtlInitUnicodeString(&MenuText, 0);
1312
1313 MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE);
1314
1315 /* copy the text string, it will be one or the other */
1316 if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
1317 {
1318 RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData);
1319 mii.dwTypeData = MenuText.Buffer;
1320 mii.cch = MenuText.Length / sizeof(WCHAR);
1321 }
1322 res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), TRUE, &mii, &MenuText);
1323 return res;
1324 }
1325
1326 /*
1327 * @implemented
1328 */
1329 BOOL
1330 WINAPI
1331 IsMenu(
1332 HMENU Menu)
1333 {
1334 if (ValidateHandle(Menu, TYPE_MENU)) return TRUE;
1335 return FALSE;
1336 }
1337
1338 /*
1339 * @implemented
1340 */
1341 HMENU WINAPI
1342 LoadMenuA(HINSTANCE hInstance,
1343 LPCSTR lpMenuName)
1344 {
1345 HANDLE Resource = FindResourceA(hInstance, lpMenuName, MAKEINTRESOURCEA(4));
1346 if (Resource == NULL)
1347 {
1348 return(NULL);
1349 }
1350 return(LoadMenuIndirectA((PVOID)LoadResource(hInstance, Resource)));
1351 }
1352
1353 /*
1354 * @implemented
1355 */
1356 HMENU WINAPI
1357 LoadMenuIndirectA(CONST MENUTEMPLATE *lpMenuTemplate)
1358 {
1359 return(LoadMenuIndirectW(lpMenuTemplate));
1360 }
1361
1362 /*
1363 * @implemented
1364 */
1365 HMENU WINAPI
1366 LoadMenuIndirectW(CONST MENUTEMPLATE *lpMenuTemplate)
1367 {
1368 HMENU hMenu;
1369 WORD version, offset;
1370 LPCSTR p = (LPCSTR)lpMenuTemplate;
1371
1372 version = GET_WORD(p);
1373 p += sizeof(WORD);
1374
1375 switch (version)
1376 {
1377 case 0: /* standard format is version of 0 */
1378 offset = GET_WORD(p);
1379 p += sizeof(WORD) + offset;
1380 if (!(hMenu = CreateMenu())) return 0;
1381 if (!MENU_ParseResource(p, hMenu))
1382 {
1383 DestroyMenu(hMenu);
1384 return 0;
1385 }
1386 return hMenu;
1387 case 1: /* extended format is version of 1 */
1388 offset = GET_WORD(p);
1389 p += sizeof(WORD) + offset;
1390 if (!(hMenu = CreateMenu())) return 0;
1391 if (!MENUEX_ParseResource(p, hMenu))
1392 {
1393 DestroyMenu( hMenu );
1394 return 0;
1395 }
1396 return hMenu;
1397 default:
1398 ERR("Menu template version %d not supported.\n", version);
1399 return 0;
1400 }
1401 }
1402
1403 /*
1404 * @implemented
1405 */
1406 HMENU WINAPI
1407 LoadMenuW(HINSTANCE hInstance,
1408 LPCWSTR lpMenuName)
1409 {
1410 HANDLE Resource = FindResourceW(hInstance, lpMenuName, RT_MENU);
1411 if (Resource == NULL)
1412 {
1413 return(NULL);
1414 }
1415 return(LoadMenuIndirectW((PVOID)LoadResource(hInstance, Resource)));
1416 }
1417
1418 /*
1419 * @implemented
1420 */
1421 BOOL
1422 WINAPI
1423 ModifyMenuA(
1424 HMENU hMenu,
1425 UINT uPosition,
1426 UINT uFlags,
1427 UINT_PTR uIDNewItem,
1428 LPCSTR lpNewItem)
1429 {
1430 MENUITEMINFOW mii;
1431 UNICODE_STRING UnicodeString;
1432 BOOL res;
1433
1434 RtlInitUnicodeString(&UnicodeString, 0);
1435
1436 MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE);
1437
1438 /* copy the text string, it will be one or the other */
1439 if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
1440 {
1441 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
1442 {
1443 SetLastError (ERROR_NOT_ENOUGH_MEMORY);
1444 return FALSE;
1445 }
1446 mii.dwTypeData = UnicodeString.Buffer;
1447 mii.cch = UnicodeString.Length / sizeof(WCHAR);
1448 }
1449 else
1450 {
1451 TRACE("Handle bitmaps\n");
1452 }
1453 res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), FALSE, &mii, &UnicodeString);
1454 if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
1455 return res;
1456 }
1457
1458 /*
1459 * @implemented
1460 */
1461 BOOL
1462 WINAPI
1463 ModifyMenuW(
1464 HMENU hMenu,
1465 UINT uPosition,
1466 UINT uFlags,
1467 UINT_PTR uIDNewItem,
1468 LPCWSTR lpNewItem)
1469 {
1470 MENUITEMINFOW mii;
1471 UNICODE_STRING MenuText;
1472 BOOL res;
1473
1474 RtlInitUnicodeString(&MenuText, 0);
1475
1476 MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE);
1477
1478 /* copy the text string, it will be one or the other */
1479 if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
1480 {
1481 RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData);
1482 mii.dwTypeData = MenuText.Buffer;
1483 mii.cch = MenuText.Length / sizeof(WCHAR);
1484 }
1485 else
1486 {
1487 TRACE("Handle bitmaps\n");
1488 }
1489 res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), FALSE, &mii, &MenuText);
1490 return res;
1491 }
1492
1493 /*
1494 * @implemented
1495 */
1496 BOOL WINAPI
1497 SetMenu(HWND hWnd,
1498 HMENU hMenu)
1499 {
1500 return NtUserSetMenu(hWnd, hMenu, TRUE);
1501 }
1502
1503 /*
1504 * @implemented
1505 */
1506 BOOL
1507 WINAPI
1508 SetMenuInfo(
1509 HMENU hmenu,
1510 LPCMENUINFO lpcmi)
1511 {
1512 MENUINFO mi;
1513 BOOL res = FALSE;
1514
1515 if (!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO)))
1516 {
1517 SetLastError(ERROR_INVALID_PARAMETER);
1518 return res;
1519 }
1520
1521 memcpy(&mi, lpcmi, sizeof(MENUINFO));
1522 return NtUserThunkedMenuInfo(hmenu, (LPCMENUINFO)&mi);
1523 }
1524
1525 /*
1526 * @implemented
1527 */
1528 BOOL
1529 WINAPI
1530 SetMenuItemBitmaps(
1531 HMENU hMenu,
1532 UINT uPosition,
1533 UINT uFlags,
1534 HBITMAP hBitmapUnchecked,
1535 HBITMAP hBitmapChecked)
1536 {
1537 MENUITEMINFOW uItem;
1538 memset ( &uItem, 0, sizeof(uItem) );
1539 uItem.cbSize = sizeof(MENUITEMINFOW);
1540 uItem.fMask = MIIM_CHECKMARKS;
1541 uItem.hbmpUnchecked = hBitmapUnchecked;
1542 uItem.hbmpChecked = hBitmapChecked;
1543 return SetMenuItemInfoW(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), &uItem);
1544 }
1545
1546 /*
1547 * @implemented
1548 */
1549 BOOL
1550 WINAPI
1551 SetMenuItemInfoA(
1552 HMENU hmenu,
1553 UINT item,
1554 BOOL bypos,
1555 LPCMENUITEMINFOA lpmii)
1556 {
1557 MENUITEMINFOW mii;
1558 UNICODE_STRING UnicodeString;
1559 BOOL Ret;
1560
1561 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu, item, bypos, lpmii);
1562
1563 RtlInitUnicodeString(&UnicodeString, 0);
1564
1565 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
1566 /*
1567 * MIIM_STRING == good
1568 * MIIM_TYPE & MFT_STRING == good
1569 * MIIM_STRING & MFT_STRING == good
1570 * MIIM_STRING & MFT_OWNERDRAW == good
1571 */
1572 if (((mii.fMask & MIIM_STRING) ||
1573 ((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING)))
1574 && mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) )
1575 {
1576 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
1577 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
1578 {
1579 SetLastError (ERROR_NOT_ENOUGH_MEMORY);
1580 return FALSE;
1581 }
1582 mii.dwTypeData = UnicodeString.Buffer;
1583 mii.cch = UnicodeString.Length / sizeof(WCHAR);
1584 }
1585 else
1586 {
1587 UnicodeString.Buffer = NULL;
1588 }
1589 Ret = NtUserThunkedMenuItemInfo(hmenu, item, bypos, FALSE, &mii, &UnicodeString);
1590 if (UnicodeString.Buffer != NULL) RtlFreeUnicodeString(&UnicodeString);
1591 return Ret;
1592 }
1593
1594 /*
1595 * @implemented
1596 */
1597 BOOL
1598 WINAPI
1599 SetMenuItemInfoW(
1600 HMENU hMenu,
1601 UINT uItem,
1602 BOOL fByPosition,
1603 LPCMENUITEMINFOW lpmii)
1604 {
1605 MENUITEMINFOW MenuItemInfoW;
1606 UNICODE_STRING UnicodeString;
1607 BOOL Ret;
1608
1609 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii);
1610
1611 RtlInitUnicodeString(&UnicodeString, 0);
1612
1613 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &MenuItemInfoW )) return FALSE;
1614
1615 if (((MenuItemInfoW.fMask & MIIM_STRING) ||
1616 ((MenuItemInfoW.fMask & MIIM_TYPE) &&
1617 (MENU_ITEM_TYPE(MenuItemInfoW.fType) == MF_STRING)))
1618 && MenuItemInfoW.dwTypeData && !(GdiValidateHandle((HGDIOBJ)MenuItemInfoW.dwTypeData)) )
1619 {
1620 RtlInitUnicodeString(&UnicodeString, (PCWSTR)MenuItemInfoW.dwTypeData);
1621 MenuItemInfoW.cch = strlenW(MenuItemInfoW.dwTypeData);
1622 }
1623 Ret = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, FALSE, &MenuItemInfoW, &UnicodeString);
1624
1625 return Ret;
1626 }
1627
1628 /*
1629 * @implemented
1630 */
1631 BOOL
1632 WINAPI
1633 SetSystemMenu (
1634 HWND hwnd,
1635 HMENU hMenu)
1636 {
1637 if(!hwnd)
1638 {
1639 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
1640 return FALSE;
1641 }
1642 if(!hMenu)
1643 {
1644 SetLastError(ERROR_INVALID_MENU_HANDLE);
1645 return FALSE;
1646 }
1647 return NtUserSetSystemMenu(hwnd, hMenu);
1648 }
1649
1650 BOOL
1651 WINAPI
1652 TrackPopupMenu(
1653 HMENU Menu,
1654 UINT Flags,
1655 int x,
1656 int y,
1657 int Reserved,
1658 HWND Wnd,
1659 CONST RECT *Rect)
1660 {
1661 return NtUserTrackPopupMenuEx( Menu,
1662 Flags,
1663 x,
1664 y,
1665 Wnd,
1666 NULL); // LPTPMPARAMS is null
1667 }
1668
1669 /*
1670 * @unimplemented
1671 */
1672 LRESULT
1673 WINAPI
1674 MenuWindowProcA(
1675 HWND hWnd,
1676 ULONG_PTR Result,
1677 UINT Msg,
1678 WPARAM wParam,
1679 LPARAM lParam
1680 )
1681 {
1682 if ( Msg < WM_USER)
1683 {
1684 return PopupMenuWndProcA(hWnd, Msg, wParam, lParam );
1685 }
1686 return NtUserMessageCall(hWnd, Msg, wParam, lParam, Result, FNID_MENU, TRUE);
1687 }
1688
1689 /*
1690 * @unimplemented
1691 */
1692 LRESULT
1693 WINAPI
1694 MenuWindowProcW(
1695 HWND hWnd,
1696 ULONG_PTR Result,
1697 UINT Msg,
1698 WPARAM wParam,
1699 LPARAM lParam
1700 )
1701 {
1702 if ( Msg < WM_USER)
1703 {
1704 return PopupMenuWndProcW(hWnd, Msg, wParam, lParam );
1705 }
1706 return NtUserMessageCall(hWnd, Msg, wParam, lParam, Result, FNID_MENU, FALSE);
1707 }
1708
1709 /*
1710 * @implemented
1711 */
1712 BOOL
1713 WINAPI
1714 ChangeMenuW(
1715 HMENU hMenu,
1716 UINT cmd,
1717 LPCWSTR lpszNewItem,
1718 UINT cmdInsert,
1719 UINT flags)
1720 {
1721 /*
1722 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
1723 for MF_DELETE. We should check the parameters for all others
1724 MF_* actions also (anybody got a doc on ChangeMenu?).
1725 */
1726
1727 switch(flags & (MF_APPEND | MF_DELETE | MF_CHANGE | MF_REMOVE | MF_INSERT))
1728 {
1729 case MF_APPEND :
1730 return AppendMenuW(hMenu, flags &~ MF_APPEND, cmdInsert, lpszNewItem);
1731
1732 case MF_DELETE :
1733 return DeleteMenu(hMenu, cmd, flags &~ MF_DELETE);
1734
1735 case MF_CHANGE :
1736 return ModifyMenuW(hMenu, cmd, flags &~ MF_CHANGE, cmdInsert, lpszNewItem);
1737
1738 case MF_REMOVE :
1739 return RemoveMenu(hMenu, flags & MF_BYPOSITION ? cmd : cmdInsert,
1740 flags &~ MF_REMOVE);
1741
1742 default : /* MF_INSERT */
1743 return InsertMenuW(hMenu, cmd, flags, cmdInsert, lpszNewItem);
1744 };
1745 }
1746
1747 /*
1748 * @implemented
1749 */
1750 BOOL
1751 WINAPI
1752 ChangeMenuA(
1753 HMENU hMenu,
1754 UINT cmd,
1755 LPCSTR lpszNewItem,
1756 UINT cmdInsert,
1757 UINT flags)
1758 {
1759 /*
1760 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
1761 for MF_DELETE. We should check the parameters for all others
1762 MF_* actions also (anybody got a doc on ChangeMenu?).
1763 */
1764
1765 switch(flags & (MF_APPEND | MF_DELETE | MF_CHANGE | MF_REMOVE | MF_INSERT))
1766 {
1767 case MF_APPEND :
1768 return AppendMenuA(hMenu, flags &~ MF_APPEND, cmdInsert, lpszNewItem);
1769
1770 case MF_DELETE :
1771 return DeleteMenu(hMenu, cmd, flags &~ MF_DELETE);
1772
1773 case MF_CHANGE :
1774 return ModifyMenuA(hMenu, cmd, flags &~ MF_CHANGE, cmdInsert, lpszNewItem);
1775
1776 case MF_REMOVE :
1777 return RemoveMenu(hMenu, flags & MF_BYPOSITION ? cmd : cmdInsert,
1778 flags &~ MF_REMOVE);
1779
1780 default : /* MF_INSERT */
1781 return InsertMenuA(hMenu, cmd, flags, cmdInsert, lpszNewItem);
1782 };
1783 }
1784