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