2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
5 * FILE: subsys/win32k/ntuser/menu.c
6 * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
10 DBG_DEFAULT_CHANNEL(UserMenu
);
12 /* INTERNAL ******************************************************************/
14 BOOL FASTCALL
IntSetMenuItemInfo(PMENU
, PITEM
, PROSMENUITEMINFO
, PUNICODE_STRING
);
16 /* maximum allowed depth of any branch in the menu tree.
17 * This value is slightly larger than in windows (25) to
18 * stay on the safe side. */
19 #define MAXMENUDEPTH 30
21 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
23 #define MENUITEMINFO_TYPE_MASK \
24 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
25 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
26 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
28 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
30 #define STATE_MASK (~TYPE_MASK)
32 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
34 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
36 /* Maximum number of menu items a menu can contain */
37 #define MAX_MENU_ITEMS (0x4000)
38 #define MAX_GOINTOSUBMENU (0x10)
40 #define UpdateMenuItemState(state, change) \
42 if((change) & MF_GRAYED) { \
43 (state) |= MF_GRAYED; \
45 (state) &= ~MF_GRAYED; \
46 } /* Separate the two for test_menu_resource_layout.*/ \
47 if((change) & MF_DISABLED) { \
48 (state) |= MF_DISABLED; \
50 (state) &= ~MF_DISABLED; \
52 if((change) & MFS_CHECKED) { \
53 (state) |= MFS_CHECKED; \
55 (state) &= ~MFS_CHECKED; \
57 if((change) & MFS_HILITE) { \
58 (state) |= MFS_HILITE; \
60 (state) &= ~MFS_HILITE; \
62 if((change) & MFS_DEFAULT) { \
63 (state) |= MFS_DEFAULT; \
65 (state) &= ~MFS_DEFAULT; \
67 if((change) & MF_MOUSESELECT) { \
68 (state) |= MF_MOUSESELECT; \
70 (state) &= ~MF_MOUSESELECT; \
76 DumpMenuItemList(PMENU Menu
, PITEM MenuItem
)
78 UINT cnt
= 0, i
= Menu
->cItems
;
81 if(MenuItem
->lpstr
.Length
)
82 DbgPrint(" %d. %wZ\n", ++cnt
, &MenuItem
->lpstr
);
84 DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt
, (DWORD
)MenuItem
->lpstr
.Buffer
);
86 if(MFT_BITMAP
& MenuItem
->fType
)
87 DbgPrint("MFT_BITMAP ");
88 if(MFT_MENUBARBREAK
& MenuItem
->fType
)
89 DbgPrint("MFT_MENUBARBREAK ");
90 if(MFT_MENUBREAK
& MenuItem
->fType
)
91 DbgPrint("MFT_MENUBREAK ");
92 if(MFT_OWNERDRAW
& MenuItem
->fType
)
93 DbgPrint("MFT_OWNERDRAW ");
94 if(MFT_RADIOCHECK
& MenuItem
->fType
)
95 DbgPrint("MFT_RADIOCHECK ");
96 if(MFT_RIGHTJUSTIFY
& MenuItem
->fType
)
97 DbgPrint("MFT_RIGHTJUSTIFY ");
98 if(MFT_SEPARATOR
& MenuItem
->fType
)
99 DbgPrint("MFT_SEPARATOR ");
100 if(MFT_STRING
& MenuItem
->fType
)
101 DbgPrint("MFT_STRING ");
102 DbgPrint("\n fState=");
103 if(MFS_DISABLED
& MenuItem
->fState
)
104 DbgPrint("MFS_DISABLED ");
106 DbgPrint("MFS_ENABLED ");
107 if(MFS_CHECKED
& MenuItem
->fState
)
108 DbgPrint("MFS_CHECKED ");
110 DbgPrint("MFS_UNCHECKED ");
111 if(MFS_HILITE
& MenuItem
->fState
)
112 DbgPrint("MFS_HILITE ");
114 DbgPrint("MFS_UNHILITE ");
115 if(MFS_DEFAULT
& MenuItem
->fState
)
116 DbgPrint("MFS_DEFAULT ");
117 if(MFS_GRAYED
& MenuItem
->fState
)
118 DbgPrint("MFS_GRAYED ");
119 DbgPrint("\n wId=%d\n", MenuItem
->wID
);
123 DbgPrint("Entries: %d\n", cnt
);
128 #define FreeMenuText(Menu,MenuItem) \
130 if((MENU_ITEM_TYPE((MenuItem)->fType) == MF_STRING) && \
131 (MenuItem)->lpstr.Length) { \
132 DesktopHeapFree(((PMENU)Menu)->head.rpdesk, (MenuItem)->lpstr.Buffer); \
137 IntGetMenuObject(HMENU hMenu
)
139 PMENU Menu
= UserGetMenuObject(hMenu
);
141 Menu
->head
.cLockObj
++;
146 PMENU FASTCALL
VerifyMenu(PMENU pMenu
)
151 if (!pMenu
) return NULL
;
153 ERR("VerifyMenu 1!\n");
156 hMenu
= UserHMGetHandle(pMenu
);
157 pItem
= pMenu
->rgItems
;
164 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
166 ERR("Run away LOOP!\n");
167 _SEH2_YIELD(return NULL
);
170 ERR("VerifyMenu 2!\n");
171 if ( UserObjectInDestroy(hMenu
))
173 ERR("VerifyMenu 3!\n");
177 BOOL
IntDestroyMenu( PMENU pMenu
, BOOL bRecurse
, BOOL RemoveFromProcess
)
179 /* DestroyMenu should not destroy system menu popup owner */
180 if ((pMenu
->fFlags
& (MNF_POPUP
| MNF_SYSSUBMENU
)) == MNF_POPUP
&& pMenu
->hWnd
)
182 //PWND pWnd = ValidateHwndNoErr(pMenu->hWnd);
183 ERR("FIXME Pop up menu window thing'ie\n");
185 //co_UserDestroyWindow( pWnd );
189 if (pMenu
->rgItems
) /* recursively destroy submenus */
192 ITEM
*item
= pMenu
->rgItems
;
193 for (i
= pMenu
->cItems
; i
> 0; i
--, item
++)
195 pMenu
->cItems
--; //// I hate recursion logic! (jt) 4/2014. See r63028 comment for IntDeleteMenuItems.
196 FreeMenuText(pMenu
,item
);
197 if (bRecurse
&& item
->spSubMenu
)//VerifyMenu(item->spSubMenu))
199 IntDestroyMenu(item
->spSubMenu
, bRecurse
, RemoveFromProcess
);
200 item
->spSubMenu
= NULL
;
203 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
204 pMenu
->rgItems
= NULL
;
205 pMenu
->cItems
= 0; //// What ever~!
211 IntDestroyMenuObject(PMENU Menu
,
212 BOOL bRecurse
, BOOL RemoveFromProcess
)
218 /* Remove all menu items */
219 IntDestroyMenu( Menu
, bRecurse
, RemoveFromProcess
);
221 if(RemoveFromProcess
)
223 RemoveEntryList(&Menu
->ListEntry
);
226 if (PsGetCurrentProcessSessionId() == Menu
->head
.rpdesk
->rpwinstaParent
->dwSessionId
)
231 Window
= UserGetWindowObject(Menu
->hWnd
);
237 //UserDereferenceObject(Menu);
238 ret
= UserDeleteObject(Menu
->head
.h
, TYPE_MENU
);
240 { // Make sure it is really dead or just marked for deletion.
241 ret
= UserObjectInDestroy(Menu
->head
.h
);
242 if (ret
&& EngGetLastError() == ERROR_INVALID_HANDLE
) ret
= FALSE
;
243 } // See test_subpopup_locked_by_menu tests....
250 /**********************************************************************
253 * detect if there are loops in the menu tree (or the depth is too large)
255 int FASTCALL
MENU_depth( PMENU pmenu
, int depth
)
261 if (!pmenu
) return depth
;
264 if( depth
> MAXMENUDEPTH
) return depth
;
265 item
= pmenu
->rgItems
;
267 for( i
= 0; item
, i
< pmenu
->cItems
&& subdepth
<= MAXMENUDEPTH
; i
++, item
++)
269 if( item
->spSubMenu
)//VerifyMenu(item->spSubMenu))
271 int bdepth
= MENU_depth( item
->spSubMenu
, depth
);
272 if( bdepth
> subdepth
) subdepth
= bdepth
;
274 if( subdepth
> MAXMENUDEPTH
)
275 TRACE("<- hmenu %p\n", item
->spSubMenu
);
280 /***********************************************************************
283 * Find a menu item. Return a pointer on the item, and modifies *hmenu
284 * in case the item was in a sub-menu.
286 PITEM FASTCALL
MENU_FindItem( PMENU
*pmenu
, UINT
*nPos
, UINT wFlags
)
289 ITEM
*fallback
= NULL
;
290 UINT fallback_pos
= 0;
293 if (!menu
) return NULL
;
295 if (wFlags
& MF_BYPOSITION
)
297 if (!menu
->cItems
) return NULL
;
298 if (*nPos
>= menu
->cItems
) return NULL
;
299 return &menu
->rgItems
[*nPos
];
303 PITEM item
= menu
->rgItems
;
304 for (i
= 0; item
, i
< menu
->cItems
; i
++, item
++)
308 PMENU psubmenu
= item
->spSubMenu
;//VerifyMenu(item->spSubMenu);
309 PITEM subitem
= MENU_FindItem( &psubmenu
, nPos
, wFlags
);
315 else if (item
->wID
== *nPos
)
317 /* fallback to this item if nothing else found */
322 else if (item
->wID
== *nPos
)
331 *nPos
= fallback_pos
;
337 IntRemoveMenuItem( PMENU pMenu
, UINT nPos
, UINT wFlags
, BOOL bRecurse
)
339 PITEM item
, NewItems
;
341 TRACE("(menu=%p pos=%04x flags=%04x)\n",pMenu
, nPos
, wFlags
);
342 if (!(item
= MENU_FindItem( &pMenu
, &nPos
, wFlags
))) return FALSE
;
346 FreeMenuText(pMenu
,item
);
347 if (bRecurse
&& item
->spSubMenu
)
349 IntDestroyMenuObject(item
->spSubMenu
, bRecurse
, TRUE
);
351 ////// Use cAlloced with inc's of 8's....
352 if (--pMenu
->cItems
== 0)
354 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
355 pMenu
->rgItems
= NULL
;
359 while(nPos
< pMenu
->cItems
)
365 NewItems
= DesktopHeapAlloc(pMenu
->head
.rpdesk
, pMenu
->cItems
* sizeof(ITEM
));
366 RtlCopyMemory(NewItems
, pMenu
->rgItems
, pMenu
->cItems
* sizeof(ITEM
));
367 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
368 pMenu
->rgItems
= NewItems
;
373 /**********************************************************************
376 * Insert (allocate) a new item into a menu.
378 ITEM
*MENU_InsertItem( PMENU menu
, UINT pos
, UINT flags
, PMENU
*submenu
, UINT
*npos
)
382 /* Find where to insert new item */
384 if (flags
& MF_BYPOSITION
) {
385 if (pos
> menu
->cItems
)
388 if (!MENU_FindItem( &menu
, &pos
, flags
))
390 if (submenu
) *submenu
= menu
;
391 if (npos
) *npos
= pos
;
396 /* Make sure that MDI system buttons stay on the right side.
397 * Note: XP treats only bitmap handles 1 - 6 as "magic" ones
398 * regardless of their id.
401 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
>= (INT_PTR
)HBMMENU_SYSTEM
&&
402 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
<= (INT_PTR
)HBMMENU_MBAR_CLOSE_D
)
405 TRACE("inserting at %u flags %x\n", pos
, flags
);
407 /* Create new items array */
409 newItems
= DesktopHeapAlloc(menu
->head
.rpdesk
, sizeof(ITEM
) * (menu
->cItems
+1) );
412 WARN("allocation failed\n" );
415 if (menu
->cItems
> 0)
417 /* Copy the old array into the new one */
418 if (pos
> 0) RtlCopyMemory( newItems
, menu
->rgItems
, pos
* sizeof(ITEM
) );
419 if (pos
< menu
->cItems
) RtlCopyMemory( &newItems
[pos
+1], &menu
->rgItems
[pos
], (menu
->cItems
-pos
)*sizeof(ITEM
) );
420 DesktopHeapFree(menu
->head
.rpdesk
, menu
->rgItems
);
422 menu
->rgItems
= newItems
;
424 RtlZeroMemory( &newItems
[pos
], sizeof(*newItems
) );
425 menu
->cyMenu
= 0; /* force size recalculate */
426 return &newItems
[pos
];
431 _In_ PMENU MenuObject
,
434 PROSMENUITEMINFO ItemInfo
,
435 PUNICODE_STRING lpstr
)
438 PMENU SubMenu
= NULL
;
440 NT_ASSERT(MenuObject
!= NULL
);
442 if (MAX_MENU_ITEMS
<= MenuObject
->cItems
)
444 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
448 SubMenu
= MenuObject
;
450 if(!(MenuItem
= MENU_InsertItem( SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, &SubMenu
, &uItem
))) return FALSE
;
452 if(!IntSetMenuItemInfo(SubMenu
, MenuItem
, ItemInfo
, lpstr
))
454 IntRemoveMenuItem(SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, FALSE
);
458 /* Force size recalculation! */
460 MenuItem
->hbmpChecked
= MenuItem
->hbmpUnchecked
= 0;
462 TRACE("IntInsertMenuItemToList = %i %d\n", uItem
, (BOOL
)((INT
)uItem
>= 0));
468 IntCreateMenu(PHANDLE Handle
, BOOL IsMenuBar
)
471 PPROCESSINFO CurrentWin32Process
;
473 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
485 Menu
->cyMax
= 0; /* Default */
486 Menu
->hbrBack
= NULL
; /* No brush */
487 Menu
->dwContextHelpId
= 0; /* Default */
488 Menu
->dwMenuData
= 0; /* Default */
489 Menu
->iItem
= NO_SELECTED_ITEM
; // Focused item
490 Menu
->fFlags
= (IsMenuBar
? 0 : MNF_POPUP
);
491 Menu
->spwndNotify
= NULL
;
492 Menu
->cyMenu
= 0; // Height
493 Menu
->cxMenu
= 0; // Width
494 Menu
->cItems
= 0; // Item count
497 Menu
->cxTextAlign
= 0;
498 Menu
->rgItems
= NULL
;
501 Menu
->TimeToHide
= FALSE
;
503 /* Insert menu item into process menu handle list */
504 CurrentWin32Process
= PsGetCurrentProcessWin32Process();
505 InsertTailList(&CurrentWin32Process
->MenuListHead
, &Menu
->ListEntry
);
511 IntCloneMenuItems(PMENU Destination
, PMENU Source
)
513 PITEM MenuItem
, NewMenuItem
= NULL
;
519 NewMenuItem
= DesktopHeapAlloc(Destination
->head
.rpdesk
, (Source
->cItems
+1) * sizeof(ITEM
));
520 if(!NewMenuItem
) return FALSE
;
522 RtlZeroMemory(NewMenuItem
, (Source
->cItems
+1) * sizeof(ITEM
));
524 Destination
->rgItems
= NewMenuItem
;
526 MenuItem
= Source
->rgItems
;
527 for (i
= 0; i
< Source
->cItems
; i
++, MenuItem
++, NewMenuItem
++)
529 NewMenuItem
->fType
= MenuItem
->fType
;
530 NewMenuItem
->fState
= MenuItem
->fState
;
531 NewMenuItem
->wID
= MenuItem
->wID
;
532 NewMenuItem
->spSubMenu
= MenuItem
->spSubMenu
;
533 NewMenuItem
->hbmpChecked
= MenuItem
->hbmpChecked
;
534 NewMenuItem
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
535 NewMenuItem
->dwItemData
= MenuItem
->dwItemData
;
536 if((MENU_ITEM_TYPE(NewMenuItem
->fType
) == MF_STRING
))
538 if(MenuItem
->lpstr
.Length
)
540 NewMenuItem
->lpstr
.Length
= 0;
541 NewMenuItem
->lpstr
.MaximumLength
= MenuItem
->lpstr
.MaximumLength
;
542 NewMenuItem
->lpstr
.Buffer
= DesktopHeapAlloc(Destination
->head
.rpdesk
, MenuItem
->lpstr
.MaximumLength
);
543 if(!NewMenuItem
->lpstr
.Buffer
)
545 DesktopHeapFree(Destination
->head
.rpdesk
, NewMenuItem
);
548 RtlCopyUnicodeString(&NewMenuItem
->lpstr
, &MenuItem
->lpstr
);
552 NewMenuItem
->lpstr
.Buffer
= MenuItem
->lpstr
.Buffer
;
557 NewMenuItem
->lpstr
.Buffer
= MenuItem
->lpstr
.Buffer
;
559 NewMenuItem
->hbmp
= MenuItem
->hbmp
;
565 IntCloneMenu(PMENU Source
)
567 PPROCESSINFO CurrentWin32Process
;
574 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
583 Menu
->fFlags
= Source
->fFlags
;
584 Menu
->cyMax
= Source
->cyMax
;
585 Menu
->hbrBack
= Source
->hbrBack
;
586 Menu
->dwContextHelpId
= Source
->dwContextHelpId
;
587 Menu
->dwMenuData
= Source
->dwMenuData
;
588 Menu
->iItem
= NO_SELECTED_ITEM
;
589 Menu
->spwndNotify
= NULL
;
592 Menu
->cItems
= Source
->cItems
;
595 Menu
->cxTextAlign
= 0;
596 Menu
->rgItems
= NULL
;
599 Menu
->TimeToHide
= FALSE
;
601 /* Insert menu item into process menu handle list */
602 CurrentWin32Process
= PsGetCurrentProcessWin32Process();
603 InsertTailList(&CurrentWin32Process
->MenuListHead
, &Menu
->ListEntry
);
605 IntCloneMenuItems(Menu
, Source
);
611 IntSetMenuFlagRtoL(PMENU Menu
)
613 Menu
->fFlags
|= MNF_RTOL
;
618 IntSetMenuContextHelpId(PMENU Menu
, DWORD dwContextHelpId
)
620 Menu
->dwContextHelpId
= dwContextHelpId
;
625 IntGetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
627 if(lpmi
->fMask
& MIM_BACKGROUND
)
628 lpmi
->hbrBack
= Menu
->hbrBack
;
629 if(lpmi
->fMask
& MIM_HELPID
)
630 lpmi
->dwContextHelpID
= Menu
->dwContextHelpId
;
631 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
632 lpmi
->cyMax
= Menu
->cyMax
;
633 if(lpmi
->fMask
& MIM_MENUDATA
)
634 lpmi
->dwMenuData
= Menu
->dwMenuData
;
635 if(lpmi
->fMask
& MIM_STYLE
)
636 lpmi
->dwStyle
= Menu
->fFlags
& MNS_STYLE_MASK
;
638 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
640 lpmi
->cItems
= Menu
->cItems
;
642 lpmi
->iItem
= Menu
->iItem
;
643 lpmi
->cxMenu
= Menu
->cxMenu
;
644 lpmi
->cyMenu
= Menu
->cyMenu
;
645 lpmi
->spwndNotify
= Menu
->spwndNotify
;
646 lpmi
->cxTextAlign
= Menu
->cxTextAlign
;
647 lpmi
->iTop
= Menu
->iMaxTop
;
648 lpmi
->iMaxTop
= Menu
->iMaxTop
;
649 lpmi
->dwArrowsOn
= Menu
->dwArrowsOn
;
651 lpmi
->fFlags
= Menu
->fFlags
;
652 lpmi
->Self
= Menu
->head
.h
;
653 lpmi
->TimeToHide
= Menu
->TimeToHide
;
654 lpmi
->Wnd
= Menu
->hWnd
;
660 IntSetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
662 if(lpmi
->fMask
& MIM_BACKGROUND
)
663 Menu
->hbrBack
= lpmi
->hbrBack
;
664 if(lpmi
->fMask
& MIM_HELPID
)
665 Menu
->dwContextHelpId
= lpmi
->dwContextHelpID
;
666 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
667 Menu
->cyMax
= lpmi
->cyMax
;
668 if(lpmi
->fMask
& MIM_MENUDATA
)
669 Menu
->dwMenuData
= lpmi
->dwMenuData
;
670 if(lpmi
->fMask
& MIM_STYLE
)
671 Menu
->fFlags
^= (Menu
->fFlags
^ lpmi
->dwStyle
) & MNS_STYLE_MASK
;
672 if(lpmi
->fMask
& MIM_APPLYTOSUBMENUS
)
675 PITEM item
= Menu
->rgItems
;
676 for ( i
= Menu
->cItems
; i
; i
--, item
++)
678 if ( item
->spSubMenu
)
680 IntSetMenuInfo( item
->spSubMenu
, lpmi
);
684 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
686 Menu
->iItem
= lpmi
->iItem
;
687 Menu
->cyMenu
= lpmi
->cyMenu
;
688 Menu
->cxMenu
= lpmi
->cxMenu
;
689 Menu
->spwndNotify
= lpmi
->spwndNotify
;
690 Menu
->cxTextAlign
= lpmi
->cxTextAlign
;
691 Menu
->iTop
= lpmi
->iTop
;
692 Menu
->iMaxTop
= lpmi
->iMaxTop
;
693 Menu
->dwArrowsOn
= lpmi
->dwArrowsOn
;
695 Menu
->TimeToHide
= lpmi
->TimeToHide
;
696 Menu
->hWnd
= lpmi
->Wnd
;
702 IntGetMenuItemInfo(PMENU Menu
, /* UNUSED PARAM!! */
703 PITEM MenuItem
, PROSMENUITEMINFO lpmii
)
707 if(lpmii
->fMask
& (MIIM_FTYPE
| MIIM_TYPE
))
709 lpmii
->fType
= MenuItem
->fType
;
711 if(lpmii
->fMask
& MIIM_BITMAP
)
713 lpmii
->hbmpItem
= MenuItem
->hbmp
;
715 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
717 lpmii
->hbmpChecked
= MenuItem
->hbmpChecked
;
718 lpmii
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
720 if(lpmii
->fMask
& MIIM_DATA
)
722 lpmii
->dwItemData
= MenuItem
->dwItemData
;
724 if(lpmii
->fMask
& MIIM_ID
)
726 lpmii
->wID
= MenuItem
->wID
;
728 if(lpmii
->fMask
& MIIM_STATE
)
730 lpmii
->fState
= MenuItem
->fState
;
732 if(lpmii
->fMask
& MIIM_SUBMENU
)
734 lpmii
->hSubMenu
= MenuItem
->spSubMenu
? MenuItem
->spSubMenu
->head
.h
: NULL
;
737 if ((lpmii
->fMask
& MIIM_STRING
) ||
738 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
740 if (lpmii
->dwTypeData
== NULL
)
742 lpmii
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
745 { //// lpmii->lpstr can be read in user mode!!!!
746 Status
= MmCopyToCaller(lpmii
->dwTypeData
, MenuItem
->lpstr
.Buffer
,
747 min(lpmii
->cch
* sizeof(WCHAR
),
748 MenuItem
->lpstr
.MaximumLength
));
749 if (! NT_SUCCESS(Status
))
751 SetLastNtError(Status
);
757 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
759 lpmii
->Rect
.left
= MenuItem
->xItem
;
760 lpmii
->Rect
.top
= MenuItem
->yItem
;
761 lpmii
->Rect
.right
= MenuItem
->cxItem
; // Do this for now......
762 lpmii
->Rect
.bottom
= MenuItem
->cyItem
;
763 lpmii
->dxTab
= MenuItem
->dxTab
;
764 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
;
765 lpmii
->maxBmpSize
.cx
= MenuItem
->cxBmp
;
766 lpmii
->maxBmpSize
.cy
= MenuItem
->cyBmp
;
773 IntSetMenuItemInfo(PMENU MenuObject
, PITEM MenuItem
, PROSMENUITEMINFO lpmii
, PUNICODE_STRING lpstr
)
777 if(!MenuItem
|| !MenuObject
|| !lpmii
)
781 if ( lpmii
->fMask
& MIIM_FTYPE
)
783 MenuItem
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
784 MenuItem
->fType
|= lpmii
->fType
& MENUITEMINFO_TYPE_MASK
;
786 if (lpmii
->fMask
& MIIM_TYPE
)
788 #if 0 //// Done in User32.
789 if (lpmii
->fMask
& ( MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
))
791 ERR("IntSetMenuItemInfo: Invalid combination of fMask bits used\n");
792 KeRosDumpStackFrames(NULL
, 20);
793 /* This does not happen on Win9x/ME */
794 SetLastNtError( ERROR_INVALID_PARAMETER
);
799 * Delete the menu item type when changing type from
802 if (MenuItem
->fType
!= lpmii
->fType
&&
803 MENU_ITEM_TYPE(MenuItem
->fType
) == MFT_STRING
)
805 FreeMenuText(MenuObject
,MenuItem
);
806 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
807 MenuItem
->Xlpstr
= NULL
;
809 if(lpmii
->fType
& MFT_BITMAP
)
812 MenuItem
->hbmp
= lpmii
->hbmpItem
;
814 { /* Win 9x/Me stuff */
815 MenuItem
->hbmp
= (HBITMAP
)((ULONG_PTR
)(LOWORD(lpmii
->dwTypeData
)));
817 lpmii
->dwTypeData
= 0;
820 if(lpmii
->fMask
& MIIM_BITMAP
)
822 MenuItem
->hbmp
= lpmii
->hbmpItem
;
824 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
826 MenuItem
->hbmpChecked
= lpmii
->hbmpChecked
;
827 MenuItem
->hbmpUnchecked
= lpmii
->hbmpUnchecked
;
829 if(lpmii
->fMask
& MIIM_DATA
)
831 MenuItem
->dwItemData
= lpmii
->dwItemData
;
833 if(lpmii
->fMask
& MIIM_ID
)
835 MenuItem
->wID
= lpmii
->wID
;
837 if(lpmii
->fMask
& MIIM_STATE
)
839 /* Remove MFS_DEFAULT flag from all other menu items if this item
840 has the MFS_DEFAULT state */
841 if(lpmii
->fState
& MFS_DEFAULT
)
842 UserSetMenuDefaultItem(MenuObject
, -1, 0);
843 /* Update the menu item state flags */
844 UpdateMenuItemState(MenuItem
->fState
, lpmii
->fState
);
847 if(lpmii
->fMask
& MIIM_SUBMENU
)
849 /* Make sure the submenu is marked as a popup menu */
852 SubMenuObject
= UserGetMenuObject(lpmii
->hSubMenu
);
853 if (SubMenuObject
!= NULL
)
855 if ( MENU_depth( SubMenuObject
, 0) > MAXMENUDEPTH
)
857 ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n");
860 SubMenuObject
->fFlags
|= MNF_POPUP
;
861 // Now fix the test_subpopup_locked_by_menu tests....
862 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
863 MenuItem
->spSubMenu
= SubMenuObject
;
864 UserReferenceObject(SubMenuObject
);
868 EngSetLastError( ERROR_INVALID_PARAMETER
);
873 { // If submenu just dereference it.
874 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
875 MenuItem
->spSubMenu
= NULL
;
879 if ((lpmii
->fMask
& MIIM_STRING
) ||
880 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
882 /* free the string when used */
883 FreeMenuText(MenuObject
,MenuItem
);
884 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
885 MenuItem
->Xlpstr
= NULL
;
887 if(lpmii
->dwTypeData
&& lpmii
->cch
&& lpstr
&& lpstr
->Buffer
)
889 UNICODE_STRING Source
;
891 Source
.Length
= Source
.MaximumLength
= lpmii
->cch
* sizeof(WCHAR
);
892 Source
.Buffer
= lpmii
->dwTypeData
;
894 MenuItem
->lpstr
.Buffer
= DesktopHeapAlloc( MenuObject
->head
.rpdesk
, Source
.Length
+ sizeof(WCHAR
));
895 if(MenuItem
->lpstr
.Buffer
!= NULL
)
897 MenuItem
->lpstr
.Length
= 0;
898 MenuItem
->lpstr
.MaximumLength
= Source
.Length
+ sizeof(WCHAR
);
899 RtlCopyUnicodeString(&MenuItem
->lpstr
, &Source
);
900 MenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
902 MenuItem
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
903 MenuItem
->Xlpstr
= (USHORT
*)MenuItem
->lpstr
.Buffer
;
908 if( !(MenuObject
->fFlags
& MNF_SYSDESKMN
) &&
910 !lpmii
->dwTypeData
&&
911 !(MenuItem
->fType
& MFT_OWNERDRAW
) &&
913 MenuItem
->fType
|= MFT_SEPARATOR
;
915 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
917 MenuItem
->xItem
= lpmii
->Rect
.left
;
918 MenuItem
->yItem
= lpmii
->Rect
.top
;
919 MenuItem
->cxItem
= lpmii
->Rect
.right
; // Do this for now......
920 MenuItem
->cyItem
= lpmii
->Rect
.bottom
;
921 MenuItem
->dxTab
= lpmii
->dxTab
;
922 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
; /* Send back new allocated string or zero */
923 MenuItem
->cxBmp
= lpmii
->maxBmpSize
.cx
;
924 MenuItem
->cyBmp
= lpmii
->maxBmpSize
.cy
;
932 IntEnableMenuItem(PMENU MenuObject
, UINT uIDEnableItem
, UINT uEnable
)
937 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDEnableItem
, uEnable
))) return (UINT
)-1;
939 res
= MenuItem
->fState
& (MF_GRAYED
| MF_DISABLED
);
941 MenuItem
->fState
^= (res
^ uEnable
) & (MF_GRAYED
| MF_DISABLED
);
943 /* If the close item in the system menu change update the close button */
944 if((MenuItem
->wID
== SC_CLOSE
) && (res
!= uEnable
))
946 if (MenuObject
->fFlags
& MNF_SYSSUBMENU
&& MenuObject
->spwndNotify
!= 0)
948 RECTL rc
= MenuObject
->spwndNotify
->rcWindow
;
950 /* Refresh the frame to reflect the change */
951 IntMapWindowPoints(0, MenuObject
->spwndNotify
, (POINT
*)&rc
, 2);
953 co_UserRedrawWindow(MenuObject
->spwndNotify
, &rc
, 0, RDW_FRAME
| RDW_INVALIDATE
| RDW_NOCHILDREN
);
960 IntCheckMenuItem(PMENU MenuObject
, UINT uIDCheckItem
, UINT uCheck
)
965 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDCheckItem
, uCheck
))) return -1;
967 res
= (DWORD
)(MenuItem
->fState
& MF_CHECKED
);
969 MenuItem
->fState
^= (res
^ uCheck
) & MF_CHECKED
;
975 IntHiliteMenuItem(PWND WindowObject
,
982 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uItemHilite
, uHilite
))) return FALSE
;
984 if (uHilite
& MF_HILITE
)
986 MenuItem
->fState
|= MF_HILITE
;
990 MenuItem
->fState
&= ~MF_HILITE
;
992 /* FIXME: Update the window's menu */
994 return TRUE
; // Always returns true!!!!
998 UserSetMenuDefaultItem(PMENU MenuObject
, UINT uItem
, UINT fByPos
)
1001 PITEM MenuItem
= MenuObject
->rgItems
;
1003 if (!MenuItem
) return FALSE
;
1005 /* reset all default-item flags */
1006 for (i
= 0; MenuItem
, i
< MenuObject
->cItems
; i
++, MenuItem
++)
1008 MenuItem
->fState
&= ~MFS_DEFAULT
;
1011 /* no default item */
1012 if(uItem
== (UINT
)-1)
1016 MenuItem
= MenuObject
->rgItems
;
1019 if ( uItem
>= MenuObject
->cItems
) return FALSE
;
1020 MenuItem
[uItem
].fState
|= MFS_DEFAULT
;
1025 for (i
= 0; MenuItem
, i
< MenuObject
->cItems
; i
++, MenuItem
++)
1027 if (MenuItem
->wID
== uItem
)
1029 MenuItem
->fState
|= MFS_DEFAULT
;
1040 IntGetMenuDefaultItem(PMENU MenuObject
, UINT fByPos
, UINT gmdiFlags
, DWORD
*gismc
)
1043 PITEM MenuItem
= MenuObject
->rgItems
;
1046 if (!MenuItem
) return -1;
1048 while ( !( MenuItem
->fState
& MFS_DEFAULT
) )
1051 if (i
>= MenuObject
->cItems
) return -1;
1054 /* default: don't return disabled items */
1055 if ( (!(GMDI_USEDISABLED
& gmdiFlags
)) && (MenuItem
->fState
& MFS_DISABLED
)) return -1;
1057 /* search rekursiv when needed */
1058 if ( (MenuItem
->fType
& MF_POPUP
) && (gmdiFlags
& GMDI_GOINTOPOPUPS
) && MenuItem
->spSubMenu
)
1062 ret
= IntGetMenuDefaultItem( MenuItem
->spSubMenu
, fByPos
, gmdiFlags
, gismc
);
1064 if ( -1 != ret
) return ret
;
1066 /* when item not found in submenu, return the popup item */
1068 return ( fByPos
) ? i
: MenuItem
->wID
;
1072 co_IntInitTracking(PWND Window
, PMENU Menu
, BOOL Popup
,
1075 /* FIXME: Hide caret */
1077 if(!(Flags
& TPM_NONOTIFY
))
1078 co_IntSendMessage(Window
->head
.h
, WM_SETCURSOR
, (WPARAM
)Window
->head
.h
, HTCAPTION
);
1080 /* FIXME: Send WM_SETCURSOR message */
1082 if(!(Flags
& TPM_NONOTIFY
))
1083 co_IntSendMessage(Window
->head
.h
, WM_INITMENU
, (WPARAM
)Menu
->head
.h
, 0);
1087 co_IntExitTracking(PWND Window
, PMENU Menu
, BOOL Popup
,
1090 if(!(Flags
& TPM_NONOTIFY
))
1091 co_IntSendMessage(Window
->head
.h
, WM_EXITMENULOOP
, 0 /* FIXME */, 0);
1093 /* FIXME: Show caret again */
1097 IntTrackMenu(PMENU Menu
, PWND Window
, INT x
, INT y
,
1104 co_IntTrackPopupMenu(PMENU Menu
, PWND Window
,
1105 UINT Flags
, POINT
*Pos
, UINT MenuPos
, RECTL
*ExcludeRect
)
1107 co_IntInitTracking(Window
, Menu
, TRUE
, Flags
);
1109 co_IntExitTracking(Window
, Menu
, TRUE
, Flags
);
1115 * Internal function. Called when the process is destroyed to free the remaining menu handles.
1118 IntCleanupMenus(struct _EPROCESS
*Process
, PPROCESSINFO Win32Process
)
1120 PEPROCESS CurrentProcess
;
1121 PLIST_ENTRY LastHead
= NULL
;
1124 CurrentProcess
= PsGetCurrentProcess();
1125 if (CurrentProcess
!= Process
)
1127 KeAttachProcess(&Process
->Pcb
);
1130 while (Win32Process
->MenuListHead
.Flink
!= &(Win32Process
->MenuListHead
) &&
1131 Win32Process
->MenuListHead
.Flink
!= LastHead
)
1133 LastHead
= Win32Process
->MenuListHead
.Flink
;
1134 MenuObject
= CONTAINING_RECORD(Win32Process
->MenuListHead
.Flink
, MENU
, ListEntry
);
1135 TRACE("Menus are stuck on the process list!\n");
1136 IntDestroyMenuObject(MenuObject
, FALSE
, TRUE
);
1139 if (CurrentProcess
!= Process
)
1147 intGetTitleBarInfo(PWND pWindowObject
, PTITLEBARINFO bti
)
1151 DWORD dwExStyle
= 0;
1152 BOOLEAN retValue
= TRUE
;
1154 if (bti
->cbSize
== sizeof(TITLEBARINFO
))
1156 RtlZeroMemory(&bti
->rgstate
[0],sizeof(DWORD
)*(CCHILDREN_TITLEBAR
+1));
1158 bti
->rgstate
[0] = STATE_SYSTEM_FOCUSABLE
;
1160 dwStyle
= pWindowObject
->style
;
1161 dwExStyle
= pWindowObject
->ExStyle
;
1163 bti
->rcTitleBar
.top
= 0;
1164 bti
->rcTitleBar
.left
= 0;
1165 bti
->rcTitleBar
.right
= pWindowObject
->rcWindow
.right
- pWindowObject
->rcWindow
.left
;
1166 bti
->rcTitleBar
.bottom
= pWindowObject
->rcWindow
.bottom
- pWindowObject
->rcWindow
.top
;
1168 /* Is it iconiced ? */
1169 if ((dwStyle
& WS_ICONIC
)!=WS_ICONIC
)
1171 /* Remove frame from rectangle */
1172 if (HAS_THICKFRAME( dwStyle
, dwExStyle
))
1174 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
1175 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXFRAME
), -UserGetSystemMetrics(SM_CYFRAME
) );
1177 else if (HAS_DLGFRAME( dwStyle
, dwExStyle
))
1179 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
1180 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXDLGFRAME
), -UserGetSystemMetrics(SM_CYDLGFRAME
));
1182 else if (HAS_THINFRAME( dwStyle
, dwExStyle
))
1184 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
1185 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
) );
1188 /* We have additional border information if the window
1189 * is a child (but not an MDI child) */
1190 if ( (dwStyle
& WS_CHILD
) &&
1191 ((dwExStyle
& WS_EX_MDICHILD
) == 0 ) )
1193 if (dwExStyle
& WS_EX_CLIENTEDGE
)
1195 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
1196 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXEDGE
), -UserGetSystemMetrics(SM_CYEDGE
));
1199 if (dwExStyle
& WS_EX_STATICEDGE
)
1201 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
1202 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
));
1207 bti
->rcTitleBar
.top
+= pWindowObject
->rcWindow
.top
;
1208 bti
->rcTitleBar
.left
+= pWindowObject
->rcWindow
.left
;
1209 bti
->rcTitleBar
.right
+= pWindowObject
->rcWindow
.left
;
1211 bti
->rcTitleBar
.bottom
= bti
->rcTitleBar
.top
;
1212 if (dwExStyle
& WS_EX_TOOLWINDOW
)
1214 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
1215 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYSMCAPTION
);
1219 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
1220 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYCAPTION
);
1221 bti
->rcTitleBar
.left
+= UserGetSystemMetrics(SM_CXSIZE
);
1224 if (dwStyle
& WS_CAPTION
)
1226 bti
->rgstate
[1] = STATE_SYSTEM_INVISIBLE
;
1227 if (dwStyle
& WS_SYSMENU
)
1229 if (!(dwStyle
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
)))
1231 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
1232 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
1236 if (!(dwStyle
& WS_MINIMIZEBOX
))
1238 bti
->rgstate
[2] = STATE_SYSTEM_UNAVAILABLE
;
1240 if (!(dwStyle
& WS_MAXIMIZEBOX
))
1242 bti
->rgstate
[3] = STATE_SYSTEM_UNAVAILABLE
;
1246 if (!(dwExStyle
& WS_EX_CONTEXTHELP
))
1248 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
1250 if (pWindowObject
->pcls
->style
& CS_NOCLOSE
)
1252 bti
->rgstate
[5] = STATE_SYSTEM_UNAVAILABLE
;
1257 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
1258 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
1259 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
1260 bti
->rgstate
[5] = STATE_SYSTEM_INVISIBLE
;
1265 bti
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
1270 EngSetLastError(ERROR_INVALID_PARAMETER
);
1282 LPCMENUITEMINFOW UnsafeItemInfo
,
1283 PUNICODE_STRING lpstr
)
1286 ROSMENUITEMINFO ItemInfo
;
1288 /* Try to copy the whole MENUITEMINFOW structure */
1289 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, sizeof(MENUITEMINFOW
));
1290 if (NT_SUCCESS(Status
))
1292 if (sizeof(MENUITEMINFOW
) != ItemInfo
.cbSize
1293 && FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
1295 EngSetLastError(ERROR_INVALID_PARAMETER
);
1298 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
1301 /* Try to copy without last field (not present in older versions) */
1302 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
));
1303 if (NT_SUCCESS(Status
))
1305 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
1307 EngSetLastError(ERROR_INVALID_PARAMETER
);
1310 ItemInfo
.hbmpItem
= (HBITMAP
)0;
1311 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
1314 SetLastNtError(Status
);
1318 UINT FASTCALL
IntGetMenuState( HMENU hMenu
, UINT uId
, UINT uFlags
)
1323 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
1328 if (!(pItem
= MENU_FindItem( &MenuObject
, &uId
, uFlags
))) return -1;
1330 if (pItem
->spSubMenu
)
1332 return (pItem
->spSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
) & 0xff);
1335 return (pItem
->fType
| pItem
->fState
);
1338 HMENU FASTCALL
IntGetSubMenu( HMENU hMenu
, int nPos
)
1343 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
1348 if (!(pItem
= MENU_FindItem( &MenuObject
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
1350 if (pItem
->spSubMenu
)
1352 HMENU hsubmenu
= UserHMGetHandle(pItem
->spSubMenu
);
1358 UINT FASTCALL
IntFindSubMenu(HMENU
*hMenu
, HMENU hSubTarget
)
1365 if (((*hMenu
)==(HMENU
)0xffff) ||(!(menu
= UserGetMenuObject(*hMenu
))))
1366 return NO_SELECTED_ITEM
;
1368 item
= menu
->rgItems
;
1369 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1371 if (!item
->spSubMenu
)
1375 hSubMenu
= UserHMGetHandle(item
->spSubMenu
);
1376 if (hSubMenu
== hSubTarget
)
1382 HMENU hsubmenu
= hSubMenu
;
1383 UINT pos
= IntFindSubMenu( &hsubmenu
, hSubTarget
);
1384 if (pos
!= NO_SELECTED_ITEM
)
1392 return NO_SELECTED_ITEM
;
1396 HMENU FASTCALL
UserCreateMenu(BOOL PopupMenu
)
1398 PWINSTATION_OBJECT WinStaObject
;
1402 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
1404 if (gpepCSRSS
!= CurrentProcess
)
1407 * gpepCSRSS does not have a Win32WindowStation
1410 Status
= IntValidateWindowStationHandle(CurrentProcess
->Win32WindowStation
,
1415 if (!NT_SUCCESS(Status
))
1417 ERR("Validation of window station handle (%p) failed\n",
1418 CurrentProcess
->Win32WindowStation
);
1419 SetLastNtError(Status
);
1422 Menu
= IntCreateMenu(&Handle
, !PopupMenu
);
1423 if (Menu
->head
.rpdesk
->rpwinstaParent
!= WinStaObject
)
1425 ERR("Desktop Window Station does not match Process one!\n");
1427 ObDereferenceObject(WinStaObject
);
1431 Menu
= IntCreateMenu(&Handle
, !PopupMenu
);
1434 if (Menu
) UserDereferenceObject(Menu
);
1435 return (HMENU
)Handle
;
1443 PROSMENUITEMINFO UnsafeItemInfo
,
1445 PUNICODE_STRING lpstr
)
1448 ROSMENUITEMINFO ItemInfo
;
1453 Status
= MmCopyFromCaller(&Size
, &UnsafeItemInfo
->cbSize
, sizeof(UINT
));
1454 if (! NT_SUCCESS(Status
))
1456 SetLastNtError(Status
);
1459 if (sizeof(MENUITEMINFOW
) != Size
1460 && FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != Size
1461 && sizeof(ROSMENUITEMINFO
) != Size
)
1463 EngSetLastError(ERROR_INVALID_PARAMETER
);
1466 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, Size
);
1467 if (! NT_SUCCESS(Status
))
1469 SetLastNtError(Status
);
1472 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
1474 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) == Size
1475 && 0 != (ItemInfo
.fMask
& MIIM_BITMAP
))
1477 EngSetLastError(ERROR_INVALID_PARAMETER
);
1481 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
1483 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
1489 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
, lpstr
);
1493 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
);
1496 Status
= MmCopyToCaller(UnsafeItemInfo
, &ItemInfo
, Size
);
1497 if (! NT_SUCCESS(Status
))
1499 SetLastNtError(Status
);
1511 PROSMENUINFO UnsafeMenuInfo
,
1517 ROSMENUINFO MenuInfo
;
1519 Status
= MmCopyFromCaller(&Size
, &UnsafeMenuInfo
->cbSize
, sizeof(DWORD
));
1520 if (! NT_SUCCESS(Status
))
1522 SetLastNtError(Status
);
1525 if(Size
< sizeof(MENUINFO
) || sizeof(ROSMENUINFO
) < Size
)
1527 EngSetLastError(ERROR_INVALID_PARAMETER
);
1530 Status
= MmCopyFromCaller(&MenuInfo
, UnsafeMenuInfo
, Size
);
1531 if (! NT_SUCCESS(Status
))
1533 SetLastNtError(Status
);
1540 Res
= IntSetMenuInfo(Menu
, &MenuInfo
);
1545 Res
= IntGetMenuInfo(Menu
, &MenuInfo
);
1548 Status
= MmCopyToCaller(UnsafeMenuInfo
, &MenuInfo
, Size
);
1549 if (! NT_SUCCESS(Status
))
1551 SetLastNtError(Status
);
1561 MENU_AdjustMenuItemRect(PMENU menu
, PRECTL rect
)
1563 if (menu
->dwArrowsOn
)
1565 UINT arrow_bitmap_height
;
1567 //GetObjectW(get_up_arrow_bitmap(), sizeof(bmp), &bmp);
1568 arrow_bitmap_height
= gpsi
->oembmi
[65].cy
; ///// Menu up arrow! OBM_UPARROW DFCS_MENUARROWUP
1569 //arrow_bitmap_height = bmp.bmHeight;
1570 rect
->top
+= arrow_bitmap_height
- menu
->iTop
;
1571 rect
->bottom
+= arrow_bitmap_height
- menu
->iTop
;
1587 HWND hWnd
= Menu
->hWnd
;
1588 if (!(pWnd
= UserGetWindowObject(hWnd
))) return FALSE
;
1591 if ((MenuItem
= MENU_FindItem (&Menu
, &uItem
, MF_BYPOSITION
)))
1593 Rect
->left
= MenuItem
->xItem
;
1594 Rect
->top
= MenuItem
->yItem
;
1595 Rect
->right
= MenuItem
->cxItem
; // Do this for now......
1596 Rect
->bottom
= MenuItem
->cyItem
;
1600 ERR("Failed Item Lookup! %d\n", uItem
);
1604 if (Menu
->fFlags
& MNF_POPUP
)
1606 XMove
= pWnd
->rcClient
.left
;
1607 YMove
= pWnd
->rcClient
.top
;
1611 XMove
= pWnd
->rcWindow
.left
;
1612 YMove
= pWnd
->rcWindow
.top
;
1615 Rect
->left
+= XMove
;
1617 Rect
->right
+= XMove
;
1618 Rect
->bottom
+= YMove
;
1623 /* FUNCTIONS *****************************************************************/
1629 NtUserCheckMenuItem(
1635 DECLARE_RETURN(DWORD
);
1637 TRACE("Enter NtUserCheckMenuItem\n");
1638 UserEnterExclusive();
1640 if(!(Menu
= UserGetMenuObject(hMenu
)))
1645 RETURN( IntCheckMenuItem(Menu
, uIDCheckItem
, uCheck
));
1648 TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_
);
1663 DECLARE_RETURN(BOOL
);
1665 TRACE("Enter NtUserDeleteMenu\n");
1666 UserEnterExclusive();
1668 if(!(Menu
= UserGetMenuObject(hMenu
)))
1673 RETURN( IntRemoveMenuItem(Menu
, uPosition
, uFlags
, TRUE
));
1676 TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_
);
1685 NtUserGetTitleBarInfo(
1690 TITLEBARINFO bartitleinfo
;
1691 DECLARE_RETURN(BOOLEAN
);
1692 BOOLEAN retValue
= TRUE
;
1694 TRACE("Enter NtUserGetTitleBarInfo\n");
1695 UserEnterExclusive();
1697 /* Vaildate the windows handle */
1698 if (!(WindowObject
= UserGetWindowObject(hwnd
)))
1700 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
1706 /* Copy our usermode buffer bti to local buffer bartitleinfo */
1707 ProbeForRead(bti
, sizeof(TITLEBARINFO
), 1);
1708 RtlCopyMemory(&bartitleinfo
, bti
, sizeof(TITLEBARINFO
));
1710 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1712 /* Fail copy the data */
1713 EngSetLastError(ERROR_INVALID_PARAMETER
);
1718 /* Get the tile bar info */
1721 retValue
= intGetTitleBarInfo(WindowObject
, &bartitleinfo
);
1726 /* Copy our buffer to user mode buffer bti */
1727 ProbeForWrite(bti
, sizeof(TITLEBARINFO
), 1);
1728 RtlCopyMemory(bti
, &bartitleinfo
, sizeof(TITLEBARINFO
));
1730 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1732 /* Fail copy the data */
1733 EngSetLastError(ERROR_INVALID_PARAMETER
);
1743 TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_
);
1751 BOOL FASTCALL
UserDestroyMenu(HMENU hMenu
)
1754 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1756 if(!(Menu
= UserGetMenuObject(hMenu
)))
1761 if (Menu
->head
.rpdesk
!= pti
->rpdesk
)
1763 EngSetLastError(ERROR_ACCESS_DENIED
);
1766 return IntDestroyMenuObject(Menu
, FALSE
, TRUE
);
1777 DECLARE_RETURN(BOOL
);
1779 TRACE("Enter NtUserDestroyMenu\n");
1780 UserEnterExclusive();
1782 if(!(Menu
= UserGetMenuObject(hMenu
)))
1786 if (Menu
->head
.rpdesk
!= gptiCurrent
->rpdesk
)
1788 EngSetLastError(ERROR_ACCESS_DENIED
);
1791 RETURN( IntDestroyMenuObject(Menu
, TRUE
, TRUE
));
1794 TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_
);
1803 NtUserEnableMenuItem(
1809 DECLARE_RETURN(UINT
);
1811 TRACE("Enter NtUserEnableMenuItem\n");
1812 UserEnterExclusive();
1814 if(!(Menu
= UserGetMenuObject(hMenu
)))
1819 RETURN( IntEnableMenuItem(Menu
, uIDEnableItem
, uEnable
));
1822 TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_
);
1831 NtUserGetMenuBarInfo(
1841 NTSTATUS Status
= STATUS_SUCCESS
;
1843 DECLARE_RETURN(BOOL
);
1845 TRACE("Enter NtUserGetMenuBarInfo\n");
1848 if (!(pWnd
= UserGetWindowObject(hwnd
)))
1850 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
1857 if (!pWnd
->pcls
->fnid
)
1859 if (pWnd
->pcls
->fnid
!= FNID_MENU
)
1861 WARN("called on invalid window: %d\n", pWnd
->pcls
->fnid
);
1862 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
1865 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
1866 hMenu
= (HMENU
)co_IntSendMessage(hwnd
, MN_GETHMENU
, 0, 0);
1869 hMenu
= UlongToHandle(pWnd
->IDMenu
);
1872 if (!(pWnd
->style
& WS_SYSMENU
)) RETURN(FALSE
);
1873 Menu
= IntGetSystemMenu(pWnd
, FALSE
, FALSE
);
1874 hMenu
= Menu
->head
.h
;
1885 kmbi
.cbSize
= pmbi
->cbSize
;
1887 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1893 if (kmbi
.cbSize
!= sizeof(MENUBARINFO
))
1895 EngSetLastError(ERROR_INVALID_PARAMETER
);
1899 if (!Menu
) Menu
= UserGetMenuObject(hMenu
);
1903 if (idItem
< 0 || idItem
> Menu
->cItems
)
1906 RECTL_vSetEmptyRect(&kmbi
.rcBar
);
1910 Ret
= IntGetMenuItemRect(pWnd
, Menu
, 0, &kmbi
.rcBar
);
1911 kmbi
.rcBar
.right
= kmbi
.rcBar
.left
+ Menu
->cxMenu
;
1912 kmbi
.rcBar
.bottom
= kmbi
.rcBar
.top
+ Menu
->cyMenu
;
1913 ERR("idItem 0 %d\n",Ret
);
1917 Ret
= IntGetMenuItemRect(pWnd
, Menu
, idItem
-1, &kmbi
.rcBar
);
1918 ERR("idItem X %d\n", Ret
);
1922 kmbi
.hwndMenu
= NULL
;
1923 kmbi
.fBarFocused
= FALSE
;
1924 kmbi
.fFocused
= FALSE
;
1925 //kmbi.fBarFocused = top_popup_hmenu == hMenu;
1929 //UINT nPos = idItem-1;
1930 kmbi
.fFocused
= Menu
->iItem
== idItem
-1;
1931 if (kmbi
.fFocused
&& (Menu
->rgItems
[idItem
- 1].spSubMenu
))
1932 //MenuItem = MENU_FindItem (&Menu, &nPos, MF_BYPOSITION);
1933 //if ( MenuItem && kmbi.fFocused && MenuItem->spSubMenu )
1935 kmbi
.hwndMenu
= Menu
->rgItems
[idItem
- 1].spSubMenu
->hWnd
;
1936 //kmbi.hwndMenu = MenuItem->spSubMenu->hWnd;
1941 kmbi.fFocused = kmbi.fBarFocused;
1946 RtlCopyMemory(pmbi
, &kmbi
, sizeof(MENUBARINFO
));
1948 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1950 Status
= _SEH2_GetExceptionCode();
1954 if (!NT_SUCCESS(Status
))
1956 SetLastNtError(Status
);
1963 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_
);
1976 PMENU Menu
, SubMenu
;
1979 DECLARE_RETURN(UINT
);
1981 TRACE("Enter NtUserGetMenuIndex\n");
1984 if ( !(Menu
= UserGetMenuObject(hMenu
)) ||
1985 !(SubMenu
= UserGetMenuObject(hSubMenu
)) )
1988 MenuItem
= Menu
->rgItems
;
1989 for (i
= 0; i
< Menu
->cItems
; i
++, MenuItem
++)
1991 if (MenuItem
->spSubMenu
== SubMenu
)
1992 RETURN(MenuItem
->wID
);
1997 TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_
);
2006 NtUserGetMenuItemRect(
2017 NTSTATUS Status
= STATUS_SUCCESS
;
2018 DECLARE_RETURN(BOOL
);
2020 TRACE("Enter NtUserGetMenuItemRect\n");
2023 if (!(Menu
= UserGetMenuObject(hMenu
)))
2028 if ((MenuItem
= MENU_FindItem (&Menu
, &uItem
, MF_BYPOSITION
)))
2030 Rect
.left
= MenuItem
->xItem
;
2031 Rect
.top
= MenuItem
->yItem
;
2032 Rect
.right
= MenuItem
->cxItem
; // Do this for now......
2033 Rect
.bottom
= MenuItem
->cyItem
;
2043 if (lprcItem
== NULL
) RETURN( FALSE
);
2045 if (!(ReferenceWnd
= UserGetWindowObject(hWnd
))) RETURN( FALSE
);
2047 if (Menu
->fFlags
& MNF_POPUP
)
2049 XMove
= ReferenceWnd
->rcClient
.left
;
2050 YMove
= ReferenceWnd
->rcClient
.top
;
2054 XMove
= ReferenceWnd
->rcWindow
.left
;
2055 YMove
= ReferenceWnd
->rcWindow
.top
;
2060 Rect
.right
+= XMove
;
2061 Rect
.bottom
+= YMove
;
2065 RtlCopyMemory(lprcItem
, &Rect
, sizeof(RECTL
));
2067 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2069 Status
= _SEH2_GetExceptionCode();
2073 if (!NT_SUCCESS(Status
))
2075 SetLastNtError(Status
);
2081 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_
);
2090 NtUserHiliteMenuItem(
2098 DECLARE_RETURN(BOOLEAN
);
2100 TRACE("Enter NtUserHiliteMenuItem\n");
2101 UserEnterExclusive();
2103 if(!(Window
= UserGetWindowObject(hWnd
)))
2105 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
2109 if(!(Menu
= UserGetMenuObject(hMenu
)))
2111 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
2115 RETURN( IntHiliteMenuItem(Window
, Menu
, uItemHilite
, uHilite
));
2118 TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_
);
2128 NtUserMenuItemFromPoint(
2138 DECLARE_RETURN(int);
2140 TRACE("Enter NtUserMenuItemFromPoint\n");
2141 UserEnterExclusive();
2143 if (!(Menu
= UserGetMenuObject(hMenu
)))
2148 if (!(Window
= UserGetWindowObject(Menu
->hWnd
)))
2153 X
-= Window
->rcWindow
.left
;
2154 Y
-= Window
->rcWindow
.top
;
2157 for (i
= 0; i
< Menu
->cItems
; i
++, mi
++)
2160 Rect
.left
= mi
->xItem
;
2161 Rect
.top
= mi
->yItem
;
2162 Rect
.right
= mi
->cxItem
; // Do this for now......
2163 Rect
.bottom
= mi
->cyItem
;
2164 //MENU_AdjustMenuItemRect(Menu, &Rect); Need gpsi OBMI via callback!
2165 if (RECTL_bPointInRect(&Rect
, X
, Y
))
2171 RETURN( (mi
? i
: NO_SELECTED_ITEM
));
2174 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_
);
2190 DECLARE_RETURN(BOOL
);
2192 TRACE("Enter NtUserRemoveMenu\n");
2193 UserEnterExclusive();
2195 if(!(Menu
= UserGetMenuObject(hMenu
)))
2200 RETURN(IntRemoveMenuItem(Menu
, uPosition
, uFlags
, FALSE
));
2203 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_
);
2213 NtUserSetMenuContextHelpId(
2215 DWORD dwContextHelpId
)
2218 DECLARE_RETURN(BOOL
);
2220 TRACE("Enter NtUserSetMenuContextHelpId\n");
2221 UserEnterExclusive();
2223 if(!(Menu
= UserGetMenuObject(hMenu
)))
2228 RETURN(IntSetMenuContextHelpId(Menu
, dwContextHelpId
));
2231 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_
);
2240 NtUserSetMenuDefaultItem(
2246 DECLARE_RETURN(BOOL
);
2248 TRACE("Enter NtUserSetMenuDefaultItem\n");
2249 UserEnterExclusive();
2251 if(!(Menu
= UserGetMenuObject(hMenu
)))
2256 RETURN( UserSetMenuDefaultItem(Menu
, uItem
, fByPos
));
2259 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_
);
2268 NtUserSetMenuFlagRtoL(
2272 DECLARE_RETURN(BOOL
);
2274 TRACE("Enter NtUserSetMenuFlagRtoL\n");
2275 UserEnterExclusive();
2277 if(!(Menu
= UserGetMenuObject(hMenu
)))
2282 RETURN(IntSetMenuFlagRtoL(Menu
));
2285 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_
);
2294 NtUserThunkedMenuInfo(
2299 DECLARE_RETURN(BOOL
);
2301 TRACE("Enter NtUserThunkedMenuInfo\n");
2302 UserEnterExclusive();
2304 if (!(Menu
= UserGetMenuObject(hMenu
)))
2309 RETURN(UserMenuInfo(Menu
, (PROSMENUINFO
)lpcmi
, TRUE
));
2312 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_
);
2321 NtUserThunkedMenuItemInfo(
2326 LPMENUITEMINFOW lpmii
,
2327 PUNICODE_STRING lpszCaption
)
2331 UNICODE_STRING lstrCaption
;
2332 DECLARE_RETURN(BOOL
);
2334 TRACE("Enter NtUserThunkedMenuItemInfo\n");
2335 UserEnterExclusive();
2337 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
2338 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */
2340 if (!(Menu
= UserGetMenuObject(hMenu
)))
2345 RtlInitUnicodeString(&lstrCaption
, 0);
2347 /* Check if we got a Caption */
2348 if (lpszCaption
&& lpszCaption
->Buffer
)
2350 /* Copy the string to kernel mode */
2351 Status
= ProbeAndCaptureUnicodeString( &lstrCaption
,
2354 if (!NT_SUCCESS(Status
))
2356 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status
);
2357 SetLastNtError(Status
);
2362 if (bInsert
) RETURN( UserInsertMenuItem(Menu
, uItem
, fByPosition
, lpmii
, &lstrCaption
));
2364 RETURN( UserMenuItemInfo(Menu
, uItem
, fByPosition
, (PROSMENUITEMINFO
)lpmii
, TRUE
, &lstrCaption
));
2367 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_
);