update for HEAD-2003091401
[reactos.git] / lib / user32 / windows / menu.c
1 /*
2  *  ReactOS kernel
3  *  Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 /* $Id$
20  *
21  * PROJECT:         ReactOS user32.dll
22  * FILE:            lib/user32/windows/menu.c
23  * PURPOSE:         Menus
24  * PROGRAMMER:      Casper S. Hornstrup (chorns@users.sourceforge.net)
25  * UPDATE HISTORY:
26  *      09-05-2001  CSH  Created
27  */
28
29 /* INCLUDES ******************************************************************/
30
31 #include <windows.h>
32 #include <user32.h>
33 #include <debug.h>
34 #include <string.h>
35 #include <draw.h>
36 #include <window.h>
37 #include <strpool.h>
38
39 #include <user32/callback.h>
40 #include "user32/regcontrol.h"
41 #include "../controls/controls.h"
42
43 /* TYPES *********************************************************************/
44
45 #define MENU_TYPE_MASK ((MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
46
47 #define MENU_ITEM_TYPE(flags) \
48   ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
49   
50 #define MENU_BAR_ITEMS_SPACE (12)
51 #define SEPARATOR_HEIGHT (5)
52 #define MENU_TAB_SPACE (8)
53
54 #ifndef MF_END
55 #define MF_END             (0x0080)
56 #endif
57
58 #ifndef MIIM_STRING
59 #define MIIM_STRING      (0x00000040)
60 #endif
61
62 #define MAKEINTATOMA(atom)  ((LPCSTR)((ULONG_PTR)((WORD)(atom))))
63 #define MAKEINTATOMW(atom)  ((LPCWSTR)((ULONG_PTR)((WORD)(atom))))
64 #define POPUPMENU_CLASS_ATOMA   MAKEINTATOMA(32768)  /* PopupMenu */
65 #define POPUPMENU_CLASS_ATOMW   MAKEINTATOMW(32768)  /* PopupMenu */
66
67 /*********************************************************************
68  * PopupMenu class descriptor
69  */
70 const struct builtin_class_descr POPUPMENU_builtin_class =
71 {
72     POPUPMENU_CLASS_ATOMW,                     /* name */
73     CS_GLOBALCLASS | CS_SAVEBITS | CS_DBLCLKS, /* style  */
74     (WNDPROC) NULL,                            /* FIXME - procW */
75     sizeof(MENUINFO *),                        /* extra */
76     (LPCWSTR) IDC_ARROW,                        /* cursor */
77     (HBRUSH)COLOR_MENU                         /* brush */
78 };
79
80
81 /* INTERNAL FUNCTIONS ********************************************************/
82
83 /* Rip the fun and easy to use and fun WINE unicode string manipulation routines. 
84  * Of course I didnt copy the ASM code because we want this to be portable 
85  * and it needs to go away.
86  */
87
88 static inline unsigned int strlenW( const WCHAR *str )
89 {
90     const WCHAR *s = str;
91     while (*s) s++;
92     return s - str;
93 }
94
95 static inline WCHAR *strncpyW( WCHAR *str1, const WCHAR *str2, int n )
96 {
97     WCHAR *ret = str1;
98     while (n-- > 0) if (!(*str1++ = *str2++)) break;
99     while (n-- > 0) *str1++ = 0;
100     return ret;
101 }
102
103 static inline WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
104 {
105     WCHAR *p = dst;
106     while ((*p++ = *src++));
107     return dst;
108 }
109
110 static inline WCHAR *strcatW( WCHAR *dst, const WCHAR *src )
111 {
112     strcpyW( dst + strlenW(dst), src );
113     return dst;
114 }
115
116 #ifndef GET_WORD
117 #define GET_WORD(ptr)  (*(WORD *)(ptr))
118 #endif
119 #ifndef GET_DWORD
120 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
121 #endif
122
123 HFONT hMenuFont = NULL;
124 HFONT hMenuFontBold = NULL;
125
126 /**********************************************************************
127  *         MENUEX_ParseResource
128  *
129  * Parse an extended menu resource and add items to the menu.
130  * Return a pointer to the end of the resource.
131  *
132  * FIXME - should we be passing an LPCSTR to a predominantly UNICODE function?
133  */
134 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
135 {
136   WORD resinfo;
137   
138   do
139     {
140       MENUITEMINFOW mii;
141
142       mii.cbSize = sizeof(mii);
143       mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
144       mii.fType = GET_DWORD(res);
145       res += sizeof(DWORD);
146       mii.fState = GET_DWORD(res);
147       res += sizeof(DWORD);
148       mii.wID = GET_DWORD(res);
149       res += sizeof(DWORD);
150       resinfo = GET_WORD(res);
151       res += sizeof(WORD);
152       /* Align the text on a word boundary.  */
153       res += (~((int)res - 1)) & 1;
154       mii.dwTypeData = (LPWSTR) res;
155       res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
156       /* Align the following fields on a dword boundary.  */
157       res += (~((int)res - 1)) & 3;
158
159       if (resinfo & 1) /* Pop-up? */
160         {
161           /* DWORD helpid = GET_DWORD(res); FIXME: use this.  */
162           res += sizeof(DWORD);
163           mii.hSubMenu = CreatePopupMenu();
164           if (!mii.hSubMenu)
165               return NULL;
166           if (!(res = MENUEX_ParseResource(res, mii.hSubMenu)))
167           {
168               DestroyMenu(mii.hSubMenu);
169               return NULL;
170           }
171           mii.fMask |= MIIM_SUBMENU;
172           mii.fType |= MF_POPUP;
173         }
174       else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR))
175         {
176           DbgPrint("WARN: Converting NULL menu item %04x, type %04x to SEPARATOR\n",
177               mii.wID, mii.fType);
178           mii.fType |= MF_SEPARATOR;
179         }
180     InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
181   }
182   while (!(resinfo & MF_END));
183   return res;
184 }
185
186
187 /**********************************************************************
188  *         MENU_ParseResource
189  *
190  * Parse a standard menu resource and add items to the menu.
191  * Return a pointer to the end of the resource.
192  *
193  * NOTE: flags is equivalent to the mtOption field
194  */
195 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
196 {
197   WORD flags, id = 0;
198   HMENU hSubMenu;
199   LPCSTR str;
200   BOOL end = FALSE;
201
202   do
203   {
204     flags = GET_WORD(res);
205
206     /* remove MF_END flag before passing it to AppendMenu()! */
207     end = (flags & MF_END);
208     if(end) flags ^= MF_END;
209
210     res += sizeof(WORD);
211     if(!(flags & MF_POPUP))
212     {
213       id = GET_WORD(res);
214       res += sizeof(WORD);
215     }
216     str = res;
217     if(!unicode)
218       res += strlen(str) + 1;
219     else
220       res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
221     if (flags & MF_POPUP)
222     {
223       hSubMenu = CreatePopupMenu();
224       if(!hSubMenu) return NULL;
225       if(!(res = MENU_ParseResource(res, hSubMenu, unicode)))
226         return NULL;
227       if(!unicode)
228         AppendMenuA(hMenu, flags, (UINT)hSubMenu, str);
229       else
230         AppendMenuW(hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str);
231     }
232     else  /* Not a popup */
233     {
234       if(!unicode)
235         AppendMenuA(hMenu, flags, id, *str ? str : NULL);
236       else
237         AppendMenuW(hMenu, flags, id,
238                     *(LPCWSTR)str ? (LPCWSTR)str : NULL);
239     }
240   } while(!end);
241
242   return res;
243 }
244
245
246 NTSTATUS STDCALL
247 User32LoadSysMenuTemplateForKernel(PVOID Arguments, ULONG ArgumentLength)
248 {
249   LRESULT Result;
250   HMODULE hUser32;
251   hUser32 = GetModuleHandleW(L"USER32");
252   Result = (LRESULT)LoadMenuW(hUser32, L"SYSMENU");
253   return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
254 }
255
256
257 BOOL
258 MenuInit(VOID)
259 {
260   NONCLIENTMETRICSW ncm;
261   
262   /* get the menu font */
263   if(!hMenuFont || !hMenuFontBold)
264   {
265     ncm.cbSize = sizeof(ncm);
266     if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
267     {
268       DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
269       return FALSE;
270     }
271     
272     hMenuFont = CreateFontIndirectW(&ncm.lfMenuFont);
273     if(hMenuFont == NULL)
274     {
275       DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
276       return FALSE;
277     }
278     
279     ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
280     hMenuFontBold = CreateFontIndirectW(&ncm.lfMenuFont);
281     if(hMenuFontBold == NULL)
282     {
283       DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
284       return FALSE;
285     }
286   }
287
288   return TRUE;
289 }
290
291
292 ULONG
293 MenuGetMenuBarHeight(HWND hWnd, ULONG MenuBarWidth, LONG OrgX, LONG OrgY)
294 {
295   /*ULONG MenuId;
296   PPOPUP_MENU Menu;
297   RECT Rect;
298   HDC hDC;
299
300   MenuId = GetWindowLong(hWnd, GWL_ID);
301   Menu = MenuGetMenu((HMENU)MenuId);
302   if (Menu == NULL)
303     {
304       return(0);
305     }
306   hDC = GetDCEx(hWnd, 0, DCX_CACHE | DCX_WINDOW);
307   SelectObject(hDC, hMenuFont);
308   SetRect(&Rect, OrgX, OrgY, OrgX + MenuBarWidth, 
309           OrgY + GetSystemMetrics(SM_CYMENU));
310   MenuMenuBarCalcSize(hDC, &Rect, Menu, hWnd);
311   ReleaseDC(hWnd, hDC);*/
312   return(GetSystemMetrics(SM_CYMENU));
313 }
314
315 static BOOL
316 MeasureMenuItem(HWND hWnd, HMENU mnu, HDC hDC, MENUITEMINFOW *mii, RECT *mir, LPWSTR str)
317 {
318   BOOL res = FALSE;
319   MEASUREITEMSTRUCT mis;
320   SIZE sz;
321   
322   if(mii->fType & MFT_OWNERDRAW)
323   {
324     /* send WM_MEASUREITEM message to window */
325     mis.CtlType = ODT_MENU;
326     mis.CtlID = 0;
327     mis.itemID = mii->wID;
328     mis.itemWidth = 0;
329     mis.itemHeight = 0;
330     mis.itemData = mii->dwItemData;
331     res = (BOOL)SendMessageW(hWnd, WM_MEASUREITEM, 0, (LPARAM)&mis);
332     if(res)
333     {
334       mir->right = mir->left + mis.itemWidth;
335       mir->bottom = mir->top + mis.itemHeight;
336     }
337     else
338     {
339       /* FIXME calculate size internally assuming the menu item is empty */
340       mir->right = mir->left + 1;
341       mir->bottom = mir->top + 1;
342     }
343     return res;
344   }
345   else
346   {
347     GetTextExtentPoint32W(hDC, str, mii->cch, &sz);
348     /* FIXME calculate the size of the menu item */
349     mir->right = mir->left + sz.cx + 6;
350     mir->bottom = mir->top + max(sz.cy, GetSystemMetrics(SM_CYMENU));
351     return TRUE;
352   }
353 }
354
355 static BOOL
356 DrawMenuItem(HWND hWnd, HMENU mnu, HDC hDC, MENUITEMINFOW *mii, RECT *mir, LPWSTR str)
357 {
358   BOOL res = FALSE;
359   DRAWITEMSTRUCT dis;
360   
361   if(mii->fType & MFT_OWNERDRAW)
362   {
363     /* send WM_DRAWITEM message to window */
364     dis.CtlType = ODT_MENU;
365     dis.CtlID = 0;
366     dis.itemID = mii->wID;
367     dis.itemAction = ODA_DRAWENTIRE; /* FIXME */
368     dis.itemState = 0; /* FIXME */
369     dis.hwndItem = (HWND)mnu;
370     dis.hDC = hDC;
371     RtlCopyMemory(&dis.rcItem, mir, sizeof(RECT));
372     dis.itemData = mii->dwItemData;
373     res = (BOOL)SendMessageW(hWnd, WM_DRAWITEM, 0, (LPARAM)&dis);
374     return res;
375   }
376   else
377   {
378     /* FIXME draw the menu item */
379     SetTextColor(hDC, COLOR_MENUTEXT);
380     DrawTextW(hDC, str, mii->cch, mir, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
381   }
382   return res;
383 }
384
385
386 UINT
387 MenuDrawMenuBar(HDC hDC, LPRECT Rect, HWND hWnd, BOOL Draw)
388 {
389   UINT height;
390   HMENU mnu;
391   HANDLE hHeap;
392   PVOID Buf, hBuf;
393   DWORD BufSize, Items, Items2;
394   MENUITEMINFOW *mii;
395   RECT *omir, *mir = NULL;
396   LPWSTR str;
397   
398   height = Rect->bottom - Rect->top;
399   mnu = GetMenu(hWnd); /* Fixme - pass menu handle as parameter */
400   /* get menu item list size */
401   BufSize = NtUserBuildMenuItemList(mnu, (VOID*)1, 0, 0);
402   if(BufSize)
403   {
404     /* FIXME cache menu bar items using NtUserDrawMenuBarTemp() 
405              instead of allocating and deallocating memory everytime */
406
407     hHeap = GetProcessHeap();
408     hBuf = HeapAlloc(hHeap, 0, BufSize);
409     if(!hBuf)
410       return(Rect->bottom - Rect->top);
411     Buf = hBuf;
412     /* copy menu items into buffer */
413     Items = Items2 = NtUserBuildMenuItemList(mnu, Buf, BufSize, 0);
414     
415     /* calculate menu item rectangles */
416     while(Items > 0)
417     {
418       omir = mir;
419       mii = (LPMENUITEMINFOW)Buf;
420       Buf += sizeof(MENUITEMINFOW);
421       mir = (LPRECT)Buf;
422       Buf += sizeof(RECT);
423       if(mii->cch)
424       {
425         str = (LPWSTR)Buf;
426         Buf += (mii->cch + 1) * sizeof(WCHAR);
427       }
428       else
429         str = NULL;
430       if(omir)
431       {
432         mir->left = omir->right + 1;
433         mir->top = omir->top;
434         mir->right += mir->left;
435         mir->bottom += mir->top;
436       }
437       else
438       {
439         mir->left = Rect->left;
440         mir->top = Rect->top;
441       }
442       MeasureMenuItem(hWnd, mnu, hDC, mii, mir, str);
443       
444       height = max(height, mir->top + mir->bottom);
445       /* DbgPrint("Measure menu item %ws: (%d, %d, %d, %d)\n", str, mir->left, mir->top, mir->right, mir->bottom); */
446       Items--;
447     }
448     height = max(height, GetSystemMetrics(SM_CYMENU));
449     
450     Buf = hBuf;
451     /* draw menu items */
452     while (Items2 > 0)
453     {
454       mii = (LPMENUITEMINFOW)Buf;
455       Buf += sizeof(MENUITEMINFOW);
456       mir = (LPRECT)Buf;
457       Buf += sizeof(RECT);
458       if(mii->cch)
459       {
460         str = (LPWSTR)Buf;
461         Buf += (mii->cch + 1) * sizeof(WCHAR);
462       }
463       else
464         str = NULL;
465       /* DbgPrint("Draw menu item %ws at (%d, %d, %d, %d)\n", str, mir->left, mir->top, mir->right, mir->bottom); */
466       DrawMenuItem(hWnd, mnu, hDC, mii, mir, str);
467       Items2--;
468     }
469     
470     HeapFree(hHeap, 0, hBuf);
471   }
472
473   return height;
474 }
475
476
477 VOID
478 MenuTrackMouseMenuBar(HWND hWnd, ULONG Ht, POINT Pt)
479 {
480 }
481
482
483 VOID
484 MenuTrackKbdMenuBar(HWND hWnd, ULONG wParam, ULONG Key)
485 {
486 }
487
488 /* FUNCTIONS *****************************************************************/
489
490 /*static BOOL
491 MenuIsStringItem(ULONG TypeData)
492 {
493   return((TypeData & MENU_TYPE_MASK) == MF_STRING);
494 }*/
495
496
497 /*
498  * @implemented
499  */
500 WINBOOL STDCALL
501 AppendMenuA(HMENU hMenu,
502             UINT uFlags,
503             UINT_PTR uIDNewItem,
504             LPCSTR lpNewItem)
505 {
506   return(InsertMenuA(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem, 
507                      lpNewItem));
508 }
509
510
511 /*
512  * @implemented
513  */
514 WINBOOL STDCALL
515 AppendMenuW(HMENU hMenu,
516             UINT uFlags,
517             UINT_PTR uIDNewItem,
518             LPCWSTR lpNewItem)
519 {
520   return(InsertMenuW(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem, 
521                      lpNewItem));
522 }
523
524
525 /*
526  * @implemented
527  */
528 DWORD STDCALL
529 CheckMenuItem(HMENU hmenu,
530               UINT uIDCheckItem,
531               UINT uCheck)
532 {
533   return NtUserCheckMenuItem(hmenu, uIDCheckItem, uCheck);
534 }
535
536
537 /*
538  * @unimplemented
539  */
540 WINBOOL STDCALL
541 CheckMenuRadioItem(HMENU hmenu,
542                    UINT idFirst,
543                    UINT idLast,
544                    UINT idCheck,
545                    UINT uFlags)
546 {
547   UNIMPLEMENTED;
548   return FALSE;
549 }
550
551
552 /*
553  * @implemented
554  */
555 HMENU STDCALL
556 CreateMenu(VOID)
557 {
558   return NtUserCreateMenu();
559 }
560
561
562 /*
563  * @implemented
564  */
565 HMENU STDCALL
566 CreatePopupMenu(VOID)
567 {
568   /* FIXME - add MF_POPUP style? */
569   return NtUserCreateMenu();
570 }
571
572
573 /*
574  * @implemented
575  */
576 WINBOOL STDCALL
577 DeleteMenu(HMENU hMenu,
578            UINT uPosition,
579            UINT uFlags)
580 {
581   return NtUserDeleteMenu(hMenu, uPosition, uFlags);
582 }
583
584
585 /*
586  * @implemented
587  */
588 WINBOOL STDCALL
589 DestroyMenu(HMENU hMenu)
590 {
591     return NtUserDestroyMenu(hMenu);
592 }
593
594
595 /*
596  * @unimplemented
597  */
598 WINBOOL STDCALL
599 DrawMenuBar(HWND hWnd)
600 {
601   UNIMPLEMENTED
602   /* FIXME - return NtUserCallHwndLock(hWnd, 0x55); */
603   return FALSE;
604 }
605
606
607 /*
608  * @implemented
609  */
610 UINT STDCALL
611 EnableMenuItem(HMENU hMenu,
612                UINT uIDEnableItem,
613                UINT uEnable)
614 {
615   return NtUserEnableMenuItem(hMenu, uIDEnableItem, uEnable);
616 }
617
618 /*
619  * @unimplemented
620  */
621 WINBOOL STDCALL
622 EndMenu(VOID)
623 {
624   UNIMPLEMENTED;
625   /* FIXME - return NtUserEndMenu(); */
626   return FALSE;
627 }
628
629
630 /*
631  * @implemented
632  */
633 HMENU STDCALL
634 GetMenu(HWND hWnd)
635 {
636   return (HMENU)NtUserCallOneParam((DWORD)hWnd, ONEPARAM_ROUTINE_GETMENU);
637 }
638
639
640 /*
641  * @unimplemented
642  */
643 WINBOOL STDCALL
644 GetMenuBarInfo(HWND hwnd,
645                LONG idObject,
646                LONG idItem,
647                PMENUBARINFO pmbi)
648 {
649   UNIMPLEMENTED;
650   return FALSE;
651 }
652
653
654 /*
655  * @implemented
656  */
657 LONG STDCALL
658 GetMenuCheckMarkDimensions(VOID)
659 {
660   return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK), 
661                   GetSystemMetrics(SM_CYMENUCHECK)));
662 }
663
664
665 /*
666  * @implemented
667  */
668 UINT STDCALL
669 GetMenuDefaultItem(HMENU hMenu,
670                    UINT fByPos,
671                    UINT gmdiFlags)
672 {
673   return NtUserGetMenuDefaultItem(hMenu, fByPos, gmdiFlags);
674 }
675
676
677 /*
678  * @implemented
679  */
680 WINBOOL STDCALL
681 GetMenuInfo(HMENU hmenu,
682             LPMENUINFO lpcmi)
683 {
684   MENUINFO mi;
685   BOOL res = FALSE;
686   
687   if(!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO)))
688     return FALSE;
689   
690   RtlZeroMemory(&mi, sizeof(MENUINFO));
691   mi.cbSize = sizeof(MENUINFO);
692   mi.fMask = lpcmi->fMask;
693   
694   res = NtUserMenuInfo(hmenu, &mi, FALSE);
695   
696   memcpy(lpcmi, &mi, sizeof(MENUINFO));
697   return res;
698 }
699
700
701 /*
702  * @implemented
703  */
704 int STDCALL
705 GetMenuItemCount(HMENU hMenu)
706 {
707   return NtUserBuildMenuItemList(hMenu, NULL, 0, 0);
708 }
709
710
711 /*
712  * @implemented
713  */
714 UINT STDCALL
715 GetMenuItemID(HMENU hMenu,
716               int nPos)
717 {
718   MENUITEMINFOW mii;
719   
720   mii.cbSize = sizeof(MENUITEMINFOW);
721   mii.fMask = MIIM_ID | MIIM_SUBMENU;
722   
723   if(!NtUserMenuItemInfo(hMenu, nPos, MF_BYPOSITION, &mii, FALSE))
724   {
725     return -1;
726   }
727   
728   if(mii.hSubMenu) return -1;
729   if(mii.wID == 0) return -1;
730   
731   return mii.wID;
732 }
733
734
735 /*
736  * @unimplemented
737  */
738 WINBOOL STDCALL
739 GetMenuItemInfoA(
740   HMENU hMenu,
741   UINT uItem,
742   WINBOOL fByPosition,
743   LPMENUITEMINFOA lpmii)
744 {
745   UNIMPLEMENTED;
746   return FALSE;
747 }
748
749
750 /*
751  * @unimplemented
752  */
753 WINBOOL
754 STDCALL
755 GetMenuItemInfoW(
756   HMENU hMenu,
757   UINT uItem,
758   WINBOOL fByPosition,
759   LPMENUITEMINFOW lpmii)
760 {
761   UNIMPLEMENTED;
762   return FALSE;
763 }
764
765
766 /*
767  * @unimplemented
768  */
769 WINBOOL STDCALL
770 GetMenuItemRect(HWND hWnd,
771                 HMENU hMenu,
772                 UINT uItem,
773                 LPRECT lprcItem)
774 {
775   UNIMPLEMENTED;
776   return(FALSE);
777 }
778
779
780 /*
781  * @implemented
782  */
783 UINT
784 STDCALL
785 GetMenuState(
786   HMENU hMenu,
787   UINT uId,
788   UINT uFlags)
789 {
790   MENUITEMINFOW mii;
791   mii.cbSize = sizeof(MENUITEMINFOW);
792   mii.fMask = MIIM_STATE | MIIM_TYPE | MIIM_SUBMENU;
793   
794   SetLastError(0);
795   if(NtUserMenuItemInfo(hMenu, uId, uFlags, &mii, FALSE))
796   {
797     UINT nSubItems = 0;
798     if(mii.hSubMenu)
799     {
800       nSubItems = (UINT)NtUserBuildMenuItemList(mii.hSubMenu, NULL, 0, 0);
801       
802       /* FIXME - ported from wine, does that work (0xff)? */
803       if(GetLastError() != ERROR_INVALID_MENU_HANDLE)
804         return (nSubItems << 8) | ((mii.fState | mii.fType) & 0xff);
805
806       return (UINT)-1; /* Invalid submenu */
807     }
808     
809     /* FIXME - ported from wine, does that work? */
810     return (mii.fType | mii.fState);
811   }
812   
813   return (UINT)-1;
814 }
815
816
817 /*
818  * @unimplemented
819  */
820 int
821 STDCALL
822 GetMenuStringA(
823   HMENU hMenu,
824   UINT uIDItem,
825   LPSTR lpString,
826   int nMaxCount,
827   UINT uFlag)
828 {
829   UNIMPLEMENTED;
830   return 0;
831 }
832
833
834 /*
835  * @unimplemented
836  */
837 int
838 STDCALL
839 GetMenuStringW(
840   HMENU hMenu,
841   UINT uIDItem,
842   LPWSTR lpString,
843   int nMaxCount,
844   UINT uFlag)
845 {
846   UNIMPLEMENTED;
847   return 0;
848 }
849
850
851 /*
852  * @implemented
853  */
854 HMENU
855 STDCALL
856 GetSubMenu(
857   HMENU hMenu,
858   int nPos)
859 {
860   MENUITEMINFOW mi;
861   mi.cbSize = sizeof(mi);
862   mi.fMask = MIIM_SUBMENU;
863   if(NtUserMenuItemInfo(hMenu, (UINT)nPos, MF_BYPOSITION, &mi, FALSE))
864   {
865     return mi.hSubMenu;
866   }
867   return (HMENU)0;
868 }
869
870
871 /*
872  * @implemented
873  */
874 WINBOOL
875 STDCALL
876 HiliteMenuItem(
877   HWND hwnd,
878   HMENU hmenu,
879   UINT uItemHilite,
880   UINT uHilite)
881 {
882   return NtUserHiliteMenuItem(hwnd, hmenu, uItemHilite, uHilite);
883 }
884
885
886 /*
887  * @implemented
888  */
889 WINBOOL
890 STDCALL
891 InsertMenuA(
892   HMENU hMenu,
893   UINT uPosition,
894   UINT uFlags,
895   UINT_PTR uIDNewItem,
896   LPCSTR lpNewItem)
897 {
898   MENUITEMINFOA mii;
899   mii.cbSize = sizeof(MENUITEMINFOA);
900   mii.fMask = MIIM_FTYPE | MIIM_STRING;
901   mii.fType = 0;  
902   
903   if(uFlags & MF_BITMAP)
904   {
905     mii.fType |= MFT_BITMAP;
906   }
907   else if(uFlags & MF_OWNERDRAW)
908   {
909     mii.fType |= MFT_OWNERDRAW;
910   }
911   mii.dwTypeData = (LPSTR)lpNewItem;
912   if(uFlags & MF_POPUP)
913   {
914     mii.fMask |= MIIM_SUBMENU;
915     mii.hSubMenu = (HMENU)uIDNewItem;
916   }
917   else
918   {
919     mii.fMask |= MIIM_ID;
920     mii.wID = (UINT)uIDNewItem;
921   }
922   return InsertMenuItemA(hMenu, uPosition, (WINBOOL)!(MF_BYPOSITION & uFlags), &mii);
923 }
924
925
926 /*
927  * @implemented
928  */
929 WINBOOL
930 STDCALL
931 InsertMenuItemA(
932   HMENU hMenu,
933   UINT uItem,
934   WINBOOL fByPosition,
935   LPCMENUITEMINFOA lpmii)
936 {
937   MENUITEMINFOW mi;
938   UNICODE_STRING MenuText;
939   WINBOOL res = FALSE;
940   BOOL CleanHeap = FALSE;
941   NTSTATUS Status;
942
943   if((lpmii->cbSize == sizeof(MENUITEMINFOA)) || 
944      (lpmii->cbSize == sizeof(MENUITEMINFOA) - sizeof(HBITMAP)))
945   {
946     RtlMoveMemory ( &mi, lpmii, lpmii->cbSize );
947
948     /* copy the text string */
949     if((mi.fMask & (MIIM_TYPE | MIIM_STRING)) && 
950       (MENU_ITEM_TYPE(mi.fType) == MF_STRING) && mi.dwTypeData)
951     {
952       Status = HEAP_strdupAtoW ( &mi.dwTypeData, (LPCSTR)mi.dwTypeData, &mi.cch );
953       if (!NT_SUCCESS (Status))
954       {
955         SetLastError (RtlNtStatusToDosError(Status));
956         return FALSE;
957       }
958       RtlInitUnicodeString(&MenuText, (PWSTR)mi.dwTypeData);
959       mi.dwTypeData = (LPWSTR)&MenuText;
960       CleanHeap = TRUE;
961     }
962
963     res = NtUserInsertMenuItem(hMenu, uItem, fByPosition, &mi);
964
965     if ( CleanHeap ) HEAP_free ( mi.dwTypeData );
966   }
967   return res;
968 }
969
970
971 /*
972  * @implemented
973  */
974 WINBOOL
975 STDCALL
976 InsertMenuItemW(
977   HMENU hMenu,
978   UINT uItem,
979   WINBOOL fByPosition,
980   LPCMENUITEMINFOW lpmii)
981 {
982   MENUITEMINFOW mi;
983   UNICODE_STRING MenuText;
984   WINBOOL res = FALSE;
985   BOOL CleanHeap = FALSE;
986   HANDLE hHeap = RtlGetProcessHeap();
987   mi.hbmpItem = (HBITMAP)0;
988
989   // while we could just pass 'lpmii' to win32k, we make a copy so that
990   // if a bad user passes bad data, we crash his process instead of the
991   // entire kernel
992
993   if((lpmii->cbSize == sizeof(MENUITEMINFOW)) || 
994      (lpmii->cbSize == sizeof(MENUITEMINFOW) - sizeof(HBITMAP)))
995   {
996     memcpy(&mi, lpmii, lpmii->cbSize);
997     
998     /* copy the text string */
999     if((mi.fMask & (MIIM_TYPE | MIIM_STRING)) && 
1000       (MENU_ITEM_TYPE(mi.fType) == MF_STRING) && mi.dwTypeData)
1001     {
1002       if(lpmii->cch > 0)
1003       {
1004         if(!RtlCreateUnicodeString(&MenuText, (PWSTR)lpmii->dwTypeData))
1005         {
1006           SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY));
1007           return FALSE;
1008         }
1009         mi.dwTypeData = (LPWSTR)&MenuText;
1010         mi.cch = MenuText.Length / sizeof(WCHAR);
1011         CleanHeap = TRUE;
1012       }
1013     };
1014     
1015     res = NtUserInsertMenuItem(hMenu, uItem, fByPosition, &mi);
1016     
1017     if(CleanHeap) RtlFreeHeap (hHeap, 0, mi.dwTypeData);
1018   }
1019   return res;
1020 }
1021
1022
1023 /*
1024  * @implemented
1025  */
1026 WINBOOL
1027 STDCALL
1028 InsertMenuW(
1029   HMENU hMenu,
1030   UINT uPosition,
1031   UINT uFlags,
1032   UINT_PTR uIDNewItem,
1033   LPCWSTR lpNewItem)
1034 {
1035   MENUITEMINFOW mii;
1036   mii.cbSize = sizeof(MENUITEMINFOW);
1037   mii.fMask = MIIM_FTYPE | MIIM_STRING;
1038   mii.fType = 0;
1039
1040   if(uFlags & MF_BITMAP)
1041   {
1042     mii.fType |= MFT_BITMAP;
1043   }
1044   else if(uFlags & MF_OWNERDRAW)
1045   {
1046     mii.fType |= MFT_OWNERDRAW;
1047   }
1048   mii.dwTypeData = (LPWSTR)lpNewItem;
1049   if(uFlags & MF_POPUP)
1050   {
1051     mii.fMask |= MIIM_SUBMENU;
1052     mii.hSubMenu = (HMENU)uIDNewItem;
1053   }
1054   else
1055   {
1056     mii.fMask |= MIIM_ID;
1057     mii.wID = (UINT)uIDNewItem;
1058   }
1059   return InsertMenuItemW(hMenu, uPosition, (WINBOOL)!(MF_BYPOSITION & uFlags), &mii);
1060 }
1061
1062
1063 /*
1064  * @implemented
1065  */
1066 WINBOOL
1067 STDCALL
1068 IsMenu(
1069   HMENU hMenu)
1070 {
1071   DWORD ret;
1072   SetLastError(ERROR_SUCCESS);
1073   ret = NtUserBuildMenuItemList(hMenu, NULL, 0, 0);
1074   return ((ret == (DWORD)-1) || (GetLastError() == ERROR_INVALID_MENU_HANDLE));
1075 }
1076
1077
1078 /*
1079  * @implemented
1080  */
1081 HMENU STDCALL
1082 LoadMenuA(HINSTANCE hInstance,
1083           LPCSTR lpMenuName)
1084 {
1085   HANDLE Resource = FindResourceA(hInstance, lpMenuName, MAKEINTRESOURCEA(4));
1086   if (Resource == NULL)
1087     {
1088       return(NULL);
1089     }
1090   return(LoadMenuIndirectA((PVOID)LoadResource(hInstance, Resource)));
1091 }
1092
1093
1094 /*
1095  * @implemented
1096  */
1097 HMENU STDCALL
1098 LoadMenuIndirectA(CONST MENUTEMPLATE *lpMenuTemplate)
1099 {
1100   return(LoadMenuIndirectW(lpMenuTemplate));
1101 }
1102
1103
1104 /*
1105  * @implemented
1106  */
1107 HMENU STDCALL
1108 LoadMenuIndirectW(CONST MENUTEMPLATE *lpMenuTemplate)
1109 {
1110   HMENU hMenu;
1111   WORD version, offset;
1112   LPCSTR p = (LPCSTR)lpMenuTemplate;
1113
1114   version = GET_WORD(p);
1115   p += sizeof(WORD);
1116
1117   switch (version)
1118   {
1119     case 0: /* standard format is version of 0 */
1120       offset = GET_WORD(p);
1121       p += sizeof(WORD) + offset;
1122       if (!(hMenu = CreateMenu())) return 0;
1123       if (!MENU_ParseResource(p, hMenu, TRUE))
1124       {
1125         DestroyMenu(hMenu);
1126         return 0;
1127       }
1128       return hMenu;
1129     case 1: /* extended format is version of 1 */
1130       offset = GET_WORD(p);
1131       p += sizeof(WORD) + offset;
1132       if (!(hMenu = CreateMenu())) return 0;
1133       if (!MENUEX_ParseResource(p, hMenu))
1134       {
1135         DestroyMenu( hMenu );
1136         return 0;
1137       }
1138       return hMenu;
1139     default:
1140       DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version);
1141       return 0;
1142   }
1143 }
1144
1145
1146 /*
1147  * @implemented
1148  */
1149 HMENU STDCALL
1150 LoadMenuW(HINSTANCE hInstance,
1151           LPCWSTR lpMenuName)
1152 {
1153   HANDLE Resource = FindResourceW(hInstance, lpMenuName, RT_MENU);
1154   if (Resource == NULL)
1155     {
1156       return(NULL);
1157     }
1158   return(LoadMenuIndirectW((PVOID)LoadResource(hInstance, Resource)));
1159 }
1160
1161
1162 /*
1163  * @unimplemented
1164  */
1165 int
1166 STDCALL
1167 MenuItemFromPoint(
1168   HWND hWnd,
1169   HMENU hMenu,
1170   POINT ptScreen)
1171 {
1172   UNIMPLEMENTED;
1173   return 0;
1174 }
1175
1176
1177 /*
1178  * @unimplemented
1179  */
1180 WINBOOL
1181 STDCALL
1182 ModifyMenuA(
1183   HMENU hMnu,
1184   UINT uPosition,
1185   UINT uFlags,
1186   UINT_PTR uIDNewItem,
1187   LPCSTR lpNewItem)
1188 {
1189   UNIMPLEMENTED;
1190   return FALSE;
1191 }
1192
1193
1194 /*
1195  * @unimplemented
1196  */
1197 WINBOOL
1198 STDCALL
1199 ModifyMenuW(
1200   HMENU hMnu,
1201   UINT uPosition,
1202   UINT uFlags,
1203   UINT_PTR uIDNewItem,
1204   LPCWSTR lpNewItem)
1205 {
1206   UNIMPLEMENTED;
1207   return FALSE;
1208 }
1209
1210
1211 /*
1212  * @implemented
1213  */
1214 WINBOOL
1215 STDCALL
1216 RemoveMenu(
1217   HMENU hMenu,
1218   UINT uPosition,
1219   UINT uFlags)
1220 {
1221   return NtUserRemoveMenu(hMenu, uPosition, uFlags);
1222 }
1223
1224
1225 /*
1226  * @implemented
1227  */
1228 WINBOOL STDCALL
1229 SetMenu(HWND hWnd,
1230         HMENU hMenu)
1231 {
1232   return NtUserSetMenu(hWnd, hMenu, TRUE);
1233 }
1234
1235
1236 /*
1237  * @implemented
1238  */
1239 WINBOOL
1240 STDCALL
1241 SetMenuDefaultItem(
1242   HMENU hMenu,
1243   UINT uItem,
1244   UINT fByPos)
1245 {
1246   return NtUserSetMenuDefaultItem(hMenu, uItem, fByPos);
1247 }
1248
1249
1250 /*
1251  * @implemented
1252  */
1253 WINBOOL
1254 STDCALL
1255 SetMenuInfo(
1256   HMENU hmenu,
1257   LPCMENUINFO lpcmi)
1258 {
1259   MENUINFO mi;
1260   BOOL res = FALSE;
1261   if(lpcmi->cbSize != sizeof(MENUINFO))
1262     return res;
1263     
1264   memcpy(&mi, lpcmi, sizeof(MENUINFO));
1265   return NtUserMenuInfo(hmenu, &mi, TRUE);
1266 }
1267
1268
1269 /*
1270  * @unimplemented
1271  */
1272 WINBOOL
1273 STDCALL
1274 SetMenuItemBitmaps(
1275   HMENU hMenu,
1276   UINT uPosition,
1277   UINT uFlags,
1278   HBITMAP hBitmapUnchecked,
1279   HBITMAP hBitmapChecked)
1280 {
1281   UNIMPLEMENTED;
1282   return FALSE;
1283 }
1284
1285
1286 /*
1287  * @unimplemented
1288  */
1289 WINBOOL
1290 STDCALL
1291 SetMenuItemInfoA(
1292   HMENU hMenu,
1293   UINT uItem,
1294   WINBOOL fByPosition,
1295   LPMENUITEMINFOA lpmii)
1296 {
1297   UNIMPLEMENTED;
1298   return FALSE;
1299 }
1300
1301
1302 /*
1303  * @unimplemented
1304  */
1305 WINBOOL
1306 STDCALL
1307 SetMenuItemInfoW(
1308   HMENU hMenu,
1309   UINT uItem,
1310   WINBOOL fByPosition,
1311   LPMENUITEMINFOW lpmii)
1312 {
1313   UNIMPLEMENTED;
1314   return FALSE;
1315 }
1316
1317
1318 /*
1319  * @unimplemented
1320  */
1321 WINBOOL
1322 STDCALL
1323 TrackPopupMenu(
1324   HMENU hMenu,
1325   UINT uFlags,
1326   int x,
1327   int y,
1328   int nReserved,
1329   HWND hWnd,
1330   CONST RECT *prcRect)
1331 {
1332   UNIMPLEMENTED;
1333   return FALSE;
1334 }
1335
1336
1337 /*
1338  * @unimplemented
1339  */
1340 WINBOOL
1341 STDCALL
1342 TrackPopupMenuEx(
1343   HMENU hmenu,
1344   UINT fuFlags,
1345   int x,
1346   int y,
1347   HWND hwnd,
1348   LPTPMPARAMS lptpm)
1349 {
1350   UNIMPLEMENTED;
1351   return FALSE;
1352 }
1353
1354
1355 /*
1356  * @implemented
1357  */
1358 WINBOOL
1359 STDCALL
1360 SetMenuContextHelpId(HMENU hmenu,
1361           DWORD dwContextHelpId)
1362 {
1363   return NtUserSetMenuContextHelpId(hmenu, dwContextHelpId);
1364 }
1365
1366
1367 /*
1368  * @implemented
1369  */
1370 DWORD
1371 STDCALL
1372 GetMenuContextHelpId(HMENU hmenu)
1373 {
1374   MENUINFO mi;
1375   mi.cbSize = sizeof(MENUINFO);
1376   mi.fMask = MIM_HELPID;
1377   
1378   if(NtUserMenuInfo(hmenu, &mi, FALSE))
1379   {
1380     return mi.dwContextHelpID;
1381   }
1382   return 0;
1383 }
1384