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