xref: /reactos/win32ss/user/user32/windows/menu.c (revision 728d5736)
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