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