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