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