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