[Win32SS]
[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 Type |= MF_POPUP; // Fix CORE-9269
1066 if (!IsMenu(hsubmenu)) return (UINT)-1;
1067 else return (pSubMenu->cItems << 8) | ((pItem->fState|pItem->fType|Type) & 0xff);
1068 }
1069 else
1070 return (pItem->fType | pItem->fState | Type);
1071 }
1072
1073 /*
1074 * @implemented
1075 */
1076 int
1077 WINAPI
1078 GetMenuStringA(
1079 HMENU hMenu,
1080 UINT uIDItem,
1081 LPSTR lpString,
1082 int nMaxCount,
1083 UINT uFlag)
1084 {
1085 ITEM *item;
1086 LPWSTR text;
1087 ////// wine Code, seems to be faster.
1088 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, uIDItem, lpString, nMaxCount, uFlag );
1089
1090 if (lpString && nMaxCount) lpString[0] = '\0';
1091
1092 if (!(item = MENU_FindItem( &hMenu, &uIDItem, uFlag )))
1093 {
1094 SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
1095 return 0;
1096 }
1097
1098 text = item->Xlpstr ? DesktopPtrToUser(item->Xlpstr) : NULL;
1099
1100 if (!text) return 0;
1101 if (!lpString || !nMaxCount) return WideCharToMultiByte( CP_ACP, 0, text, -1, NULL, 0, NULL, NULL );
1102 if (!WideCharToMultiByte( CP_ACP, 0, text, -1, lpString, nMaxCount, NULL, NULL ))
1103 lpString[nMaxCount-1] = 0;
1104 TRACE("A returning %s\n", lpString);
1105 return strlen(lpString);
1106 }
1107
1108 /*
1109 * @implemented
1110 */
1111 int
1112 WINAPI
1113 GetMenuStringW(
1114 HMENU hMenu,
1115 UINT uIDItem,
1116 LPWSTR lpString,
1117 int nMaxCount,
1118 UINT uFlag)
1119 {
1120 ITEM *item;
1121 LPWSTR text;
1122
1123 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, uIDItem, lpString, nMaxCount, uFlag );
1124
1125 if (lpString && nMaxCount) lpString[0] = '\0';
1126
1127 if (!(item = MENU_FindItem( &hMenu, &uIDItem, uFlag )))
1128 {
1129 SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
1130 return 0;
1131 }
1132
1133 text = item->Xlpstr ? DesktopPtrToUser(item->Xlpstr) : NULL;
1134
1135 if (!lpString || !nMaxCount) return text ? strlenW(text) : 0;
1136 if( !(text))
1137 {
1138 lpString[0] = 0;
1139 return 0;
1140 }
1141 lstrcpynW( lpString, text, nMaxCount );
1142 TRACE("W returning %S\n", lpString);
1143 return strlenW(lpString);
1144 }
1145
1146 /*
1147 * @implemented
1148 */
1149 HMENU
1150 WINAPI
1151 GetSubMenu(
1152 HMENU hMenu,
1153 int nPos)
1154 {
1155 PITEM pItem;
1156 if (!(pItem = MENU_FindItem( &hMenu, (UINT*)&nPos, MF_BYPOSITION ))) return NULL;
1157
1158 if (pItem->spSubMenu)
1159 {
1160 PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
1161 HMENU hsubmenu = UserHMGetHandle(pSubMenu);
1162 if (IsMenu(hsubmenu)) return hsubmenu;
1163 }
1164 return NULL;
1165 }
1166
1167 /*
1168 * @implemented
1169 */
1170 HMENU
1171 WINAPI
1172 GetSystemMenu(HWND hWnd, BOOL bRevert)
1173 {
1174 return NtUserGetSystemMenu(hWnd, bRevert);
1175 }
1176
1177 /*
1178 * @implemented
1179 */
1180 BOOL
1181 WINAPI
1182 InsertMenuA(
1183 HMENU hMenu,
1184 UINT uPosition,
1185 UINT uFlags,
1186 UINT_PTR uIDNewItem,
1187 LPCSTR lpNewItem)
1188 {
1189 MENUITEMINFOW mii;
1190 UNICODE_STRING UnicodeString;
1191 BOOL res;
1192
1193 RtlInitUnicodeString(&UnicodeString, 0);
1194
1195 MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE);
1196
1197 /* copy the text string, it will be one or the other */
1198 if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
1199 {
1200 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
1201 {
1202 SetLastError (ERROR_NOT_ENOUGH_MEMORY);
1203 return FALSE;
1204 }
1205 mii.dwTypeData = UnicodeString.Buffer;
1206 mii.cch = UnicodeString.Length / sizeof(WCHAR);
1207 }
1208 else
1209 {
1210 TRACE("Handle bitmaps\n");
1211 }
1212 res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), TRUE, &mii, &UnicodeString);
1213 if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
1214 return res;
1215 }
1216
1217 /*
1218 * @implemented
1219 */
1220 BOOL
1221 WINAPI
1222 InsertMenuItemA(
1223 HMENU hMenu,
1224 UINT uItem,
1225 BOOL fByPosition,
1226 LPCMENUITEMINFOA lpmii)
1227 {
1228 MENUITEMINFOW mii;
1229 UNICODE_STRING UnicodeString;
1230 BOOL res;
1231
1232 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii);
1233
1234 RtlInitUnicodeString(&UnicodeString, 0);
1235
1236 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
1237
1238 /* copy the text string */
1239 if (((mii.fMask & MIIM_STRING) ||
1240 ((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING)))
1241 && mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) )
1242 {
1243 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
1244 {
1245 SetLastError (ERROR_NOT_ENOUGH_MEMORY);
1246 return FALSE;
1247 }
1248 mii.dwTypeData = UnicodeString.Buffer;
1249 mii.cch = UnicodeString.Length / sizeof(WCHAR);
1250 }
1251 else
1252 {
1253 TRACE("Handle bitmaps\n");
1254 }
1255 res = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, TRUE, &mii, &UnicodeString);
1256 if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
1257 return res;
1258 }
1259
1260 /*
1261 * @implemented
1262 */
1263 BOOL
1264 WINAPI
1265 InsertMenuItemW(
1266 HMENU hMenu,
1267 UINT uItem,
1268 BOOL fByPosition,
1269 LPCMENUITEMINFOW lpmii)
1270 {
1271 MENUITEMINFOW mii;
1272 UNICODE_STRING MenuText;
1273 BOOL res = FALSE;
1274
1275 /* while we could just pass 'lpmii' to win32k, we make a copy so that
1276 if a bad user passes bad data, we crash his process instead of the
1277 entire kernel */
1278
1279 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii);
1280
1281 RtlInitUnicodeString(&MenuText, 0);
1282
1283 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
1284
1285 /* copy the text string */
1286 if (((mii.fMask & MIIM_STRING) ||
1287 ((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING)))
1288 && mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) )
1289 {
1290 RtlInitUnicodeString(&MenuText, (PWSTR)lpmii->dwTypeData);
1291 mii.dwTypeData = MenuText.Buffer;
1292 mii.cch = MenuText.Length / sizeof(WCHAR);
1293 }
1294 res = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, TRUE, &mii, &MenuText);
1295 return res;
1296 }
1297
1298 /*
1299 * @implemented
1300 */
1301 BOOL
1302 WINAPI
1303 InsertMenuW(
1304 HMENU hMenu,
1305 UINT uPosition,
1306 UINT uFlags,
1307 UINT_PTR uIDNewItem,
1308 LPCWSTR lpNewItem)
1309 {
1310 MENUITEMINFOW mii;
1311 UNICODE_STRING MenuText;
1312 BOOL res;
1313
1314 RtlInitUnicodeString(&MenuText, 0);
1315
1316 MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE);
1317
1318 /* copy the text string, it will be one or the other */
1319 if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
1320 {
1321 RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData);
1322 mii.dwTypeData = MenuText.Buffer;
1323 mii.cch = MenuText.Length / sizeof(WCHAR);
1324 }
1325 res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), TRUE, &mii, &MenuText);
1326 return res;
1327 }
1328
1329 /*
1330 * @implemented
1331 */
1332 BOOL
1333 WINAPI
1334 IsMenu(
1335 HMENU Menu)
1336 {
1337 if (ValidateHandle(Menu, TYPE_MENU)) return TRUE;
1338 return FALSE;
1339 }
1340
1341 /*
1342 * @implemented
1343 */
1344 HMENU WINAPI
1345 LoadMenuA(HINSTANCE hInstance,
1346 LPCSTR lpMenuName)
1347 {
1348 HANDLE Resource = FindResourceA(hInstance, lpMenuName, MAKEINTRESOURCEA(4));
1349 if (Resource == NULL)
1350 {
1351 return(NULL);
1352 }
1353 return(LoadMenuIndirectA((PVOID)LoadResource(hInstance, Resource)));
1354 }
1355
1356 /*
1357 * @implemented
1358 */
1359 HMENU WINAPI
1360 LoadMenuIndirectA(CONST MENUTEMPLATE *lpMenuTemplate)
1361 {
1362 return(LoadMenuIndirectW(lpMenuTemplate));
1363 }
1364
1365 /*
1366 * @implemented
1367 */
1368 HMENU WINAPI
1369 LoadMenuIndirectW(CONST MENUTEMPLATE *lpMenuTemplate)
1370 {
1371 HMENU hMenu;
1372 WORD version, offset;
1373 LPCSTR p = (LPCSTR)lpMenuTemplate;
1374
1375 version = GET_WORD(p);
1376 p += sizeof(WORD);
1377
1378 switch (version)
1379 {
1380 case 0: /* standard format is version of 0 */
1381 offset = GET_WORD(p);
1382 p += sizeof(WORD) + offset;
1383 if (!(hMenu = CreateMenu())) return 0;
1384 if (!MENU_ParseResource(p, hMenu))
1385 {
1386 DestroyMenu(hMenu);
1387 return 0;
1388 }
1389 return hMenu;
1390 case 1: /* extended format is version of 1 */
1391 offset = GET_WORD(p);
1392 p += sizeof(WORD) + offset;
1393 if (!(hMenu = CreateMenu())) return 0;
1394 if (!MENUEX_ParseResource(p, hMenu))
1395 {
1396 DestroyMenu( hMenu );
1397 return 0;
1398 }
1399 return hMenu;
1400 default:
1401 ERR("Menu template version %d not supported.\n", version);
1402 return 0;
1403 }
1404 }
1405
1406 /*
1407 * @implemented
1408 */
1409 HMENU WINAPI
1410 LoadMenuW(HINSTANCE hInstance,
1411 LPCWSTR lpMenuName)
1412 {
1413 HANDLE Resource = FindResourceW(hInstance, lpMenuName, RT_MENU);
1414 if (Resource == NULL)
1415 {
1416 return(NULL);
1417 }
1418 return(LoadMenuIndirectW((PVOID)LoadResource(hInstance, Resource)));
1419 }
1420
1421 /*
1422 * @implemented
1423 */
1424 BOOL
1425 WINAPI
1426 ModifyMenuA(
1427 HMENU hMenu,
1428 UINT uPosition,
1429 UINT uFlags,
1430 UINT_PTR uIDNewItem,
1431 LPCSTR lpNewItem)
1432 {
1433 MENUITEMINFOW mii;
1434 UNICODE_STRING UnicodeString;
1435 BOOL res;
1436
1437 RtlInitUnicodeString(&UnicodeString, 0);
1438
1439 MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE);
1440
1441 /* copy the text string, it will be one or the other */
1442 if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
1443 {
1444 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
1445 {
1446 SetLastError (ERROR_NOT_ENOUGH_MEMORY);
1447 return FALSE;
1448 }
1449 mii.dwTypeData = UnicodeString.Buffer;
1450 mii.cch = UnicodeString.Length / sizeof(WCHAR);
1451 }
1452 else
1453 {
1454 TRACE("Handle bitmaps\n");
1455 }
1456 res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), FALSE, &mii, &UnicodeString);
1457 if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
1458 return res;
1459 }
1460
1461 /*
1462 * @implemented
1463 */
1464 BOOL
1465 WINAPI
1466 ModifyMenuW(
1467 HMENU hMenu,
1468 UINT uPosition,
1469 UINT uFlags,
1470 UINT_PTR uIDNewItem,
1471 LPCWSTR lpNewItem)
1472 {
1473 MENUITEMINFOW mii;
1474 UNICODE_STRING MenuText;
1475 BOOL res;
1476
1477 RtlInitUnicodeString(&MenuText, 0);
1478
1479 MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE);
1480
1481 /* copy the text string, it will be one or the other */
1482 if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
1483 {
1484 RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData);
1485 mii.dwTypeData = MenuText.Buffer;
1486 mii.cch = MenuText.Length / sizeof(WCHAR);
1487 }
1488 else
1489 {
1490 TRACE("Handle bitmaps\n");
1491 }
1492 res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), FALSE, &mii, &MenuText);
1493 return res;
1494 }
1495
1496 /*
1497 * @implemented
1498 */
1499 BOOL WINAPI
1500 SetMenu(HWND hWnd,
1501 HMENU hMenu)
1502 {
1503 return NtUserSetMenu(hWnd, hMenu, TRUE);
1504 }
1505
1506 /*
1507 * @implemented
1508 */
1509 BOOL
1510 WINAPI
1511 SetMenuInfo(
1512 HMENU hmenu,
1513 LPCMENUINFO lpcmi)
1514 {
1515 MENUINFO mi;
1516 BOOL res = FALSE;
1517
1518 if (!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO)))
1519 {
1520 SetLastError(ERROR_INVALID_PARAMETER);
1521 return res;
1522 }
1523
1524 memcpy(&mi, lpcmi, sizeof(MENUINFO));
1525 return NtUserThunkedMenuInfo(hmenu, (LPCMENUINFO)&mi);
1526 }
1527
1528 /*
1529 * @implemented
1530 */
1531 BOOL
1532 WINAPI
1533 SetMenuItemBitmaps(
1534 HMENU hMenu,
1535 UINT uPosition,
1536 UINT uFlags,
1537 HBITMAP hBitmapUnchecked,
1538 HBITMAP hBitmapChecked)
1539 {
1540 MENUITEMINFOW uItem;
1541 memset ( &uItem, 0, sizeof(uItem) );
1542 uItem.cbSize = sizeof(MENUITEMINFOW);
1543 uItem.fMask = MIIM_CHECKMARKS;
1544 uItem.hbmpUnchecked = hBitmapUnchecked;
1545 uItem.hbmpChecked = hBitmapChecked;
1546 return SetMenuItemInfoW(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), &uItem);
1547 }
1548
1549 /*
1550 * @implemented
1551 */
1552 BOOL
1553 WINAPI
1554 SetMenuItemInfoA(
1555 HMENU hmenu,
1556 UINT item,
1557 BOOL bypos,
1558 LPCMENUITEMINFOA lpmii)
1559 {
1560 MENUITEMINFOW mii;
1561 UNICODE_STRING UnicodeString;
1562 BOOL Ret;
1563
1564 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu, item, bypos, lpmii);
1565
1566 RtlInitUnicodeString(&UnicodeString, 0);
1567
1568 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
1569 /*
1570 * MIIM_STRING == good
1571 * MIIM_TYPE & MFT_STRING == good
1572 * MIIM_STRING & MFT_STRING == good
1573 * MIIM_STRING & MFT_OWNERDRAW == good
1574 */
1575 if (((mii.fMask & MIIM_STRING) ||
1576 ((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING)))
1577 && mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) )
1578 {
1579 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
1580 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
1581 {
1582 SetLastError (ERROR_NOT_ENOUGH_MEMORY);
1583 return FALSE;
1584 }
1585 mii.dwTypeData = UnicodeString.Buffer;
1586 mii.cch = UnicodeString.Length / sizeof(WCHAR);
1587 }
1588 else
1589 {
1590 UnicodeString.Buffer = NULL;
1591 }
1592 Ret = NtUserThunkedMenuItemInfo(hmenu, item, bypos, FALSE, &mii, &UnicodeString);
1593 if (UnicodeString.Buffer != NULL) RtlFreeUnicodeString(&UnicodeString);
1594 return Ret;
1595 }
1596
1597 /*
1598 * @implemented
1599 */
1600 BOOL
1601 WINAPI
1602 SetMenuItemInfoW(
1603 HMENU hMenu,
1604 UINT uItem,
1605 BOOL fByPosition,
1606 LPCMENUITEMINFOW lpmii)
1607 {
1608 MENUITEMINFOW MenuItemInfoW;
1609 UNICODE_STRING UnicodeString;
1610 BOOL Ret;
1611
1612 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii);
1613
1614 RtlInitUnicodeString(&UnicodeString, 0);
1615
1616 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &MenuItemInfoW )) return FALSE;
1617
1618 if (((MenuItemInfoW.fMask & MIIM_STRING) ||
1619 ((MenuItemInfoW.fMask & MIIM_TYPE) &&
1620 (MENU_ITEM_TYPE(MenuItemInfoW.fType) == MF_STRING)))
1621 && MenuItemInfoW.dwTypeData && !(GdiValidateHandle((HGDIOBJ)MenuItemInfoW.dwTypeData)) )
1622 {
1623 RtlInitUnicodeString(&UnicodeString, (PCWSTR)MenuItemInfoW.dwTypeData);
1624 MenuItemInfoW.cch = strlenW(MenuItemInfoW.dwTypeData);
1625 }
1626 Ret = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, FALSE, &MenuItemInfoW, &UnicodeString);
1627
1628 return Ret;
1629 }
1630
1631 /*
1632 * @implemented
1633 */
1634 BOOL
1635 WINAPI
1636 SetSystemMenu (
1637 HWND hwnd,
1638 HMENU hMenu)
1639 {
1640 if(!hwnd)
1641 {
1642 SetLastError(ERROR_INVALID_WINDOW_HANDLE);
1643 return FALSE;
1644 }
1645 if(!hMenu)
1646 {
1647 SetLastError(ERROR_INVALID_MENU_HANDLE);
1648 return FALSE;
1649 }
1650 return NtUserSetSystemMenu(hwnd, hMenu);
1651 }
1652
1653 BOOL
1654 WINAPI
1655 TrackPopupMenu(
1656 HMENU Menu,
1657 UINT Flags,
1658 int x,
1659 int y,
1660 int Reserved,
1661 HWND Wnd,
1662 CONST RECT *Rect)
1663 {
1664 return NtUserTrackPopupMenuEx( Menu,
1665 Flags,
1666 x,
1667 y,
1668 Wnd,
1669 NULL); // LPTPMPARAMS is null
1670 }
1671
1672 /*
1673 * @unimplemented
1674 */
1675 LRESULT
1676 WINAPI
1677 MenuWindowProcA(
1678 HWND hWnd,
1679 ULONG_PTR Result,
1680 UINT Msg,
1681 WPARAM wParam,
1682 LPARAM lParam
1683 )
1684 {
1685 if ( Msg < WM_USER)
1686 {
1687 return PopupMenuWndProcA(hWnd, Msg, wParam, lParam );
1688 }
1689 return NtUserMessageCall(hWnd, Msg, wParam, lParam, Result, FNID_MENU, TRUE);
1690 }
1691
1692 /*
1693 * @unimplemented
1694 */
1695 LRESULT
1696 WINAPI
1697 MenuWindowProcW(
1698 HWND hWnd,
1699 ULONG_PTR Result,
1700 UINT Msg,
1701 WPARAM wParam,
1702 LPARAM lParam
1703 )
1704 {
1705 if ( Msg < WM_USER)
1706 {
1707 return PopupMenuWndProcW(hWnd, Msg, wParam, lParam );
1708 }
1709 return NtUserMessageCall(hWnd, Msg, wParam, lParam, Result, FNID_MENU, FALSE);
1710 }
1711
1712 /*
1713 * @implemented
1714 */
1715 BOOL
1716 WINAPI
1717 ChangeMenuW(
1718 HMENU hMenu,
1719 UINT cmd,
1720 LPCWSTR lpszNewItem,
1721 UINT cmdInsert,
1722 UINT flags)
1723 {
1724 /*
1725 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
1726 for MF_DELETE. We should check the parameters for all others
1727 MF_* actions also (anybody got a doc on ChangeMenu?).
1728 */
1729
1730 switch(flags & (MF_APPEND | MF_DELETE | MF_CHANGE | MF_REMOVE | MF_INSERT))
1731 {
1732 case MF_APPEND :
1733 return AppendMenuW(hMenu, flags &~ MF_APPEND, cmdInsert, lpszNewItem);
1734
1735 case MF_DELETE :
1736 return DeleteMenu(hMenu, cmd, flags &~ MF_DELETE);
1737
1738 case MF_CHANGE :
1739 return ModifyMenuW(hMenu, cmd, flags &~ MF_CHANGE, cmdInsert, lpszNewItem);
1740
1741 case MF_REMOVE :
1742 return RemoveMenu(hMenu, flags & MF_BYPOSITION ? cmd : cmdInsert,
1743 flags &~ MF_REMOVE);
1744
1745 default : /* MF_INSERT */
1746 return InsertMenuW(hMenu, cmd, flags, cmdInsert, lpszNewItem);
1747 };
1748 }
1749
1750 /*
1751 * @implemented
1752 */
1753 BOOL
1754 WINAPI
1755 ChangeMenuA(
1756 HMENU hMenu,
1757 UINT cmd,
1758 LPCSTR lpszNewItem,
1759 UINT cmdInsert,
1760 UINT flags)
1761 {
1762 /*
1763 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
1764 for MF_DELETE. We should check the parameters for all others
1765 MF_* actions also (anybody got a doc on ChangeMenu?).
1766 */
1767
1768 switch(flags & (MF_APPEND | MF_DELETE | MF_CHANGE | MF_REMOVE | MF_INSERT))
1769 {
1770 case MF_APPEND :
1771 return AppendMenuA(hMenu, flags &~ MF_APPEND, cmdInsert, lpszNewItem);
1772
1773 case MF_DELETE :
1774 return DeleteMenu(hMenu, cmd, flags &~ MF_DELETE);
1775
1776 case MF_CHANGE :
1777 return ModifyMenuA(hMenu, cmd, flags &~ MF_CHANGE, cmdInsert, lpszNewItem);
1778
1779 case MF_REMOVE :
1780 return RemoveMenu(hMenu, flags & MF_BYPOSITION ? cmd : cmdInsert,
1781 flags &~ MF_REMOVE);
1782
1783 default : /* MF_INSERT */
1784 return InsertMenuA(hMenu, cmd, flags, cmdInsert, lpszNewItem);
1785 };
1786 }
1787