Create a branch for working on csrss and co.
[reactos.git] / win32ss / user / ntuser / menu.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Menus
5 * FILE: subsys/win32k/ntuser/menu.c
6 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserMenu);
11
12 /* INTERNAL ******************************************************************/
13
14 /* Maximum number of menu items a menu can contain */
15 #define MAX_MENU_ITEMS (0x4000)
16 #define MAX_GOINTOSUBMENU (0x10)
17
18 #define UpdateMenuItemState(state, change) \
19 {\
20 if((change) & MFS_DISABLED) { \
21 (state) |= MFS_DISABLED; \
22 } else { \
23 (state) &= ~MFS_DISABLED; \
24 } \
25 if((change) & MFS_CHECKED) { \
26 (state) |= MFS_CHECKED; \
27 } else { \
28 (state) &= ~MFS_CHECKED; \
29 } \
30 if((change) & MFS_HILITE) { \
31 (state) |= MFS_HILITE; \
32 } else { \
33 (state) &= ~MFS_HILITE; \
34 } \
35 if((change) & MFS_DEFAULT) { \
36 (state) |= MFS_DEFAULT; \
37 } else { \
38 (state) &= ~MFS_DEFAULT; \
39 } \
40 if((change) & MF_MOUSESELECT) { \
41 (state) |= MF_MOUSESELECT; \
42 } else { \
43 (state) &= ~MF_MOUSESELECT; \
44 } \
45 }
46
47 #define FreeMenuText(MenuItem) \
48 { \
49 if((MENU_ITEM_TYPE((MenuItem)->fType) == MF_STRING) && \
50 (MenuItem)->Text.Length) { \
51 ExFreePoolWithTag((MenuItem)->Text.Buffer, TAG_STRING); \
52 } \
53 }
54
55
56 PMENU_OBJECT FASTCALL UserGetMenuObject(HMENU hMenu)
57 {
58 PMENU_OBJECT Menu;
59
60 if (!hMenu)
61 {
62 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
63 return NULL;
64 }
65
66 Menu = (PMENU_OBJECT)UserGetObject(gHandleTable, hMenu, otMenu);
67 if (!Menu)
68 {
69 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
70 return NULL;
71 }
72
73 return Menu;
74 }
75
76
77 #if 0
78 void FASTCALL
79 DumpMenuItemList(PMENU_ITEM MenuItem)
80 {
81 UINT cnt = 0;
82 while(MenuItem)
83 {
84 if(MenuItem->Text.Length)
85 DbgPrint(" %d. %wZ\n", ++cnt, &MenuItem->Text);
86 else
87 DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt, (DWORD)MenuItem->Text.Buffer);
88 DbgPrint(" fType=");
89 if(MFT_BITMAP & MenuItem->fType)
90 DbgPrint("MFT_BITMAP ");
91 if(MFT_MENUBARBREAK & MenuItem->fType)
92 DbgPrint("MFT_MENUBARBREAK ");
93 if(MFT_MENUBREAK & MenuItem->fType)
94 DbgPrint("MFT_MENUBREAK ");
95 if(MFT_OWNERDRAW & MenuItem->fType)
96 DbgPrint("MFT_OWNERDRAW ");
97 if(MFT_RADIOCHECK & MenuItem->fType)
98 DbgPrint("MFT_RADIOCHECK ");
99 if(MFT_RIGHTJUSTIFY & MenuItem->fType)
100 DbgPrint("MFT_RIGHTJUSTIFY ");
101 if(MFT_SEPARATOR & MenuItem->fType)
102 DbgPrint("MFT_SEPARATOR ");
103 if(MFT_STRING & MenuItem->fType)
104 DbgPrint("MFT_STRING ");
105 DbgPrint("\n fState=");
106 if(MFS_DISABLED & MenuItem->fState)
107 DbgPrint("MFS_DISABLED ");
108 else
109 DbgPrint("MFS_ENABLED ");
110 if(MFS_CHECKED & MenuItem->fState)
111 DbgPrint("MFS_CHECKED ");
112 else
113 DbgPrint("MFS_UNCHECKED ");
114 if(MFS_HILITE & MenuItem->fState)
115 DbgPrint("MFS_HILITE ");
116 else
117 DbgPrint("MFS_UNHILITE ");
118 if(MFS_DEFAULT & MenuItem->fState)
119 DbgPrint("MFS_DEFAULT ");
120 if(MFS_GRAYED & MenuItem->fState)
121 DbgPrint("MFS_GRAYED ");
122 DbgPrint("\n wId=%d\n", MenuItem->wID);
123 MenuItem = MenuItem->Next;
124 }
125 DbgPrint("Entries: %d\n", cnt);
126 return;
127 }
128 #endif
129
130 PMENU_OBJECT FASTCALL
131 IntGetMenuObject(HMENU hMenu)
132 {
133 PMENU_OBJECT Menu = UserGetMenuObject(hMenu);
134 if (Menu)
135 Menu->head.cLockObj++;
136
137 return Menu;
138 }
139
140 BOOL FASTCALL
141 IntFreeMenuItem(PMENU_OBJECT Menu, PMENU_ITEM MenuItem, BOOL bRecurse)
142 {
143 FreeMenuText(MenuItem);
144 if(bRecurse && MenuItem->hSubMenu)
145 {
146 PMENU_OBJECT SubMenu;
147 SubMenu = UserGetMenuObject(MenuItem->hSubMenu );
148 if(SubMenu)
149 {
150 IntDestroyMenuObject(SubMenu, bRecurse, TRUE);
151 }
152 }
153
154 /* Free memory */
155 ExFreePoolWithTag(MenuItem, TAG_MENUITEM);
156
157 return TRUE;
158 }
159
160 BOOL FASTCALL
161 IntRemoveMenuItem(PMENU_OBJECT Menu, UINT uPosition, UINT uFlags,
162 BOOL bRecurse)
163 {
164 PMENU_ITEM PrevMenuItem, MenuItem;
165 if(IntGetMenuItemByFlag(Menu, uPosition, uFlags, &Menu, &MenuItem,
166 &PrevMenuItem) > -1)
167 {
168 if(MenuItem)
169 {
170 if(PrevMenuItem)
171 PrevMenuItem->Next = MenuItem->Next;
172 else
173 {
174 Menu->MenuItemList = MenuItem->Next;
175 }
176 Menu->MenuInfo.MenuItemCount--;
177 return IntFreeMenuItem(Menu, MenuItem, bRecurse);
178 }
179 }
180 return FALSE;
181 }
182
183 UINT FASTCALL
184 IntDeleteMenuItems(PMENU_OBJECT Menu, BOOL bRecurse)
185 {
186 UINT res = 0;
187 PMENU_ITEM NextItem;
188 PMENU_ITEM CurItem = Menu->MenuItemList;
189 while(CurItem)
190 {
191 NextItem = CurItem->Next;
192 IntFreeMenuItem(Menu, CurItem, bRecurse);
193 CurItem = NextItem;
194 res++;
195 }
196 Menu->MenuInfo.MenuItemCount = 0;
197 Menu->MenuItemList = NULL;
198 return res;
199 }
200
201 BOOL FASTCALL
202 IntDestroyMenuObject(PMENU_OBJECT Menu,
203 BOOL bRecurse, BOOL RemoveFromProcess)
204 {
205 if(Menu)
206 {
207 PWND Window;
208 PWINSTATION_OBJECT WindowStation;
209 NTSTATUS Status;
210
211 /* Remove all menu items */
212 IntDeleteMenuItems(Menu, bRecurse); /* Do not destroy submenus */
213
214 if(RemoveFromProcess)
215 {
216 RemoveEntryList(&Menu->ListEntry);
217 }
218
219 Status = ObReferenceObjectByHandle(Menu->Process->Win32WindowStation,
220 0,
221 ExWindowStationObjectType,
222 KernelMode,
223 (PVOID*)&WindowStation,
224 NULL);
225 if(NT_SUCCESS(Status))
226 {
227 BOOL ret;
228 if (Menu->MenuInfo.Wnd)
229 {
230 Window = UserGetWindowObject(Menu->MenuInfo.Wnd);
231 if (Window)
232 {
233 Window->IDMenu = 0;
234 }
235 }
236 // UserDereferenceObject(Menu);
237 ret = UserDeleteObject(Menu->MenuInfo.Self, otMenu);
238 ObDereferenceObject(WindowStation);
239 return ret;
240 }
241 }
242 return FALSE;
243 }
244
245 PMENU_OBJECT FASTCALL
246 IntCreateMenu(PHANDLE Handle, BOOL IsMenuBar)
247 {
248 PMENU_OBJECT Menu;
249 PPROCESSINFO CurrentWin32Process;
250
251 Menu = (PMENU_OBJECT)UserCreateObject( gHandleTable,
252 NULL,
253 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
1818 if (MenuObject->MenuItemList)
1819 {
1820 SubMenuObject = UserGetMenuObject(MenuObject->MenuItemList->hSubMenu);
1821 if(SubMenuObject) kmbi.hwndMenu = SubMenuObject->MenuInfo.Wnd;
1822 }
1823 TRACE("OBJID_MENU, idItem = %d\n",idItem);
1824 break;
1825 }
1826 case OBJID_CLIENT:
1827 {
1828 PMENU_OBJECT SubMenuObject, XSubMenuObject;
1829 HMENU hMenuChk;
1830 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
1831 hMenuChk = (HMENU)co_IntSendMessage(hwnd, MN_GETHMENU, 0, 0);
1832
1833 if (!(MenuObject = UserGetMenuObject(hMenuChk)))
1834 {
1835 ERR("Window does not have a Popup Menu!\n");
1836 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
1837 RETURN(FALSE);
1838 }
1839
1840 SubMenuObject = UserGetMenuObject(MenuObject->MenuItemList->hSubMenu);
1841 if(SubMenuObject) kmbi.hMenu = SubMenuObject->MenuInfo.Self;
1842 else
1843 {
1844 Res = FALSE;
1845 ERR("OBJID_CLIENT, No SubMenu!\n");
1846 break;
1847 }
1848 if (idItem)
1849 {
1850 if (IntGetMenuItemByFlag(SubMenuObject, idItem-1, MF_BYPOSITION, NULL, &mi, NULL) > -1)
1851 kmbi.rcBar = mi->Rect;
1852 else
1853 {
1854 Res = FALSE;
1855 break;
1856 }
1857 }
1858 else
1859 {
1860 PWND SubWinObj;
1861 if (!(SubWinObj = UserGetWindowObject(SubMenuObject->MenuInfo.Wnd)))
1862 {
1863 Res = FALSE;
1864 break;
1865 }
1866 if (!(IntGetClientOrigin(SubWinObj, &Offset)))
1867 {
1868 Res = FALSE;
1869 break;
1870 }
1871 Rect.left = Offset.x;
1872 Rect.right = Offset.x + SubMenuObject->MenuInfo.Width;
1873 Rect.top = Offset.y;
1874 Rect.bottom = Offset.y + SubMenuObject->MenuInfo.Height;
1875 kmbi.rcBar = Rect;
1876 }
1877 if (idItem)
1878 {
1879 if (idItem-1 == SubMenuObject->MenuInfo.FocusedItem)
1880 kmbi.fFocused = TRUE;
1881 }
1882 if (SubMenuObject->MenuInfo.FocusedItem != NO_SELECTED_ITEM)
1883 kmbi.fBarFocused = TRUE;
1884 XSubMenuObject = UserGetMenuObject(SubMenuObject->MenuItemList->hSubMenu);
1885 if (XSubMenuObject) kmbi.hwndMenu = XSubMenuObject->MenuInfo.Wnd;
1886 TRACE("OBJID_CLIENT, idItem = %d\n",idItem);
1887 break;
1888 }
1889 case OBJID_SYSMENU:
1890 {
1891 PMENU_OBJECT SysMenuObject, SubMenuObject;
1892 if(!(SysMenuObject = IntGetSystemMenu(WindowObject, FALSE, FALSE)))
1893 {
1894 Res = FALSE;
1895 break;
1896 }
1897 kmbi.hMenu = SysMenuObject->MenuInfo.Self;
1898 if (idItem)
1899 {
1900 if (IntGetMenuItemByFlag(SysMenuObject, idItem-1, MF_BYPOSITION, NULL, &mi, NULL) > -1)
1901 kmbi.rcBar = mi->Rect;
1902 else
1903 {
1904 Res = FALSE;
1905 break;
1906 }
1907 }
1908 else
1909 {
1910 PWND SysWinObj;
1911 if (!(SysWinObj = UserGetWindowObject(SysMenuObject->MenuInfo.Wnd)))
1912 {
1913 Res = FALSE;
1914 break;
1915 }
1916 if (!(IntGetClientOrigin(SysWinObj, &Offset)))
1917 {
1918 Res = FALSE;
1919 break;
1920 }
1921 Rect.left = Offset.x;
1922 Rect.right = Offset.x + SysMenuObject->MenuInfo.Width;
1923 Rect.top = Offset.y;
1924 Rect.bottom = Offset.y + SysMenuObject->MenuInfo.Height;
1925 kmbi.rcBar = Rect;
1926 }
1927 if (idItem)
1928 {
1929 if (idItem-1 == SysMenuObject->MenuInfo.FocusedItem)
1930 kmbi.fFocused = TRUE;
1931 }
1932 if (SysMenuObject->MenuInfo.FocusedItem != NO_SELECTED_ITEM)
1933 kmbi.fBarFocused = TRUE;
1934 SubMenuObject = UserGetMenuObject(SysMenuObject->MenuItemList->hSubMenu);
1935 if(SubMenuObject) kmbi.hwndMenu = SubMenuObject->MenuInfo.Wnd;
1936 TRACE("OBJID_SYSMENU, idItem = %d\n",idItem);
1937 break;
1938 }
1939 default:
1940 Res = FALSE;
1941 ERR("Unknown idObject = %d, idItem = %d\n",idObject,idItem);
1942 }
1943 if (Res)
1944 {
1945 NTSTATUS Status = MmCopyToCaller(pmbi, &kmbi, sizeof(MENUBARINFO));
1946 if (! NT_SUCCESS(Status))
1947 {
1948 SetLastNtError(Status);
1949 RETURN(FALSE);
1950 }
1951 }
1952 RETURN(Res);
1953
1954 CLEANUP:
1955 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_);
1956 UserLeave();
1957 END_CLEANUP;
1958 }
1959
1960 /*
1961 * @implemented
1962 */
1963 UINT APIENTRY
1964 NtUserGetMenuIndex(
1965 HMENU hMenu,
1966 HMENU hSubMenu)
1967 {
1968 PMENU_OBJECT Menu, SubMenu;
1969 PMENU_ITEM MenuItem;
1970 DECLARE_RETURN(UINT);
1971
1972 TRACE("Enter NtUserGetMenuIndex\n");
1973 UserEnterShared();
1974
1975 if ( !(Menu = UserGetMenuObject(hMenu)) ||
1976 !(SubMenu = UserGetMenuObject(hSubMenu)) )
1977 RETURN(0xFFFFFFFF);
1978
1979 MenuItem = Menu->MenuItemList;
1980 while(MenuItem)
1981 {
1982 if (MenuItem->hSubMenu == hSubMenu)
1983 RETURN(MenuItem->wID);
1984 MenuItem = MenuItem->Next;
1985 }
1986
1987 RETURN(0xFFFFFFFF);
1988
1989 CLEANUP:
1990 TRACE("Leave NtUserGetMenuIndex, ret=%i\n",_ret_);
1991 UserLeave();
1992 END_CLEANUP;
1993 }
1994
1995 /*
1996 * @implemented
1997 */
1998 BOOL APIENTRY
1999 NtUserGetMenuItemRect(
2000 HWND hWnd,
2001 HMENU hMenu,
2002 UINT uItem,
2003 PRECTL lprcItem)
2004 {
2005 PWND ReferenceWnd;
2006 LONG XMove, YMove;
2007 RECTL Rect;
2008 NTSTATUS Status;
2009 PMENU_OBJECT Menu;
2010 PMENU_ITEM MenuItem;
2011 DECLARE_RETURN(BOOL);
2012
2013 TRACE("Enter NtUserGetMenuItemRect\n");
2014 UserEnterShared();
2015
2016 if (!(Menu = UserGetMenuObject(hMenu)))
2017 {
2018 RETURN(FALSE);
2019 }
2020
2021 if (IntGetMenuItemByFlag(Menu, uItem, MF_BYPOSITION, NULL, &MenuItem, NULL) > -1)
2022 Rect = MenuItem->Rect;
2023 else
2024 RETURN(FALSE);
2025
2026 if(!hWnd)
2027 {
2028 hWnd = Menu->MenuInfo.Wnd;
2029 }
2030
2031 if (lprcItem == NULL) RETURN( FALSE);
2032
2033 if (!(ReferenceWnd = UserGetWindowObject(hWnd))) RETURN( FALSE);
2034
2035 if(MenuItem->fType & MF_POPUP)
2036 {
2037 XMove = ReferenceWnd->rcClient.left;
2038 YMove = ReferenceWnd->rcClient.top;
2039 }
2040 else
2041 {
2042 XMove = ReferenceWnd->rcWindow.left;
2043 YMove = ReferenceWnd->rcWindow.top;
2044 }
2045
2046 Rect.left += XMove;
2047 Rect.top += YMove;
2048 Rect.right += XMove;
2049 Rect.bottom += YMove;
2050
2051 Status = MmCopyToCaller(lprcItem, &Rect, sizeof(RECT));
2052 if (! NT_SUCCESS(Status))
2053 {
2054 SetLastNtError(Status);
2055 RETURN( FALSE);
2056 }
2057 RETURN( TRUE);
2058
2059 CLEANUP:
2060 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_);
2061 UserLeave();
2062 END_CLEANUP;
2063 }
2064
2065 /*
2066 * @implemented
2067 */
2068 BOOL APIENTRY
2069 NtUserHiliteMenuItem(
2070 HWND hWnd,
2071 HMENU hMenu,
2072 UINT uItemHilite,
2073 UINT uHilite)
2074 {
2075 PMENU_OBJECT Menu;
2076 PWND Window;
2077 DECLARE_RETURN(BOOLEAN);
2078
2079 TRACE("Enter NtUserHiliteMenuItem\n");
2080 UserEnterExclusive();
2081
2082 if(!(Window = UserGetWindowObject(hWnd)))
2083 {
2084 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
2085 RETURN(FALSE);
2086 }
2087
2088 if(!(Menu = UserGetMenuObject(hMenu)))
2089 {
2090 EngSetLastError(ERROR_INVALID_MENU_HANDLE);
2091 RETURN(FALSE);
2092 }
2093
2094 if(Window->IDMenu == (UINT)(UINT_PTR)hMenu)
2095 {
2096 RETURN( IntHiliteMenuItem(Window, Menu, uItemHilite, uHilite));
2097 }
2098
2099 RETURN(FALSE);
2100
2101 CLEANUP:
2102 TRACE("Leave NtUserHiliteMenuItem, ret=%i\n",_ret_);
2103 UserLeave();
2104 END_CLEANUP;
2105 }
2106
2107 static
2108 BOOL FASTCALL
2109 UserMenuInfo(
2110 PMENU_OBJECT Menu,
2111 PROSMENUINFO UnsafeMenuInfo,
2112 BOOL SetOrGet)
2113 {
2114 BOOL Res;
2115 DWORD Size;
2116 NTSTATUS Status;
2117 ROSMENUINFO MenuInfo;
2118
2119 Status = MmCopyFromCaller(&Size, &UnsafeMenuInfo->cbSize, sizeof(DWORD));
2120 if (! NT_SUCCESS(Status))
2121 {
2122 SetLastNtError(Status);
2123 return( FALSE);
2124 }
2125 if(Size < sizeof(MENUINFO) || sizeof(ROSMENUINFO) < Size)
2126 {
2127 EngSetLastError(ERROR_INVALID_PARAMETER);
2128 return( FALSE);
2129 }
2130 Status = MmCopyFromCaller(&MenuInfo, UnsafeMenuInfo, Size);
2131 if (! NT_SUCCESS(Status))
2132 {
2133 SetLastNtError(Status);
2134 return( FALSE);
2135 }
2136
2137 if(SetOrGet)
2138 {
2139 /* Set MenuInfo */
2140 Res = IntSetMenuInfo(Menu, &MenuInfo);
2141 }
2142 else
2143 {
2144 /* Get MenuInfo */
2145 Res = IntGetMenuInfo(Menu, &MenuInfo);
2146 if (Res)
2147 {
2148 Status = MmCopyToCaller(UnsafeMenuInfo, &MenuInfo, Size);
2149 if (! NT_SUCCESS(Status))
2150 {
2151 SetLastNtError(Status);
2152 return( FALSE);
2153 }
2154 }
2155 }
2156
2157 return( Res);
2158 }
2159
2160 /*
2161 * @implemented
2162 */
2163 int APIENTRY
2164 NtUserMenuItemFromPoint(
2165 HWND hWnd,
2166 HMENU hMenu,
2167 DWORD X,
2168 DWORD Y)
2169 {
2170 PMENU_OBJECT Menu;
2171 PWND Window = NULL;
2172 PMENU_ITEM mi;
2173 int i;
2174 DECLARE_RETURN(int);
2175
2176 TRACE("Enter NtUserMenuItemFromPoint\n");
2177 UserEnterExclusive();
2178
2179 if (!(Menu = UserGetMenuObject(hMenu)))
2180 {
2181 RETURN( -1);
2182 }
2183
2184 if (!(Window = UserGetWindowObject(Menu->MenuInfo.Wnd)))
2185 {
2186 RETURN( -1);
2187 }
2188
2189 X -= Window->rcWindow.left;
2190 Y -= Window->rcWindow.top;
2191
2192 mi = Menu->MenuItemList;
2193 for (i = 0; NULL != mi; i++)
2194 {
2195 if (RECTL_bPointInRect(&(mi->Rect), X, Y))
2196 {
2197 break;
2198 }
2199 mi = mi->Next;
2200 }
2201
2202 RETURN( (mi ? i : NO_SELECTED_ITEM));
2203
2204 CLEANUP:
2205 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_);
2206 UserLeave();
2207 END_CLEANUP;
2208 }
2209
2210 static
2211 BOOL FASTCALL
2212 UserMenuItemInfo(
2213 PMENU_OBJECT Menu,
2214 UINT Item,
2215 BOOL ByPosition,
2216 PROSMENUITEMINFO UnsafeItemInfo,
2217 BOOL SetOrGet)
2218 {
2219 PMENU_ITEM MenuItem;
2220 ROSMENUITEMINFO ItemInfo;
2221 NTSTATUS Status;
2222 UINT Size;
2223 BOOL Ret;
2224
2225 Status = MmCopyFromCaller(&Size, &UnsafeItemInfo->cbSize, sizeof(UINT));
2226 if (! NT_SUCCESS(Status))
2227 {
2228 SetLastNtError(Status);
2229 return( FALSE);
2230 }
2231 if (sizeof(MENUITEMINFOW) != Size
2232 && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != Size
2233 && sizeof(ROSMENUITEMINFO) != Size)
2234 {
2235 EngSetLastError(ERROR_INVALID_PARAMETER);
2236 return( FALSE);
2237 }
2238 Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, Size);
2239 if (! NT_SUCCESS(Status))
2240 {
2241 SetLastNtError(Status);
2242 return( FALSE);
2243 }
2244 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
2245 set/get hbmpItem */
2246 if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) == Size
2247 && 0 != (ItemInfo.fMask & MIIM_BITMAP))
2248 {
2249 EngSetLastError(ERROR_INVALID_PARAMETER);
2250 return( FALSE);
2251 }
2252
2253 if (IntGetMenuItemByFlag(Menu, Item,
2254 (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND),
2255 NULL, &MenuItem, NULL) < 0)
2256 {
2257 EngSetLastError(ERROR_INVALID_PARAMETER);
2258 // This will crash menu (line 80) correct_behavior test!
2259 // "NT4 and below can't handle a bigger MENUITEMINFO struct"
2260 //EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND);
2261 return( FALSE);
2262 }
2263
2264 if (SetOrGet)
2265 {
2266 Ret = IntSetMenuItemInfo(Menu, MenuItem, &ItemInfo);
2267 }
2268 else
2269 {
2270 Ret = IntGetMenuItemInfo(Menu, MenuItem, &ItemInfo);
2271 if (Ret)
2272 {
2273 Status = MmCopyToCaller(UnsafeItemInfo, &ItemInfo, Size);
2274 if (! NT_SUCCESS(Status))
2275 {
2276 SetLastNtError(Status);
2277 return( FALSE);
2278 }
2279 }
2280 }
2281
2282 return( Ret);
2283 }
2284
2285 /*
2286 * @implemented
2287 */
2288 BOOL APIENTRY
2289 NtUserRemoveMenu(
2290 HMENU hMenu,
2291 UINT uPosition,
2292 UINT uFlags)
2293 {
2294 PMENU_OBJECT Menu;
2295 DECLARE_RETURN(BOOL);
2296
2297 TRACE("Enter NtUserRemoveMenu\n");
2298 UserEnterExclusive();
2299
2300 if(!(Menu = UserGetMenuObject(hMenu)))
2301 {
2302 RETURN( FALSE);
2303 }
2304
2305 RETURN(IntRemoveMenuItem(Menu, uPosition, uFlags, FALSE));
2306
2307 CLEANUP:
2308 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_);
2309 UserLeave();
2310 END_CLEANUP;
2311
2312 }
2313
2314 /*
2315 * @implemented
2316 */
2317 BOOL APIENTRY
2318 NtUserSetMenuContextHelpId(
2319 HMENU hMenu,
2320 DWORD dwContextHelpId)
2321 {
2322 PMENU_OBJECT Menu;
2323 DECLARE_RETURN(BOOL);
2324
2325 TRACE("Enter NtUserSetMenuContextHelpId\n");
2326 UserEnterExclusive();
2327
2328 if(!(Menu = UserGetMenuObject(hMenu)))
2329 {
2330 RETURN( FALSE);
2331 }
2332
2333 RETURN(IntSetMenuContextHelpId(Menu, dwContextHelpId));
2334
2335 CLEANUP:
2336 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_);
2337 UserLeave();
2338 END_CLEANUP;
2339 }
2340
2341 /*
2342 * @implemented
2343 */
2344 BOOL APIENTRY
2345 NtUserSetMenuDefaultItem(
2346 HMENU hMenu,
2347 UINT uItem,
2348 UINT fByPos)
2349 {
2350 PMENU_OBJECT Menu;
2351 DECLARE_RETURN(BOOL);
2352
2353 TRACE("Enter NtUserSetMenuDefaultItem\n");
2354 UserEnterExclusive();
2355
2356 if(!(Menu = UserGetMenuObject(hMenu)))
2357 {
2358 RETURN( FALSE);
2359 }
2360
2361 RETURN( UserSetMenuDefaultItem(Menu, uItem, fByPos));
2362
2363 CLEANUP:
2364 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_);
2365 UserLeave();
2366 END_CLEANUP;
2367 }
2368
2369 /*
2370 * @implemented
2371 */
2372 BOOL APIENTRY
2373 NtUserSetMenuFlagRtoL(
2374 HMENU hMenu)
2375 {
2376 PMENU_OBJECT Menu;
2377 DECLARE_RETURN(BOOL);
2378
2379 TRACE("Enter NtUserSetMenuFlagRtoL\n");
2380 UserEnterExclusive();
2381
2382 if(!(Menu = UserGetMenuObject(hMenu)))
2383 {
2384 RETURN( FALSE);
2385 }
2386
2387 RETURN(IntSetMenuFlagRtoL(Menu));
2388
2389 CLEANUP:
2390 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_);
2391 UserLeave();
2392 END_CLEANUP;
2393 }
2394
2395 /*
2396 * @implemented
2397 */
2398 BOOL APIENTRY
2399 NtUserThunkedMenuInfo(
2400 HMENU hMenu,
2401 LPCMENUINFO lpcmi)
2402 {
2403 PMENU_OBJECT Menu;
2404 DECLARE_RETURN(BOOL);
2405
2406 TRACE("Enter NtUserThunkedMenuInfo\n");
2407 UserEnterExclusive();
2408
2409 if (!(Menu = UserGetMenuObject(hMenu)))
2410 {
2411 RETURN(FALSE);
2412 }
2413
2414 RETURN(UserMenuInfo(Menu, (PROSMENUINFO)lpcmi, TRUE));
2415
2416 CLEANUP:
2417 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_);
2418 UserLeave();
2419 END_CLEANUP;
2420 }
2421
2422 /*
2423 * @implemented
2424 */
2425 BOOL APIENTRY
2426 NtUserThunkedMenuItemInfo(
2427 HMENU hMenu,
2428 UINT uItem,
2429 BOOL fByPosition,
2430 BOOL bInsert,
2431 LPMENUITEMINFOW lpmii,
2432 PUNICODE_STRING lpszCaption)
2433 {
2434 PMENU_OBJECT Menu;
2435 NTSTATUS Status;
2436 UNICODE_STRING lstrCaption;
2437 DECLARE_RETURN(BOOL);
2438
2439 TRACE("Enter NtUserThunkedMenuItemInfo\n");
2440 UserEnterExclusive();
2441
2442 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
2443 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */
2444
2445 if (!(Menu = UserGetMenuObject(hMenu)))
2446 {
2447 RETURN(FALSE);
2448 }
2449
2450 lstrCaption.Buffer = NULL;
2451
2452 /* Check if we got a Caption */
2453 if (lpszCaption)
2454 {
2455 /* Copy the string to kernel mode */
2456 Status = ProbeAndCaptureUnicodeString( &lstrCaption,
2457 UserMode,
2458 lpszCaption);
2459 if (!NT_SUCCESS(Status))
2460 {
2461 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status);
2462 SetLastNtError(Status);
2463 RETURN(FALSE);
2464 }
2465 }
2466
2467 if (bInsert) RETURN( UserInsertMenuItem(Menu, uItem, fByPosition, lpmii));
2468
2469 RETURN( UserMenuItemInfo(Menu, uItem, fByPosition, (PROSMENUITEMINFO)lpmii, TRUE));
2470
2471 CLEANUP:
2472 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_);
2473 UserLeave();
2474 END_CLEANUP;
2475 }
2476
2477 ////// ReactOS NtUserBad
2478 /*
2479 * @implemented
2480 */
2481 DWORD
2482 APIENTRY
2483 NtUserBuildMenuItemList(
2484 HMENU hMenu,
2485 VOID* Buffer,
2486 ULONG nBufSize,
2487 DWORD Reserved)
2488 {
2489 DWORD res = -1;
2490 PMENU_OBJECT Menu;
2491 DECLARE_RETURN(DWORD);
2492
2493 TRACE("Enter NtUserBuildMenuItemList\n");
2494 UserEnterExclusive();
2495
2496 if(!(Menu = UserGetMenuObject(hMenu)))
2497 {
2498 RETURN( (DWORD)-1);
2499 }
2500
2501 if(Buffer)
2502 {
2503 res = IntBuildMenuItemList(Menu, Buffer, nBufSize);
2504 }
2505 else
2506 {
2507 res = Menu->MenuInfo.MenuItemCount;
2508 }
2509
2510 RETURN( res);
2511
2512 CLEANUP:
2513 TRACE("Leave NtUserBuildMenuItemList, ret=%i\n",_ret_);
2514 UserLeave();
2515 END_CLEANUP;
2516 }
2517
2518 /*
2519 * @implemented
2520 */
2521 UINT APIENTRY
2522 NtUserGetMenuDefaultItem(
2523 HMENU hMenu,
2524 UINT fByPos,
2525 UINT gmdiFlags)
2526 {
2527 PMENU_OBJECT Menu;
2528 DWORD gismc = 0;
2529 DECLARE_RETURN(UINT);
2530
2531 TRACE("Enter NtUserGetMenuDefaultItem\n");
2532 UserEnterExclusive();
2533
2534 if(!(Menu = UserGetMenuObject(hMenu)))
2535 {
2536 RETURN(-1);
2537 }
2538
2539 RETURN( IntGetMenuDefaultItem(Menu, fByPos, gmdiFlags, &gismc));
2540
2541 CLEANUP:
2542 TRACE("Leave NtUserGetMenuDefaultItem, ret=%i\n",_ret_);
2543 UserLeave();
2544 END_CLEANUP;
2545 }
2546
2547 /*
2548 * @implemented
2549 */
2550 BOOL
2551 APIENTRY
2552 NtUserMenuInfo(
2553 HMENU hMenu,
2554 PROSMENUINFO UnsafeMenuInfo,
2555 BOOL SetOrGet)
2556 {
2557 PMENU_OBJECT Menu;
2558 DECLARE_RETURN(BOOL);
2559
2560 TRACE("Enter NtUserMenuInfo\n");
2561 UserEnterShared();
2562
2563 if (!(Menu = UserGetMenuObject(hMenu)))
2564 {
2565 RETURN(FALSE);
2566 }
2567
2568 RETURN(UserMenuInfo(Menu, UnsafeMenuInfo, SetOrGet));
2569
2570 CLEANUP:
2571 TRACE("Leave NtUserMenuInfo, ret=%i\n",_ret_);
2572 UserLeave();
2573 END_CLEANUP;
2574 }
2575
2576 /*
2577 * @implemented
2578 */
2579 BOOL
2580 APIENTRY
2581 NtUserMenuItemInfo(
2582 HMENU hMenu,
2583 UINT Item,
2584 BOOL ByPosition,
2585 PROSMENUITEMINFO UnsafeItemInfo,
2586 BOOL SetOrGet)
2587 {
2588 PMENU_OBJECT Menu;
2589 DECLARE_RETURN(BOOL);
2590
2591 TRACE("Enter NtUserMenuItemInfo\n");
2592 UserEnterExclusive();
2593
2594 if (!(Menu = UserGetMenuObject(hMenu)))
2595 {
2596 RETURN(FALSE);
2597 }
2598
2599 RETURN( UserMenuItemInfo(Menu, Item, ByPosition, UnsafeItemInfo, SetOrGet));
2600
2601 CLEANUP:
2602 TRACE("Leave NtUserMenuItemInfo, ret=%i\n",_ret_);
2603 UserLeave();
2604 END_CLEANUP;
2605
2606 }
2607
2608 /* EOF */