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