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