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