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