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