Implemtened : NtUserGetTitleBarInfo
[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 = NULL;
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 (SubMenu == NULL)
955 {
956 /* default to last position of menu */
957 SubMenu = MenuObject;
958 pos = MenuObject->MenuInfo.MenuItemCount;
959 }
960
961
962 if (pos < -1)
963 {
964 pos = -1;
965 }
966
967 MenuItem = ExAllocatePoolWithTag(PagedPool, sizeof(MENU_ITEM), TAG_MENUITEM);
968 if (NULL == MenuItem)
969 {
970 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
971 return FALSE;
972 }
973
974 MenuItem->fType = MFT_STRING;
975 MenuItem->fState = MFS_ENABLED | MFS_UNCHECKED;
976 MenuItem->wID = 0;
977 MenuItem->hSubMenu = (HMENU)0;
978 MenuItem->hbmpChecked = (HBITMAP)0;
979 MenuItem->hbmpUnchecked = (HBITMAP)0;
980 MenuItem->dwItemData = 0;
981 RtlInitUnicodeString(&MenuItem->Text, NULL);
982 MenuItem->hbmpItem = (HBITMAP)0;
983
984 if(!IntSetMenuItemInfo(SubMenu, MenuItem, ItemInfo))
985 {
986 ExFreePool(MenuItem);
987 return FALSE;
988 }
989
990 /* Force size recalculation! */
991 MenuObject->MenuInfo.Height = 0;
992
993 pos = IntInsertMenuItemToList(SubMenu, MenuItem, pos);
994
995 DPRINT("IntInsertMenuItemToList = %i\n", pos);
996
997 return (pos >= 0);
998 }
999
1000 UINT FASTCALL
1001 IntEnableMenuItem(PMENU_OBJECT MenuObject, UINT uIDEnableItem, UINT uEnable)
1002 {
1003 PMENU_ITEM MenuItem;
1004 UINT res = IntGetMenuItemByFlag(MenuObject, uIDEnableItem, uEnable, NULL, &MenuItem, NULL);
1005 if(!MenuItem || (res == (UINT)-1))
1006 {
1007 return (UINT)-1;
1008 }
1009
1010 res = MenuItem->fState & (MF_GRAYED | MF_DISABLED);
1011
1012 if(uEnable & MF_DISABLED)
1013 {
1014 if(!(MenuItem->fState & MF_DISABLED))
1015 MenuItem->fState |= MF_DISABLED;
1016 if(uEnable & MF_GRAYED)
1017 {
1018 if(!(MenuItem->fState & MF_GRAYED))
1019 MenuItem->fState |= MF_GRAYED;
1020 }
1021 }
1022 else
1023 {
1024 if(uEnable & MF_GRAYED)
1025 {
1026 if(!(MenuItem->fState & MF_GRAYED))
1027 MenuItem->fState |= MF_GRAYED;
1028 if(!(MenuItem->fState & MF_DISABLED))
1029 MenuItem->fState |= MF_DISABLED;
1030 }
1031 else
1032 {
1033 if(MenuItem->fState & MF_DISABLED)
1034 MenuItem->fState ^= MF_DISABLED;
1035 if(MenuItem->fState & MF_GRAYED)
1036 MenuItem->fState ^= MF_GRAYED;
1037 }
1038 }
1039
1040 return res;
1041 }
1042
1043
1044 DWORD FASTCALL
1045 IntBuildMenuItemList(PMENU_OBJECT MenuObject, PVOID Buffer, ULONG nMax)
1046 {
1047 DWORD res = 0;
1048 UINT sz;
1049 ROSMENUITEMINFO mii;
1050 PVOID Buf;
1051 PMENU_ITEM CurItem = MenuObject->MenuItemList;
1052 PWCHAR StrOut;
1053 NTSTATUS Status;
1054 WCHAR NulByte;
1055
1056 if (0 != nMax)
1057 {
1058 if (nMax < MenuObject->MenuInfo.MenuItemCount * sizeof(ROSMENUITEMINFO))
1059 {
1060 return 0;
1061 }
1062 StrOut = (PWCHAR)((char *) Buffer + MenuObject->MenuInfo.MenuItemCount
1063 * sizeof(ROSMENUITEMINFO));
1064 nMax -= MenuObject->MenuInfo.MenuItemCount * sizeof(ROSMENUITEMINFO);
1065 sz = sizeof(ROSMENUITEMINFO);
1066 Buf = Buffer;
1067 mii.cbSize = sizeof(ROSMENUITEMINFO);
1068 mii.fMask = 0;
1069 NulByte = L'\0';
1070
1071 while (NULL != CurItem)
1072 {
1073 mii.cch = CurItem->Text.Length / sizeof(WCHAR);
1074 mii.dwItemData = CurItem->dwItemData;
1075 if (0 != CurItem->Text.Length)
1076 {
1077 mii.dwTypeData = StrOut;
1078 }
1079 else
1080 {
1081 mii.dwTypeData = NULL;
1082 }
1083 mii.fState = CurItem->fState;
1084 mii.fType = CurItem->fType;
1085 mii.hbmpChecked = CurItem->hbmpChecked;
1086 mii.hbmpItem = CurItem->hbmpItem;
1087 mii.hbmpUnchecked = CurItem->hbmpUnchecked;
1088 mii.hSubMenu = CurItem->hSubMenu;
1089 mii.Rect = CurItem->Rect;
1090 mii.XTab = CurItem->XTab;
1091 mii.Text = CurItem->Text.Buffer;
1092
1093 Status = MmCopyToCaller(Buf, &mii, sizeof(ROSMENUITEMINFO));
1094 if (! NT_SUCCESS(Status))
1095 {
1096 SetLastNtError(Status);
1097 return 0;
1098 }
1099 Buf = (PVOID)((ULONG_PTR)Buf + sizeof(ROSMENUITEMINFO));
1100
1101 if (0 != CurItem->Text.Length
1102 && (nMax >= CurItem->Text.Length + sizeof(WCHAR)))
1103 {
1104 /* copy string */
1105 Status = MmCopyToCaller(StrOut, CurItem->Text.Buffer,
1106 CurItem->Text.Length);
1107 if (! NT_SUCCESS(Status))
1108 {
1109 SetLastNtError(Status);
1110 return 0;
1111 }
1112 StrOut += CurItem->Text.Length / sizeof(WCHAR);
1113 Status = MmCopyToCaller(StrOut, &NulByte, sizeof(WCHAR));
1114 if (! NT_SUCCESS(Status))
1115 {
1116 SetLastNtError(Status);
1117 return 0;
1118 }
1119 StrOut++;
1120 nMax -= CurItem->Text.Length + sizeof(WCHAR);
1121 }
1122 else if (0 != CurItem->Text.Length)
1123 {
1124 break;
1125 }
1126
1127 CurItem = CurItem->Next;
1128 res++;
1129 }
1130 }
1131 else
1132 {
1133 while (NULL != CurItem)
1134 {
1135 res += sizeof(ROSMENUITEMINFO) + CurItem->Text.Length + sizeof(WCHAR);
1136 CurItem = CurItem->Next;
1137 }
1138 }
1139
1140 return res;
1141 }
1142
1143
1144 DWORD FASTCALL
1145 IntCheckMenuItem(PMENU_OBJECT MenuObject, UINT uIDCheckItem, UINT uCheck)
1146 {
1147 PMENU_ITEM MenuItem;
1148 int res = -1;
1149
1150 if((IntGetMenuItemByFlag(MenuObject, uIDCheckItem, uCheck, NULL, &MenuItem, NULL) < 0) || !MenuItem)
1151 {
1152 return -1;
1153 }
1154
1155 res = (DWORD)(MenuItem->fState & MF_CHECKED);
1156 if(uCheck & MF_CHECKED)
1157 {
1158 if(!(MenuItem->fState & MF_CHECKED))
1159 MenuItem->fState |= MF_CHECKED;
1160 }
1161 else
1162 {
1163 if(MenuItem->fState & MF_CHECKED)
1164 MenuItem->fState ^= MF_CHECKED;
1165 }
1166
1167 return (DWORD)res;
1168 }
1169
1170 BOOL FASTCALL
1171 IntHiliteMenuItem(PWINDOW_OBJECT WindowObject, PMENU_OBJECT MenuObject,
1172 UINT uItemHilite, UINT uHilite)
1173 {
1174 PMENU_ITEM MenuItem;
1175 BOOL res = IntGetMenuItemByFlag(MenuObject, uItemHilite, uHilite, NULL, &MenuItem, NULL);
1176 if(!MenuItem || !res)
1177 {
1178 return FALSE;
1179 }
1180
1181 if(uHilite & MF_HILITE)
1182 {
1183 if(!(MenuItem->fState & MF_HILITE))
1184 MenuItem->fState |= MF_HILITE;
1185 }
1186 else
1187 {
1188 if(MenuItem->fState & MF_HILITE)
1189 MenuItem->fState ^= MF_HILITE;
1190 }
1191
1192 /* FIXME - update the window's menu */
1193
1194 return TRUE;
1195 }
1196
1197 BOOL FASTCALL
1198 UserSetMenuDefaultItem(PMENU_OBJECT MenuObject, UINT uItem, UINT fByPos)
1199 {
1200 BOOL ret = FALSE;
1201 PMENU_ITEM MenuItem = MenuObject->MenuItemList;
1202
1203 if(uItem == (UINT)-1)
1204 {
1205 while(MenuItem)
1206 {
1207 if(MenuItem->fState & MFS_DEFAULT)
1208 MenuItem->fState ^= MFS_DEFAULT;
1209 MenuItem = MenuItem->Next;
1210 }
1211 return TRUE;
1212 }
1213
1214 if(fByPos)
1215 {
1216 UINT pos = 0;
1217 while(MenuItem)
1218 {
1219 if(pos == uItem)
1220 {
1221 if(!(MenuItem->fState & MFS_DEFAULT))
1222 MenuItem->fState |= MFS_DEFAULT;
1223 ret = TRUE;
1224 }
1225 else
1226 {
1227 if(MenuItem->fState & MFS_DEFAULT)
1228 MenuItem->fState ^= MFS_DEFAULT;
1229 }
1230 pos++;
1231 MenuItem = MenuItem->Next;
1232 }
1233 }
1234 else
1235 {
1236 while(MenuItem)
1237 {
1238 if(!ret && (MenuItem->wID == uItem))
1239 {
1240 if(!(MenuItem->fState & MFS_DEFAULT))
1241 MenuItem->fState |= MFS_DEFAULT;
1242 ret = TRUE;
1243 }
1244 else
1245 {
1246 if(MenuItem->fState & MFS_DEFAULT)
1247 MenuItem->fState ^= MFS_DEFAULT;
1248 }
1249 MenuItem = MenuItem->Next;
1250 }
1251 }
1252 return ret;
1253 }
1254
1255
1256 UINT FASTCALL
1257 IntGetMenuDefaultItem(PMENU_OBJECT MenuObject, UINT fByPos, UINT gmdiFlags,
1258 DWORD *gismc)
1259 {
1260 UINT x = 0;
1261 UINT res = -1;
1262 UINT sres;
1263 PMENU_OBJECT SubMenuObject;
1264 PMENU_ITEM MenuItem = MenuObject->MenuItemList;
1265
1266 while(MenuItem)
1267 {
1268 if(MenuItem->fState & MFS_DEFAULT)
1269 {
1270
1271 if(!(gmdiFlags & GMDI_USEDISABLED) && (MenuItem->fState & MFS_DISABLED))
1272 break;
1273
1274 if(fByPos)
1275 res = x;
1276 else
1277 res = MenuItem->wID;
1278
1279 if((*gismc < MAX_GOINTOSUBMENU) && (gmdiFlags & GMDI_GOINTOPOPUPS) &&
1280 MenuItem->hSubMenu)
1281 {
1282
1283 SubMenuObject = UserGetMenuObject(MenuItem->hSubMenu);
1284 if(!SubMenuObject || (SubMenuObject == MenuObject))
1285 break;
1286
1287 (*gismc)++;
1288 sres = IntGetMenuDefaultItem(SubMenuObject, fByPos, gmdiFlags, gismc);
1289 (*gismc)--;
1290
1291 if(sres > (UINT)-1)
1292 res = sres;
1293 }
1294
1295 break;
1296 }
1297
1298 MenuItem = MenuItem->Next;
1299 x++;
1300 }
1301
1302 return res;
1303 }
1304
1305 VOID FASTCALL
1306 co_IntInitTracking(PWINDOW_OBJECT Window, PMENU_OBJECT Menu, BOOL Popup,
1307 UINT Flags)
1308 {
1309 /* FIXME - hide caret */
1310
1311 if(!(Flags & TPM_NONOTIFY))
1312 co_IntSendMessage(Window->hSelf, WM_SETCURSOR, (WPARAM)Window->hSelf, HTCAPTION);
1313
1314 /* FIXME - send WM_SETCURSOR message */
1315
1316 if(!(Flags & TPM_NONOTIFY))
1317 co_IntSendMessage(Window->hSelf, WM_INITMENU, (WPARAM)Menu->MenuInfo.Self, 0);
1318 }
1319
1320 VOID FASTCALL
1321 co_IntExitTracking(PWINDOW_OBJECT Window, PMENU_OBJECT Menu, BOOL Popup,
1322 UINT Flags)
1323 {
1324 if(!(Flags & TPM_NONOTIFY))
1325 co_IntSendMessage(Window->hSelf, WM_EXITMENULOOP, 0 /* FIXME */, 0);
1326
1327 /* FIXME - Show caret again */
1328 }
1329
1330 INT FASTCALL
1331 IntTrackMenu(PMENU_OBJECT Menu, PWINDOW_OBJECT Window, INT x, INT y,
1332 RECT lprect)
1333 {
1334 return 0;
1335 }
1336
1337 BOOL FASTCALL
1338 co_IntTrackPopupMenu(PMENU_OBJECT Menu, PWINDOW_OBJECT Window,
1339 UINT Flags, POINT *Pos, UINT MenuPos, RECT *ExcludeRect)
1340 {
1341 co_IntInitTracking(Window, Menu, TRUE, Flags);
1342
1343 co_IntExitTracking(Window, Menu, TRUE, Flags);
1344 return FALSE;
1345 }
1346
1347 BOOL FASTCALL
1348 IntSetMenuItemRect(PMENU_OBJECT Menu, UINT Item, BOOL fByPos, RECT *rcRect)
1349 {
1350 PMENU_ITEM mi;
1351 if(IntGetMenuItemByFlag(Menu, Item, (fByPos ? MF_BYPOSITION : MF_BYCOMMAND),
1352 NULL, &mi, NULL) > -1)
1353 {
1354 mi->Rect = *rcRect;
1355 return TRUE;
1356 }
1357 return FALSE;
1358 }
1359
1360
1361 /*!
1362 * Internal function. Called when the process is destroyed to free the remaining menu handles.
1363 */
1364 BOOL FASTCALL
1365 IntCleanupMenus(struct _EPROCESS *Process, PW32PROCESS Win32Process)
1366 {
1367 PEPROCESS CurrentProcess;
1368 PLIST_ENTRY LastHead = NULL;
1369 PMENU_OBJECT MenuObject;
1370
1371 CurrentProcess = PsGetCurrentProcess();
1372 if (CurrentProcess != Process)
1373 {
1374 KeAttachProcess(&Process->Pcb);
1375 }
1376
1377 while (Win32Process->MenuListHead.Flink != &(Win32Process->MenuListHead) &&
1378 Win32Process->MenuListHead.Flink != LastHead)
1379 {
1380 LastHead = Win32Process->MenuListHead.Flink;
1381 MenuObject = CONTAINING_RECORD(Win32Process->MenuListHead.Flink, MENU_OBJECT, ListEntry);
1382
1383 IntDestroyMenuObject(MenuObject, FALSE, TRUE);
1384 }
1385
1386 if (CurrentProcess != Process)
1387 {
1388 KeDetachProcess();
1389 }
1390 return TRUE;
1391 }
1392
1393 VOID STDCALL
1394 co_InflateRect(LPRECT rect, int dx, int dy)
1395 {
1396 rect->left -= dx;
1397 rect->top -= dy;
1398 rect->right += dx;
1399 rect->bottom += dy;
1400 }
1401
1402 BOOLEAN STDCALL
1403 intGetTitleBarInfo(PWINDOW_OBJECT pWindowObject, PTITLEBARINFO bti)
1404 {
1405
1406 DWORD dwStyle = 0;
1407 DWORD dwExStyle = 0;
1408 BOOLEAN retValue = TRUE;
1409
1410 if (bti->cbSize == sizeof(TITLEBARINFO))
1411 {
1412 RtlZeroMemory(&bti->rgstate[0],sizeof(DWORD)*(CCHILDREN_TITLEBAR+1));
1413
1414 bti->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1415
1416 dwStyle = pWindowObject->Wnd->Style;
1417 dwExStyle = pWindowObject->Wnd->ExStyle;
1418
1419 bti->rcTitleBar.top = 0;
1420 bti->rcTitleBar.left = 0;
1421 bti->rcTitleBar.right = pWindowObject->Wnd->WindowRect.right - pWindowObject->Wnd->WindowRect.left;
1422 bti->rcTitleBar.bottom = pWindowObject->Wnd->WindowRect.bottom - pWindowObject->Wnd->WindowRect.top;
1423
1424 /* is it iconiced ? */
1425 if ((dwStyle & WS_ICONIC)!=WS_ICONIC)
1426 {
1427 /* Remove frame from rectangle */
1428 if (HAS_THICKFRAME( dwStyle, dwExStyle ))
1429 {
1430 /* FIXME : Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
1431 co_InflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) );
1432 }
1433 else if (HAS_DLGFRAME( dwStyle, dwExStyle ))
1434 {
1435 /* FIXME : Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
1436 co_InflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
1437 }
1438 else if (HAS_THINFRAME( dwStyle, dwExStyle))
1439 {
1440 /* FIXME : Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
1441 co_InflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER) );
1442 }
1443
1444 /* We have additional border information if the window
1445 * is a child (but not an MDI child) */
1446 if ( (dwStyle & WS_CHILD) &&
1447 ((dwExStyle & WS_EX_MDICHILD) == 0 ) )
1448 {
1449 if (dwExStyle & WS_EX_CLIENTEDGE)
1450 {
1451 /* FIXME : Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
1452 co_InflateRect (&bti->rcTitleBar, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE));
1453 }
1454
1455 if (dwExStyle & WS_EX_STATICEDGE)
1456 {
1457 /* FIXME : Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
1458 co_InflateRect (&bti->rcTitleBar, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
1459 }
1460 }
1461 }
1462
1463 bti->rcTitleBar.top += pWindowObject->Wnd->WindowRect.top;
1464 bti->rcTitleBar.left += pWindowObject->Wnd->WindowRect.left;
1465 bti->rcTitleBar.right += pWindowObject->Wnd->WindowRect.left;
1466
1467 bti->rcTitleBar.bottom = bti->rcTitleBar.top;
1468 if (dwExStyle & WS_EX_TOOLWINDOW)
1469 {
1470 /* FIXME : Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
1471 bti->rcTitleBar.bottom += UserGetSystemMetrics(SM_CYSMCAPTION);
1472 }
1473 else
1474 {
1475 /* FIXME : Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
1476 bti->rcTitleBar.bottom += UserGetSystemMetrics(SM_CYCAPTION);
1477 bti->rcTitleBar.left += UserGetSystemMetrics(SM_CXSIZE);
1478 }
1479
1480 if (dwStyle & WS_CAPTION)
1481 {
1482 bti->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1483 if (dwStyle & WS_SYSMENU)
1484 {
1485 if (!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX)))
1486 {
1487 bti->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1488 bti->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1489 }
1490 else
1491 {
1492 if (!(dwStyle & WS_MINIMIZEBOX))
1493 {
1494 bti->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1495 }
1496 if (!(dwStyle & WS_MAXIMIZEBOX))
1497 {
1498 bti->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1499 }
1500 }
1501
1502 if (!(dwExStyle & WS_EX_CONTEXTHELP))
1503 {
1504 bti->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1505 }
1506 if (pWindowObject->Wnd->Class->Style & CS_NOCLOSE)
1507 {
1508 bti->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1509 }
1510 }
1511 else
1512 {
1513 bti->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1514 bti->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1515 bti->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1516 bti->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1517 }
1518 }
1519 else
1520 {
1521 bti->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1522 }
1523 }
1524 else
1525 {
1526 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1527 retValue = FALSE;
1528 }
1529
1530 return retValue;
1531 }
1532
1533 /* FUNCTIONS *****************************************************************/
1534
1535
1536 /*
1537 * @implemented
1538 */
1539 DWORD
1540 STDCALL
1541 NtUserBuildMenuItemList(
1542 HMENU hMenu,
1543 VOID* Buffer,
1544 ULONG nBufSize,
1545 DWORD Reserved)
1546 {
1547 DWORD res = -1;
1548 PMENU_OBJECT Menu;
1549 DECLARE_RETURN(DWORD);
1550
1551 DPRINT("Enter NtUserBuildMenuItemList\n");
1552 UserEnterExclusive();
1553
1554 if(!(Menu = UserGetMenuObject(hMenu)))
1555 {
1556 RETURN( (DWORD)-1);
1557 }
1558
1559 if(Buffer)
1560 {
1561 res = IntBuildMenuItemList(Menu, Buffer, nBufSize);
1562 }
1563 else
1564 {
1565 res = Menu->MenuInfo.MenuItemCount;
1566 }
1567
1568 RETURN( res);
1569
1570 CLEANUP:
1571 DPRINT("Leave NtUserBuildMenuItemList, ret=%i\n",_ret_);
1572 UserLeave();
1573 END_CLEANUP;
1574 }
1575
1576
1577 /*
1578 * @implemented
1579 */
1580 DWORD STDCALL
1581 NtUserCheckMenuItem(
1582 HMENU hMenu,
1583 UINT uIDCheckItem,
1584 UINT uCheck)
1585 {
1586 PMENU_OBJECT Menu;
1587 DECLARE_RETURN(DWORD);
1588
1589 DPRINT("Enter NtUserCheckMenuItem\n");
1590 UserEnterExclusive();
1591
1592 if(!(Menu = UserGetMenuObject(hMenu)))
1593 {
1594 RETURN( (DWORD)-1);
1595 }
1596
1597 RETURN( IntCheckMenuItem(Menu, uIDCheckItem, uCheck));
1598
1599 CLEANUP:
1600 DPRINT("Leave NtUserCheckMenuItem, ret=%i\n",_ret_);
1601 UserLeave();
1602 END_CLEANUP;
1603 }
1604
1605
1606 HMENU FASTCALL UserCreateMenu(BOOL PopupMenu)
1607 {
1608 PWINSTATION_OBJECT WinStaObject;
1609 HANDLE Handle;
1610 PMENU_OBJECT Menu;
1611 NTSTATUS Status;
1612 PEPROCESS CurrentProcess = PsGetCurrentProcess();
1613
1614 if (CsrProcess != CurrentProcess)
1615 {
1616 /*
1617 * CsrProcess does not have a Win32WindowStation
1618 *
1619 */
1620
1621 Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation,
1622 KernelMode,
1623 0,
1624 &WinStaObject);
1625
1626 if (!NT_SUCCESS(Status))
1627 {
1628 DPRINT1("Validation of window station handle (0x%X) failed\n",
1629 CurrentProcess->Win32WindowStation);
1630 SetLastNtError(Status);
1631 return (HMENU)0;
1632 }
1633 Menu = IntCreateMenu(&Handle, !PopupMenu);
1634 UserDereferenceObject(Menu);
1635 ObDereferenceObject(WinStaObject);
1636 }
1637 else
1638 {
1639 Menu = IntCreateMenu(&Handle, !PopupMenu);
1640 UserDereferenceObject(Menu);
1641 }
1642
1643 return (HMENU)Handle;
1644 }
1645
1646
1647 /*
1648 * @implemented
1649 */
1650 BOOL STDCALL
1651 NtUserDeleteMenu(
1652 HMENU hMenu,
1653 UINT uPosition,
1654 UINT uFlags)
1655 {
1656 PMENU_OBJECT Menu;
1657 DECLARE_RETURN(BOOL);
1658
1659 DPRINT("Enter NtUserDeleteMenu\n");
1660 UserEnterExclusive();
1661
1662 if(!(Menu = UserGetMenuObject(hMenu)))
1663 {
1664 RETURN( FALSE);
1665 }
1666
1667 RETURN( IntRemoveMenuItem(Menu, uPosition, uFlags, TRUE));
1668
1669 CLEANUP:
1670 DPRINT("Leave NtUserDeleteMenu, ret=%i\n",_ret_);
1671 UserLeave();
1672 END_CLEANUP;
1673 }
1674
1675 /*
1676 * @implemented
1677 */
1678 BOOLEAN STDCALL
1679 NtUserGetTitleBarInfo(
1680 HWND hwnd,
1681 PTITLEBARINFO bti)
1682 {
1683 PWINDOW_OBJECT WindowObject;
1684 TITLEBARINFO bartitleinfo;
1685 DECLARE_RETURN(BOOLEAN);
1686 BOOLEAN retValue = FALSE;
1687
1688 DPRINT("Enter NtUserGetTitleBarInfo\n");
1689 UserEnterExclusive();
1690
1691 /* Vaildate the windows handle */
1692 if (!(WindowObject = UserGetWindowObject(hwnd)))
1693 {
1694 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1695 retValue = FALSE;
1696 }
1697
1698 _SEH_TRY
1699 {
1700 /* Copy our usermode buffer bti to local buffer bartitleinfo */
1701 ProbeForRead(bti, sizeof(TITLEBARINFO), 1);
1702 RtlCopyMemory(&bartitleinfo, bti, sizeof(TITLEBARINFO));
1703 }
1704 _SEH_HANDLE
1705 {
1706 /* Fail copy the data */
1707 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1708 retValue = FALSE;
1709 }
1710 _SEH_END
1711
1712 /* Get the tile bar info */
1713 if (retValue)
1714 {
1715 retValue = intGetTitleBarInfo(WindowObject, &bartitleinfo);
1716 if (retValue)
1717 {
1718 _SEH_TRY
1719 {
1720 /* Copy our buffer to user mode buffer bti */
1721 ProbeForWrite(bti, sizeof(TITLEBARINFO), 1);
1722 RtlCopyMemory(bti, &bartitleinfo, sizeof(TITLEBARINFO));
1723 }
1724 _SEH_HANDLE
1725 {
1726 /* Fail copy the data */
1727 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1728 retValue = FALSE;
1729 }
1730 _SEH_END
1731 }
1732 }
1733
1734 RETURN( retValue );
1735
1736 CLEANUP:
1737 DPRINT("Leave NtUserGetTitleBarInfo, ret=%i\n",_ret_);
1738 UserLeave();
1739 END_CLEANUP;
1740 }
1741
1742
1743
1744 /*
1745 * @implemented
1746 */
1747 BOOL FASTCALL UserDestroyMenu(HMENU hMenu)
1748 {
1749 PMENU_OBJECT Menu;
1750
1751 if(!(Menu = UserGetMenuObject(hMenu)))
1752 {
1753 return FALSE;
1754 }
1755
1756 if(Menu->Process != PsGetCurrentProcess())
1757 {
1758 SetLastWin32Error(ERROR_ACCESS_DENIED);
1759 return FALSE;
1760 }
1761
1762 return IntDestroyMenuObject(Menu, FALSE, TRUE);
1763 }
1764
1765 /*
1766 * @implemented
1767 */
1768 BOOL STDCALL
1769 NtUserDestroyMenu(
1770 HMENU hMenu)
1771 {
1772 PMENU_OBJECT Menu;
1773 DECLARE_RETURN(BOOL);
1774
1775 DPRINT("Enter NtUserDestroyMenu\n");
1776 UserEnterExclusive();
1777
1778 if(!(Menu = UserGetMenuObject(hMenu)))
1779 {
1780 RETURN( FALSE);
1781 }
1782
1783 if(Menu->Process != PsGetCurrentProcess())
1784 {
1785 SetLastWin32Error(ERROR_ACCESS_DENIED);
1786 RETURN( FALSE);
1787 }
1788
1789 RETURN( IntDestroyMenuObject(Menu, TRUE, TRUE));
1790
1791 CLEANUP:
1792 DPRINT("Leave NtUserDestroyMenu, ret=%i\n",_ret_);
1793 UserLeave();
1794 END_CLEANUP;
1795 }
1796
1797
1798 /*
1799 * @implemented
1800 */
1801 UINT STDCALL
1802 NtUserEnableMenuItem(
1803 HMENU hMenu,
1804 UINT uIDEnableItem,
1805 UINT uEnable)
1806 {
1807 PMENU_OBJECT Menu;
1808 DECLARE_RETURN(UINT);
1809
1810 DPRINT("Enter NtUserEnableMenuItem\n");
1811 UserEnterExclusive();
1812
1813 if(!(Menu = UserGetMenuObject(hMenu)))
1814 {
1815 RETURN(-1);
1816 }
1817
1818 RETURN( IntEnableMenuItem(Menu, uIDEnableItem, uEnable));
1819
1820 CLEANUP:
1821 DPRINT("Leave NtUserEnableMenuItem, ret=%i\n",_ret_);
1822 UserLeave();
1823 END_CLEANUP;
1824 }
1825
1826
1827 /*
1828 * @implemented
1829 */
1830 DWORD STDCALL
1831 UserInsertMenuItem(
1832 HMENU hMenu,
1833 UINT uItem,
1834 BOOL fByPosition,
1835 LPCMENUITEMINFOW UnsafeItemInfo)
1836 {
1837 PMENU_OBJECT Menu;
1838 NTSTATUS Status;
1839 ROSMENUITEMINFO ItemInfo;
1840 DECLARE_RETURN(DWORD);
1841
1842 DPRINT("Enter UserInsertMenuItem\n");
1843 UserEnterExclusive();
1844
1845 if(!(Menu = UserGetMenuObject(hMenu)))
1846 {
1847 RETURN( FALSE);
1848 }
1849
1850 /* Try to copy the whole MENUITEMINFOW structure */
1851 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, sizeof(MENUITEMINFOW));
1852 if (NT_SUCCESS(Status))
1853 {
1854 if (sizeof(MENUITEMINFOW) != ItemInfo.cbSize
1855 && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize)
1856 {
1857 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1858 RETURN( FALSE);
1859 }
1860 RETURN( IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo));
1861 }
1862
1863 /* Try to copy without last field (not present in older versions) */
1864 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, FIELD_OFFSET(MENUITEMINFOW, hbmpItem));
1865 if (NT_SUCCESS(Status))
1866 {
1867 if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize)
1868 {
1869 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1870 RETURN( FALSE);
1871 }
1872 ItemInfo.hbmpItem = (HBITMAP)0;
1873 RETURN( IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo));
1874 }
1875
1876 SetLastNtError(Status);
1877 RETURN( FALSE);
1878
1879 CLEANUP:
1880 DPRINT("Leave UserInsertMenuItem, ret=%i\n",_ret_);
1881 UserLeave();
1882 END_CLEANUP;
1883 }
1884
1885
1886 /*
1887 * @unimplemented
1888 */
1889 BOOL STDCALL
1890 NtUserEndMenu(VOID)
1891 {
1892 UNIMPLEMENTED
1893
1894 return 0;
1895 }
1896
1897
1898 /*
1899 * @implemented
1900 */
1901 UINT STDCALL
1902 NtUserGetMenuDefaultItem(
1903 HMENU hMenu,
1904 UINT fByPos,
1905 UINT gmdiFlags)
1906 {
1907 PMENU_OBJECT Menu;
1908 DWORD gismc = 0;
1909 DECLARE_RETURN(UINT);
1910
1911 DPRINT("Enter NtUserGetMenuDefaultItem\n");
1912 UserEnterExclusive();
1913
1914 if(!(Menu = UserGetMenuObject(hMenu)))
1915 {
1916 RETURN(-1);
1917 }
1918
1919 RETURN( IntGetMenuDefaultItem(Menu, fByPos, gmdiFlags, &gismc));
1920
1921 CLEANUP:
1922 DPRINT("Leave NtUserGetMenuDefaultItem, ret=%i\n",_ret_);
1923 UserLeave();
1924 END_CLEANUP;
1925 }
1926
1927
1928 /*
1929 * @implemented
1930 */
1931 BOOL STDCALL
1932 NtUserGetMenuBarInfo(
1933 HWND hwnd,
1934 LONG idObject,
1935 LONG idItem,
1936 PMENUBARINFO pmbi)
1937 {
1938 BOOL Res = TRUE;
1939 PMENU_OBJECT MenuObject;
1940 PMENU_ITEM mi;
1941 PWINDOW_OBJECT WindowObject;
1942 HMENU hMenu;
1943 POINT Offset;
1944 RECT Rect;
1945 MENUBARINFO kmbi;
1946 DECLARE_RETURN(BOOL);
1947
1948 DPRINT("Enter NtUserGetMenuBarInfo\n");
1949 UserEnterShared();
1950
1951 if (!(WindowObject = UserGetWindowObject(hwnd)))
1952 {
1953 SetLastWin32Error(ERROR_INVALID_WINDOW_HANDLE);
1954 RETURN(FALSE);
1955 }
1956
1957 hMenu = (HMENU)WindowObject->Wnd->IDMenu;
1958
1959 if (!(MenuObject = UserGetMenuObject(hMenu)))
1960 {
1961 SetLastWin32Error(ERROR_INVALID_MENU_HANDLE);
1962 RETURN(FALSE);
1963 }
1964
1965 if (pmbi->cbSize != sizeof(MENUBARINFO))
1966 {
1967 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1968 RETURN(FALSE);
1969 }
1970
1971 kmbi.cbSize = sizeof(MENUBARINFO);
1972 kmbi.fBarFocused = FALSE;
1973 kmbi.fFocused = FALSE;
1974 kmbi.hwndMenu = NULL;
1975
1976 switch (idObject)
1977 {
1978 case OBJID_MENU:
1979 {
1980 PMENU_OBJECT SubMenuObject;
1981 kmbi.hMenu = hMenu;
1982 if (idItem) /* Non-Zero-Based. */
1983 {
1984 if (IntGetMenuItemByFlag(MenuObject, idItem-1, MF_BYPOSITION, NULL, &mi, NULL) > -1)
1985 kmbi.rcBar = mi->Rect;
1986 else
1987 {
1988 Res = FALSE;
1989 break;
1990 }
1991 }
1992 else
1993 {
1994 /* If items is zero we assume info for the menu itself. */
1995 if (!(IntGetClientOrigin(WindowObject, &Offset)))
1996 {
1997 Res = FALSE;
1998 break;
1999 }
2000 Rect.left = Offset.x;
2001 Rect.right = Offset.x + MenuObject->MenuInfo.Width;
2002 Rect.top = Offset.y;
2003 Rect.bottom = Offset.y + MenuObject->MenuInfo.Height;
2004 kmbi.rcBar = Rect;
2005 DPRINT("Rect top = %d bottom = %d left = %d right = %d \n",
2006 Rect.top, Rect.bottom, Rect.left, Rect.right);
2007 }
2008 if (idItem)
2009 {
2010 if (idItem-1 == MenuObject->MenuInfo.FocusedItem)
2011 kmbi.fFocused = TRUE;
2012 }
2013 if (MenuObject->MenuInfo.FocusedItem != NO_SELECTED_ITEM)
2014 kmbi.fBarFocused = TRUE;
2015 SubMenuObject = UserGetMenuObject(MenuObject->MenuItemList->hSubMenu);
2016 if(SubMenuObject) kmbi.hwndMenu = SubMenuObject->MenuInfo.Wnd;
2017 DPRINT("OBJID_MENU, idItem = %d\n",idItem);
2018 break;
2019 }
2020 case OBJID_CLIENT:
2021 {
2022 PMENU_OBJECT SubMenuObject, XSubMenuObject;
2023 SubMenuObject = UserGetMenuObject(MenuObject->MenuItemList->hSubMenu);
2024 if(SubMenuObject) kmbi.hMenu = SubMenuObject->MenuInfo.Self;
2025 else
2026 {
2027 Res = FALSE;
2028 DPRINT1("OBJID_CLIENT, No SubMenu!\n");
2029 break;
2030 }
2031 if (idItem)
2032 {
2033 if (IntGetMenuItemByFlag(SubMenuObject, idItem-1, MF_BYPOSITION, NULL, &mi, NULL) > -1)
2034 kmbi.rcBar = mi->Rect;
2035 else
2036 {
2037 Res = FALSE;
2038 break;
2039 }
2040 }
2041 else
2042 {
2043 PWINDOW_OBJECT SubWinObj;
2044 if (!(SubWinObj = UserGetWindowObject(SubMenuObject->MenuInfo.Wnd)))
2045 {
2046 Res = FALSE;
2047 break;
2048 }
2049 if (!(IntGetClientOrigin(SubWinObj, &Offset)))
2050 {
2051 Res = FALSE;
2052 break;
2053 }
2054 Rect.left = Offset.x;
2055 Rect.right = Offset.x + SubMenuObject->MenuInfo.Width;
2056 Rect.top = Offset.y;
2057 Rect.bottom = Offset.y + SubMenuObject->MenuInfo.Height;
2058 kmbi.rcBar = Rect;
2059 }
2060 if (idItem)
2061 {
2062 if (idItem-1 == SubMenuObject->MenuInfo.FocusedItem)
2063 kmbi.fFocused = TRUE;
2064 }
2065 if (SubMenuObject->MenuInfo.FocusedItem != NO_SELECTED_ITEM)
2066 kmbi.fBarFocused = TRUE;
2067 XSubMenuObject = UserGetMenuObject(SubMenuObject->MenuItemList->hSubMenu);
2068 if (XSubMenuObject) kmbi.hwndMenu = XSubMenuObject->MenuInfo.Wnd;
2069 DPRINT("OBJID_CLIENT, idItem = %d\n",idItem);
2070 break;
2071 }
2072 case OBJID_SYSMENU:
2073 {
2074 PMENU_OBJECT SysMenuObject, SubMenuObject;
2075 if(!(SysMenuObject = IntGetSystemMenu(WindowObject, FALSE, FALSE)))
2076 {
2077 Res = FALSE;
2078 break;
2079 }
2080 kmbi.hMenu = SysMenuObject->MenuInfo.Self;
2081 if (idItem)
2082 {
2083 if (IntGetMenuItemByFlag(SysMenuObject, idItem-1, MF_BYPOSITION, NULL, &mi, NULL) > -1)
2084 kmbi.rcBar = mi->Rect;
2085 else
2086 {
2087 Res = FALSE;
2088 break;
2089 }
2090 }
2091 else
2092 {
2093 PWINDOW_OBJECT SysWinObj;
2094 if (!(SysWinObj = UserGetWindowObject(SysMenuObject->MenuInfo.Wnd)))
2095 {
2096 Res = FALSE;
2097 break;
2098 }
2099 if (!(IntGetClientOrigin(SysWinObj, &Offset)))
2100 {
2101 Res = FALSE;
2102 break;
2103 }
2104 Rect.left = Offset.x;
2105 Rect.right = Offset.x + SysMenuObject->MenuInfo.Width;
2106 Rect.top = Offset.y;
2107 Rect.bottom = Offset.y + SysMenuObject->MenuInfo.Height;
2108 kmbi.rcBar = Rect;
2109 }
2110 if (idItem)
2111 {
2112 if (idItem-1 == SysMenuObject->MenuInfo.FocusedItem)
2113 kmbi.fFocused = TRUE;
2114 }
2115 if (SysMenuObject->MenuInfo.FocusedItem != NO_SELECTED_ITEM)
2116 kmbi.fBarFocused = TRUE;
2117 SubMenuObject = UserGetMenuObject(SysMenuObject->MenuItemList->hSubMenu);
2118 if(SubMenuObject) kmbi.hwndMenu = SubMenuObject->MenuInfo.Wnd;
2119 DPRINT("OBJID_SYSMENU, idItem = %d\n",idItem);
2120 break;
2121 }
2122 default:
2123 Res = FALSE;
2124 DPRINT1("Unknown idObject = %d, idItem = %d\n",idObject,idItem);
2125 }
2126 if (Res)
2127 {
2128 NTSTATUS Status = MmCopyToCaller(pmbi, &kmbi, sizeof(MENUBARINFO));
2129 if (! NT_SUCCESS(Status))
2130 {
2131 SetLastNtError(Status);
2132 RETURN(FALSE);
2133 }
2134 }
2135 RETURN(Res);
2136
2137 CLEANUP:
2138 DPRINT("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_);
2139 UserLeave();
2140 END_CLEANUP;
2141 }
2142
2143
2144 /*
2145 * @unimplemented
2146 */
2147 UINT STDCALL
2148 NtUserGetMenuIndex(
2149 HMENU hMenu,
2150 UINT wID)
2151 {
2152 UNIMPLEMENTED
2153
2154 return 0;
2155 }
2156
2157
2158 /*
2159 * @implemented
2160 */
2161 BOOL STDCALL
2162 NtUserGetMenuItemRect(
2163 HWND hWnd,
2164 HMENU hMenu,
2165 UINT uItem,
2166 LPRECT lprcItem)
2167 {
2168 ROSMENUINFO mi;
2169 PWINDOW_OBJECT ReferenceWnd;
2170 LONG XMove, YMove;
2171 RECT Rect;
2172 NTSTATUS Status;
2173 PMENU_OBJECT Menu;
2174 PMENU_ITEM MenuItem;
2175 DECLARE_RETURN(BOOL);
2176
2177 DPRINT("Enter NtUserGetMenuItemRect\n");
2178 UserEnterShared();
2179
2180 if (!(Menu = UserGetMenuObject(hMenu)))
2181 {
2182 RETURN(FALSE);
2183 }
2184
2185 if (IntGetMenuItemByFlag(Menu, uItem, MF_BYPOSITION, NULL, &MenuItem, NULL) > -1)
2186 Rect = MenuItem->Rect;
2187 else
2188 RETURN(FALSE);
2189
2190 if(!hWnd)
2191 {
2192 if(!UserMenuInfo(Menu, &mi, FALSE))
2193 RETURN( FALSE);
2194 if(mi.Wnd == 0)
2195 RETURN( FALSE);
2196 }
2197
2198 if (lprcItem == NULL) RETURN( FALSE);
2199
2200 if (!(ReferenceWnd = UserGetWindowObject(mi.Wnd))) RETURN( FALSE);
2201
2202 if(MenuItem->fType & MF_POPUP)
2203 {
2204 XMove = ReferenceWnd->Wnd->ClientRect.left;
2205 YMove = ReferenceWnd->Wnd->ClientRect.top;
2206 }
2207 else
2208 {
2209 XMove = ReferenceWnd->Wnd->WindowRect.left;
2210 YMove = ReferenceWnd->Wnd->WindowRect.top;
2211 }
2212
2213 Rect.left += XMove;
2214 Rect.top += YMove;
2215 Rect.right += XMove;
2216 Rect.bottom += YMove;
2217
2218 Status = MmCopyToCaller(lprcItem, &Rect, sizeof(RECT));
2219 if (! NT_SUCCESS(Status))
2220 {
2221 SetLastNtError(Status);
2222 RETURN( FALSE);
2223 }
2224 RETURN( TRUE);
2225
2226 CLEANUP:
2227 DPRINT("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_);
2228 UserLeave();
2229 END_CLEANUP;
2230 }
2231
2232
2233 /*
2234 * @implemented
2235 */
2236 BOOL STDCALL
2237 NtUserHiliteMenuItem(
2238 HWND hWnd,
2239 HMENU hMenu,
2240 UINT uItemHilite,
2241 UINT uHilite)
2242 {
2243 PMENU_OBJECT Menu;
2244 PWINDOW_OBJECT Window;
2245 DECLARE_RETURN(BOOLEAN);
2246
2247 DPRINT("Enter NtUserHiliteMenuItem\n");
2248 UserEnterExclusive();
2249
2250 if(!(Window = UserGetWindowObject(hWnd)))
2251 {
2252 RETURN(FALSE);
2253 }
2254
2255 if(!(Menu = UserGetMenuObject(hMenu)))
2256 {
2257 RETURN(FALSE);
2258 }
2259
2260 if(Window->Wnd->IDMenu == (UINT)hMenu)
2261 {
2262 RETURN( IntHiliteMenuItem(Window, Menu, uItemHilite, uHilite));
2263 }
2264
2265 RETURN(FALSE);
2266
2267 CLEANUP:
2268 DPRINT("Leave NtUserHiliteMenuItem, ret=%i\n",_ret_);
2269 UserLeave();
2270 END_CLEANUP;
2271 }
2272
2273
2274 static
2275 BOOL FASTCALL
2276 UserMenuInfo(
2277 PMENU_OBJECT Menu,
2278 PROSMENUINFO UnsafeMenuInfo,
2279 BOOL SetOrGet)
2280 {
2281 BOOL Res;
2282 DWORD Size;
2283 NTSTATUS Status;
2284 ROSMENUINFO MenuInfo;
2285
2286 Status = MmCopyFromCaller(&Size, &UnsafeMenuInfo->cbSize, sizeof(DWORD));
2287 if (! NT_SUCCESS(Status))
2288 {
2289 SetLastNtError(Status);
2290 return( FALSE);
2291 }
2292 if(Size < sizeof(MENUINFO) || sizeof(ROSMENUINFO) < Size)
2293 {
2294 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2295 return( FALSE);
2296 }
2297 Status = MmCopyFromCaller(&MenuInfo, UnsafeMenuInfo, Size);
2298 if (! NT_SUCCESS(Status))
2299 {
2300 SetLastNtError(Status);
2301 return( FALSE);
2302 }
2303
2304 if(SetOrGet)
2305 {
2306 /* Set MenuInfo */
2307 Res = IntSetMenuInfo(Menu, &MenuInfo);
2308 }
2309 else
2310 {
2311 /* Get MenuInfo */
2312 Res = IntGetMenuInfo(Menu, &MenuInfo);
2313 if (Res)
2314 {
2315 Status = MmCopyToCaller(UnsafeMenuInfo, &MenuInfo, Size);
2316 if (! NT_SUCCESS(Status))
2317 {
2318 SetLastNtError(Status);
2319 return( FALSE);
2320 }
2321 }
2322 }
2323
2324 return( Res);
2325 }
2326
2327
2328
2329
2330
2331 /*
2332 * @implemented
2333 */
2334 BOOL
2335 STDCALL
2336 NtUserMenuInfo(
2337 HMENU hMenu,
2338 PROSMENUINFO UnsafeMenuInfo,
2339 BOOL SetOrGet)
2340 {
2341 PMENU_OBJECT Menu;
2342 DECLARE_RETURN(BOOL);
2343
2344 DPRINT("Enter NtUserMenuInfo\n");
2345 UserEnterShared();
2346
2347 if (!(Menu = UserGetMenuObject(hMenu)))
2348 {
2349 RETURN(FALSE);
2350 }
2351
2352 RETURN(UserMenuInfo(Menu, UnsafeMenuInfo, SetOrGet));
2353
2354 CLEANUP:
2355 DPRINT("Leave NtUserMenuInfo, ret=%i\n",_ret_);
2356 UserLeave();
2357 END_CLEANUP;
2358 }
2359
2360
2361
2362 /*
2363 * @implemented
2364 */
2365 int STDCALL
2366 NtUserMenuItemFromPoint(
2367 HWND hWnd,
2368 HMENU hMenu,
2369 DWORD X,
2370 DWORD Y)
2371 {
2372 PMENU_OBJECT Menu;
2373 PWINDOW_OBJECT Window = NULL;
2374 PMENU_ITEM mi;
2375 int i;
2376 DECLARE_RETURN(int);
2377
2378 DPRINT("Enter NtUserMenuItemFromPoint\n");
2379 UserEnterExclusive();
2380
2381 if (!(Menu = UserGetMenuObject(hMenu)))
2382 {
2383 RETURN( -1);
2384 }
2385
2386 if (!(Window = UserGetWindowObject(Menu->MenuInfo.Wnd)))
2387 {
2388 RETURN( -1);
2389 }
2390
2391 X -= Window->Wnd->WindowRect.left;
2392 Y -= Window->Wnd->WindowRect.top;
2393
2394 mi = Menu->MenuItemList;
2395 for (i = 0; NULL != mi; i++)
2396 {
2397 if (InRect(mi->Rect, X, Y))
2398 {
2399 break;
2400 }
2401 mi = mi->Next;
2402 }
2403
2404 RETURN( (mi ? i : NO_SELECTED_ITEM));
2405
2406 CLEANUP:
2407 DPRINT("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_);
2408 UserLeave();
2409 END_CLEANUP;
2410 }
2411
2412
2413
2414 static
2415 BOOL FASTCALL
2416 UserMenuItemInfo(
2417 PMENU_OBJECT Menu,
2418 UINT Item,
2419 BOOL ByPosition,
2420 PROSMENUITEMINFO UnsafeItemInfo,
2421 BOOL SetOrGet)
2422 {
2423 PMENU_ITEM MenuItem;
2424 ROSMENUITEMINFO ItemInfo;
2425 NTSTATUS Status;
2426 UINT Size;
2427 BOOL Ret;
2428
2429 Status = MmCopyFromCaller(&Size, &UnsafeItemInfo->cbSize, sizeof(UINT));
2430 if (! NT_SUCCESS(Status))
2431 {
2432 SetLastNtError(Status);
2433 return( FALSE);
2434 }
2435 if (sizeof(MENUITEMINFOW) != Size
2436 && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != Size
2437 && sizeof(ROSMENUITEMINFO) != Size)
2438 {
2439 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2440 return( FALSE);
2441 }
2442 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, Size);
2443 if (! NT_SUCCESS(Status))
2444 {
2445 SetLastNtError(Status);
2446 return( FALSE);
2447 }
2448 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
2449 set/get hbmpItem */
2450 if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) == Size
2451 && 0 != (ItemInfo.fMask & MIIM_BITMAP))
2452 {
2453 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2454 return( FALSE);
2455 }
2456
2457 if (IntGetMenuItemByFlag(Menu, Item,
2458 (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND),
2459 NULL, &MenuItem, NULL) < 0)
2460 {
2461 SetLastWin32Error(ERROR_INVALID_PARAMETER);
2462 return( FALSE);
2463 }
2464
2465 if (SetOrGet)
2466 {
2467 Ret = IntSetMenuItemInfo(Menu, MenuItem, &ItemInfo);
2468 }
2469 else
2470 {
2471 Ret = IntGetMenuItemInfo(Menu, MenuItem, &ItemInfo);
2472 if (Ret)
2473 {
2474 Status = MmCopyToCaller(UnsafeItemInfo, &ItemInfo, Size);
2475 if (! NT_SUCCESS(Status))
2476 {
2477 SetLastNtError(Status);
2478 return( FALSE);
2479 }
2480 }
2481 }
2482
2483 return( Ret);
2484 }
2485
2486
2487
2488 /*
2489 * @implemented
2490 */
2491 BOOL
2492 STDCALL
2493 NtUserMenuItemInfo(
2494 HMENU hMenu,
2495 UINT Item,
2496 BOOL ByPosition,
2497 PROSMENUITEMINFO UnsafeItemInfo,
2498 BOOL SetOrGet)
2499 {
2500 PMENU_OBJECT Menu;
2501 DECLARE_RETURN(BOOL);
2502
2503 DPRINT("Enter NtUserMenuItemInfo\n");
2504 UserEnterExclusive();
2505
2506 if (!(Menu = UserGetMenuObject(hMenu)))
2507 {
2508 RETURN(FALSE);
2509 }
2510
2511 RETURN( UserMenuItemInfo(Menu, Item, ByPosition, UnsafeItemInfo, SetOrGet));
2512
2513 CLEANUP:
2514 DPRINT("Leave NtUserMenuItemInfo, ret=%i\n",_ret_);
2515 UserLeave();
2516 END_CLEANUP;
2517
2518 }
2519
2520
2521 /*
2522 * @implemented
2523 */
2524 BOOL STDCALL
2525 NtUserRemoveMenu(
2526 HMENU hMenu,
2527 UINT uPosition,
2528 UINT uFlags)
2529 {
2530 PMENU_OBJECT Menu;
2531 DECLARE_RETURN(BOOL);
2532
2533 DPRINT("Enter NtUserRemoveMenu\n");
2534 UserEnterExclusive();
2535
2536 if(!(Menu = UserGetMenuObject(hMenu)))
2537 {
2538 RETURN( FALSE);
2539 }
2540
2541 RETURN(IntRemoveMenuItem(Menu, uPosition, uFlags, FALSE));
2542
2543 CLEANUP:
2544 DPRINT("Leave NtUserRemoveMenu, ret=%i\n",_ret_);
2545 UserLeave();
2546 END_CLEANUP;
2547
2548 }
2549
2550
2551 /*
2552 * @implemented
2553 */
2554 BOOL STDCALL
2555 NtUserSetMenuContextHelpId(
2556 HMENU hMenu,
2557 DWORD dwContextHelpId)
2558 {
2559 PMENU_OBJECT Menu;
2560 DECLARE_RETURN(BOOL);
2561
2562 DPRINT("Enter NtUserSetMenuContextHelpId\n");
2563 UserEnterExclusive();
2564
2565 if(!(Menu = UserGetMenuObject(hMenu)))
2566 {
2567 RETURN( FALSE);
2568 }
2569
2570 RETURN(IntSetMenuContextHelpId(Menu, dwContextHelpId));
2571
2572 CLEANUP:
2573 DPRINT("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_);
2574 UserLeave();
2575 END_CLEANUP;
2576 }
2577
2578
2579
2580 /*
2581 * @implemented
2582 */
2583 BOOL STDCALL
2584 NtUserSetMenuDefaultItem(
2585 HMENU hMenu,
2586 UINT uItem,
2587 UINT fByPos)
2588 {
2589 PMENU_OBJECT Menu;
2590 DECLARE_RETURN(BOOL);
2591
2592 DPRINT("Enter NtUserSetMenuDefaultItem\n");
2593 UserEnterExclusive();
2594
2595 if(!(Menu = UserGetMenuObject(hMenu)))
2596 {
2597 RETURN( FALSE);
2598 }
2599
2600 RETURN( UserSetMenuDefaultItem(Menu, uItem, fByPos));
2601
2602 CLEANUP:
2603 DPRINT("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_);
2604 UserLeave();
2605 END_CLEANUP;
2606 }
2607
2608
2609 /*
2610 * @implemented
2611 */
2612 BOOL STDCALL
2613 NtUserSetMenuFlagRtoL(
2614 HMENU hMenu)
2615 {
2616 PMENU_OBJECT Menu;
2617 DECLARE_RETURN(BOOL);
2618
2619 DPRINT("Enter NtUserSetMenuFlagRtoL\n");
2620 UserEnterExclusive();
2621
2622 if(!(Menu = UserGetMenuObject(hMenu)))
2623 {
2624 RETURN( FALSE);
2625 }
2626
2627 RETURN(IntSetMenuFlagRtoL(Menu));
2628
2629 CLEANUP:
2630 DPRINT("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_);
2631 UserLeave();
2632 END_CLEANUP;
2633 }
2634
2635
2636 /*
2637 * @unimplemented
2638 */
2639 DWORD STDCALL
2640 NtUserThunkedMenuInfo(
2641 HMENU hMenu,
2642 LPCMENUINFO lpcmi)
2643 {
2644 UNIMPLEMENTED
2645 /* This function seems just to call SetMenuInfo() */
2646 return 0;
2647 }
2648
2649
2650 /*
2651 * @unimplemented
2652 */
2653 DWORD STDCALL
2654 NtUserThunkedMenuItemInfo(
2655 HMENU hMenu,
2656 UINT uItem,
2657 BOOL fByPosition,
2658 BOOL bInsert,
2659 LPMENUITEMINFOW lpmii,
2660 PUNICODE_STRING lpszCaption)
2661 {
2662
2663 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
2664 if bInsert == TRUE call NtUserInsertMenuItem() else NtUserSetMenuItemInfo() */
2665
2666 if (bInsert) return UserInsertMenuItem(hMenu, uItem, fByPosition, lpmii);
2667
2668 UNIMPLEMENTED
2669 return 0;
2670 }
2671
2672
2673 /*
2674 * @implemented
2675 */
2676 /* NOTE: unused function */
2677 BOOL STDCALL
2678 NtUserTrackPopupMenuEx(
2679 HMENU hMenu,
2680 UINT fuFlags,
2681 int x,
2682 int y,
2683 HWND hWnd,
2684 LPTPMPARAMS lptpm)
2685 {
2686 UNIMPLEMENTED
2687
2688 return FALSE;
2689 }
2690
2691
2692 /* EOF */