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