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