Some changes for menus and unstubbed NtUserGetSystemMenu(), NtUserSetSystemMenu(...
[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.19 2003/08/06 13:17:43 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
38 /* TYPES *********************************************************************/
39
40 #define MENU_TYPE_MASK ((MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
41
42 #define MENU_ITEM_TYPE(flags) \
43 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
44
45 #define MENU_BAR_ITEMS_SPACE (12)
46 #define SEPARATOR_HEIGHT (5)
47 #define MENU_TAB_SPACE (8)
48
49 #define MENU_MAGIC (0x554D)
50
51 #define NO_SELECTED_ITEM (0xffff)
52
53 #ifndef MF_END
54 #define MF_END (0x0080)
55 #endif
56
57 #ifndef MIIM_STRING
58 #define MIIM_STRING (0x00000040)
59 #endif
60
61
62 /* INTERNAL FUNCTIONS ********************************************************/
63
64 /* Rip the fun and easy to use and fun WINE unicode string manipulation routines.
65 * Of course I didnt copy the ASM code because we want this to be portable
66 * and it needs to go away.
67 */
68
69 static inline unsigned int strlenW( const WCHAR *str )
70 {
71 const WCHAR *s = str;
72 while (*s) s++;
73 return s - str;
74 }
75
76 static inline WCHAR *strncpyW( WCHAR *str1, const WCHAR *str2, int n )
77 {
78 WCHAR *ret = str1;
79 while (n-- > 0) if (!(*str1++ = *str2++)) break;
80 while (n-- > 0) *str1++ = 0;
81 return ret;
82 }
83
84 static inline WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
85 {
86 WCHAR *p = dst;
87 while ((*p++ = *src++));
88 return dst;
89 }
90
91 static inline WCHAR *strcatW( WCHAR *dst, const WCHAR *src )
92 {
93 strcpyW( dst + strlenW(dst), src );
94 return dst;
95 }
96
97 NTSTATUS
98 STATIC HEAP_strdupA2W ( HANDLE hHeap, LPWSTR* ppszW, LPCSTR lpszA, UINT* NewLen )
99 {
100 ULONG len;
101 NTSTATUS Status;
102 *ppszW = NULL;
103 if ( !lpszA )
104 return STATUS_SUCCESS;
105 len = lstrlenA(lpszA);
106 *ppszW = RtlAllocateHeap ( hHeap, 0, (len+1) * sizeof(WCHAR) );
107 if ( !*ppszW )
108 return STATUS_NO_MEMORY;
109 Status = RtlMultiByteToUnicodeN ( *ppszW, len*sizeof(WCHAR), NULL, (PCHAR)lpszA, len );
110 (*ppszW)[len] = L'\0';
111 if(NewLen) (*NewLen) = (UINT)len;
112 return Status;
113 }
114
115 #ifndef GET_WORD
116 #define GET_WORD(ptr) (*(WORD *)(ptr))
117 #endif
118 #ifndef GET_DWORD
119 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
120 #endif
121
122 HFONT hMenuFont = NULL;
123 HFONT hMenuFontBold = NULL;
124
125 /**********************************************************************
126 * MENUEX_ParseResource
127 *
128 * Parse an extended menu resource and add items to the menu.
129 * Return a pointer to the end of the resource.
130 *
131 * FIXME - should we be passing an LPCSTR to a predominantly UNICODE function?
132 */
133 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
134 {
135 WORD resinfo;
136
137 do
138 {
139 MENUITEMINFOW mii;
140
141 mii.cbSize = sizeof(mii);
142 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
143 mii.fType = GET_DWORD(res);
144 res += sizeof(DWORD);
145 mii.fState = GET_DWORD(res);
146 res += sizeof(DWORD);
147 mii.wID = GET_DWORD(res);
148 res += sizeof(DWORD);
149 resinfo = GET_WORD(res);
150 res += sizeof(WORD);
151 /* Align the text on a word boundary. */
152 res += (~((int)res - 1)) & 1;
153 mii.dwTypeData = (LPWSTR) res;
154 res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
155 /* Align the following fields on a dword boundary. */
156 res += (~((int)res - 1)) & 3;
157
158 if (resinfo & 1) /* Pop-up? */
159 {
160 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
161 res += sizeof(DWORD);
162 mii.hSubMenu = CreatePopupMenu();
163 if (!mii.hSubMenu)
164 return NULL;
165 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu)))
166 {
167 DestroyMenu(mii.hSubMenu);
168 return NULL;
169 }
170 mii.fMask |= MIIM_SUBMENU;
171 mii.fType |= MF_POPUP;
172 }
173 else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR))
174 {
175 DbgPrint("WARN: Converting NULL menu item %04x, type %04x to SEPARATOR\n",
176 mii.wID, mii.fType);
177 mii.fType |= MF_SEPARATOR;
178 }
179 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
180 }
181 while (!(resinfo & MF_END));
182 return res;
183 }
184
185
186 /**********************************************************************
187 * MENU_ParseResource
188 *
189 * Parse a standard menu resource and add items to the menu.
190 * Return a pointer to the end of the resource.
191 *
192 * NOTE: flags is equivalent to the mtOption field
193 */
194 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
195 {
196 WORD flags, id = 0;
197 LPCSTR str;
198 BOOL end = FALSE;
199
200 do
201 {
202 flags = GET_WORD(res);
203
204 /* remove MF_END flag before passing it to AppendMenu()! */
205 end = (flags & MF_END);
206 if(end) flags ^= MF_END;
207
208 res += sizeof(WORD);
209 if(!(flags & MF_POPUP))
210 {
211 id = GET_WORD(res);
212 res += sizeof(WORD);
213 }
214 str = res;
215 if(!unicode)
216 res += strlen(str) + 1;
217 else
218 res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
219 if (flags & MF_POPUP)
220 {
221 HMENU hSubMenu = CreatePopupMenu();
222 if(!hSubMenu) return NULL;
223 if(!(res = MENU_ParseResource(res, hSubMenu, unicode)))
224 return NULL;
225 if(!unicode)
226 AppendMenuA(hMenu, flags, (UINT)hSubMenu, str);
227 else
228 AppendMenuW(hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str);
229 }
230 else /* Not a popup */
231 {
232 if(!unicode)
233 AppendMenuA(hMenu, flags, id, *str ? str : NULL);
234 else
235 AppendMenuW(hMenu, flags, id,
236 *(LPCWSTR)str ? (LPCWSTR)str : NULL);
237 }
238 } while(!end);
239
240 return res;
241 }
242
243
244 BOOL
245 MenuInit(VOID)
246 {
247 NONCLIENTMETRICSW ncm;
248
249 /* get the menu font */
250 if(!hMenuFont || !hMenuFontBold)
251 {
252 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
253 {
254 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
255 return FALSE;
256 }
257
258 hMenuFont = CreateFontIndirect(&ncm.lfMenuFont);
259 if(hMenuFont == NULL)
260 {
261 DbgPrint("MenuInit(): CreateFontIndirect(hMenuFont) failed!\n");
262 return FALSE;
263 }
264
265 ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
266 hMenuFontBold = CreateFontIndirect(&ncm.lfMenuFont);
267 if(hMenuFontBold == NULL)
268 {
269 DbgPrint("MenuInit(): CreateFontIndirect(hMenuFontBold) failed!\n");
270 return FALSE;
271 }
272 }
273
274 return TRUE;
275 }
276
277
278 ULONG
279 MenuGetMenuBarHeight(HWND hWnd, ULONG MenuBarWidth, LONG OrgX, LONG OrgY)
280 {
281 /*ULONG MenuId;
282 PPOPUP_MENU Menu;
283 RECT Rect;
284 HDC hDC;
285
286 MenuId = GetWindowLong(hWnd, GWL_ID);
287 Menu = MenuGetMenu((HMENU)MenuId);
288 if (Menu == NULL)
289 {
290 return(0);
291 }
292 hDC = GetDCEx(hWnd, 0, DCX_CACHE | DCX_WINDOW);
293 SelectObject(hDC, hMenuFont);
294 SetRect(&Rect, OrgX, OrgY, OrgX + MenuBarWidth,
295 OrgY + GetSystemMetrics(SM_CYMENU));
296 MenuMenuBarCalcSize(hDC, &Rect, Menu, hWnd);
297 ReleaseDC(hWnd, hDC);*/
298 return(GetSystemMetrics(SM_CYMENU));
299 }
300
301
302 UINT
303 MenuDrawMenuBar(HDC hDC, LPRECT Rect, HWND hWnd, BOOL Draw)
304 {
305 HFONT hFontOld = SelectObject(hDC, hMenuFont);
306 //DrawTextA(hDC, "This is the menu bar", 19, Rect, DT_SINGLELINE);
307 SelectObject(hDC, hFontOld);
308 return(GetSystemMetrics(SM_CYMENU));
309 /*
310 ULONG MenuID;
311 PPOPUP_MENU Menu;
312 HFONT hFontOld;
313 ULONG i;
314
315 MenuID = GetWindowLong(hWnd, GWL_ID);
316 Menu = MenuGetMenu((HMENU)MenuID);
317
318 if (Menu == NULL || Rect == NULL)
319 {
320 return(GetSystemMetrics(SM_CYMENU));
321 }
322
323 hFontOld = SelectObject(hDC, hMenuFont);
324
325 if (Menu->Height == 0)
326 {
327 MenuMenuBarCalcSize(hDC, Rect, Menu, hWnd);
328 }
329
330 Rect->bottom = Rect->top + Menu->Height;
331
332 if (!Draw)
333 {
334 SelectObject(hDC, hFontOld);
335 return(Menu->Height);
336 }
337
338 FillRect(hDC, Rect, GetSysColorBrush(COLOR_MENU));
339
340 SelectObject(hDC, GetSysColorPen(COLOR_WINDOWFRAME));
341 MoveToEx(hDC, Rect->left, Rect->bottom, NULL);
342 LineTo(hDC, Rect->right, Rect->bottom);
343
344 if (Menu->NrItems == 0)
345 {
346 SelectObject(hDC, hFontOld);
347 return(GetSystemMetrics(SM_CYMENU));
348 }
349
350 for (i = 0; i < Menu->NrItems; i++)
351 {
352 MenuDrawMenuItem(hWnd, (HMENU)MenuID, hWnd, hDC,
353 Menu->Items + i, Menu->Height, TRUE, ODA_DRAWENTIRE);
354 }
355
356 SelectObject(hDC, hFontOld);
357 return(Menu->Height);*/
358 }
359
360
361 VOID
362 MenuTrackMouseMenuBar(HWND hWnd, ULONG Ht, POINT Pt)
363 {
364 }
365
366
367 VOID
368 MenuTrackKbdMenuBar(HWND hWnd, ULONG wParam, ULONG Key)
369 {
370 }
371
372 /* FUNCTIONS *****************************************************************/
373
374 /*static BOOL
375 MenuIsStringItem(ULONG TypeData)
376 {
377 return((TypeData & MENU_TYPE_MASK) == MF_STRING);
378 }*/
379
380
381 /*
382 * @implemented
383 */
384 WINBOOL STDCALL
385 AppendMenuA(HMENU hMenu,
386 UINT uFlags,
387 UINT_PTR uIDNewItem,
388 LPCSTR lpNewItem)
389 {
390 return(InsertMenuA(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem,
391 lpNewItem));
392 }
393
394
395 /*
396 * @implemented
397 */
398 WINBOOL STDCALL
399 AppendMenuW(HMENU hMenu,
400 UINT uFlags,
401 UINT_PTR uIDNewItem,
402 LPCWSTR lpNewItem)
403 {
404 return(InsertMenuW(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem,
405 lpNewItem));
406 }
407
408
409 /*
410 * @implemented
411 */
412 DWORD STDCALL
413 CheckMenuItem(HMENU hmenu,
414 UINT uIDCheckItem,
415 UINT uCheck)
416 {
417 return NtUserCheckMenuItem(hmenu, uIDCheckItem, uCheck);
418 }
419
420
421 /*
422 * @unimplemented
423 */
424 WINBOOL STDCALL
425 CheckMenuRadioItem(HMENU hmenu,
426 UINT idFirst,
427 UINT idLast,
428 UINT idCheck,
429 UINT uFlags)
430 {
431 UNIMPLEMENTED;
432 return FALSE;
433 }
434
435
436 /*
437 * @implemented
438 */
439 HMENU STDCALL
440 CreateMenu(VOID)
441 {
442 return NtUserCreateMenu();
443 }
444
445
446 /*
447 * @implemented
448 */
449 HMENU STDCALL
450 CreatePopupMenu(VOID)
451 {
452 /* FIXME - add MF_POPUP style? */
453 return NtUserCreateMenu();
454 }
455
456
457 /*
458 * @implemented
459 */
460 WINBOOL STDCALL
461 DeleteMenu(HMENU hMenu,
462 UINT uPosition,
463 UINT uFlags)
464 {
465 return NtUserDeleteMenu(hMenu, uPosition, uFlags);
466 }
467
468
469 /*
470 * @implemented
471 */
472 WINBOOL STDCALL
473 DestroyMenu(HMENU hMenu)
474 {
475 return NtUserDestroyMenu(hMenu);
476 }
477
478
479 /*
480 * @unimplemented
481 */
482 WINBOOL STDCALL
483 DrawMenuBar(HWND hWnd)
484 {
485 UNIMPLEMENTED
486 /* FIXME - return NtUserCallHwndLock(hWnd, 0x55); */
487 return FALSE;
488 }
489
490
491 /*
492 * @implemented
493 */
494 UINT STDCALL
495 EnableMenuItem(HMENU hMenu,
496 UINT uIDEnableItem,
497 UINT uEnable)
498 {
499 return NtUserEnableMenuItem(hMenu, uIDEnableItem, uEnable);
500 }
501
502 /*
503 * @unimplemented
504 */
505 WINBOOL STDCALL
506 EndMenu(VOID)
507 {
508 UNIMPLEMENTED;
509 /* FIXME - return NtUserEndMenu(); */
510 return FALSE;
511 }
512
513
514 /*
515 * @implemented
516 */
517 HMENU STDCALL
518 GetMenu(HWND hWnd)
519 {
520 return (HMENU)NtUserCallOneParam((DWORD)hWnd, ONEPARAM_ROUTINE_GETMENU);
521 }
522
523
524 /*
525 * @unimplemented
526 */
527 WINBOOL STDCALL
528 GetMenuBarInfo(HWND hwnd,
529 LONG idObject,
530 LONG idItem,
531 PMENUBARINFO pmbi)
532 {
533 UNIMPLEMENTED;
534 return FALSE;
535 }
536
537
538 /*
539 * @implemented
540 */
541 LONG STDCALL
542 GetMenuCheckMarkDimensions(VOID)
543 {
544 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK),
545 GetSystemMetrics(SM_CYMENUCHECK)));
546 }
547
548
549 /*
550 * @unimplemented
551 */
552 UINT STDCALL
553 GetMenuDefaultItem(HMENU hMenu,
554 UINT fByPos,
555 UINT gmdiFlags)
556 {
557 UNIMPLEMENTED;
558 return -1;
559 }
560
561
562 /*
563 * @implemented
564 */
565 WINBOOL STDCALL
566 GetMenuInfo(HMENU hmenu,
567 LPMENUINFO lpcmi)
568 {
569 MENUINFO mi;
570 BOOL res = FALSE;
571
572 if(!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO)))
573 return FALSE;
574
575 RtlZeroMemory(&mi, sizeof(MENUINFO));
576 mi.cbSize = sizeof(MENUINFO);
577 mi.fMask = lpcmi->fMask;
578
579 res = NtUserMenuInfo(hmenu, &mi, FALSE);
580
581 memcpy(lpcmi, &mi, sizeof(MENUINFO));
582 return res;
583 }
584
585
586 /*
587 * @implemented
588 */
589 int STDCALL
590 GetMenuItemCount(HMENU hMenu)
591 {
592 return NtUserBuildMenuItemList(hMenu, NULL, 0, 0);
593 }
594
595
596 /*
597 * @implemented
598 */
599 UINT STDCALL
600 GetMenuItemID(HMENU hMenu,
601 int nPos)
602 {
603 MENUITEMINFOW mii;
604
605 mii.cbSize = sizeof(MENUITEMINFOW);
606 mii.fMask = MIIM_ID | MIIM_SUBMENU;
607
608 if(!NtUserMenuItemInfo(hMenu, nPos, MF_BYPOSITION, &mii, FALSE))
609 {
610 return -1;
611 }
612
613 if(mii.hSubMenu) return -1;
614 if(mii.wID == 0) return -1;
615
616 return mii.wID;
617 }
618
619
620 /*
621 * @unimplemented
622 */
623 WINBOOL STDCALL
624 GetMenuItemInfoA(
625 HMENU hMenu,
626 UINT uItem,
627 WINBOOL fByPosition,
628 LPMENUITEMINFOA lpmii)
629 {
630 UNIMPLEMENTED;
631 return FALSE;
632 }
633
634
635 /*
636 * @unimplemented
637 */
638 WINBOOL
639 STDCALL
640 GetMenuItemInfoW(
641 HMENU hMenu,
642 UINT uItem,
643 WINBOOL fByPosition,
644 LPMENUITEMINFOW lpmii)
645 {
646 UNIMPLEMENTED;
647 return FALSE;
648 }
649
650
651 /*
652 * @unimplemented
653 */
654 WINBOOL STDCALL
655 GetMenuItemRect(HWND hWnd,
656 HMENU hMenu,
657 UINT uItem,
658 LPRECT lprcItem)
659 {
660 UNIMPLEMENTED;
661 return(FALSE);
662 }
663
664
665 /*
666 * @implemented
667 */
668 UINT
669 STDCALL
670 GetMenuState(
671 HMENU hMenu,
672 UINT uId,
673 UINT uFlags)
674 {
675 MENUITEMINFOW mii;
676 mii.cbSize = sizeof(MENUITEMINFOW);
677 mii.fMask = MIIM_STATE | MIIM_TYPE | MIIM_SUBMENU;
678
679 SetLastError(0);
680 if(NtUserMenuItemInfo(hMenu, uId, uFlags, &mii, FALSE))
681 {
682 UINT nSubItems = 0;
683 if(mii.hSubMenu)
684 {
685 nSubItems = (UINT)NtUserBuildMenuItemList(mii.hSubMenu, NULL, 0, 0);
686
687 /* FIXME - ported from wine, does that work (0xff)? */
688 if(GetLastError() != ERROR_INVALID_MENU_HANDLE)
689 return (nSubItems << 8) | ((mii.fState | mii.fType) & 0xff);
690
691 return (UINT)-1; /* Invalid submenu */
692 }
693
694 /* FIXME - ported from wine, does that work? */
695 return (mii.fType | mii.fState);
696 }
697
698 return (UINT)-1;
699 }
700
701
702 /*
703 * @unimplemented
704 */
705 int
706 STDCALL
707 GetMenuStringA(
708 HMENU hMenu,
709 UINT uIDItem,
710 LPSTR lpString,
711 int nMaxCount,
712 UINT uFlag)
713 {
714 UNIMPLEMENTED;
715 return 0;
716 }
717
718
719 /*
720 * @unimplemented
721 */
722 int
723 STDCALL
724 GetMenuStringW(
725 HMENU hMenu,
726 UINT uIDItem,
727 LPWSTR lpString,
728 int nMaxCount,
729 UINT uFlag)
730 {
731 UNIMPLEMENTED;
732 return 0;
733 }
734
735
736 /*
737 * @implemented
738 */
739 HMENU
740 STDCALL
741 GetSubMenu(
742 HMENU hMenu,
743 int nPos)
744 {
745 MENUITEMINFOW mi;
746 mi.cbSize = sizeof(MENUITEMINFO);
747 mi.fMask = MIIM_SUBMENU;
748 if(NtUserMenuItemInfo(hMenu, (UINT)nPos, MF_BYPOSITION, &mi, FALSE))
749 {
750 return mi.hSubMenu;
751 }
752 return (HMENU)0;
753 }
754
755
756 /*
757 * @implemented
758 */
759 WINBOOL
760 STDCALL
761 HiliteMenuItem(
762 HWND hwnd,
763 HMENU hmenu,
764 UINT uItemHilite,
765 UINT uHilite)
766 {
767 return NtUserHiliteMenuItem(hwnd, hmenu, uItemHilite, uHilite);
768 }
769
770
771 /*
772 * @unimplemented
773 */
774 WINBOOL
775 STDCALL
776 InsertMenuA(
777 HMENU hMenu,
778 UINT uPosition,
779 UINT uFlags,
780 UINT_PTR uIDNewItem,
781 LPCSTR lpNewItem)
782 {
783 UNIMPLEMENTED;
784 return FALSE;
785 }
786
787
788 /*
789 * @implemented
790 */
791 WINBOOL
792 STDCALL
793 InsertMenuItemA(
794 HMENU hMenu,
795 UINT uItem,
796 WINBOOL fByPosition,
797 LPCMENUITEMINFOA lpmii)
798 {
799 MENUITEMINFOW mi;
800 WINBOOL res = FALSE;
801 BOOL CleanHeap = FALSE;
802 NTSTATUS Status;
803 HANDLE hHeap = RtlGetProcessHeap();
804
805 if((lpmii->cbSize == sizeof(MENUITEMINFO)) ||
806 (lpmii->cbSize == sizeof(MENUITEMINFO) - sizeof(HBITMAP)))
807 {
808 memcpy(&mi, lpmii, lpmii->cbSize);
809
810 /* copy the text string */
811 if((mi.fMask & (MIIM_TYPE | MIIM_STRING)) &&
812 (MENU_ITEM_TYPE(mi.fType) == MF_STRING) && mi.dwTypeData)
813 {
814 Status = HEAP_strdupA2W (hHeap, &mi.dwTypeData, (LPCSTR)mi.dwTypeData, &mi.cch);
815 if (!NT_SUCCESS (Status))
816 {
817 SetLastError (RtlNtStatusToDosError(Status));
818 return FALSE;
819 }
820 CleanHeap = TRUE;
821 }
822
823 res = NtUserInsertMenuItem(hMenu, uItem, fByPosition, &mi);
824
825 if(CleanHeap) RtlFreeHeap (hHeap, 0, mi.dwTypeData);
826 }
827 return res;
828 }
829
830
831 /*
832 * @implemented
833 */
834 WINBOOL
835 STDCALL
836 InsertMenuItemW(
837 HMENU hMenu,
838 UINT uItem,
839 WINBOOL fByPosition,
840 LPCMENUITEMINFOW lpmii)
841 {
842 MENUITEMINFOW mi;
843 WINBOOL res = FALSE;
844 BOOL CleanHeap = FALSE;
845 ULONG len = 0;
846 HANDLE hHeap = RtlGetProcessHeap();
847
848 if((lpmii->cbSize == sizeof(MENUITEMINFO)) ||
849 (lpmii->cbSize == sizeof(MENUITEMINFO) - sizeof(HBITMAP)))
850 {
851 memcpy(&mi, lpmii, lpmii->cbSize);
852
853 /* copy the text string */
854 if((mi.fMask & (MIIM_TYPE | MIIM_STRING)) &&
855 (MENU_ITEM_TYPE(mi.fType) == MF_STRING) && mi.dwTypeData)
856 {
857 len = lstrlenW(lpmii->dwTypeData);
858
859 mi.dwTypeData = RtlAllocateHeap(hHeap, 0, (len + 1) * sizeof(WCHAR));
860 if(!mi.dwTypeData)
861 {
862 SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY));
863 return FALSE;
864 }
865 memcpy(&mi.dwTypeData, &lpmii->dwTypeData, len);
866 CleanHeap = TRUE;
867 mi.cch = len;
868 }
869
870 res = NtUserInsertMenuItem(hMenu, uItem, fByPosition, &mi);
871
872 if(CleanHeap) RtlFreeHeap (hHeap, 0, mi.dwTypeData);
873 }
874 return res;
875 }
876
877
878 /*
879 * @unimplemented
880 */
881 WINBOOL
882 STDCALL
883 InsertMenuW(
884 HMENU hMenu,
885 UINT uPosition,
886 UINT uFlags,
887 UINT_PTR uIDNewItem,
888 LPCWSTR lpNewItem)
889 {
890 UNIMPLEMENTED;
891 return FALSE;
892 }
893
894
895 /*
896 * @implemented
897 */
898 WINBOOL
899 STDCALL
900 IsMenu(
901 HMENU hMenu)
902 {
903 SetLastError(ERROR_SUCCESS);
904 DWORD ret = NtUserBuildMenuItemList(hMenu, NULL, 0, 0);
905 return ((ret == -1) || (GetLastError() == ERROR_INVALID_MENU_HANDLE));
906 }
907
908
909 /*
910 * @implemented
911 */
912 HMENU STDCALL
913 LoadMenuA(HINSTANCE hInstance,
914 LPCSTR lpMenuName)
915 {
916 HANDLE Resource = FindResourceA(hInstance, lpMenuName, MAKEINTRESOURCEA(4));
917 if (Resource == NULL)
918 {
919 return(NULL);
920 }
921 return(LoadMenuIndirectA((PVOID)LoadResource(hInstance, Resource)));
922 }
923
924
925 /*
926 * @implemented
927 */
928 HMENU STDCALL
929 LoadMenuIndirectA(CONST MENUTEMPLATE *lpMenuTemplate)
930 {
931 return(LoadMenuIndirectW(lpMenuTemplate));
932 }
933
934
935 /*
936 * @implemented
937 */
938 HMENU STDCALL
939 LoadMenuIndirectW(CONST MENUTEMPLATE *lpMenuTemplate)
940 {
941 HMENU hMenu;
942 WORD version, offset;
943 LPCSTR p = (LPCSTR)lpMenuTemplate;
944
945 version = GET_WORD(p);
946 p += sizeof(WORD);
947
948 switch (version)
949 {
950 case 0: /* standard format is version of 0 */
951 offset = GET_WORD(p);
952 p += sizeof(WORD) + offset;
953 if (!(hMenu = CreateMenu())) return 0;
954 if (!MENU_ParseResource(p, hMenu, TRUE))
955 {
956 DestroyMenu(hMenu);
957 return 0;
958 }
959 return hMenu;
960 case 1: /* extended format is version of 1 */
961 offset = GET_WORD(p);
962 p += sizeof(WORD) + offset;
963 if (!(hMenu = CreateMenu())) return 0;
964 if (!MENUEX_ParseResource(p, hMenu))
965 {
966 DestroyMenu( hMenu );
967 return 0;
968 }
969 return hMenu;
970 default:
971 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version);
972 return 0;
973 }
974 }
975
976
977 /*
978 * @implemented
979 */
980 HMENU STDCALL
981 LoadMenuW(HINSTANCE hInstance,
982 LPCWSTR lpMenuName)
983 {
984 HANDLE Resource = FindResourceW(hInstance, lpMenuName, RT_MENU);
985 if (Resource == NULL)
986 {
987 return(NULL);
988 }
989 return(LoadMenuIndirectW((PVOID)LoadResource(hInstance, Resource)));
990 }
991
992
993 /*
994 * @unimplemented
995 */
996 int
997 STDCALL
998 MenuItemFromPoint(
999 HWND hWnd,
1000 HMENU hMenu,
1001 POINT ptScreen)
1002 {
1003 UNIMPLEMENTED;
1004 return 0;
1005 }
1006
1007
1008 /*
1009 * @unimplemented
1010 */
1011 WINBOOL
1012 STDCALL
1013 ModifyMenuA(
1014 HMENU hMnu,
1015 UINT uPosition,
1016 UINT uFlags,
1017 UINT_PTR uIDNewItem,
1018 LPCSTR lpNewItem)
1019 {
1020 UNIMPLEMENTED;
1021 return FALSE;
1022 }
1023
1024
1025 /*
1026 * @unimplemented
1027 */
1028 WINBOOL
1029 STDCALL
1030 ModifyMenuW(
1031 HMENU hMnu,
1032 UINT uPosition,
1033 UINT uFlags,
1034 UINT_PTR uIDNewItem,
1035 LPCWSTR lpNewItem)
1036 {
1037 UNIMPLEMENTED;
1038 return FALSE;
1039 }
1040
1041
1042 /*
1043 * @implemented
1044 */
1045 WINBOOL
1046 STDCALL
1047 RemoveMenu(
1048 HMENU hMenu,
1049 UINT uPosition,
1050 UINT uFlags)
1051 {
1052 return NtUserRemoveMenu(hMenu, uPosition, uFlags);
1053 }
1054
1055
1056 /*
1057 * @implemented
1058 */
1059 WINBOOL STDCALL
1060 SetMenu(HWND hWnd,
1061 HMENU hMenu)
1062 {
1063 return NtUserSetMenu(hWnd, hMenu, TRUE);
1064 }
1065
1066
1067 /*
1068 * @implemented
1069 */
1070 WINBOOL
1071 STDCALL
1072 SetMenuDefaultItem(
1073 HMENU hMenu,
1074 UINT uItem,
1075 UINT fByPos)
1076 {
1077 return NtUserSetMenuDefaultItem(hMenu, uItem, fByPos);
1078 }
1079
1080
1081 /*
1082 * @implemented
1083 */
1084 WINBOOL
1085 STDCALL
1086 SetMenuInfo(
1087 HMENU hmenu,
1088 LPCMENUINFO lpcmi)
1089 {
1090 MENUINFO mi;
1091 BOOL res = FALSE;
1092 if(lpcmi->cbSize != sizeof(MENUINFO))
1093 return res;
1094
1095 memcpy(&mi, lpcmi, sizeof(MENUINFO));
1096 return NtUserMenuInfo(hmenu, &mi, TRUE);
1097 }
1098
1099
1100 /*
1101 * @unimplemented
1102 */
1103 WINBOOL
1104 STDCALL
1105 SetMenuItemBitmaps(
1106 HMENU hMenu,
1107 UINT uPosition,
1108 UINT uFlags,
1109 HBITMAP hBitmapUnchecked,
1110 HBITMAP hBitmapChecked)
1111 {
1112 UNIMPLEMENTED;
1113 return FALSE;
1114 }
1115
1116
1117 /*
1118 * @unimplemented
1119 */
1120 WINBOOL
1121 STDCALL
1122 SetMenuItemInfoA(
1123 HMENU hMenu,
1124 UINT uItem,
1125 WINBOOL fByPosition,
1126 LPMENUITEMINFOA lpmii)
1127 {
1128 UNIMPLEMENTED;
1129 return FALSE;
1130 }
1131
1132
1133 /*
1134 * @unimplemented
1135 */
1136 WINBOOL
1137 STDCALL
1138 SetMenuItemInfoW(
1139 HMENU hMenu,
1140 UINT uItem,
1141 WINBOOL fByPosition,
1142 LPMENUITEMINFOW lpmii)
1143 {
1144 UNIMPLEMENTED;
1145 return FALSE;
1146 }
1147
1148
1149 /*
1150 * @unimplemented
1151 */
1152 WINBOOL
1153 STDCALL
1154 TrackPopupMenu(
1155 HMENU hMenu,
1156 UINT uFlags,
1157 int x,
1158 int y,
1159 int nReserved,
1160 HWND hWnd,
1161 CONST RECT *prcRect)
1162 {
1163 UNIMPLEMENTED;
1164 return FALSE;
1165 }
1166
1167
1168 /*
1169 * @unimplemented
1170 */
1171 WINBOOL
1172 STDCALL
1173 TrackPopupMenuEx(
1174 HMENU hmenu,
1175 UINT fuFlags,
1176 int x,
1177 int y,
1178 HWND hwnd,
1179 LPTPMPARAMS lptpm)
1180 {
1181 UNIMPLEMENTED;
1182 return FALSE;
1183 }
1184
1185
1186 /*
1187 * @implemented
1188 */
1189 WINBOOL
1190 STDCALL
1191 SetMenuContextHelpId(HMENU hmenu,
1192 DWORD dwContextHelpId)
1193 {
1194 return NtUserSetMenuContextHelpId(hmenu, dwContextHelpId);
1195 }
1196
1197
1198 /*
1199 * @implemented
1200 */
1201 DWORD
1202 STDCALL
1203 GetMenuContextHelpId(HMENU hmenu)
1204 {
1205 MENUINFO mi;
1206 mi.cbSize = sizeof(MENUINFO);
1207 mi.fMask = MIM_HELPID;
1208
1209 if(NtUserMenuInfo(hmenu, &mi, FALSE))
1210 {
1211 return mi.dwContextHelpID;
1212 }
1213 return 0;
1214 }
1215