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