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