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