small changes
[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.29 2003/08/23 17:06:07 weiden 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 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
266 {
267 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
268 return FALSE;
269 }
270
271 hMenuFont = CreateFontIndirectW(&ncm.lfMenuFont);
272 if(hMenuFont == NULL)
273 {
274 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
275 return FALSE;
276 }
277
278 ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
279 hMenuFontBold = CreateFontIndirectW(&ncm.lfMenuFont);
280 if(hMenuFontBold == NULL)
281 {
282 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
283 return FALSE;
284 }
285 }
286
287 return TRUE;
288 }
289
290
291 ULONG
292 MenuGetMenuBarHeight(HWND hWnd, ULONG MenuBarWidth, LONG OrgX, LONG OrgY)
293 {
294 /*ULONG MenuId;
295 PPOPUP_MENU Menu;
296 RECT Rect;
297 HDC hDC;
298
299 MenuId = GetWindowLong(hWnd, GWL_ID);
300 Menu = MenuGetMenu((HMENU)MenuId);
301 if (Menu == NULL)
302 {
303 return(0);
304 }
305 hDC = GetDCEx(hWnd, 0, DCX_CACHE | DCX_WINDOW);
306 SelectObject(hDC, hMenuFont);
307 SetRect(&Rect, OrgX, OrgY, OrgX + MenuBarWidth,
308 OrgY + GetSystemMetrics(SM_CYMENU));
309 MenuMenuBarCalcSize(hDC, &Rect, Menu, hWnd);
310 ReleaseDC(hWnd, hDC);*/
311 return(GetSystemMetrics(SM_CYMENU));
312 }
313
314
315 UINT
316 MenuDrawMenuBar(HDC hDC, LPRECT Rect, HWND hWnd, BOOL Draw)
317 {
318 /* FIXME cache menu bar items using NtUserDrawMenuBarTemp() */
319
320 /* FIXME select menu font first */
321
322 DrawTextW(hDC, L"FIXME: Draw Menubar", -1, Rect, DT_SINGLELINE | DT_VCENTER);
323
324 return(Rect->bottom - Rect->top);
325 }
326
327
328 VOID
329 MenuTrackMouseMenuBar(HWND hWnd, ULONG Ht, POINT Pt)
330 {
331 }
332
333
334 VOID
335 MenuTrackKbdMenuBar(HWND hWnd, ULONG wParam, ULONG Key)
336 {
337 }
338
339 /* FUNCTIONS *****************************************************************/
340
341 /*static BOOL
342 MenuIsStringItem(ULONG TypeData)
343 {
344 return((TypeData & MENU_TYPE_MASK) == MF_STRING);
345 }*/
346
347
348 /*
349 * @implemented
350 */
351 WINBOOL STDCALL
352 AppendMenuA(HMENU hMenu,
353 UINT uFlags,
354 UINT_PTR uIDNewItem,
355 LPCSTR lpNewItem)
356 {
357 return(InsertMenuA(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem,
358 lpNewItem));
359 }
360
361
362 /*
363 * @implemented
364 */
365 WINBOOL STDCALL
366 AppendMenuW(HMENU hMenu,
367 UINT uFlags,
368 UINT_PTR uIDNewItem,
369 LPCWSTR lpNewItem)
370 {
371 return(InsertMenuW(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem,
372 lpNewItem));
373 }
374
375
376 /*
377 * @implemented
378 */
379 DWORD STDCALL
380 CheckMenuItem(HMENU hmenu,
381 UINT uIDCheckItem,
382 UINT uCheck)
383 {
384 return NtUserCheckMenuItem(hmenu, uIDCheckItem, uCheck);
385 }
386
387
388 /*
389 * @unimplemented
390 */
391 WINBOOL STDCALL
392 CheckMenuRadioItem(HMENU hmenu,
393 UINT idFirst,
394 UINT idLast,
395 UINT idCheck,
396 UINT uFlags)
397 {
398 UNIMPLEMENTED;
399 return FALSE;
400 }
401
402
403 /*
404 * @implemented
405 */
406 HMENU STDCALL
407 CreateMenu(VOID)
408 {
409 return NtUserCreateMenu();
410 }
411
412
413 /*
414 * @implemented
415 */
416 HMENU STDCALL
417 CreatePopupMenu(VOID)
418 {
419 /* FIXME - add MF_POPUP style? */
420 return NtUserCreateMenu();
421 }
422
423
424 /*
425 * @implemented
426 */
427 WINBOOL STDCALL
428 DeleteMenu(HMENU hMenu,
429 UINT uPosition,
430 UINT uFlags)
431 {
432 return NtUserDeleteMenu(hMenu, uPosition, uFlags);
433 }
434
435
436 /*
437 * @implemented
438 */
439 WINBOOL STDCALL
440 DestroyMenu(HMENU hMenu)
441 {
442 return NtUserDestroyMenu(hMenu);
443 }
444
445
446 /*
447 * @unimplemented
448 */
449 WINBOOL STDCALL
450 DrawMenuBar(HWND hWnd)
451 {
452 UNIMPLEMENTED
453 /* FIXME - return NtUserCallHwndLock(hWnd, 0x55); */
454 return FALSE;
455 }
456
457
458 /*
459 * @implemented
460 */
461 UINT STDCALL
462 EnableMenuItem(HMENU hMenu,
463 UINT uIDEnableItem,
464 UINT uEnable)
465 {
466 return NtUserEnableMenuItem(hMenu, uIDEnableItem, uEnable);
467 }
468
469 /*
470 * @unimplemented
471 */
472 WINBOOL STDCALL
473 EndMenu(VOID)
474 {
475 UNIMPLEMENTED;
476 /* FIXME - return NtUserEndMenu(); */
477 return FALSE;
478 }
479
480
481 /*
482 * @implemented
483 */
484 HMENU STDCALL
485 GetMenu(HWND hWnd)
486 {
487 return (HMENU)NtUserCallOneParam((DWORD)hWnd, ONEPARAM_ROUTINE_GETMENU);
488 }
489
490
491 /*
492 * @unimplemented
493 */
494 WINBOOL STDCALL
495 GetMenuBarInfo(HWND hwnd,
496 LONG idObject,
497 LONG idItem,
498 PMENUBARINFO pmbi)
499 {
500 UNIMPLEMENTED;
501 return FALSE;
502 }
503
504
505 /*
506 * @implemented
507 */
508 LONG STDCALL
509 GetMenuCheckMarkDimensions(VOID)
510 {
511 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK),
512 GetSystemMetrics(SM_CYMENUCHECK)));
513 }
514
515
516 /*
517 * @implemented
518 */
519 UINT STDCALL
520 GetMenuDefaultItem(HMENU hMenu,
521 UINT fByPos,
522 UINT gmdiFlags)
523 {
524 return NtUserGetMenuDefaultItem(hMenu, fByPos, gmdiFlags);
525 }
526
527
528 /*
529 * @implemented
530 */
531 WINBOOL STDCALL
532 GetMenuInfo(HMENU hmenu,
533 LPMENUINFO lpcmi)
534 {
535 MENUINFO mi;
536 BOOL res = FALSE;
537
538 if(!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO)))
539 return FALSE;
540
541 RtlZeroMemory(&mi, sizeof(MENUINFO));
542 mi.cbSize = sizeof(MENUINFO);
543 mi.fMask = lpcmi->fMask;
544
545 res = NtUserMenuInfo(hmenu, &mi, FALSE);
546
547 memcpy(lpcmi, &mi, sizeof(MENUINFO));
548 return res;
549 }
550
551
552 /*
553 * @implemented
554 */
555 int STDCALL
556 GetMenuItemCount(HMENU hMenu)
557 {
558 return NtUserBuildMenuItemList(hMenu, NULL, 0, 0);
559 }
560
561
562 /*
563 * @implemented
564 */
565 UINT STDCALL
566 GetMenuItemID(HMENU hMenu,
567 int nPos)
568 {
569 MENUITEMINFOW mii;
570
571 mii.cbSize = sizeof(MENUITEMINFOW);
572 mii.fMask = MIIM_ID | MIIM_SUBMENU;
573
574 if(!NtUserMenuItemInfo(hMenu, nPos, MF_BYPOSITION, &mii, FALSE))
575 {
576 return -1;
577 }
578
579 if(mii.hSubMenu) return -1;
580 if(mii.wID == 0) return -1;
581
582 return mii.wID;
583 }
584
585
586 /*
587 * @unimplemented
588 */
589 WINBOOL STDCALL
590 GetMenuItemInfoA(
591 HMENU hMenu,
592 UINT uItem,
593 WINBOOL fByPosition,
594 LPMENUITEMINFOA lpmii)
595 {
596 UNIMPLEMENTED;
597 return FALSE;
598 }
599
600
601 /*
602 * @unimplemented
603 */
604 WINBOOL
605 STDCALL
606 GetMenuItemInfoW(
607 HMENU hMenu,
608 UINT uItem,
609 WINBOOL fByPosition,
610 LPMENUITEMINFOW lpmii)
611 {
612 UNIMPLEMENTED;
613 return FALSE;
614 }
615
616
617 /*
618 * @unimplemented
619 */
620 WINBOOL STDCALL
621 GetMenuItemRect(HWND hWnd,
622 HMENU hMenu,
623 UINT uItem,
624 LPRECT lprcItem)
625 {
626 UNIMPLEMENTED;
627 return(FALSE);
628 }
629
630
631 /*
632 * @implemented
633 */
634 UINT
635 STDCALL
636 GetMenuState(
637 HMENU hMenu,
638 UINT uId,
639 UINT uFlags)
640 {
641 MENUITEMINFOW mii;
642 mii.cbSize = sizeof(MENUITEMINFOW);
643 mii.fMask = MIIM_STATE | MIIM_TYPE | MIIM_SUBMENU;
644
645 SetLastError(0);
646 if(NtUserMenuItemInfo(hMenu, uId, uFlags, &mii, FALSE))
647 {
648 UINT nSubItems = 0;
649 if(mii.hSubMenu)
650 {
651 nSubItems = (UINT)NtUserBuildMenuItemList(mii.hSubMenu, NULL, 0, 0);
652
653 /* FIXME - ported from wine, does that work (0xff)? */
654 if(GetLastError() != ERROR_INVALID_MENU_HANDLE)
655 return (nSubItems << 8) | ((mii.fState | mii.fType) & 0xff);
656
657 return (UINT)-1; /* Invalid submenu */
658 }
659
660 /* FIXME - ported from wine, does that work? */
661 return (mii.fType | mii.fState);
662 }
663
664 return (UINT)-1;
665 }
666
667
668 /*
669 * @unimplemented
670 */
671 int
672 STDCALL
673 GetMenuStringA(
674 HMENU hMenu,
675 UINT uIDItem,
676 LPSTR lpString,
677 int nMaxCount,
678 UINT uFlag)
679 {
680 UNIMPLEMENTED;
681 return 0;
682 }
683
684
685 /*
686 * @unimplemented
687 */
688 int
689 STDCALL
690 GetMenuStringW(
691 HMENU hMenu,
692 UINT uIDItem,
693 LPWSTR lpString,
694 int nMaxCount,
695 UINT uFlag)
696 {
697 UNIMPLEMENTED;
698 return 0;
699 }
700
701
702 /*
703 * @implemented
704 */
705 HMENU
706 STDCALL
707 GetSubMenu(
708 HMENU hMenu,
709 int nPos)
710 {
711 MENUITEMINFOW mi;
712 mi.cbSize = sizeof(mi);
713 mi.fMask = MIIM_SUBMENU;
714 if(NtUserMenuItemInfo(hMenu, (UINT)nPos, MF_BYPOSITION, &mi, FALSE))
715 {
716 return mi.hSubMenu;
717 }
718 return (HMENU)0;
719 }
720
721
722 /*
723 * @implemented
724 */
725 WINBOOL
726 STDCALL
727 HiliteMenuItem(
728 HWND hwnd,
729 HMENU hmenu,
730 UINT uItemHilite,
731 UINT uHilite)
732 {
733 return NtUserHiliteMenuItem(hwnd, hmenu, uItemHilite, uHilite);
734 }
735
736
737 /*
738 * @implemented
739 */
740 WINBOOL
741 STDCALL
742 InsertMenuA(
743 HMENU hMenu,
744 UINT uPosition,
745 UINT uFlags,
746 UINT_PTR uIDNewItem,
747 LPCSTR lpNewItem)
748 {
749 MENUITEMINFOA mii;
750 mii.cbSize = sizeof(MENUITEMINFOA);
751 mii.fMask = MIIM_FTYPE | MIIM_STRING;
752 mii.fType = 0;
753 if(uFlags & MF_BITMAP)
754 mii.fType |= MFT_BITMAP;
755 else
756 {
757 if(uFlags & MF_STRING)
758 {
759 mii.fType |= MFT_STRING;
760 }
761 else if(uFlags & MF_OWNERDRAW)
762 {
763 mii.fType |= MFT_OWNERDRAW;
764 }
765 else
766 {
767 SetLastError(ERROR_INVALID_PARAMETER);
768 return FALSE;
769 }
770 }
771 mii.dwTypeData = (LPSTR)lpNewItem;
772
773 return InsertMenuItemA(hMenu, uPosition, (WINBOOL)!(MF_BYPOSITION & uFlags), &mii);
774 }
775
776
777 /*
778 * @implemented
779 */
780 WINBOOL
781 STDCALL
782 InsertMenuItemA(
783 HMENU hMenu,
784 UINT uItem,
785 WINBOOL fByPosition,
786 LPCMENUITEMINFOA lpmii)
787 {
788 MENUITEMINFOW mi;
789 WINBOOL res = FALSE;
790 BOOL CleanHeap = FALSE;
791 NTSTATUS Status;
792
793 if((lpmii->cbSize == sizeof(MENUITEMINFOA)) ||
794 (lpmii->cbSize == sizeof(MENUITEMINFOA) - sizeof(HBITMAP)))
795 {
796 RtlMoveMemory ( &mi, lpmii, lpmii->cbSize );
797
798 /* copy the text string */
799 if((mi.fMask & (MIIM_TYPE | MIIM_STRING)) &&
800 (MENU_ITEM_TYPE(mi.fType) == MF_STRING) && mi.dwTypeData)
801 {
802 Status = HEAP_strdupAtoW ( &mi.dwTypeData, (LPCSTR)mi.dwTypeData, &mi.cch );
803 if (!NT_SUCCESS (Status))
804 {
805 SetLastError (RtlNtStatusToDosError(Status));
806 return FALSE;
807 }
808 CleanHeap = TRUE;
809 }
810
811 res = NtUserInsertMenuItem(hMenu, uItem, fByPosition, &mi);
812
813 if ( CleanHeap ) HEAP_free ( mi.dwTypeData );
814 }
815 return res;
816 }
817
818
819 /*
820 * @implemented
821 */
822 WINBOOL
823 STDCALL
824 InsertMenuItemW(
825 HMENU hMenu,
826 UINT uItem,
827 WINBOOL fByPosition,
828 LPCMENUITEMINFOW lpmii)
829 {
830 MENUITEMINFOW mi;
831 WINBOOL res = FALSE;
832 BOOL CleanHeap = FALSE;
833 ULONG len = 0;
834 HANDLE hHeap = RtlGetProcessHeap();
835 mi.hbmpItem = (HBITMAP)0;
836
837 // while we could just pass 'lpmii' to win32k, we make a copy so that
838 // if a bad user passes bad data, we crash his process instead of the
839 // entire kernel
840
841 if((lpmii->cbSize == sizeof(MENUITEMINFOW)) ||
842 (lpmii->cbSize == sizeof(MENUITEMINFOW) - sizeof(HBITMAP)))
843 {
844 memcpy(&mi, lpmii, lpmii->cbSize);
845
846 /* copy the text string */
847 if((mi.fMask & (MIIM_TYPE | MIIM_STRING)) &&
848 (MENU_ITEM_TYPE(mi.fType) == MF_STRING) && mi.dwTypeData)
849 {
850 if(lpmii->cch > 0)
851 {
852 len = lstrlenW(lpmii->dwTypeData);
853 mi.dwTypeData = RtlAllocateHeap(hHeap, 0, (len + 1) * sizeof(WCHAR));
854 if(!mi.dwTypeData)
855 {
856 SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY));
857 return FALSE;
858 }
859 memcpy(&mi.dwTypeData, &lpmii->dwTypeData, len);
860 CleanHeap = TRUE;
861 mi.cch = len;
862 }
863 };
864
865 res = NtUserInsertMenuItem(hMenu, uItem, fByPosition, &mi);
866
867 if(CleanHeap) RtlFreeHeap (hHeap, 0, mi.dwTypeData);
868 }
869 return res;
870 }
871
872
873 /*
874 * @implemented
875 */
876 WINBOOL
877 STDCALL
878 InsertMenuW(
879 HMENU hMenu,
880 UINT uPosition,
881 UINT uFlags,
882 UINT_PTR uIDNewItem,
883 LPCWSTR lpNewItem)
884 {
885 MENUITEMINFOW mii;
886 mii.cbSize = sizeof(MENUITEMINFOW);
887 mii.fMask = MIIM_FTYPE | MIIM_STRING;
888 mii.fType = 0;
889
890 if(uFlags & MF_BITMAP)
891 {
892 mii.fType |= MFT_BITMAP;
893 }
894 else if(uFlags & MF_OWNERDRAW)
895 {
896 mii.fType |= MFT_OWNERDRAW;
897 }
898 else if(uFlags & MF_POPUP)
899 {
900 mii.fMask |= MIIM_SUBMENU;
901 mii.hSubMenu = (HMENU)uIDNewItem;
902 mii.wID = 0;
903 }
904 mii.dwTypeData = (LPWSTR)lpNewItem;
905
906 return InsertMenuItemW(hMenu, uPosition, (WINBOOL)!(MF_BYPOSITION & uFlags), &mii);
907 }
908
909
910 /*
911 * @implemented
912 */
913 WINBOOL
914 STDCALL
915 IsMenu(
916 HMENU hMenu)
917 {
918 DWORD ret;
919 SetLastError(ERROR_SUCCESS);
920 ret = NtUserBuildMenuItemList(hMenu, NULL, 0, 0);
921 return ((ret == (DWORD)-1) || (GetLastError() == ERROR_INVALID_MENU_HANDLE));
922 }
923
924
925 /*
926 * @implemented
927 */
928 HMENU STDCALL
929 LoadMenuA(HINSTANCE hInstance,
930 LPCSTR lpMenuName)
931 {
932 HANDLE Resource = FindResourceA(hInstance, lpMenuName, MAKEINTRESOURCEA(4));
933 if (Resource == NULL)
934 {
935 return(NULL);
936 }
937 return(LoadMenuIndirectA((PVOID)LoadResource(hInstance, Resource)));
938 }
939
940
941 /*
942 * @implemented
943 */
944 HMENU STDCALL
945 LoadMenuIndirectA(CONST MENUTEMPLATE *lpMenuTemplate)
946 {
947 return(LoadMenuIndirectW(lpMenuTemplate));
948 }
949
950
951 /*
952 * @implemented
953 */
954 HMENU STDCALL
955 LoadMenuIndirectW(CONST MENUTEMPLATE *lpMenuTemplate)
956 {
957 HMENU hMenu;
958 WORD version, offset;
959 LPCSTR p = (LPCSTR)lpMenuTemplate;
960
961 version = GET_WORD(p);
962 p += sizeof(WORD);
963
964 switch (version)
965 {
966 case 0: /* standard format is version of 0 */
967 offset = GET_WORD(p);
968 p += sizeof(WORD) + offset;
969 if (!(hMenu = CreateMenu())) return 0;
970 if (!MENU_ParseResource(p, hMenu, TRUE))
971 {
972 DestroyMenu(hMenu);
973 return 0;
974 }
975 return hMenu;
976 case 1: /* extended format is version of 1 */
977 offset = GET_WORD(p);
978 p += sizeof(WORD) + offset;
979 if (!(hMenu = CreateMenu())) return 0;
980 if (!MENUEX_ParseResource(p, hMenu))
981 {
982 DestroyMenu( hMenu );
983 return 0;
984 }
985 return hMenu;
986 default:
987 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version);
988 return 0;
989 }
990 }
991
992
993 /*
994 * @implemented
995 */
996 HMENU STDCALL
997 LoadMenuW(HINSTANCE hInstance,
998 LPCWSTR lpMenuName)
999 {
1000 HANDLE Resource = FindResourceW(hInstance, lpMenuName, RT_MENU);
1001 if (Resource == NULL)
1002 {
1003 return(NULL);
1004 }
1005 return(LoadMenuIndirectW((PVOID)LoadResource(hInstance, Resource)));
1006 }
1007
1008
1009 /*
1010 * @unimplemented
1011 */
1012 int
1013 STDCALL
1014 MenuItemFromPoint(
1015 HWND hWnd,
1016 HMENU hMenu,
1017 POINT ptScreen)
1018 {
1019 UNIMPLEMENTED;
1020 return 0;
1021 }
1022
1023
1024 /*
1025 * @unimplemented
1026 */
1027 WINBOOL
1028 STDCALL
1029 ModifyMenuA(
1030 HMENU hMnu,
1031 UINT uPosition,
1032 UINT uFlags,
1033 UINT_PTR uIDNewItem,
1034 LPCSTR lpNewItem)
1035 {
1036 UNIMPLEMENTED;
1037 return FALSE;
1038 }
1039
1040
1041 /*
1042 * @unimplemented
1043 */
1044 WINBOOL
1045 STDCALL
1046 ModifyMenuW(
1047 HMENU hMnu,
1048 UINT uPosition,
1049 UINT uFlags,
1050 UINT_PTR uIDNewItem,
1051 LPCWSTR lpNewItem)
1052 {
1053 UNIMPLEMENTED;
1054 return FALSE;
1055 }
1056
1057
1058 /*
1059 * @implemented
1060 */
1061 WINBOOL
1062 STDCALL
1063 RemoveMenu(
1064 HMENU hMenu,
1065 UINT uPosition,
1066 UINT uFlags)
1067 {
1068 return NtUserRemoveMenu(hMenu, uPosition, uFlags);
1069 }
1070
1071
1072 /*
1073 * @implemented
1074 */
1075 WINBOOL STDCALL
1076 SetMenu(HWND hWnd,
1077 HMENU hMenu)
1078 {
1079 return NtUserSetMenu(hWnd, hMenu, TRUE);
1080 }
1081
1082
1083 /*
1084 * @implemented
1085 */
1086 WINBOOL
1087 STDCALL
1088 SetMenuDefaultItem(
1089 HMENU hMenu,
1090 UINT uItem,
1091 UINT fByPos)
1092 {
1093 return NtUserSetMenuDefaultItem(hMenu, uItem, fByPos);
1094 }
1095
1096
1097 /*
1098 * @implemented
1099 */
1100 WINBOOL
1101 STDCALL
1102 SetMenuInfo(
1103 HMENU hmenu,
1104 LPCMENUINFO lpcmi)
1105 {
1106 MENUINFO mi;
1107 BOOL res = FALSE;
1108 if(lpcmi->cbSize != sizeof(MENUINFO))
1109 return res;
1110
1111 memcpy(&mi, lpcmi, sizeof(MENUINFO));
1112 return NtUserMenuInfo(hmenu, &mi, TRUE);
1113 }
1114
1115
1116 /*
1117 * @unimplemented
1118 */
1119 WINBOOL
1120 STDCALL
1121 SetMenuItemBitmaps(
1122 HMENU hMenu,
1123 UINT uPosition,
1124 UINT uFlags,
1125 HBITMAP hBitmapUnchecked,
1126 HBITMAP hBitmapChecked)
1127 {
1128 UNIMPLEMENTED;
1129 return FALSE;
1130 }
1131
1132
1133 /*
1134 * @unimplemented
1135 */
1136 WINBOOL
1137 STDCALL
1138 SetMenuItemInfoA(
1139 HMENU hMenu,
1140 UINT uItem,
1141 WINBOOL fByPosition,
1142 LPMENUITEMINFOA lpmii)
1143 {
1144 UNIMPLEMENTED;
1145 return FALSE;
1146 }
1147
1148
1149 /*
1150 * @unimplemented
1151 */
1152 WINBOOL
1153 STDCALL
1154 SetMenuItemInfoW(
1155 HMENU hMenu,
1156 UINT uItem,
1157 WINBOOL fByPosition,
1158 LPMENUITEMINFOW lpmii)
1159 {
1160 UNIMPLEMENTED;
1161 return FALSE;
1162 }
1163
1164
1165 /*
1166 * @unimplemented
1167 */
1168 WINBOOL
1169 STDCALL
1170 TrackPopupMenu(
1171 HMENU hMenu,
1172 UINT uFlags,
1173 int x,
1174 int y,
1175 int nReserved,
1176 HWND hWnd,
1177 CONST RECT *prcRect)
1178 {
1179 UNIMPLEMENTED;
1180 return FALSE;
1181 }
1182
1183
1184 /*
1185 * @unimplemented
1186 */
1187 WINBOOL
1188 STDCALL
1189 TrackPopupMenuEx(
1190 HMENU hmenu,
1191 UINT fuFlags,
1192 int x,
1193 int y,
1194 HWND hwnd,
1195 LPTPMPARAMS lptpm)
1196 {
1197 UNIMPLEMENTED;
1198 return FALSE;
1199 }
1200
1201
1202 /*
1203 * @implemented
1204 */
1205 WINBOOL
1206 STDCALL
1207 SetMenuContextHelpId(HMENU hmenu,
1208 DWORD dwContextHelpId)
1209 {
1210 return NtUserSetMenuContextHelpId(hmenu, dwContextHelpId);
1211 }
1212
1213
1214 /*
1215 * @implemented
1216 */
1217 DWORD
1218 STDCALL
1219 GetMenuContextHelpId(HMENU hmenu)
1220 {
1221 MENUINFO mi;
1222 mi.cbSize = sizeof(MENUINFO);
1223 mi.fMask = MIM_HELPID;
1224
1225 if(NtUserMenuInfo(hmenu, &mi, FALSE))
1226 {
1227 return mi.dwContextHelpID;
1228 }
1229 return 0;
1230 }
1231