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