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