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