Various fixes by Filip Navara
[reactos.git] / reactos / 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: menu.c,v 1.32 2003/08/29 09:29:11 gvg Exp $
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, -1, 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