Fix typo!
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / menu.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Menus
24 * FILE: subsys/win32k/ntuser/menu.c
25 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
26 * REVISION HISTORY:
27 * 07/30/2003 CSH Created
28 */
29 /* INCLUDES ******************************************************************/
30
31 #include <w32k.h>
32
33 #define NDEBUG
34 #include <debug.h>
35
36 PMENU_OBJECT FASTCALL
37 IntGetSystemMenu(PWINDOW_OBJECT Window, BOOL bRevert, BOOL RetMenu);
38
39
40
41 /* STATIC FUNCTION ***********************************************************/
42
43 static
44 BOOL FASTCALL
45 UserMenuItemInfo(
46 PMENU_OBJECT Menu,
47 UINT Item,
48 BOOL ByPosition,
49 PROSMENUITEMINFO UnsafeItemInfo,
50 BOOL SetOrGet);
51
52 static
53 BOOL FASTCALL
54 UserMenuInfo(
55 PMENU_OBJECT Menu,
56 PROSMENUINFO UnsafeMenuInfo,
57 BOOL SetOrGet);
58
59 /* INTERNAL ******************************************************************/
60
61 /* maximum number of menu items a menu can contain */
62 #define MAX_MENU_ITEMS (0x4000)
63 #define MAX_GOINTOSUBMENU (0x10)
64
65 #define UpdateMenuItemState(state, change) \
66 {\
67 if((change) & MFS_DISABLED) { \
68 (state) |= MFS_DISABLED; \
69 } else { \
70 (state) &= ~MFS_DISABLED; \
71 } \
72 if((change) & MFS_CHECKED) { \
73 (state) |= MFS_CHECKED; \
74 } else { \
75 (state) &= ~MFS_CHECKED; \
76 } \
77 if((change) & MFS_HILITE) { \
78 (state) |= MFS_HILITE; \
79 } else { \
80 (state) &= ~MFS_HILITE; \
81 } \
82 if((change) & MFS_DEFAULT) { \
83 (state) |= MFS_DEFAULT; \
84 } else { \
85 (state) &= ~MFS_DEFAULT; \
86 } \
87 if((change) & MF_MOUSESELECT) { \
88 (state) |= MF_MOUSESELECT; \
89 } else { \
90 (state) &= ~MF_MOUSESELECT; \
91 } \
92 }
93
94 #define FreeMenuText(MenuItem) \
95 { \
96 if((MENU_ITEM_TYPE((MenuItem)->fType) == MF_STRING) && \
97 (MenuItem)->Text.Length) { \
98 RtlFreeUnicodeString(&(MenuItem)->Text); \
99 } \
100 }
101
102 #define InRect(r, x, y) \
103 ( ( ((r).right >= x)) && \
104 ( ((r).left <= x)) && \
105 ( ((r).bottom >= y)) && \
106 ( ((r).top <= y)) )
107
108 NTSTATUS FASTCALL
109 InitMenuImpl(VOID)
110 {
111 return(STATUS_SUCCESS);
112 }
113
114 NTSTATUS FASTCALL
115 CleanupMenuImpl(VOID)
116 {
117 return(STATUS_SUCCESS);
118 }
119
120 PMENU_OBJECT FASTCALL UserGetMenuObject(HMENU hMenu)
121 {
122 PMENU_OBJECT Menu;
123
124 if (!hMenu)
125 {
126 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
127 return NULL;
128 }
129
130 Menu = (PMENU_OBJECT)UserGetObject(gHandleTable, hMenu, otMenu);
131 if (!Menu)
132 {
133 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
134 return NULL;
135 }
136
137 ASSERT(USER_BODY_TO_HEADER(Menu)->RefCount >= 0);
138 return Menu;
139 }
140
141
142 #if 0
143 void FASTCALL
144 DumpMenuItemList(PMENU_ITEM MenuItem)
145 {
146 UINT cnt = 0;
147 while(MenuItem)
148 {
149 if(MenuItem->Text.Length)
150 DbgPrint(" %d. %wZ\n", ++cnt, &MenuItem->Text);
151 else
152 DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt, (DWORD)MenuItem->Text.Buffer);
153 DbgPrint(" fType=");
154 if(MFT_BITMAP & MenuItem->fType)
155 DbgPrint("MFT_BITMAP ");
156 if(MFT_MENUBARBREAK & MenuItem->fType)
157 DbgPrint("MFT_MENUBARBREAK ");
158 if(MFT_MENUBREAK & MenuItem->fType)
159 DbgPrint("MFT_MENUBREAK ");
160 if(MFT_OWNERDRAW & MenuItem->fType)
161 DbgPrint("MFT_OWNERDRAW ");
162 if(MFT_RADIOCHECK & MenuItem->fType)
163 DbgPrint("MFT_RADIOCHECK ");
164 if(MFT_RIGHTJUSTIFY & MenuItem->fType)
165 DbgPrint("MFT_RIGHTJUSTIFY ");
166 if(MFT_SEPARATOR & MenuItem->fType)
167 DbgPrint("MFT_SEPARATOR ");
168 if(MFT_STRING & MenuItem->fType)
169 DbgPrint("MFT_STRING ");
170 DbgPrint("\n fState=");
171 if(MFS_DISABLED & MenuItem->fState)
172 DbgPrint("MFS_DISABLED ");
173 else
174 DbgPrint("MFS_ENABLED ");
175 if(MFS_CHECKED & MenuItem->fState)
176 DbgPrint("MFS_CHECKED ");
177 else
178 DbgPrint("MFS_UNCHECKED ");
179 if(MFS_HILITE & MenuItem->fState)
180 DbgPrint("MFS_HILITE ");
181 else
182 DbgPrint("MFS_UNHILITE ");
183 if(MFS_DEFAULT & MenuItem->fState)
184 DbgPrint("MFS_DEFAULT ");
185 if(MFS_GRAYED & MenuItem->fState)
186 DbgPrint("MFS_GRAYED ");
187 DbgPrint("\n wId=%d\n", MenuItem->wID);
188 MenuItem = MenuItem->Next;
189 }
190 DbgPrint("Entries: %d\n", cnt);
191 return;
192 }
193 #endif
194
195 PMENU_OBJECT FASTCALL
196 IntGetMenuObject(HMENU hMenu)
197 {
198 PMENU_OBJECT Menu = UserGetMenuObject(hMenu);
199 if (Menu)
200 {
201 ASSERT(USER_BODY_TO_HEADER(Menu)->RefCount >= 0);
202
203 USER_BODY_TO_HEADER(Menu)->RefCount++;
204 }
205 return Menu;
206 }
207
208 BOOL FASTCALL
209 IntFreeMenuItem(PMENU_OBJECT Menu, PMENU_ITEM MenuItem,
210 BOOL RemoveFromList, BOOL bRecurse)
211 {
212 FreeMenuText(MenuItem);
213 if(RemoveFromList)
214 {
215 PMENU_ITEM CurItem = Menu->MenuItemList;
216 while(CurItem)
217 {
218 if (CurItem->Next == MenuItem)
219 {
220 CurItem->Next = MenuItem->Next;
221 break;
222 }
223 else
224 {
225 CurItem = CurItem->Next;
226 }
227 }
228 Menu->MenuInfo.MenuItemCount--;
229 }
230 if(bRecurse && MenuItem->hSubMenu)
231 {
232 PMENU_OBJECT SubMenu;
233 SubMenu = UserGetMenuObject(MenuItem->hSubMenu );
234 if(SubMenu)
235 {
236 IntDestroyMenuObject(SubMenu, bRecurse, TRUE);
237 }
238 }
239
240 /* Free memory */
241 ExFreePool(MenuItem);
242
243 return TRUE;
244 }
245
246 BOOL FASTCALL
247 IntRemoveMenuItem(PMENU_OBJECT Menu, UINT uPosition, UINT uFlags,
248 BOOL bRecurse)
249 {
250 PMENU_ITEM PrevMenuItem, MenuItem;
251 if(IntGetMenuItemByFlag(Menu, uPosition, uFlags, NULL, &MenuItem,
252 &PrevMenuItem) > -1)
253 {
254 if(MenuItem)
255 {
256 if(PrevMenuItem)
257 PrevMenuItem->Next = MenuItem->Next;
258 else
259 {
260 Menu->MenuItemList = MenuItem->Next;
261 }
262 return IntFreeMenuItem(Menu, MenuItem, TRUE, bRecurse);
263 }
264 }
265 return FALSE;
266 }
267
268 UINT FASTCALL
269 IntDeleteMenuItems(PMENU_OBJECT Menu, BOOL bRecurse)
270 {
271 UINT res = 0;
272 PMENU_ITEM NextItem;
273 PMENU_ITEM CurItem = Menu->MenuItemList;
274 while(CurItem)
275 {
276 NextItem = CurItem->Next;
277 IntFreeMenuItem(Menu, CurItem, FALSE, bRecurse);
278 CurItem = NextItem;
279 res++;
280 }
281 Menu->MenuInfo.MenuItemCount = 0;
282 Menu->MenuItemList = NULL;
283 return res;
284 }
285
286 BOOL FASTCALL
287 IntDestroyMenuObject(PMENU_OBJECT Menu,
288 BOOL bRecurse, BOOL RemoveFromProcess)
289 {
290 if(Menu)
291 {
292 PWINDOW_OBJECT Window;
293 PWINSTATION_OBJECT WindowStation;
294 NTSTATUS Status;
295
296 /* remove all menu items */
297 IntDeleteMenuItems(Menu, bRecurse); /* do not destroy submenus */
298
299 if(RemoveFromProcess)
300 {
301 RemoveEntryList(&Menu->ListEntry);
302 }
303
304 Status = ObReferenceObjectByHandle(Menu->Process->Win32WindowStation,
305 0,
306 ExWindowStationObjectType,
307 KernelMode,
308 (PVOID*)&WindowStation,
309 NULL);
310 if(NT_SUCCESS(Status))
311 {
312 if (Menu->MenuInfo.Wnd)
313 {
314 Window = UserGetWindowObject(Menu->MenuInfo.Wnd);
315 if (Window)
316 {
317 Window->Wnd->IDMenu = 0;
318 }
319 }
320 ObmDeleteObject(Menu->MenuInfo.Self, otMenu);
321 ObDereferenceObject(WindowStation);
322 return TRUE;
323 }
324 }
325 return FALSE;
326 }
327
328 PMENU_OBJECT FASTCALL
329 IntCreateMenu(PHANDLE Handle, BOOL IsMenuBar)
330 {
331 PMENU_OBJECT Menu;
332
333 Menu = (PMENU_OBJECT)ObmCreateObject(
334 gHandleTable, Handle,
335 otMenu, sizeof(MENU_OBJECT));
336
337 if(!Menu)
338 {
339 *Handle = 0;
340 return NULL;
341 }
342
343 Menu->Process = PsGetCurrentProcess();
344 Menu->RtoL = FALSE; /* default */
345 Menu->MenuInfo.cbSize = sizeof(MENUINFO); /* not used */
346 Menu->MenuInfo.fMask = 0; /* not used */
347 Menu->MenuInfo.dwStyle = 0; /* FIXME */
348 Menu->MenuInfo.cyMax = 0; /* default */
349 Menu->MenuInfo.hbrBack =
350 NtGdiCreateSolidBrush(RGB(192, 192, 192), 0); /* FIXME: default background color */
351 Menu->MenuInfo.dwContextHelpID = 0; /* default */
352 Menu->MenuInfo.dwMenuData = 0; /* default */
353 Menu->MenuInfo.Self = *Handle;
354 Menu->MenuInfo.FocusedItem = NO_SELECTED_ITEM;
355 Menu->MenuInfo.Flags = (IsMenuBar ? 0 : MF_POPUP);
356 Menu->MenuInfo.Wnd = NULL;
357 Menu->MenuInfo.WndOwner = NULL;
358 Menu->MenuInfo.Height = 0;
359 Menu->MenuInfo.Width = 0;
360 Menu->MenuInfo.TimeToHide = FALSE;
361
362 Menu->MenuInfo.MenuItemCount = 0;
363 Menu->MenuItemList = NULL;
364
365 /* Insert menu item into process menu handle list */
366 InsertTailList(&PsGetCurrentProcessWin32Process()->MenuListHead, &Menu->ListEntry);
367
368 return Menu;
369 }
370
371 BOOL FASTCALL
372 IntCloneMenuItems(PMENU_OBJECT Destination, PMENU_OBJECT Source)
373 {
374 PMENU_ITEM MenuItem, NewMenuItem = NULL;
375 PMENU_ITEM Old = NULL;
376
377 if(!Source->MenuInfo.MenuItemCount)
378 return FALSE;
379
380 MenuItem = Source->MenuItemList;
381 while(MenuItem)
382 {
383 Old = NewMenuItem;
384 if(NewMenuItem)
385 NewMenuItem->Next = MenuItem;
386 NewMenuItem = ExAllocatePoolWithTag(PagedPool, sizeof(MENU_ITEM), TAG_MENUITEM);
387 if(!NewMenuItem)
388 break;
389 NewMenuItem->fType = MenuItem->fType;
390 NewMenuItem->fState = MenuItem->fState;
391 NewMenuItem->wID = MenuItem->wID;
392 NewMenuItem->hSubMenu = MenuItem->hSubMenu;
393 NewMenuItem->hbmpChecked = MenuItem->hbmpChecked;
394 NewMenuItem->hbmpUnchecked = MenuItem->hbmpUnchecked;
395 NewMenuItem->dwItemData = MenuItem->dwItemData;
396 if((MENU_ITEM_TYPE(NewMenuItem->fType) == MF_STRING))
397 {
398 if(MenuItem->Text.Length)
399 {
400 NewMenuItem->Text.Length = 0;
401 NewMenuItem->Text.MaximumLength = MenuItem->Text.MaximumLength;
402 NewMenuItem->Text.Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, MenuItem->Text.MaximumLength, TAG_STRING);
403 if(!NewMenuItem->Text.Buffer)
404 {
405 ExFreePool(NewMenuItem);
406 break;
407 }
408 RtlCopyUnicodeString(&NewMenuItem->Text, &MenuItem->Text);
409 }
410 else
411 {
412 NewMenuItem->Text.Buffer = MenuItem->Text.Buffer;
413 }
414 }
415 else
416 {
417 NewMenuItem->Text.Buffer = MenuItem->Text.Buffer;
418 }
419 NewMenuItem->hbmpItem = MenuItem->hbmpItem;
420
421 NewMenuItem->Next = NULL;
422 if(Old)
423 Old->Next = NewMenuItem;
424 else
425 Destination->MenuItemList = NewMenuItem;
426 Destination->MenuInfo.MenuItemCount++;
427 MenuItem = MenuItem->Next;
428 }
429
430 return TRUE;
431 }
432
433 PMENU_OBJECT FASTCALL
434 IntCloneMenu(PMENU_OBJECT Source)
435 {
436 HANDLE hMenu;
437 PMENU_OBJECT Menu;
438
439 if(!Source)
440 return NULL;
441
442 Menu = (PMENU_OBJECT)ObmCreateObject(
443 gHandleTable, &hMenu,
444 otMenu, sizeof(MENU_OBJECT));
445
446 if(!Menu)
447 return NULL;
448
449 Menu->Process = PsGetCurrentProcess();
450 Menu->RtoL = Source->RtoL;
451 Menu->MenuInfo.cbSize = sizeof(MENUINFO); /* not used */
452 Menu->MenuInfo.fMask = Source->MenuInfo.fMask;
453 Menu->MenuInfo.dwStyle = Source->MenuInfo.dwStyle;
454 Menu->MenuInfo.cyMax = Source->MenuInfo.cyMax;
455 Menu->MenuInfo.hbrBack = Source->MenuInfo.hbrBack;
456 Menu->MenuInfo.dwContextHelpID = Source->MenuInfo.dwContextHelpID;
457 Menu->MenuInfo.dwMenuData = Source->MenuInfo.dwMenuData;
458 Menu->MenuInfo.Self = hMenu;
459 Menu->MenuInfo.FocusedItem = NO_SELECTED_ITEM;
460 Menu->MenuInfo.Wnd = NULL;
461 Menu->MenuInfo.WndOwner = NULL;
462 Menu->MenuInfo.Height = 0;
463 Menu->MenuInfo.Width = 0;
464 Menu->MenuInfo.TimeToHide = FALSE;
465
466 Menu->MenuInfo.MenuItemCount = 0;
467 Menu->MenuItemList = NULL;
468
469 /* Insert menu item into process menu handle list */
470 InsertTailList(&PsGetCurrentProcessWin32Process()->MenuListHead, &Menu->ListEntry);
471
472 IntCloneMenuItems(Menu, Source);
473
474 return Menu;
475 }
476
477 BOOL FASTCALL
478 IntSetMenuFlagRtoL(PMENU_OBJECT Menu)
479 {
480 Menu->RtoL = TRUE;
481 return TRUE;
482 }
483
484 BOOL FASTCALL
485 IntSetMenuContextHelpId(PMENU_OBJECT Menu, DWORD dwContextHelpId)
486 {
487 Menu->MenuInfo.dwContextHelpID = dwContextHelpId;
488 return TRUE;
489 }
490
491 BOOL FASTCALL
492 IntGetMenuInfo(PMENU_OBJECT Menu, PROSMENUINFO lpmi)
493 {
494 if(lpmi->fMask & MIM_BACKGROUND)
495 lpmi->hbrBack = Menu->MenuInfo.hbrBack;
496 if(lpmi->fMask & MIM_HELPID)
497 lpmi->dwContextHelpID = Menu->MenuInfo.dwContextHelpID;
498 if(lpmi->fMask & MIM_MAXHEIGHT)
499 lpmi->cyMax = Menu->MenuInfo.cyMax;
500 if(lpmi->fMask & MIM_MENUDATA)
501 lpmi->dwMenuData = Menu->MenuInfo.dwMenuData;
502 if(lpmi->fMask & MIM_STYLE)
503 lpmi->dwStyle = Menu->MenuInfo.dwStyle;
504 if (sizeof(MENUINFO) < lpmi->cbSize)
505 {
506 RtlCopyMemory((char *) lpmi + sizeof(MENUINFO),
507 (char *) &Menu->MenuInfo + sizeof(MENUINFO),
508 lpmi->cbSize - sizeof(MENUINFO));
509 }
510 if (sizeof(ROSMENUINFO) == lpmi->cbSize)
511 {
512 lpmi->maxBmpSize.cx = Menu->MenuInfo.maxBmpSize.cx;
513 lpmi->maxBmpSize.cy = Menu->MenuInfo.maxBmpSize.cy;
514 }
515 return TRUE;
516 }
517
518
519 BOOL FASTCALL
520 IntIsMenu(HMENU hMenu)
521 {
522 PMENU_OBJECT Menu;
523
524 if((Menu = UserGetMenuObject(hMenu)))
525 {
526 return TRUE;
527 }
528 return FALSE;
529 }
530
531
532 BOOL FASTCALL
533 IntSetMenuInfo(PMENU_OBJECT Menu, PROSMENUINFO lpmi)
534 {
535 if(lpmi->fMask & MIM_BACKGROUND)
536 Menu->MenuInfo.hbrBack = lpmi->hbrBack;
537 if(lpmi->fMask & MIM_HELPID)
538 Menu->MenuInfo.dwContextHelpID = lpmi->dwContextHelpID;
539 if(lpmi->fMask & MIM_MAXHEIGHT)
540 Menu->MenuInfo.cyMax = lpmi->cyMax;
541 if(lpmi->fMask & MIM_MENUDATA)
542 Menu->MenuInfo.dwMenuData = lpmi->dwMenuData;
543 if(lpmi->fMask & MIM_STYLE)
544 Menu->MenuInfo.dwStyle = lpmi->dwStyle;
545 if(lpmi->fMask & MIM_APPLYTOSUBMENUS)
546 {
547 /* FIXME */
548 }
549 if (sizeof(MENUINFO) < lpmi->cbSize)
550 {
551 Menu->MenuInfo.FocusedItem = lpmi->FocusedItem;
552 Menu->MenuInfo.Height = lpmi->Height;
553 Menu->MenuInfo.Width = lpmi->Width;
554 Menu->MenuInfo.Wnd = lpmi->Wnd;
555 Menu->MenuInfo.WndOwner = lpmi->WndOwner;
556 Menu->MenuInfo.TimeToHide = lpmi->TimeToHide;
557 }
558 if (sizeof(ROSMENUINFO) == lpmi->cbSize)
559 {
560 Menu->MenuInfo.maxBmpSize.cx = lpmi->maxBmpSize.cx;
561 Menu->MenuInfo.maxBmpSize.cy = lpmi->maxBmpSize.cy;
562 }
563 return TRUE;
564 }
565
566
567 int FASTCALL
568 IntGetMenuItemByFlag(PMENU_OBJECT Menu, UINT uSearchBy, UINT fFlag,
569 PMENU_OBJECT *SubMenu, PMENU_ITEM *MenuItem,
570 PMENU_ITEM *PrevMenuItem)
571 {
572 PMENU_ITEM PrevItem = NULL;
573 PMENU_ITEM CurItem = Menu->MenuItemList;
574 int p;
575 int ret;
576
577 if(MF_BYPOSITION & fFlag)
578 {
579 p = uSearchBy;
580 while(CurItem && (p > 0))
581 {
582 PrevItem = CurItem;
583 CurItem = CurItem->Next;
584 p--;
585 }
586 if(CurItem)
587 {
588 if(MenuItem)
589 *MenuItem = CurItem;
590 if(PrevMenuItem)
591 *PrevMenuItem = PrevItem;
592 }
593 else
594 {
595 if(MenuItem)
596 *MenuItem = NULL;
597 if(PrevMenuItem)
598 *PrevMenuItem = NULL; /* ? */
599 return -1;
600 }
601
602 return uSearchBy - p;
603 }
604 else
605 {
606 p = 0;
607 while(CurItem)
608 {
609 if(CurItem->wID == uSearchBy)
610 {
611 if(MenuItem)
612 *MenuItem = CurItem;
613 if(PrevMenuItem)
614 *PrevMenuItem = PrevItem;
615 if(SubMenu)
616 *SubMenu = Menu;
617
618 return p;
619 }
620 else
621 {
622 if(CurItem->fType & MF_POPUP)
623 {
624 PMENU_OBJECT NewMenu = UserGetMenuObject(CurItem->hSubMenu);
625 if(Menu)
626 {
627 ret = IntGetMenuItemByFlag(NewMenu, uSearchBy, fFlag,
628 SubMenu, MenuItem, PrevMenuItem);
629 if(ret != -1)
630 {
631 return ret;
632 }
633 }
634 }
635 }
636 PrevItem = CurItem;
637 CurItem = CurItem->Next;
638 p++;
639 }
640 }
641 return -1;
642 }
643
644
645 int FASTCALL
646 IntInsertMenuItemToList(PMENU_OBJECT Menu, PMENU_ITEM MenuItem, int pos)
647 {
648 PMENU_ITEM CurItem;
649 PMENU_ITEM LastItem = NULL;
650 UINT npos = 0;
651
652 CurItem = Menu->MenuItemList;
653 if(pos <= -1)
654 {
655 while(CurItem)
656 {
657 LastItem = CurItem;
658 CurItem = CurItem->Next;
659 npos++;
660 }
661 }
662 else
663 {
664 while(CurItem && (pos > 0))
665 {
666 LastItem = CurItem;
667 CurItem = CurItem->Next;
668 pos--;
669 npos++;
670 }
671 }
672
673 if(CurItem)
674 {
675 if(LastItem)
676 {
677 /* insert the item before CurItem */
678 MenuItem->Next = LastItem->Next;
679 LastItem->Next = MenuItem;
680 }
681 else
682 {
683 /* insert at the beginning */
684 Menu->MenuItemList = MenuItem;
685 MenuItem->Next = CurItem;
686 }
687 }
688 else
689 {
690 if(LastItem)
691 {
692 /* append item */
693 LastItem->Next = MenuItem;
694 MenuItem->Next = NULL;
695 }
696 else
697 {
698 /* insert first item */
699 Menu->MenuItemList = MenuItem;
700 MenuItem->Next = NULL;
701 }
702 }
703 Menu->MenuInfo.MenuItemCount++;
704
705 return npos;
706 }
707
708 BOOL FASTCALL
709 IntGetMenuItemInfo(PMENU_OBJECT Menu, /* UNUSED PARAM!! */
710 PMENU_ITEM MenuItem, PROSMENUITEMINFO lpmii)
711 {
712 NTSTATUS Status;
713
714 if(lpmii->fMask & (MIIM_FTYPE | MIIM_TYPE))
715 {
716 lpmii->fType = MenuItem->fType;
717 }
718 if(lpmii->fMask & MIIM_BITMAP)
719 {
720 lpmii->hbmpItem = MenuItem->hbmpItem;
721 }
722 if(lpmii->fMask & MIIM_CHECKMARKS)
723 {
724 lpmii->hbmpChecked = MenuItem->hbmpChecked;
725 lpmii->hbmpUnchecked = MenuItem->hbmpUnchecked;
726 }
727 if(lpmii->fMask & MIIM_DATA)
728 {
729 lpmii->dwItemData = MenuItem->dwItemData;
730 }
731 if(lpmii->fMask & MIIM_ID)
732 {
733 lpmii->wID = MenuItem->wID;
734 }
735 if(lpmii->fMask & MIIM_STATE)
736 {
737 lpmii->fState = MenuItem->fState;
738 }
739 if(lpmii->fMask & MIIM_SUBMENU)
740 {
741 lpmii->hSubMenu = MenuItem->hSubMenu;
742 }
743
744 if ((lpmii->fMask & MIIM_STRING) ||
745 ((lpmii->fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(lpmii->fType) == MF_STRING)))
746 {
747 if (lpmii->dwTypeData == NULL)
748 {
749 lpmii->cch = MenuItem->Text.Length / sizeof(WCHAR);
750 }
751 else
752 {
753 Status = MmCopyToCaller(lpmii->dwTypeData, MenuItem->Text.Buffer,
754 min(lpmii->cch * sizeof(WCHAR),
755 MenuItem->Text.MaximumLength));
756 if (! NT_SUCCESS(Status))
757 {
758 SetLastNtError(Status);
759 return FALSE;
760 }
761 }
762 }
763
764 if (sizeof(ROSMENUITEMINFO) == lpmii->cbSize)
765 {
766 lpmii->Rect = MenuItem->Rect;
767 lpmii->XTab = MenuItem->XTab;
768 lpmii->Text = MenuItem->Text.Buffer;
769 }
770
771 return TRUE;
772 }
773
774 BOOL FASTCALL
775 IntSetMenuItemInfo(PMENU_OBJECT MenuObject, PMENU_ITEM MenuItem, PROSMENUITEMINFO lpmii)
776 {
777 PMENU_OBJECT SubMenuObject;
778 UINT fTypeMask = (MFT_BITMAP | MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_OWNERDRAW | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_SEPARATOR | MF_POPUP);
779
780 if(!MenuItem || !MenuObject || !lpmii)
781 {
782 return FALSE;
783 }
784 if( lpmii->fType & ~fTypeMask)
785 {
786 DbgPrint("IntSetMenuItemInfo invalid fType flags %x\n", lpmii->fType & ~fTypeMask);
787 lpmii->fMask &= ~(MIIM_TYPE | MIIM_FTYPE);
788 }
789 if(lpmii->fMask & MIIM_TYPE)
790 {
791 if(lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP))
792 {
793 DbgPrint("IntSetMenuItemInfo: Invalid combination of fMask bits used\n");
794 /* this does not happen on Win9x/ME */
795 SetLastNtError( ERROR_INVALID_PARAMETER);
796 return FALSE;
797 }
798 /*
799 * Delete the menu item type when changing type from
800 * MF_STRING.
801 */
802 if (MenuItem->fType != lpmii->fType &&
803 MENU_ITEM_TYPE(MenuItem->fType) == MFT_STRING)
804 {
805 FreeMenuText(MenuItem);
806 RtlInitUnicodeString(&MenuItem->Text, NULL);
807 }
808 if(lpmii->fType & MFT_BITMAP)
809 {
810 if(lpmii->hbmpItem)
811 MenuItem->hbmpItem = lpmii->hbmpItem;
812 else
813 { /* Win 9x/Me stuff */
814 MenuItem->hbmpItem = (HBITMAP)((ULONG_PTR)(LOWORD(lpmii->dwTypeData)));
815 }
816 }
817 MenuItem->fType |= lpmii->fType;
818 }
819 if (lpmii->fMask & MIIM_FTYPE )
820 {
821 if(( lpmii->fType & MFT_BITMAP))
822 {
823 DbgPrint("IntSetMenuItemInfo: Can not use FTYPE and MFT_BITMAP.\n");
824 SetLastNtError( ERROR_INVALID_PARAMETER);
825 return FALSE;
826 }
827 MenuItem->fType |= lpmii->fType; /* Need to save all the flags, this fixed MFT_RIGHTJUSTIFY */
828 }
829 if(lpmii->fMask & MIIM_BITMAP)
830 {
831 MenuItem->hbmpItem = lpmii->hbmpItem;
832 }
833 if(lpmii->fMask & MIIM_CHECKMARKS)
834 {
835 MenuItem->hbmpChecked = lpmii->hbmpChecked;
836 MenuItem->hbmpUnchecked = lpmii->hbmpUnchecked;
837 }
838 if(lpmii->fMask & MIIM_DATA)
839 {
840 MenuItem->dwItemData = lpmii->dwItemData;
841 }
842 if(lpmii->fMask & MIIM_ID)
843 {
844 MenuItem->wID = lpmii->wID;
845 }
846 if(lpmii->fMask & MIIM_STATE)
847 {
848 /* remove MFS_DEFAULT flag from all other menu items if this item
849 has the MFS_DEFAULT state */
850 if(lpmii->fState & MFS_DEFAULT)
851 UserSetMenuDefaultItem(MenuObject, -1, 0);
852 /* update the menu item state flags */
853 UpdateMenuItemState(MenuItem->fState, lpmii->fState);
854 }
855
856 if(lpmii->fMask & MIIM_SUBMENU)
857 {
858 MenuItem->hSubMenu = lpmii->hSubMenu;
859 /* Make sure the submenu is marked as a popup menu */
860 if (MenuItem->hSubMenu)
861 {
862 SubMenuObject = UserGetMenuObject(MenuItem->hSubMenu);
863 if (SubMenuObject != NULL)
864 {
865 SubMenuObject->MenuInfo.Flags |= MF_POPUP;
866 MenuItem->fType |= MF_POPUP;
867 }
868 else
869 {
870 MenuItem->fType &= ~MF_POPUP;
871 }
872 }
873 else
874 {
875 MenuItem->fType &= ~MF_POPUP;
876 }
877 }
878
879 if ((lpmii->fMask & MIIM_STRING) ||
880 ((lpmii->fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(lpmii->fType) == MF_STRING)))
881 {
882 FreeMenuText(MenuItem);
883
884 if(lpmii->dwTypeData && lpmii->cch)
885 {
886 UNICODE_STRING Source;
887
888 Source.Length =
889 Source.MaximumLength = lpmii->cch * sizeof(WCHAR);
890 Source.Buffer = lpmii->dwTypeData;
891
892 MenuItem->Text.Buffer = (PWSTR)ExAllocatePoolWithTag(
893 PagedPool, Source.Length + sizeof(WCHAR), TAG_STRING);
894 if(MenuItem->Text.Buffer != NULL)
895 {
896 MenuItem->Text.Length = 0;
897 MenuItem->Text.MaximumLength = Source.Length + sizeof(WCHAR);
898 RtlCopyUnicodeString(&MenuItem->Text, &Source);
899 MenuItem->Text.Buffer[MenuItem->Text.Length / sizeof(WCHAR)] = 0;
900 }
901 else
902 {
903 RtlInitUnicodeString(&MenuItem->Text, NULL);
904 }
905 }
906 else
907 {
908 if (0 == (MenuObject->MenuInfo.Flags & MF_SYSMENU))
909 {
910 MenuItem->fType |= MF_SEPARATOR;
911 }
912 RtlInitUnicodeString(&MenuItem->Text, NULL);
913 }
914 }
915
916 if (sizeof(ROSMENUITEMINFO) == lpmii->cbSize)
917 {
918 MenuItem->Rect = lpmii->Rect;
919 MenuItem->XTab = lpmii->XTab;
920 lpmii->Text = MenuItem->Text.Buffer; /* Send back new allocated string or zero */
921 }
922
923 return TRUE;
924 }
925
926 BOOL FASTCALL
927 IntInsertMenuItem(PMENU_OBJECT MenuObject, UINT uItem, BOOL fByPosition,
928 PROSMENUITEMINFO ItemInfo)
929 {
930 int pos = (int)uItem;
931 PMENU_ITEM MenuItem;
932 PMENU_OBJECT SubMenu;
933
934 if (MAX_MENU_ITEMS <= MenuObject->MenuInfo.MenuItemCount)
935 {
936 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
937 return FALSE;
938 }
939
940 if (fByPosition)
941 {
942 SubMenu = MenuObject;
943 /* calculate position */
944 if(MenuObject->MenuInfo.MenuItemCount < pos)
945 {
946 pos = MenuObject->MenuInfo.MenuItemCount;
947 }
948 }
949 else
950 {
951 pos = IntGetMenuItemByFlag(MenuObject, uItem, MF_BYCOMMAND, &SubMenu, NULL, NULL);
952 }
953 if (pos < -1)
954 {
955 pos = -1;
956 }
957
958 MenuItem = ExAllocatePoolWithTag(PagedPool, sizeof(MENU_ITEM), TAG_MENUITEM);
959 if (NULL == MenuItem)
960 {
961 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
962 return FALSE;
963 }
964
965 MenuItem->fType = MFT_STRING;
966 MenuItem->fState = MFS_ENABLED | MFS_UNCHECKED;
967 MenuItem->wID = 0;
968 MenuItem->hSubMenu = (HMENU)0;
969 MenuItem->hbmpChecked = (HBITMAP)0;
970 MenuItem->hbmpUnchecked = (HBITMAP)0;
971 MenuItem->dwItemData = 0;
972 RtlInitUnicodeString(&MenuItem->Text, NULL);
973 MenuItem->hbmpItem = (HBITMAP)0;
974
975 if(!IntSetMenuItemInfo(SubMenu, MenuItem, ItemInfo))
976 {
977 ExFreePool(MenuItem);
978 return FALSE;
979 }
980
981 /* Force size recalculation! */
982 MenuObject->MenuInfo.Height = 0;
983
984 pos = IntInsertMenuItemToList(SubMenu, MenuItem, pos);
985
986 DPRINT("IntInsertMenuItemToList = %i\n", pos);
987
988 return (pos >= 0);
989 }
990
991 UINT FASTCALL
992 IntEnableMenuItem(PMENU_OBJECT MenuObject, UINT uIDEnableItem, UINT uEnable)
993 {
994 PMENU_ITEM MenuItem;
995 UINT res = IntGetMenuItemByFlag(MenuObject, uIDEnableItem, uEnable, NULL, &MenuItem, NULL);
996 if(!MenuItem || (res == (UINT)-1))
997 {
998 return (UINT)-1;
999 }
1000
1001 res = MenuItem->fState & (MF_GRAYED | MF_DISABLED);
1002
1003 if(uEnable & MF_DISABLED)
1004 {
1005 if(!(MenuItem->fState & MF_DISABLED))
1006 MenuItem->fState |= MF_DISABLED;
1007 if(uEnable & MF_GRAYED)
1008 {
1009 if(!(MenuItem->fState & MF_GRAYED))
1010 MenuItem->fState |= MF_GRAYED;
1011 }
1012 }
1013 else
1014 {
1015 if(uEnable & MF_GRAYED)
1016 {
1017 if(!(MenuItem->fState & MF_GRAYED))
1018 MenuItem->fState |= MF_GRAYED;
1019 if(!(MenuItem->fState & MF_DISABLED))
1020 MenuItem->fState |= MF_DISABLED;
1021 }
1022 else
1023 {
1024 if(MenuItem->fState & MF_DISABLED)
1025 MenuItem->fState ^= MF_DISABLED;
1026 if(MenuItem->fState & MF_GRAYED)
1027 MenuItem->fState ^= MF_GRAYED;
1028 }
1029 }
1030
1031 return res;
1032 }
1033
1034
1035 DWORD FASTCALL
1036 IntBuildMenuItemList(PMENU_OBJECT MenuObject, PVOID Buffer, ULONG nMax)
1037 {
1038 DWORD res = 0;
1039 UINT sz;
1040 ROSMENUITEMINFO mii;
1041 PVOID Buf;
1042 PMENU_ITEM CurItem = MenuObject->MenuItemList;
1043 PWCHAR StrOut;
1044 NTSTATUS Status;
1045 WCHAR NulByte;
1046
1047 if (0 != nMax)
1048 {
1049 if (nMax < MenuObject->MenuInfo.MenuItemCount * sizeof(ROSMENUITEMINFO))
1050 {
1051 return 0;
1052 }
1053 StrOut = (PWCHAR)((char *) Buffer + MenuObject->MenuInfo.MenuItemCount
1054 * sizeof(ROSMENUITEMINFO));
1055 nMax -= MenuObject->MenuInfo.MenuItemCount * sizeof(ROSMENUITEMINFO);
1056 sz = sizeof(ROSMENUITEMINFO);
1057 Buf = Buffer;
1058 mii.cbSize = sizeof(ROSMENUITEMINFO);
1059 mii.fMask = 0;
1060 NulByte = L'\0';
1061
1062 while (NULL != CurItem)
1063 {
1064 mii.cch = CurItem->Text.Length / sizeof(WCHAR);
1065 mii.dwItemData = CurItem->dwItemData;
1066 if (0 != CurItem->Text.Length)
1067 {
1068 mii.dwTypeData = StrOut;
1069 }
1070 else
1071 {
1072 mii.dwTypeData = NULL;
1073 }
1074 mii.fState = CurItem->fState;
1075 mii.fType = CurItem->fType;
1076 mii.hbmpChecked = CurItem->hbmpChecked;
1077 mii.hbmpItem = CurItem->hbmpItem;
1078 mii.hbmpUnchecked = CurItem->hbmpUnchecked;
1079 mii.hSubMenu = CurItem->hSubMenu;
1080 mii.Rect = CurItem->Rect;
1081 mii.XTab = CurItem->XTab;
1082 mii.Text = CurItem->Text.Buffer;
1083
1084 Status = MmCopyToCaller(Buf, &mii, sizeof(ROSMENUITEMINFO));
1085 if (! NT_SUCCESS(Status))
1086 {
1087 SetLastNtError(Status);
1088 return 0;
1089 }
1090 Buf = (PVOID)((ULONG_PTR)Buf + sizeof(ROSMENUITEMINFO));
1091
1092 if (0 != CurItem->Text.Length
1093 && (nMax >= CurItem->Text.Length + sizeof(WCHAR)))
1094 {
1095 /* copy string */
1096 Status = MmCopyToCaller(StrOut, CurItem->Text.Buffer,
1097 CurItem->Text.Length);
1098 if (! NT_SUCCESS(Status))
1099 {
1100 SetLastNtError(Status);
1101 return 0;
1102 }
1103 StrOut += CurItem->Text.Length / sizeof(WCHAR);
1104 Status = MmCopyToCaller(StrOut, &NulByte, sizeof(WCHAR));
1105 if (! NT_SUCCESS(Status))
1106 {
1107 SetLastNtError(Status);
1108 return 0;
1109 }
1110 StrOut++;
1111 nMax -= CurItem->Text.Length + sizeof(WCHAR);
1112 }
1113 else if (0 != CurItem->Text.Length)
1114 {
1115 break;
1116 }
1117
1118 CurItem = CurItem->Next;
1119 res++;
1120 }
1121 }
1122 else
1123 {
1124 while (NULL != CurItem)
1125 {
1126 res += sizeof(ROSMENUITEMINFO) + CurItem->Text.Length + sizeof(WCHAR);
1127 CurItem = CurItem->Next;
1128 }
1129 }
1130
1131 return res;
1132 }
1133
1134
1135 DWORD FASTCALL
1136 IntCheckMenuItem(PMENU_OBJECT MenuObject, UINT uIDCheckItem, UINT uCheck)
1137 {
1138 PMENU_ITEM MenuItem;
1139 int res = -1;
1140
1141 if((IntGetMenuItemByFlag(MenuObject, uIDCheckItem, uCheck, NULL, &MenuItem, NULL) < 0) || !MenuItem)
1142 {
1143 return -1;
1144 }
1145
1146 res = (DWORD)(MenuItem->fState & MF_CHECKED);
1147 if(uCheck & MF_CHECKED)
1148 {
1149 if(!(MenuItem->fState & MF_CHECKED))
1150 MenuItem->fState |= MF_CHECKED;
1151 }
1152 else
1153 {
1154 if(MenuItem->fState & MF_CHECKED)
1155 MenuItem->fState ^= MF_CHECKED;
1156 }
1157
1158 return (DWORD)res;
1159 }
1160
1161 BOOL FASTCALL
1162 IntHiliteMenuItem(PWINDOW_OBJECT WindowObject, PMENU_OBJECT MenuObject,
1163 UINT uItemHilite, UINT uHilite)
1164 {
1165 PMENU_ITEM MenuItem;
1166 BOOL res = IntGetMenuItemByFlag(MenuObject, uItemHilite, uHilite, NULL, &MenuItem, NULL);
1167 if(!MenuItem || !res)
1168 {
1169 return FALSE;
1170 }
1171
1172 if(uHilite & MF_HILITE)
1173 {
1174 if(!(MenuItem->fState & MF_HILITE))
1175 MenuItem->fState |= MF_HILITE;
1176 }
1177 else
1178 {
1179 if(MenuItem->fState & MF_HILITE)
1180 MenuItem->fState ^= MF_HILITE;
1181 }
1182
1183 /* FIXME - update the window's menu */
1184
1185 return TRUE;
1186 }
1187
1188 BOOL FASTCALL
1189 UserSetMenuDefaultItem(PMENU_OBJECT MenuObject, UINT uItem, UINT fByPos)
1190 {
1191 BOOL ret = FALSE;
1192 PMENU_ITEM MenuItem = MenuObject->MenuItemList;
1193
1194 if(uItem == (UINT)-1)
1195 {
1196 while(MenuItem)
1197 {
1198 if(MenuItem->fState & MFS_DEFAULT)
1199 MenuItem->fState ^= MFS_DEFAULT;
1200 MenuItem = MenuItem->Next;
1201 }
1202 return TRUE;
1203 }
1204
1205 if(fByPos)
1206 {
1207 UINT pos = 0;
1208 while(MenuItem)
1209 {
1210 if(pos == uItem)
1211 {
1212 if(!(MenuItem->fState & MFS_DEFAULT))
1213 MenuItem->fState |= MFS_DEFAULT;
1214 ret = TRUE;
1215 }
1216 else
1217 {
1218 if(MenuItem->fState & MFS_DEFAULT)
1219 MenuItem->fState ^= MFS_DEFAULT;
1220 }
1221 pos++;
1222 MenuItem = MenuItem->Next;
1223 }
1224 }
1225 else
1226 {
1227 while(MenuItem)
1228 {
1229 if(!ret && (MenuItem->wID == uItem))
1230 {
1231 if(!(MenuItem->fState & MFS_DEFAULT))
1232 MenuItem->fState |= MFS_DEFAULT;
1233 ret = TRUE;
1234 }
1235 else
1236 {
1237 if(MenuItem->fState & MFS_DEFAULT)
1238 MenuItem->fState ^= MFS_DEFAULT;
1239 }
1240 MenuItem = MenuItem->Next;
1241 }
1242 }
1243 return ret;
1244 }
1245
1246
1247 UINT FASTCALL
1248 IntGetMenuDefaultItem(PMENU_OBJECT MenuObject, UINT fByPos, UINT gmdiFlags,
1249 DWORD *gismc)
1250 {
1251 UINT x = 0;
1252 UINT res = -1;
1253 UINT sres;
1254 PMENU_OBJECT SubMenuObject;
1255 PMENU_ITEM MenuItem = MenuObject->MenuItemList;
1256
1257 while(MenuItem)
1258 {
1259 if(MenuItem->fState & MFS_DEFAULT)
1260 {
1261
1262 if(!(gmdiFlags & GMDI_USEDISABLED) && (MenuItem->fState & MFS_DISABLED))
1263 break;
1264
1265 if(fByPos)
1266 res = x;
1267 else
1268 res = MenuItem->wID;
1269
1270 if((*gismc < MAX_GOINTOSUBMENU) && (gmdiFlags & GMDI_GOINTOPOPUPS) &&
1271 MenuItem->hSubMenu)
1272 {
1273
1274 SubMenuObject = UserGetMenuObject(MenuItem->hSubMenu);
1275 if(!SubMenuObject || (SubMenuObject == MenuObject))
1276 break;
1277
1278 (*gismc)++;
1279 sres = IntGetMenuDefaultItem(SubMenuObject, fByPos, gmdiFlags, gismc);
1280 (*gismc)--;
1281
1282 if(sres > (UINT)-1)
1283 res = sres;
1284 }
1285
1286 break;
1287 }
1288
1289 MenuItem = MenuItem->Next;
1290 x++;
1291 }
1292
1293 return res;
1294 }
1295
1296 VOID FASTCALL
1297 co_IntInitTracking(PWINDOW_OBJECT Window, PMENU_OBJECT Menu, BOOL Popup,
1298 UINT Flags)
1299 {
1300 /* FIXME - hide caret */
1301
1302 if(!(Flags & TPM_NONOTIFY))
1303 co_IntSendMessage(Window->hSelf, WM_SETCURSOR, (WPARAM)Window->hSelf, HTCAPTION);
1304
1305 /* FIXME - send WM_SETCURSOR message */
1306
1307 if(!(Flags & TPM_NONOTIFY))
1308 co_IntSendMessage(Window->hSelf, WM_INITMENU, (WPARAM)Menu->MenuInfo.Self, 0);
1309 }
1310
1311 VOID FASTCALL
1312 co_IntExitTracking(PWINDOW_OBJECT Window, PMENU_OBJECT Menu, BOOL Popup,
1313 UINT Flags)
1314 {
1315 if(!(Flags & TPM_NONOTIFY))
1316 co_IntSendMessage(Window->hSelf, WM_EXITMENULOOP, 0 /* FIXME */, 0);
1317
1318 /* FIXME - Show caret again */
1319 }
1320
1321 INT FASTCALL
1322 IntTrackMenu(PMENU_OBJECT Menu, PWINDOW_OBJECT Window, INT x, INT y,
1323 RECT lprect)
1324 {
1325 return 0;
1326 }
1327
1328 BOOL FASTCALL
1329 co_IntTrackPopupMenu(PMENU_OBJECT Menu, PWINDOW_OBJECT Window,
1330 UINT Flags, POINT *Pos, UINT MenuPos, RECT *ExcludeRect)
1331 {
1332 co_IntInitTracking(Window, Menu, TRUE, Flags);
1333
1334 co_IntExitTracking(Window, Menu, TRUE, Flags);
1335 return FALSE;
1336 }
1337
1338 BOOL FASTCALL
1339 IntSetMenuItemRect(PMENU_OBJECT Menu, UINT Item, BOOL fByPos, RECT *rcRect)
1340 {
1341 PMENU_ITEM mi;
1342 if(IntGetMenuItemByFlag(Menu, Item, (fByPos ? MF_BYPOSITION : MF_BYCOMMAND),
1343 NULL, &mi, NULL) > -1)
1344 {
1345 mi->Rect = *rcRect;
1346 return TRUE;
1347 }
1348 return FALSE;
1349 }
1350
1351
1352 /*!
1353 * Internal function. Called when the process is destroyed to free the remaining menu handles.
1354 */
1355 BOOL FASTCALL
1356 IntCleanupMenus(struct _EPROCESS *Process, PW32PROCESS Win32Process)
1357 {
1358 PEPROCESS CurrentProcess;
1359 PLIST_ENTRY LastHead = NULL;
1360 PMENU_OBJECT MenuObject;
1361
1362 CurrentProcess = PsGetCurrentProcess();
1363 if (CurrentProcess != Process)
1364 {
1365 KeAttachProcess(&Process->Pcb);
1366 }
1367
1368 while (Win32Process->MenuListHead.Flink != &(Win32Process->MenuListHead) &&
1369 Win32Process->MenuListHead.Flink != LastHead)
1370 {
1371 LastHead = Win32Process->MenuListHead.Flink;
1372 MenuObject = CONTAINING_RECORD(Win32Process->MenuListHead.Flink, MENU_OBJECT, ListEntry);
1373
1374 IntDestroyMenuObject(MenuObject, FALSE, TRUE);
1375 }
1376
1377 if (CurrentProcess != Process)
1378 {
1379 KeDetachProcess();
1380 }
1381 return TRUE;
1382 }
1383
1384 /* FUNCTIONS *****************************************************************/
1385
1386
1387 /*
1388 * @implemented
1389 */
1390 DWORD
1391 STDCALL
1392 NtUserBuildMenuItemList(
1393 HMENU hMenu,
1394 VOID* Buffer,
1395 ULONG nBufSize,
1396 DWORD Reserved)
1397 {
1398 DWORD res = -1;
1399 PMENU_OBJECT Menu;
1400 DECLARE_RETURN(DWORD);
1401
1402 DPRINT("Enter NtUserBuildMenuItemList\n");
1403 UserEnterExclusive();
1404
1405 if(!(Menu = UserGetMenuObject(hMenu)))
1406 {
1407 RETURN( (DWORD)-1);
1408 }
1409
1410 if(Buffer)
1411 {
1412 res = IntBuildMenuItemList(Menu, Buffer, nBufSize);
1413 }
1414 else
1415 {
1416 res = Menu->MenuInfo.MenuItemCount;
1417 }
1418
1419 RETURN( res);
1420
1421 CLEANUP:
1422 DPRINT("Leave NtUserBuildMenuItemList, ret=%i\n",_ret_);
1423 UserLeave();
1424 END_CLEANUP;
1425 }
1426
1427
1428 /*
1429 * @implemented
1430 */
1431 DWORD STDCALL
1432 NtUserCheckMenuItem(
1433 HMENU hMenu,
1434 UINT uIDCheckItem,
1435 UINT uCheck)
1436 {
1437 PMENU_OBJECT Menu;
1438 DECLARE_RETURN(DWORD);
1439
1440 DPRINT("Enter NtUserCheckMenuItem\n");
1441 UserEnterExclusive();
1442
1443 if(!(Menu = UserGetMenuObject(hMenu)))
1444 {
1445 RETURN( (DWORD)-1);
1446 }
1447
1448 RETURN( IntCheckMenuItem(Menu, uIDCheckItem, uCheck));
1449
1450 CLEANUP:
1451 DPRINT("Leave NtUserCheckMenuItem, ret=%i\n",_ret_);
1452 UserLeave();
1453 END_CLEANUP;
1454 }
1455
1456
1457 HMENU FASTCALL UserCreateMenu(BOOL PopupMenu)
1458 {
1459 PWINSTATION_OBJECT WinStaObject;
1460 HANDLE Handle;
1461 NTSTATUS Status;
1462 PEPROCESS CurrentProcess = PsGetCurrentProcess();
1463
1464 if (CsrProcess != CurrentProcess)
1465 {
1466 /*
1467 * CsrProcess does not have a Win32WindowStation
1468 *
1469 */
1470
1471 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
1472 KernelMode,
1473 0,
1474 &WinStaObject);
1475
1476 if (!NT_SUCCESS(Status))
1477 {
1478 DPRINT1("Validation of window station handle (0x%X) failed\n",
1479 CurrentProcess->Win32WindowStation);
1480 SetLastNtError(Status);
1481 return (HMENU)0;
1482 }
1483 IntCreateMenu(&Handle, !PopupMenu);
1484 ObDereferenceObject(WinStaObject);
1485 }
1486 else
1487 {
1488 IntCreateMenu(&Handle, !PopupMenu);
1489 }
1490
1491 return (HMENU)Handle;
1492 }
1493
1494
1495 /*
1496 * @implemented
1497 */
1498 BOOL STDCALL
1499 NtUserDeleteMenu(
1500 HMENU hMenu,
1501 UINT uPosition,
1502 UINT uFlags)
1503 {
1504 PMENU_OBJECT Menu;
1505 DECLARE_RETURN(BOOL);
1506
1507 DPRINT("Enter NtUserDeleteMenu\n");
1508 UserEnterExclusive();
1509
1510 if(!(Menu = UserGetMenuObject(hMenu)))
1511 {
1512 RETURN( FALSE);
1513 }
1514
1515 RETURN( IntRemoveMenuItem(Menu, uPosition, uFlags, TRUE));
1516
1517 CLEANUP:
1518 DPRINT("Leave NtUserDeleteMenu, ret=%i\n",_ret_);
1519 UserLeave();
1520 END_CLEANUP;
1521 }
1522
1523
1524
1525 /*
1526 * @implemented
1527 */
1528 BOOL FASTCALL UserDestroyMenu(HMENU hMenu)
1529 {
1530 PMENU_OBJECT Menu;
1531
1532 if(!(Menu = UserGetMenuObject(hMenu)))
1533 {
1534 return FALSE;
1535 }
1536
1537 if(Menu->Process != PsGetCurrentProcess())
1538 {
1539 SetLastWin32Error(ERROR_ACCESS_DENIED);
1540 return FALSE;
1541 }
1542
1543 return IntDestroyMenuObject(Menu, FALSE, TRUE);
1544 }
1545
1546 /*
1547 * @implemented
1548 */
1549 BOOL STDCALL
1550 NtUserDestroyMenu(
1551 HMENU hMenu)
1552 {
1553 PMENU_OBJECT Menu;
1554 DECLARE_RETURN(BOOL);
1555
1556 DPRINT("Enter NtUserDestroyMenu\n");
1557 UserEnterExclusive();
1558
1559 if(!(Menu = UserGetMenuObject(hMenu)))
1560 {
1561 RETURN( FALSE);
1562 }
1563
1564 if(Menu->Process != PsGetCurrentProcess())
1565 {
1566 SetLastWin32Error(ERROR_ACCESS_DENIED);
1567 RETURN( FALSE);
1568 }
1569
1570 RETURN( IntDestroyMenuObject(Menu, FALSE, TRUE));
1571
1572 CLEANUP:
1573 DPRINT("Leave NtUserDestroyMenu, ret=%i\n",_ret_);
1574 UserLeave();
1575 END_CLEANUP;
1576 }
1577
1578
1579 /*
1580 * @implemented
1581 */
1582 UINT STDCALL
1583 NtUserEnableMenuItem(
1584 HMENU hMenu,
1585 UINT uIDEnableItem,
1586 UINT uEnable)
1587 {
1588 PMENU_OBJECT Menu;
1589 DECLARE_RETURN(UINT);
1590
1591 DPRINT("Enter NtUserEnableMenuItem\n");
1592 UserEnterExclusive();
1593
1594 if(!(Menu = UserGetMenuObject(hMenu)))
1595 {
1596 RETURN(-1);
1597 }
1598
1599 RETURN( IntEnableMenuItem(Menu, uIDEnableItem, uEnable));
1600
1601 CLEANUP:
1602 DPRINT("Leave NtUserEnableMenuItem, ret=%i\n",_ret_);
1603 UserLeave();
1604 END_CLEANUP;
1605 }
1606
1607
1608 /*
1609 * @implemented
1610 */
1611 DWORD STDCALL
1612 NtUserInsertMenuItem(
1613 HMENU hMenu,
1614 UINT uItem,
1615 BOOL fByPosition,
1616 LPCMENUITEMINFOW UnsafeItemInfo)
1617 {
1618 PMENU_OBJECT Menu;
1619 NTSTATUS Status;
1620 ROSMENUITEMINFO ItemInfo;
1621 DECLARE_RETURN(DWORD);
1622
1623 DPRINT("Enter NtUserInsertMenuItem\n");
1624 UserEnterExclusive();
1625
1626 if(!(Menu = UserGetMenuObject(hMenu)))
1627 {
1628 RETURN( FALSE);
1629 }
1630
1631 /* Try to copy the whole MENUITEMINFOW structure */
1632 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, sizeof(MENUITEMINFOW));
1633 if (NT_SUCCESS(Status))
1634 {
1635 if (sizeof(MENUITEMINFOW) != ItemInfo.cbSize
1636 && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize)
1637 {
1638 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1639 RETURN( FALSE);
1640 }
1641 RETURN( IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo));
1642 }
1643
1644 /* Try to copy without last field (not present in older versions) */
1645 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, FIELD_OFFSET(MENUITEMINFOW, hbmpItem));
1646 if (NT_SUCCESS(Status))
1647 {
1648 if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize)
1649 {
1650 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1651 RETURN( FALSE);
1652 }
1653 ItemInfo.hbmpItem = (HBITMAP)0;
1654 RETURN( IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo));
1655 }
1656
1657 SetLastNtError(Status);
1658 RETURN( FALSE);
1659
1660 CLEANUP:
1661 DPRINT("Leave NtUserInsertMenuItem, ret=%i\n",_ret_);
1662 UserLeave();
1663 END_CLEANUP;
1664 }
1665
1666
1667 /*
1668 * @unimplemented
1669 */
1670 BOOL STDCALL
1671 NtUserEndMenu(VOID)
1672 {
1673 UNIMPLEMENTED
1674
1675 return 0;
1676 }
1677
1678
1679 /*
1680 * @implemented
1681 */
1682 UINT STDCALL
1683 NtUserGetMenuDefaultItem(
1684 HMENU hMenu,
1685 UINT fByPos,
1686 UINT gmdiFlags)
1687 {
1688 PMENU_OBJECT Menu;
1689 DWORD gismc = 0;
1690 DECLARE_RETURN(UINT);
1691
1692 DPRINT("Enter NtUserGetMenuDefaultItem\n");
1693 UserEnterExclusive();
1694
1695 if(!(Menu = UserGetMenuObject(hMenu)))
1696 {
1697 RETURN(-1);
1698 }
1699
1700 RETURN( IntGetMenuDefaultItem(Menu, fByPos, gmdiFlags, &gismc));
1701
1702 CLEANUP:
1703 DPRINT("Leave NtUserGetMenuDefaultItem, ret=%i\n",_ret_);
1704 UserLeave();
1705 END_CLEANUP;
1706 }
1707
1708
1709 /*
1710 * @implemented
1711 */
1712 BOOL STDCALL
1713 NtUserGetMenuBarInfo(
1714 HWND hwnd,
1715 LONG idObject,
1716 LONG idItem,
1717 PMENUBARINFO pmbi)
1718 {
1719 BOOL Res = TRUE;
1720 PMENU_OBJECT MenuObject;
1721 PMENU_ITEM mi;
1722 PWINDOW_OBJECT WindowObject;
1723 HMENU hMenu;
1724 POINT Offset;
1725 RECT Rect;
1726 MENUBARINFO kmbi;
1727 DECLARE_RETURN(BOOL);
1728
1729 DPRINT("Enter NtUserGetMenuBarInfo\n");
1730 UserEnterShared();
1731
1732 if (!(WindowObject = UserGetWindowObject(hwnd)))
1733 {
1734 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1735 RETURN(FALSE);
1736 }
1737
1738 hMenu = (HMENU)WindowObject->Wnd->IDMenu;
1739
1740 if (!(MenuObject = UserGetMenuObject(hMenu)))
1741 {
1742 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1743 RETURN(FALSE);
1744 }
1745
1746 if (pmbi->cbSize != sizeof(MENUBARINFO))
1747 {
1748 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1749 RETURN(FALSE);
1750 }
1751
1752 kmbi.cbSize = sizeof(MENUBARINFO);
1753 kmbi.fBarFocused = FALSE;
1754 kmbi.fFocused = FALSE;
1755 kmbi.hwndMenu = NULL;
1756
1757 switch (idObject)
1758 {
1759 case OBJID_MENU:
1760 {
1761 PMENU_OBJECT SubMenuObject;
1762 kmbi.hMenu = hMenu;
1763 if (idItem) /* Non-Zero-Based. */
1764 {
1765 if (IntGetMenuItemByFlag(MenuObject, idItem-1, MF_BYPOSITION, NULL, &mi, NULL) > -1)
1766 kmbi.rcBar = mi->Rect;
1767 else
1768 {
1769 Res = FALSE;
1770 break;
1771 }
1772 }
1773 else
1774 {
1775 /* If items is zero we assume info for the menu itself. */
1776 if (!(IntGetClientOrigin(WindowObject, &Offset)))
1777 {
1778 Res = FALSE;
1779 break;
1780 }
1781 Rect.left = Offset.x;
1782 Rect.right = Offset.x + MenuObject->MenuInfo.Width;
1783 Rect.top = Offset.y;
1784 Rect.bottom = Offset.y + MenuObject->MenuInfo.Height;
1785 kmbi.rcBar = Rect;
1786 DPRINT("Rect top = %d bottom = %d left = %d right = %d \n",
1787 Rect.top, Rect.bottom, Rect.left, Rect.right);
1788 }
1789 if (idItem)
1790 {
1791 if (idItem-1 == MenuObject->MenuInfo.FocusedItem)
1792 kmbi.fFocused = TRUE;
1793 }
1794 if (MenuObject->MenuInfo.FocusedItem != NO_SELECTED_ITEM)
1795 kmbi.fBarFocused = TRUE;
1796 SubMenuObject = UserGetMenuObject(MenuObject->MenuItemList->hSubMenu);
1797 if(SubMenuObject) kmbi.hwndMenu = SubMenuObject->MenuInfo.Wnd;
1798 DPRINT("OBJID_MENU, idItem = %d\n",idItem);
1799 break;
1800 }
1801 case OBJID_CLIENT:
1802 {
1803 PMENU_OBJECT SubMenuObject, XSubMenuObject;
1804 SubMenuObject = UserGetMenuObject(MenuObject->MenuItemList->hSubMenu);
1805 if(SubMenuObject) kmbi.hMenu = SubMenuObject->MenuInfo.Self;
1806 else
1807 {
1808 Res = FALSE;
1809 DPRINT1("OBJID_CLIENT, No SubMenu!\n");
1810 break;
1811 }
1812 if (idItem)
1813 {
1814 if (IntGetMenuItemByFlag(SubMenuObject, idItem-1, MF_BYPOSITION, NULL, &mi, NULL) > -1)
1815 kmbi.rcBar = mi->Rect;
1816 else
1817 {
1818 Res = FALSE;
1819 break;
1820 }
1821 }
1822 else
1823 {
1824 PWINDOW_OBJECT SubWinObj;
1825 if (!(SubWinObj = UserGetWindowObject(SubMenuObject->MenuInfo.Wnd)))
1826 {
1827 Res = FALSE;
1828 break;
1829 }
1830 if (!(IntGetClientOrigin(SubWinObj, &Offset)))
1831 {
1832 Res = FALSE;
1833 break;
1834 }
1835 Rect.left = Offset.x;
1836 Rect.right = Offset.x + SubMenuObject->MenuInfo.Width;
1837 Rect.top = Offset.y;
1838 Rect.bottom = Offset.y + SubMenuObject->MenuInfo.Height;
1839 kmbi.rcBar = Rect;
1840 }
1841 if (idItem)
1842 {
1843 if (idItem-1 == SubMenuObject->MenuInfo.FocusedItem)
1844 kmbi.fFocused = TRUE;
1845 }
1846 if (SubMenuObject->MenuInfo.FocusedItem != NO_SELECTED_ITEM)
1847 kmbi.fBarFocused = TRUE;
1848 XSubMenuObject = UserGetMenuObject(SubMenuObject->MenuItemList->hSubMenu);
1849 if (XSubMenuObject) kmbi.hwndMenu = XSubMenuObject->MenuInfo.Wnd;
1850 DPRINT("OBJID_CLIENT, idItem = %d\n",idItem);
1851 break;
1852 }
1853 case OBJID_SYSMENU:
1854 {
1855 PMENU_OBJECT SysMenuObject, SubMenuObject;
1856 if(!(SysMenuObject = IntGetSystemMenu(WindowObject, FALSE, FALSE)))
1857 {
1858 Res = FALSE;
1859 break;
1860 }
1861 kmbi.hMenu = SysMenuObject->MenuInfo.Self;
1862 if (idItem)
1863 {
1864 if (IntGetMenuItemByFlag(SysMenuObject, idItem-1, MF_BYPOSITION, NULL, &mi, NULL) > -1)
1865 kmbi.rcBar = mi->Rect;
1866 else
1867 {
1868 Res = FALSE;
1869 break;
1870 }
1871 }
1872 else
1873 {
1874 PWINDOW_OBJECT SysWinObj;
1875 if (!(SysWinObj = UserGetWindowObject(SysMenuObject->MenuInfo.Wnd)))
1876 {
1877 Res = FALSE;
1878 break;
1879 }
1880 if (!(IntGetClientOrigin(SysWinObj, &Offset)))
1881 {
1882 Res = FALSE;
1883 break;
1884 }
1885 Rect.left = Offset.x;
1886 Rect.right = Offset.x + SysMenuObject->MenuInfo.Width;
1887 Rect.top = Offset.y;
1888 Rect.bottom = Offset.y + SysMenuObject->MenuInfo.Height;
1889 kmbi.rcBar = Rect;
1890 }
1891 if (idItem)
1892 {
1893 if (idItem-1 == SysMenuObject->MenuInfo.FocusedItem)
1894 kmbi.fFocused = TRUE;
1895 }
1896 if (SysMenuObject->MenuInfo.FocusedItem != NO_SELECTED_ITEM)
1897 kmbi.fBarFocused = TRUE;
1898 SubMenuObject = UserGetMenuObject(SysMenuObject->MenuItemList->hSubMenu);
1899 if(SubMenuObject) kmbi.hwndMenu = SubMenuObject->MenuInfo.Wnd;
1900 DPRINT("OBJID_SYSMENU, idItem = %d\n",idItem);
1901 break;
1902 }
1903 default:
1904 Res = FALSE;
1905 DPRINT1("Unknown idObject = %d, idItem = %d\n",idObject,idItem);
1906 }
1907 if (Res)
1908 {
1909 NTSTATUS Status = MmCopyToCaller(pmbi, &kmbi, sizeof(MENUBARINFO));
1910 if (! NT_SUCCESS(Status))
1911 {
1912 SetLastNtError(Status);
1913 RETURN(FALSE);
1914 }
1915 }
1916 RETURN(Res);
1917
1918 CLEANUP:
1919 DPRINT("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_);
1920 UserLeave();
1921 END_CLEANUP;
1922 }
1923
1924
1925 /*
1926 * @unimplemented
1927 */
1928 UINT STDCALL
1929 NtUserGetMenuIndex(
1930 HMENU hMenu,
1931 UINT wID)
1932 {
1933 UNIMPLEMENTED
1934
1935 return 0;
1936 }
1937
1938
1939 /*
1940 * @implemented
1941 */
1942 BOOL STDCALL
1943 NtUserGetMenuItemRect(
1944 HWND hWnd,
1945 HMENU hMenu,
1946 UINT uItem,
1947 LPRECT lprcItem)
1948 {
1949 ROSMENUINFO mi;
1950 PWINDOW_OBJECT ReferenceWnd;
1951 LONG XMove, YMove;
1952 RECT Rect;
1953 NTSTATUS Status;
1954 PMENU_OBJECT Menu;
1955 PMENU_ITEM MenuItem;
1956 DECLARE_RETURN(BOOL);
1957
1958 DPRINT("Enter NtUserGetMenuItemRect\n");
1959 UserEnterShared();
1960
1961 if (!(Menu = UserGetMenuObject(hMenu)))
1962 {
1963 RETURN(FALSE);
1964 }
1965
1966 if (IntGetMenuItemByFlag(Menu, uItem, MF_BYPOSITION, NULL, &MenuItem, NULL) > -1)
1967 Rect = MenuItem->Rect;
1968 else
1969 RETURN(FALSE);
1970
1971 if(!hWnd)
1972 {
1973 if(!UserMenuInfo(Menu, &mi, FALSE))
1974 RETURN( FALSE);
1975 if(mi.Wnd == 0)
1976 RETURN( FALSE);
1977 }
1978
1979 if (lprcItem == NULL) RETURN( FALSE);
1980
1981 if (!(ReferenceWnd = UserGetWindowObject(mi.Wnd))) RETURN( FALSE);
1982
1983 if(MenuItem->fType & MF_POPUP)
1984 {
1985 XMove = ReferenceWnd->Wnd->ClientRect.left;
1986 YMove = ReferenceWnd->Wnd->ClientRect.top;
1987 }
1988 else
1989 {
1990 XMove = ReferenceWnd->Wnd->WindowRect.left;
1991 YMove = ReferenceWnd->Wnd->WindowRect.top;
1992 }
1993
1994 Rect.left += XMove;
1995 Rect.top += YMove;
1996 Rect.right += XMove;
1997 Rect.bottom += YMove;
1998
1999 Status = MmCopyToCaller(lprcItem, &Rect, sizeof(RECT));
2000 if (! NT_SUCCESS(Status))
2001 {
2002 SetLastNtError(Status);
2003 RETURN( FALSE);
2004 }
2005 RETURN( TRUE);
2006
2007 CLEANUP:
2008 DPRINT("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_);
2009 UserLeave();
2010 END_CLEANUP;
2011 }
2012
2013
2014 /*
2015 * @implemented
2016 */
2017 BOOL STDCALL
2018 NtUserHiliteMenuItem(
2019 HWND hWnd,
2020 HMENU hMenu,
2021 UINT uItemHilite,
2022 UINT uHilite)
2023 {
2024 PMENU_OBJECT Menu;
2025 PWINDOW_OBJECT Window;
2026 DECLARE_RETURN(BOOLEAN);
2027
2028 DPRINT("Enter NtUserHiliteMenuItem\n");
2029 UserEnterExclusive();
2030
2031 if(!(Window = UserGetWindowObject(hWnd)))
2032 {
2033 RETURN(FALSE);
2034 }
2035
2036 if(!(Menu = UserGetMenuObject(hMenu)))
2037 {
2038 RETURN(FALSE);
2039 }
2040
2041 if(Window->Wnd->IDMenu == (UINT)hMenu)
2042 {
2043 RETURN( IntHiliteMenuItem(Window, Menu, uItemHilite, uHilite));
2044 }
2045
2046 RETURN(FALSE);
2047
2048 CLEANUP:
2049 DPRINT("Leave NtUserHiliteMenuItem, ret=%i\n",_ret_);
2050 UserLeave();
2051 END_CLEANUP;
2052 }
2053
2054
2055 static
2056 BOOL FASTCALL
2057 UserMenuInfo(
2058 PMENU_OBJECT Menu,
2059 PROSMENUINFO UnsafeMenuInfo,
2060 BOOL SetOrGet)
2061 {
2062 BOOL Res;
2063 DWORD Size;
2064 NTSTATUS Status;
2065 ROSMENUINFO MenuInfo;
2066
2067 Status = MmCopyFromCaller(&Size, &UnsafeMenuInfo->cbSize, sizeof(DWORD));
2068 if (! NT_SUCCESS(Status))
2069 {
2070 SetLastNtError(Status);
2071 return( FALSE);
2072 }
2073 if(Size < sizeof(MENUINFO) || sizeof(ROSMENUINFO) < Size)
2074 {
2075 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2076 return( FALSE);
2077 }
2078 Status = MmCopyFromCaller(&MenuInfo, UnsafeMenuInfo, Size);
2079 if (! NT_SUCCESS(Status))
2080 {
2081 SetLastNtError(Status);
2082 return( FALSE);
2083 }
2084
2085 if(SetOrGet)
2086 {
2087 /* Set MenuInfo */
2088 Res = IntSetMenuInfo(Menu, &MenuInfo);
2089 }
2090 else
2091 {
2092 /* Get MenuInfo */
2093 Res = IntGetMenuInfo(Menu, &MenuInfo);
2094 if (Res)
2095 {
2096 Status = MmCopyToCaller(UnsafeMenuInfo, &MenuInfo, Size);
2097 if (! NT_SUCCESS(Status))
2098 {
2099 SetLastNtError(Status);
2100 return( FALSE);
2101 }
2102 }
2103 }
2104
2105 return( Res);
2106 }
2107
2108
2109
2110
2111
2112 /*
2113 * @implemented
2114 */
2115 BOOL
2116 STDCALL
2117 NtUserMenuInfo(
2118 HMENU hMenu,
2119 PROSMENUINFO UnsafeMenuInfo,
2120 BOOL SetOrGet)
2121 {
2122 PMENU_OBJECT Menu;
2123 DECLARE_RETURN(BOOL);
2124
2125 DPRINT("Enter NtUserMenuInfo\n");
2126 UserEnterShared();
2127
2128 if (!(Menu = UserGetMenuObject(hMenu)))
2129 {
2130 RETURN(FALSE);
2131 }
2132
2133 RETURN(UserMenuInfo(Menu, UnsafeMenuInfo, SetOrGet));
2134
2135 CLEANUP:
2136 DPRINT("Leave NtUserMenuInfo, ret=%i\n",_ret_);
2137 UserLeave();
2138 END_CLEANUP;
2139 }
2140
2141
2142
2143 /*
2144 * @implemented
2145 */
2146 int STDCALL
2147 NtUserMenuItemFromPoint(
2148 HWND hWnd,
2149 HMENU hMenu,
2150 DWORD X,
2151 DWORD Y)
2152 {
2153 PMENU_OBJECT Menu;
2154 PWINDOW_OBJECT Window = NULL;
2155 PMENU_ITEM mi;
2156 int i;
2157 DECLARE_RETURN(int);
2158
2159 DPRINT("Enter NtUserMenuItemFromPoint\n");
2160 UserEnterExclusive();
2161
2162 if (!(Menu = UserGetMenuObject(hMenu)))
2163 {
2164 RETURN( -1);
2165 }
2166
2167 if (!(Window = UserGetWindowObject(Menu->MenuInfo.Wnd)))
2168 {
2169 RETURN( -1);
2170 }
2171
2172 X -= Window->Wnd->WindowRect.left;
2173 Y -= Window->Wnd->WindowRect.top;
2174
2175 mi = Menu->MenuItemList;
2176 for (i = 0; NULL != mi; i++)
2177 {
2178 if (InRect(mi->Rect, X, Y))
2179 {
2180 break;
2181 }
2182 mi = mi->Next;
2183 }
2184
2185 RETURN( (mi ? i : NO_SELECTED_ITEM));
2186
2187 CLEANUP:
2188 DPRINT("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_);
2189 UserLeave();
2190 END_CLEANUP;
2191 }
2192
2193
2194
2195 static
2196 BOOL FASTCALL
2197 UserMenuItemInfo(
2198 PMENU_OBJECT Menu,
2199 UINT Item,
2200 BOOL ByPosition,
2201 PROSMENUITEMINFO UnsafeItemInfo,
2202 BOOL SetOrGet)
2203 {
2204 PMENU_ITEM MenuItem;
2205 ROSMENUITEMINFO ItemInfo;
2206 NTSTATUS Status;
2207 UINT Size;
2208 BOOL Ret;
2209
2210 Status = MmCopyFromCaller(&Size, &UnsafeItemInfo->cbSize, sizeof(UINT));
2211 if (! NT_SUCCESS(Status))
2212 {
2213 SetLastNtError(Status);
2214 return( FALSE);
2215 }
2216 if (sizeof(MENUITEMINFOW) != Size
2217 && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != Size
2218 && sizeof(ROSMENUITEMINFO) != Size)
2219 {
2220 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2221 return( FALSE);
2222 }
2223 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, Size);
2224 if (! NT_SUCCESS(Status))
2225 {
2226 SetLastNtError(Status);
2227 return( FALSE);
2228 }
2229 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
2230 set/get hbmpItem */
2231 if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) == Size
2232 && 0 != (ItemInfo.fMask & MIIM_BITMAP))
2233 {
2234 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2235 return( FALSE);
2236 }
2237
2238 if (IntGetMenuItemByFlag(Menu, Item,
2239 (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND),
2240 NULL, &MenuItem, NULL) < 0)
2241 {
2242 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2243 return( FALSE);
2244 }
2245
2246 if (SetOrGet)
2247 {
2248 Ret = IntSetMenuItemInfo(Menu, MenuItem, &ItemInfo);
2249 }
2250 else
2251 {
2252 Ret = IntGetMenuItemInfo(Menu, MenuItem, &ItemInfo);
2253 if (Ret)
2254 {
2255 Status = MmCopyToCaller(UnsafeItemInfo, &ItemInfo, Size);
2256 if (! NT_SUCCESS(Status))
2257 {
2258 SetLastNtError(Status);
2259 return( FALSE);
2260 }
2261 }
2262 }
2263
2264 return( Ret);
2265 }
2266
2267
2268
2269 /*
2270 * @implemented
2271 */
2272 BOOL
2273 STDCALL
2274 NtUserMenuItemInfo(
2275 HMENU hMenu,
2276 UINT Item,
2277 BOOL ByPosition,
2278 PROSMENUITEMINFO UnsafeItemInfo,
2279 BOOL SetOrGet)
2280 {
2281 PMENU_OBJECT Menu;
2282 DECLARE_RETURN(BOOL);
2283
2284 DPRINT("Enter NtUserMenuItemInfo\n");
2285 UserEnterExclusive();
2286
2287 if (!(Menu = UserGetMenuObject(hMenu)))
2288 {
2289 RETURN(FALSE);
2290 }
2291
2292 RETURN( UserMenuItemInfo(Menu, Item, ByPosition, UnsafeItemInfo, SetOrGet));
2293
2294 CLEANUP:
2295 DPRINT("Leave NtUserMenuItemInfo, ret=%i\n",_ret_);
2296 UserLeave();
2297 END_CLEANUP;
2298
2299 }
2300
2301
2302 /*
2303 * @implemented
2304 */
2305 BOOL STDCALL
2306 NtUserRemoveMenu(
2307 HMENU hMenu,
2308 UINT uPosition,
2309 UINT uFlags)
2310 {
2311 PMENU_OBJECT Menu;
2312 DECLARE_RETURN(BOOL);
2313
2314 DPRINT("Enter NtUserRemoveMenu\n");
2315 UserEnterExclusive();
2316
2317 if(!(Menu = UserGetMenuObject(hMenu)))
2318 {
2319 RETURN( FALSE);
2320 }
2321
2322 RETURN(IntRemoveMenuItem(Menu, uPosition, uFlags, FALSE));
2323
2324 CLEANUP:
2325 DPRINT("Leave NtUserRemoveMenu, ret=%i\n",_ret_);
2326 UserLeave();
2327 END_CLEANUP;
2328
2329 }
2330
2331
2332 /*
2333 * @implemented
2334 */
2335 BOOL STDCALL
2336 NtUserSetMenuContextHelpId(
2337 HMENU hMenu,
2338 DWORD dwContextHelpId)
2339 {
2340 PMENU_OBJECT Menu;
2341 DECLARE_RETURN(BOOL);
2342
2343 DPRINT("Enter NtUserSetMenuContextHelpId\n");
2344 UserEnterExclusive();
2345
2346 if(!(Menu = UserGetMenuObject(hMenu)))
2347 {
2348 RETURN( FALSE);
2349 }
2350
2351 RETURN(IntSetMenuContextHelpId(Menu, dwContextHelpId));
2352
2353 CLEANUP:
2354 DPRINT("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_);
2355 UserLeave();
2356 END_CLEANUP;
2357 }
2358
2359
2360
2361 /*
2362 * @implemented
2363 */
2364 BOOL STDCALL
2365 NtUserSetMenuDefaultItem(
2366 HMENU hMenu,
2367 UINT uItem,
2368 UINT fByPos)
2369 {
2370 PMENU_OBJECT Menu;
2371 DECLARE_RETURN(BOOL);
2372
2373 DPRINT("Enter NtUserSetMenuDefaultItem\n");
2374 UserEnterExclusive();
2375
2376 if(!(Menu = UserGetMenuObject(hMenu)))
2377 {
2378 RETURN( FALSE);
2379 }
2380
2381 RETURN( UserSetMenuDefaultItem(Menu, uItem, fByPos));
2382
2383 CLEANUP:
2384 DPRINT("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_);
2385 UserLeave();
2386 END_CLEANUP;
2387 }
2388
2389
2390 /*
2391 * @implemented
2392 */
2393 BOOL STDCALL
2394 NtUserSetMenuFlagRtoL(
2395 HMENU hMenu)
2396 {
2397 PMENU_OBJECT Menu;
2398 DECLARE_RETURN(BOOL);
2399
2400 DPRINT("Enter NtUserSetMenuFlagRtoL\n");
2401 UserEnterExclusive();
2402
2403 if(!(Menu = UserGetMenuObject(hMenu)))
2404 {
2405 RETURN( FALSE);
2406 }
2407
2408 RETURN(IntSetMenuFlagRtoL(Menu));
2409
2410 CLEANUP:
2411 DPRINT("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_);
2412 UserLeave();
2413 END_CLEANUP;
2414 }
2415
2416
2417 /*
2418 * @unimplemented
2419 */
2420 DWORD STDCALL
2421 NtUserThunkedMenuInfo(
2422 HMENU hMenu,
2423 LPCMENUINFO lpcmi)
2424 {
2425 UNIMPLEMENTED
2426 /* This function seems just to call SetMenuInfo() */
2427 return 0;
2428 }
2429
2430
2431 /*
2432 * @unimplemented
2433 */
2434 DWORD STDCALL
2435 NtUserThunkedMenuItemInfo(
2436 HMENU hMenu,
2437 UINT uItem,
2438 BOOL fByPosition,
2439 BOOL bInsert,
2440 LPMENUITEMINFOW lpmii,
2441 PUNICODE_STRING lpszCaption)
2442 {
2443 UNIMPLEMENTED
2444 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
2445 if bInsert == TRUE call NtUserInsertMenuItem() else NtUserSetMenuItemInfo()
2446 */
2447 return 0;
2448 }
2449
2450
2451 /*
2452 * @implemented
2453 */
2454 /* NOTE: unused function */
2455 BOOL STDCALL
2456 NtUserTrackPopupMenuEx(
2457 HMENU hMenu,
2458 UINT fuFlags,
2459 int x,
2460 int y,
2461 HWND hWnd,
2462 LPTPMPARAMS lptpm)
2463 {
2464 UNIMPLEMENTED
2465
2466 return FALSE;
2467 }
2468
2469
2470 /* EOF */