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