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
;
155 hMenu
= UserHMGetHandle(pMenu
);
156 pItem
= pMenu
->rgItems
;
163 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
165 ERR("Run away LOOP!\n");
166 _SEH2_YIELD(return NULL
);
170 if ( UserObjectInDestroy(hMenu
))
172 ERR("Menu is marked for destruction!\n");
179 BOOL
IntDestroyMenu( PMENU pMenu
, BOOL bRecurse
, BOOL RemoveFromProcess
)
181 /* DestroyMenu should not destroy system menu popup owner */
182 if ((pMenu
->fFlags
& (MNF_POPUP
| MNF_SYSSUBMENU
)) == MNF_POPUP
&& pMenu
->hWnd
)
184 //PWND pWnd = ValidateHwndNoErr(pMenu->hWnd);
185 ERR("FIXME Pop up menu window thing'ie\n");
187 //co_UserDestroyWindow( pWnd );
191 if (pMenu
->rgItems
) /* recursively destroy submenus */
194 ITEM
*item
= pMenu
->rgItems
;
195 for (i
= pMenu
->cItems
; i
> 0; i
--, item
++)
197 pMenu
->cItems
--; //// I hate recursion logic! (jt) 4/2014. See r63028 comment for IntDeleteMenuItems.
198 FreeMenuText(pMenu
,item
);
199 if (bRecurse
&& item
->spSubMenu
)//VerifyMenu(item->spSubMenu))
201 IntDestroyMenu(item
->spSubMenu
, bRecurse
, RemoveFromProcess
);
202 item
->spSubMenu
= NULL
;
205 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
206 pMenu
->rgItems
= NULL
;
207 pMenu
->cItems
= 0; //// What ever~!
213 IntDestroyMenuObject(PMENU Menu
,
214 BOOL bRecurse
, BOOL RemoveFromProcess
)
220 /* Remove all menu items */
221 IntDestroyMenu( Menu
, bRecurse
, RemoveFromProcess
);
223 if(RemoveFromProcess
)
225 RemoveEntryList(&Menu
->ListEntry
);
228 if (PsGetCurrentProcessSessionId() == Menu
->head
.rpdesk
->rpwinstaParent
->dwSessionId
)
233 Window
= UserGetWindowObject(Menu
->hWnd
);
239 //UserDereferenceObject(Menu);
240 ret
= UserDeleteObject(Menu
->head
.h
, TYPE_MENU
);
242 { // Make sure it is really dead or just marked for deletion.
243 ret
= UserObjectInDestroy(Menu
->head
.h
);
244 if (ret
&& EngGetLastError() == ERROR_INVALID_HANDLE
) ret
= FALSE
;
245 } // See test_subpopup_locked_by_menu tests....
252 /**********************************************************************
255 * detect if there are loops in the menu tree (or the depth is too large)
257 int FASTCALL
MENU_depth( PMENU pmenu
, int depth
)
263 if (!pmenu
) return depth
;
266 if( depth
> MAXMENUDEPTH
) return depth
;
267 item
= pmenu
->rgItems
;
269 for( i
= 0; item
, i
< pmenu
->cItems
&& subdepth
<= MAXMENUDEPTH
; i
++, item
++)
271 if( item
->spSubMenu
)//VerifyMenu(item->spSubMenu))
273 int bdepth
= MENU_depth( item
->spSubMenu
, depth
);
274 if( bdepth
> subdepth
) subdepth
= bdepth
;
276 if( subdepth
> MAXMENUDEPTH
)
277 TRACE("<- hmenu %p\n", item
->spSubMenu
);
282 /***********************************************************************
285 * Find a menu item. Return a pointer on the item, and modifies *hmenu
286 * in case the item was in a sub-menu.
288 PITEM FASTCALL
MENU_FindItem( PMENU
*pmenu
, UINT
*nPos
, UINT wFlags
)
291 ITEM
*fallback
= NULL
;
292 UINT fallback_pos
= 0;
295 if (!menu
) return NULL
;
297 if (wFlags
& MF_BYPOSITION
)
299 if (!menu
->cItems
) return NULL
;
300 if (*nPos
>= menu
->cItems
) return NULL
;
301 return &menu
->rgItems
[*nPos
];
305 PITEM item
= menu
->rgItems
;
306 for (i
= 0; item
, i
< menu
->cItems
; i
++, item
++)
310 PMENU psubmenu
= item
->spSubMenu
;//VerifyMenu(item->spSubMenu);
311 PITEM subitem
= MENU_FindItem( &psubmenu
, nPos
, wFlags
);
317 else if (item
->wID
== *nPos
)
319 /* fallback to this item if nothing else found */
324 else if (item
->wID
== *nPos
)
333 *nPos
= fallback_pos
;
339 IntRemoveMenuItem( PMENU pMenu
, UINT nPos
, UINT wFlags
, BOOL bRecurse
)
341 PITEM item
, NewItems
;
343 TRACE("(menu=%p pos=%04x flags=%04x)\n",pMenu
, nPos
, wFlags
);
344 if (!(item
= MENU_FindItem( &pMenu
, &nPos
, wFlags
))) return FALSE
;
348 FreeMenuText(pMenu
,item
);
349 if (bRecurse
&& item
->spSubMenu
)
351 IntDestroyMenuObject(item
->spSubMenu
, bRecurse
, TRUE
);
353 ////// Use cAlloced with inc's of 8's....
354 if (--pMenu
->cItems
== 0)
356 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
357 pMenu
->rgItems
= NULL
;
361 while(nPos
< pMenu
->cItems
)
367 NewItems
= DesktopHeapAlloc(pMenu
->head
.rpdesk
, pMenu
->cItems
* sizeof(ITEM
));
368 RtlCopyMemory(NewItems
, pMenu
->rgItems
, pMenu
->cItems
* sizeof(ITEM
));
369 DesktopHeapFree(pMenu
->head
.rpdesk
, pMenu
->rgItems
);
370 pMenu
->rgItems
= NewItems
;
375 /**********************************************************************
378 * Insert (allocate) a new item into a menu.
380 ITEM
*MENU_InsertItem( PMENU menu
, UINT pos
, UINT flags
, PMENU
*submenu
, UINT
*npos
)
384 /* Find where to insert new item */
386 if (flags
& MF_BYPOSITION
) {
387 if (pos
> menu
->cItems
)
390 if (!MENU_FindItem( &menu
, &pos
, flags
))
392 if (submenu
) *submenu
= menu
;
393 if (npos
) *npos
= pos
;
398 /* Make sure that MDI system buttons stay on the right side.
399 * Note: XP treats only bitmap handles 1 - 6 as "magic" ones
400 * regardless of their id.
403 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
>= (INT_PTR
)HBMMENU_SYSTEM
&&
404 (INT_PTR
)menu
->rgItems
[pos
- 1].hbmp
<= (INT_PTR
)HBMMENU_MBAR_CLOSE_D
)
407 TRACE("inserting at %u flags %x\n", pos
, flags
);
409 /* Create new items array */
411 newItems
= DesktopHeapAlloc(menu
->head
.rpdesk
, sizeof(ITEM
) * (menu
->cItems
+1) );
414 WARN("allocation failed\n" );
417 if (menu
->cItems
> 0)
419 /* Copy the old array into the new one */
420 if (pos
> 0) RtlCopyMemory( newItems
, menu
->rgItems
, pos
* sizeof(ITEM
) );
421 if (pos
< menu
->cItems
) RtlCopyMemory( &newItems
[pos
+1], &menu
->rgItems
[pos
], (menu
->cItems
-pos
)*sizeof(ITEM
) );
422 DesktopHeapFree(menu
->head
.rpdesk
, menu
->rgItems
);
424 menu
->rgItems
= newItems
;
426 RtlZeroMemory( &newItems
[pos
], sizeof(*newItems
) );
427 menu
->cyMenu
= 0; /* force size recalculate */
428 return &newItems
[pos
];
433 _In_ PMENU MenuObject
,
436 PROSMENUITEMINFO ItemInfo
,
437 PUNICODE_STRING lpstr
)
440 PMENU SubMenu
= NULL
;
442 NT_ASSERT(MenuObject
!= NULL
);
444 if (MAX_MENU_ITEMS
<= MenuObject
->cItems
)
446 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
450 SubMenu
= MenuObject
;
452 if(!(MenuItem
= MENU_InsertItem( SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, &SubMenu
, &uItem
))) return FALSE
;
454 if(!IntSetMenuItemInfo(SubMenu
, MenuItem
, ItemInfo
, lpstr
))
456 IntRemoveMenuItem(SubMenu
, uItem
, fByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
, FALSE
);
460 /* Force size recalculation! */
462 MenuItem
->hbmpChecked
= MenuItem
->hbmpUnchecked
= 0;
464 TRACE("IntInsertMenuItemToList = %i %d\n", uItem
, (BOOL
)((INT
)uItem
>= 0));
470 IntCreateMenu(PHANDLE Handle
, BOOL IsMenuBar
)
473 PPROCESSINFO CurrentWin32Process
;
475 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
487 Menu
->cyMax
= 0; /* Default */
488 Menu
->hbrBack
= NULL
; /* No brush */
489 Menu
->dwContextHelpId
= 0; /* Default */
490 Menu
->dwMenuData
= 0; /* Default */
491 Menu
->iItem
= NO_SELECTED_ITEM
; // Focused item
492 Menu
->fFlags
= (IsMenuBar
? 0 : MNF_POPUP
);
493 Menu
->spwndNotify
= NULL
;
494 Menu
->cyMenu
= 0; // Height
495 Menu
->cxMenu
= 0; // Width
496 Menu
->cItems
= 0; // Item count
499 Menu
->cxTextAlign
= 0;
500 Menu
->rgItems
= NULL
;
503 Menu
->TimeToHide
= FALSE
;
505 /* Insert menu item into process menu handle list */
506 CurrentWin32Process
= PsGetCurrentProcessWin32Process();
507 InsertTailList(&CurrentWin32Process
->MenuListHead
, &Menu
->ListEntry
);
513 IntCloneMenuItems(PMENU Destination
, PMENU Source
)
515 PITEM MenuItem
, NewMenuItem
= NULL
;
521 NewMenuItem
= DesktopHeapAlloc(Destination
->head
.rpdesk
, (Source
->cItems
+1) * sizeof(ITEM
));
522 if(!NewMenuItem
) return FALSE
;
524 RtlZeroMemory(NewMenuItem
, (Source
->cItems
+1) * sizeof(ITEM
));
526 Destination
->rgItems
= NewMenuItem
;
528 MenuItem
= Source
->rgItems
;
529 for (i
= 0; i
< Source
->cItems
; i
++, MenuItem
++, NewMenuItem
++)
531 NewMenuItem
->fType
= MenuItem
->fType
;
532 NewMenuItem
->fState
= MenuItem
->fState
;
533 NewMenuItem
->wID
= MenuItem
->wID
;
534 NewMenuItem
->spSubMenu
= MenuItem
->spSubMenu
;
535 NewMenuItem
->hbmpChecked
= MenuItem
->hbmpChecked
;
536 NewMenuItem
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
537 NewMenuItem
->dwItemData
= MenuItem
->dwItemData
;
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
);
549 NewMenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
550 NewMenuItem
->Xlpstr
= NewMenuItem
->lpstr
.Buffer
;
554 NewMenuItem
->lpstr
.Buffer
= MenuItem
->lpstr
.Buffer
;
555 NewMenuItem
->Xlpstr
= NewMenuItem
->lpstr
.Buffer
;
557 NewMenuItem
->hbmp
= MenuItem
->hbmp
;
563 IntCloneMenu(PMENU Source
)
565 PPROCESSINFO CurrentWin32Process
;
572 Menu
= (PMENU
)UserCreateObject( gHandleTable
,
581 Menu
->fFlags
= Source
->fFlags
;
582 Menu
->cyMax
= Source
->cyMax
;
583 Menu
->hbrBack
= Source
->hbrBack
;
584 Menu
->dwContextHelpId
= Source
->dwContextHelpId
;
585 Menu
->dwMenuData
= Source
->dwMenuData
;
586 Menu
->iItem
= NO_SELECTED_ITEM
;
587 Menu
->spwndNotify
= NULL
;
590 Menu
->cItems
= Source
->cItems
;
593 Menu
->cxTextAlign
= 0;
594 Menu
->rgItems
= NULL
;
597 Menu
->TimeToHide
= FALSE
;
599 /* Insert menu item into process menu handle list */
600 CurrentWin32Process
= PsGetCurrentProcessWin32Process();
601 InsertTailList(&CurrentWin32Process
->MenuListHead
, &Menu
->ListEntry
);
603 IntCloneMenuItems(Menu
, Source
);
609 IntSetMenuFlagRtoL(PMENU Menu
)
611 Menu
->fFlags
|= MNF_RTOL
;
616 IntSetMenuContextHelpId(PMENU Menu
, DWORD dwContextHelpId
)
618 Menu
->dwContextHelpId
= dwContextHelpId
;
623 IntGetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
625 if(lpmi
->fMask
& MIM_BACKGROUND
)
626 lpmi
->hbrBack
= Menu
->hbrBack
;
627 if(lpmi
->fMask
& MIM_HELPID
)
628 lpmi
->dwContextHelpID
= Menu
->dwContextHelpId
;
629 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
630 lpmi
->cyMax
= Menu
->cyMax
;
631 if(lpmi
->fMask
& MIM_MENUDATA
)
632 lpmi
->dwMenuData
= Menu
->dwMenuData
;
633 if(lpmi
->fMask
& MIM_STYLE
)
634 lpmi
->dwStyle
= Menu
->fFlags
& MNS_STYLE_MASK
;
636 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
638 lpmi
->cItems
= Menu
->cItems
;
640 lpmi
->iItem
= Menu
->iItem
;
641 lpmi
->cxMenu
= Menu
->cxMenu
;
642 lpmi
->cyMenu
= Menu
->cyMenu
;
643 lpmi
->spwndNotify
= Menu
->spwndNotify
;
644 lpmi
->cxTextAlign
= Menu
->cxTextAlign
;
645 lpmi
->iTop
= Menu
->iMaxTop
;
646 lpmi
->iMaxTop
= Menu
->iMaxTop
;
647 lpmi
->dwArrowsOn
= Menu
->dwArrowsOn
;
649 lpmi
->fFlags
= Menu
->fFlags
;
650 lpmi
->Self
= Menu
->head
.h
;
651 lpmi
->TimeToHide
= Menu
->TimeToHide
;
652 lpmi
->Wnd
= Menu
->hWnd
;
658 IntSetMenuInfo(PMENU Menu
, PROSMENUINFO lpmi
)
660 if(lpmi
->fMask
& MIM_BACKGROUND
)
661 Menu
->hbrBack
= lpmi
->hbrBack
;
662 if(lpmi
->fMask
& MIM_HELPID
)
663 Menu
->dwContextHelpId
= lpmi
->dwContextHelpID
;
664 if(lpmi
->fMask
& MIM_MAXHEIGHT
)
665 Menu
->cyMax
= lpmi
->cyMax
;
666 if(lpmi
->fMask
& MIM_MENUDATA
)
667 Menu
->dwMenuData
= lpmi
->dwMenuData
;
668 if(lpmi
->fMask
& MIM_STYLE
)
669 Menu
->fFlags
^= (Menu
->fFlags
^ lpmi
->dwStyle
) & MNS_STYLE_MASK
;
670 if(lpmi
->fMask
& MIM_APPLYTOSUBMENUS
)
673 PITEM item
= Menu
->rgItems
;
674 for ( i
= Menu
->cItems
; i
; i
--, item
++)
676 if ( item
->spSubMenu
)
678 IntSetMenuInfo( item
->spSubMenu
, lpmi
);
682 if (sizeof(MENUINFO
) < lpmi
->cbSize
)
684 Menu
->iItem
= lpmi
->iItem
;
685 Menu
->cyMenu
= lpmi
->cyMenu
;
686 Menu
->cxMenu
= lpmi
->cxMenu
;
687 Menu
->spwndNotify
= lpmi
->spwndNotify
;
688 Menu
->cxTextAlign
= lpmi
->cxTextAlign
;
689 Menu
->iTop
= lpmi
->iTop
;
690 Menu
->iMaxTop
= lpmi
->iMaxTop
;
691 Menu
->dwArrowsOn
= lpmi
->dwArrowsOn
;
693 Menu
->TimeToHide
= lpmi
->TimeToHide
;
694 Menu
->hWnd
= lpmi
->Wnd
;
700 IntGetMenuItemInfo(PMENU Menu
, /* UNUSED PARAM!! */
701 PITEM MenuItem
, PROSMENUITEMINFO lpmii
)
705 if(lpmii
->fMask
& (MIIM_FTYPE
| MIIM_TYPE
))
707 lpmii
->fType
= MenuItem
->fType
;
709 if(lpmii
->fMask
& MIIM_BITMAP
)
711 lpmii
->hbmpItem
= MenuItem
->hbmp
;
713 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
715 lpmii
->hbmpChecked
= MenuItem
->hbmpChecked
;
716 lpmii
->hbmpUnchecked
= MenuItem
->hbmpUnchecked
;
718 if(lpmii
->fMask
& MIIM_DATA
)
720 lpmii
->dwItemData
= MenuItem
->dwItemData
;
722 if(lpmii
->fMask
& MIIM_ID
)
724 lpmii
->wID
= MenuItem
->wID
;
726 if(lpmii
->fMask
& MIIM_STATE
)
728 lpmii
->fState
= MenuItem
->fState
;
730 if(lpmii
->fMask
& MIIM_SUBMENU
)
732 lpmii
->hSubMenu
= MenuItem
->spSubMenu
? MenuItem
->spSubMenu
->head
.h
: NULL
;
735 if ((lpmii
->fMask
& MIIM_STRING
) ||
736 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
738 if (lpmii
->dwTypeData
== NULL
)
740 lpmii
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
743 { //// lpmii->lpstr can be read in user mode!!!!
744 Status
= MmCopyToCaller(lpmii
->dwTypeData
, MenuItem
->lpstr
.Buffer
,
745 min(lpmii
->cch
* sizeof(WCHAR
),
746 MenuItem
->lpstr
.MaximumLength
));
747 if (! NT_SUCCESS(Status
))
749 SetLastNtError(Status
);
755 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
757 lpmii
->Rect
.left
= MenuItem
->xItem
;
758 lpmii
->Rect
.top
= MenuItem
->yItem
;
759 lpmii
->Rect
.right
= MenuItem
->cxItem
; // Do this for now......
760 lpmii
->Rect
.bottom
= MenuItem
->cyItem
;
761 lpmii
->dxTab
= MenuItem
->dxTab
;
762 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
;
763 lpmii
->maxBmpSize
.cx
= MenuItem
->cxBmp
;
764 lpmii
->maxBmpSize
.cy
= MenuItem
->cyBmp
;
771 IntSetMenuItemInfo(PMENU MenuObject
, PITEM MenuItem
, PROSMENUITEMINFO lpmii
, PUNICODE_STRING lpstr
)
774 BOOL circref
= FALSE
;
776 if(!MenuItem
|| !MenuObject
|| !lpmii
)
780 if ( lpmii
->fMask
& MIIM_FTYPE
)
782 MenuItem
->fType
&= ~MENUITEMINFO_TYPE_MASK
;
783 MenuItem
->fType
|= lpmii
->fType
& MENUITEMINFO_TYPE_MASK
;
785 if (lpmii
->fMask
& MIIM_TYPE
)
787 #if 0 //// Done in User32.
788 if (lpmii
->fMask
& ( MIIM_STRING
| MIIM_FTYPE
| MIIM_BITMAP
))
790 ERR("IntSetMenuItemInfo: Invalid combination of fMask bits used\n");
791 KeRosDumpStackFrames(NULL
, 20);
792 /* This does not happen on Win9x/ME */
793 SetLastNtError( ERROR_INVALID_PARAMETER
);
798 * Delete the menu item type when changing type from
801 if (MenuItem
->fType
!= lpmii
->fType
&&
802 MENU_ITEM_TYPE(MenuItem
->fType
) == MFT_STRING
)
804 FreeMenuText(MenuObject
,MenuItem
);
805 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
806 MenuItem
->Xlpstr
= NULL
;
808 if(lpmii
->fType
& MFT_BITMAP
)
811 MenuItem
->hbmp
= lpmii
->hbmpItem
;
813 { /* Win 9x/Me stuff */
814 MenuItem
->hbmp
= (HBITMAP
)((ULONG_PTR
)(LOWORD(lpmii
->dwTypeData
)));
816 lpmii
->dwTypeData
= 0;
819 if(lpmii
->fMask
& MIIM_BITMAP
)
821 MenuItem
->hbmp
= lpmii
->hbmpItem
;
823 if(lpmii
->fMask
& MIIM_CHECKMARKS
)
825 MenuItem
->hbmpChecked
= lpmii
->hbmpChecked
;
826 MenuItem
->hbmpUnchecked
= lpmii
->hbmpUnchecked
;
828 if(lpmii
->fMask
& MIIM_DATA
)
830 MenuItem
->dwItemData
= lpmii
->dwItemData
;
832 if(lpmii
->fMask
& MIIM_ID
)
834 MenuItem
->wID
= lpmii
->wID
;
836 if(lpmii
->fMask
& MIIM_STATE
)
838 /* Remove MFS_DEFAULT flag from all other menu items if this item
839 has the MFS_DEFAULT state */
840 if(lpmii
->fState
& MFS_DEFAULT
)
841 UserSetMenuDefaultItem(MenuObject
, -1, 0);
842 /* Update the menu item state flags */
843 UpdateMenuItemState(MenuItem
->fState
, lpmii
->fState
);
846 if(lpmii
->fMask
& MIIM_SUBMENU
)
850 SubMenuObject
= UserGetMenuObject(lpmii
->hSubMenu
);
851 if ( SubMenuObject
&& !(UserObjectInDestroy(lpmii
->hSubMenu
)) )
853 //// wine Bug 12171 : Adding Popup Menu to itself! Could create endless loops.
855 if (MenuObject
== SubMenuObject
)
858 ERR("Pop Up Menu Double Trouble!\n");
859 SubMenuObject
= IntCreateMenu(&hMenu
, FALSE
); // It will be marked.
860 if (!SubMenuObject
) return FALSE
;
863 if ( MENU_depth( SubMenuObject
, 0) > MAXMENUDEPTH
)
865 ERR( "Loop detected in menu hierarchy or maximum menu depth exceeded!\n");
866 if (circref
) IntDestroyMenuObject(SubMenuObject
, FALSE
, TRUE
);
869 /* Make sure the submenu is marked as a popup menu */
870 SubMenuObject
->fFlags
|= MNF_POPUP
;
871 // Now fix the test_subpopup_locked_by_menu tests....
872 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
873 MenuItem
->spSubMenu
= SubMenuObject
;
874 UserReferenceObject(SubMenuObject
);
878 EngSetLastError( ERROR_INVALID_PARAMETER
);
883 { // If submenu just dereference it.
884 if (MenuItem
->spSubMenu
) IntReleaseMenuObject(MenuItem
->spSubMenu
);
885 MenuItem
->spSubMenu
= NULL
;
889 if ((lpmii
->fMask
& MIIM_STRING
) ||
890 ((lpmii
->fMask
& MIIM_TYPE
) && (MENU_ITEM_TYPE(lpmii
->fType
) == MF_STRING
)))
892 /* free the string when used */
893 FreeMenuText(MenuObject
,MenuItem
);
894 RtlInitUnicodeString(&MenuItem
->lpstr
, NULL
);
895 MenuItem
->Xlpstr
= NULL
;
897 if(lpmii
->dwTypeData
&& lpmii
->cch
&& lpstr
&& lpstr
->Buffer
)
899 UNICODE_STRING Source
;
901 Source
.Length
= Source
.MaximumLength
= lpmii
->cch
* sizeof(WCHAR
);
902 Source
.Buffer
= lpmii
->dwTypeData
;
904 MenuItem
->lpstr
.Buffer
= DesktopHeapAlloc( MenuObject
->head
.rpdesk
, Source
.Length
+ sizeof(WCHAR
));
905 if(MenuItem
->lpstr
.Buffer
!= NULL
)
907 MenuItem
->lpstr
.Length
= 0;
908 MenuItem
->lpstr
.MaximumLength
= Source
.Length
+ sizeof(WCHAR
);
909 RtlCopyUnicodeString(&MenuItem
->lpstr
, &Source
);
910 MenuItem
->lpstr
.Buffer
[MenuItem
->lpstr
.Length
/ sizeof(WCHAR
)] = 0;
912 MenuItem
->cch
= MenuItem
->lpstr
.Length
/ sizeof(WCHAR
);
913 MenuItem
->Xlpstr
= (USHORT
*)MenuItem
->lpstr
.Buffer
;
918 if( !(MenuObject
->fFlags
& MNF_SYSDESKMN
) &&
920 !lpmii
->dwTypeData
&&
921 !(MenuItem
->fType
& MFT_OWNERDRAW
) &&
923 MenuItem
->fType
|= MFT_SEPARATOR
;
925 if (sizeof(ROSMENUITEMINFO
) == lpmii
->cbSize
)
927 MenuItem
->xItem
= lpmii
->Rect
.left
;
928 MenuItem
->yItem
= lpmii
->Rect
.top
;
929 MenuItem
->cxItem
= lpmii
->Rect
.right
; // Do this for now......
930 MenuItem
->cyItem
= lpmii
->Rect
.bottom
;
931 MenuItem
->dxTab
= lpmii
->dxTab
;
932 lpmii
->lpstr
= MenuItem
->lpstr
.Buffer
; /* Send back new allocated string or zero */
933 MenuItem
->cxBmp
= lpmii
->maxBmpSize
.cx
;
934 MenuItem
->cyBmp
= lpmii
->maxBmpSize
.cy
;
942 IntEnableMenuItem(PMENU MenuObject
, UINT uIDEnableItem
, UINT uEnable
)
947 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDEnableItem
, uEnable
))) return (UINT
)-1;
949 res
= MenuItem
->fState
& (MF_GRAYED
| MF_DISABLED
);
951 MenuItem
->fState
^= (res
^ uEnable
) & (MF_GRAYED
| MF_DISABLED
);
953 /* If the close item in the system menu change update the close button */
954 if((MenuItem
->wID
== SC_CLOSE
) && (res
!= uEnable
))
956 if (MenuObject
->fFlags
& MNF_SYSSUBMENU
&& MenuObject
->spwndNotify
!= 0)
958 RECTL rc
= MenuObject
->spwndNotify
->rcWindow
;
960 /* Refresh the frame to reflect the change */
961 IntMapWindowPoints(0, MenuObject
->spwndNotify
, (POINT
*)&rc
, 2);
963 co_UserRedrawWindow(MenuObject
->spwndNotify
, &rc
, 0, RDW_FRAME
| RDW_INVALIDATE
| RDW_NOCHILDREN
);
970 IntCheckMenuItem(PMENU MenuObject
, UINT uIDCheckItem
, UINT uCheck
)
975 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uIDCheckItem
, uCheck
))) return -1;
977 res
= (DWORD
)(MenuItem
->fState
& MF_CHECKED
);
979 MenuItem
->fState
^= (res
^ uCheck
) & MF_CHECKED
;
985 IntHiliteMenuItem(PWND WindowObject
,
992 if (!(MenuItem
= MENU_FindItem( &MenuObject
, &uItemHilite
, uHilite
))) return FALSE
;
994 if (uHilite
& MF_HILITE
)
996 MenuItem
->fState
|= MF_HILITE
;
1000 MenuItem
->fState
&= ~MF_HILITE
;
1002 /* FIXME: Update the window's menu */
1004 return TRUE
; // Always returns true!!!!
1008 UserSetMenuDefaultItem(PMENU MenuObject
, UINT uItem
, UINT fByPos
)
1011 PITEM MenuItem
= MenuObject
->rgItems
;
1013 if (!MenuItem
) return FALSE
;
1015 /* reset all default-item flags */
1016 for (i
= 0; MenuItem
, i
< MenuObject
->cItems
; i
++, MenuItem
++)
1018 MenuItem
->fState
&= ~MFS_DEFAULT
;
1021 /* no default item */
1022 if(uItem
== (UINT
)-1)
1026 MenuItem
= MenuObject
->rgItems
;
1029 if ( uItem
>= MenuObject
->cItems
) return FALSE
;
1030 MenuItem
[uItem
].fState
|= MFS_DEFAULT
;
1035 for (i
= 0; MenuItem
, i
< MenuObject
->cItems
; i
++, MenuItem
++)
1037 if (MenuItem
->wID
== uItem
)
1039 MenuItem
->fState
|= MFS_DEFAULT
;
1050 IntGetMenuDefaultItem(PMENU MenuObject
, UINT fByPos
, UINT gmdiFlags
, DWORD
*gismc
)
1053 PITEM MenuItem
= MenuObject
->rgItems
;
1056 if (!MenuItem
) return -1;
1058 while ( !( MenuItem
->fState
& MFS_DEFAULT
) )
1061 if (i
>= MenuObject
->cItems
) return -1;
1064 /* default: don't return disabled items */
1065 if ( (!(GMDI_USEDISABLED
& gmdiFlags
)) && (MenuItem
->fState
& MFS_DISABLED
)) return -1;
1067 /* search rekursiv when needed */
1068 if ( (MenuItem
->fType
& MF_POPUP
) && (gmdiFlags
& GMDI_GOINTOPOPUPS
) && MenuItem
->spSubMenu
)
1072 ret
= IntGetMenuDefaultItem( MenuItem
->spSubMenu
, fByPos
, gmdiFlags
, gismc
);
1074 if ( -1 != ret
) return ret
;
1076 /* when item not found in submenu, return the popup item */
1078 return ( fByPos
) ? i
: MenuItem
->wID
;
1082 co_IntInitTracking(PWND Window
, PMENU Menu
, BOOL Popup
,
1085 /* FIXME: Hide caret */
1087 if(!(Flags
& TPM_NONOTIFY
))
1088 co_IntSendMessage(Window
->head
.h
, WM_SETCURSOR
, (WPARAM
)Window
->head
.h
, HTCAPTION
);
1090 /* FIXME: Send WM_SETCURSOR message */
1092 if(!(Flags
& TPM_NONOTIFY
))
1093 co_IntSendMessage(Window
->head
.h
, WM_INITMENU
, (WPARAM
)Menu
->head
.h
, 0);
1097 co_IntExitTracking(PWND Window
, PMENU Menu
, BOOL Popup
,
1100 if(!(Flags
& TPM_NONOTIFY
))
1101 co_IntSendMessage(Window
->head
.h
, WM_EXITMENULOOP
, 0 /* FIXME */, 0);
1103 /* FIXME: Show caret again */
1107 IntTrackMenu(PMENU Menu
, PWND Window
, INT x
, INT y
,
1114 co_IntTrackPopupMenu(PMENU Menu
, PWND Window
,
1115 UINT Flags
, POINT
*Pos
, UINT MenuPos
, RECTL
*ExcludeRect
)
1117 co_IntInitTracking(Window
, Menu
, TRUE
, Flags
);
1119 co_IntExitTracking(Window
, Menu
, TRUE
, Flags
);
1125 * Internal function. Called when the process is destroyed to free the remaining menu handles.
1128 IntCleanupMenus(struct _EPROCESS
*Process
, PPROCESSINFO Win32Process
)
1130 PEPROCESS CurrentProcess
;
1131 PLIST_ENTRY LastHead
= NULL
;
1134 CurrentProcess
= PsGetCurrentProcess();
1135 if (CurrentProcess
!= Process
)
1137 KeAttachProcess(&Process
->Pcb
);
1140 while (Win32Process
->MenuListHead
.Flink
!= &(Win32Process
->MenuListHead
) &&
1141 Win32Process
->MenuListHead
.Flink
!= LastHead
)
1143 LastHead
= Win32Process
->MenuListHead
.Flink
;
1144 MenuObject
= CONTAINING_RECORD(Win32Process
->MenuListHead
.Flink
, MENU
, ListEntry
);
1145 TRACE("Menus are stuck on the process list!\n");
1146 IntDestroyMenuObject(MenuObject
, FALSE
, TRUE
);
1149 if (CurrentProcess
!= Process
)
1157 intGetTitleBarInfo(PWND pWindowObject
, PTITLEBARINFO bti
)
1161 DWORD dwExStyle
= 0;
1162 BOOLEAN retValue
= TRUE
;
1164 if (bti
->cbSize
== sizeof(TITLEBARINFO
))
1166 RtlZeroMemory(&bti
->rgstate
[0],sizeof(DWORD
)*(CCHILDREN_TITLEBAR
+1));
1168 bti
->rgstate
[0] = STATE_SYSTEM_FOCUSABLE
;
1170 dwStyle
= pWindowObject
->style
;
1171 dwExStyle
= pWindowObject
->ExStyle
;
1173 bti
->rcTitleBar
.top
= 0;
1174 bti
->rcTitleBar
.left
= 0;
1175 bti
->rcTitleBar
.right
= pWindowObject
->rcWindow
.right
- pWindowObject
->rcWindow
.left
;
1176 bti
->rcTitleBar
.bottom
= pWindowObject
->rcWindow
.bottom
- pWindowObject
->rcWindow
.top
;
1178 /* Is it iconiced ? */
1179 if ((dwStyle
& WS_ICONIC
)!=WS_ICONIC
)
1181 /* Remove frame from rectangle */
1182 if (HAS_THICKFRAME( dwStyle
, dwExStyle
))
1184 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */
1185 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXFRAME
), -UserGetSystemMetrics(SM_CYFRAME
) );
1187 else if (HAS_DLGFRAME( dwStyle
, dwExStyle
))
1189 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */
1190 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXDLGFRAME
), -UserGetSystemMetrics(SM_CYDLGFRAME
));
1192 else if (HAS_THINFRAME( dwStyle
, dwExStyle
))
1194 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
1195 RECTL_vInflateRect( &bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
) );
1198 /* We have additional border information if the window
1199 * is a child (but not an MDI child) */
1200 if ( (dwStyle
& WS_CHILD
) &&
1201 ((dwExStyle
& WS_EX_MDICHILD
) == 0 ) )
1203 if (dwExStyle
& WS_EX_CLIENTEDGE
)
1205 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */
1206 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXEDGE
), -UserGetSystemMetrics(SM_CYEDGE
));
1209 if (dwExStyle
& WS_EX_STATICEDGE
)
1211 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */
1212 RECTL_vInflateRect (&bti
->rcTitleBar
, -UserGetSystemMetrics(SM_CXBORDER
), -UserGetSystemMetrics(SM_CYBORDER
));
1217 bti
->rcTitleBar
.top
+= pWindowObject
->rcWindow
.top
;
1218 bti
->rcTitleBar
.left
+= pWindowObject
->rcWindow
.left
;
1219 bti
->rcTitleBar
.right
+= pWindowObject
->rcWindow
.left
;
1221 bti
->rcTitleBar
.bottom
= bti
->rcTitleBar
.top
;
1222 if (dwExStyle
& WS_EX_TOOLWINDOW
)
1224 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */
1225 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYSMCAPTION
);
1229 /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */
1230 bti
->rcTitleBar
.bottom
+= UserGetSystemMetrics(SM_CYCAPTION
);
1231 bti
->rcTitleBar
.left
+= UserGetSystemMetrics(SM_CXSIZE
);
1234 if (dwStyle
& WS_CAPTION
)
1236 bti
->rgstate
[1] = STATE_SYSTEM_INVISIBLE
;
1237 if (dwStyle
& WS_SYSMENU
)
1239 if (!(dwStyle
& (WS_MINIMIZEBOX
|WS_MAXIMIZEBOX
)))
1241 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
1242 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
1246 if (!(dwStyle
& WS_MINIMIZEBOX
))
1248 bti
->rgstate
[2] = STATE_SYSTEM_UNAVAILABLE
;
1250 if (!(dwStyle
& WS_MAXIMIZEBOX
))
1252 bti
->rgstate
[3] = STATE_SYSTEM_UNAVAILABLE
;
1256 if (!(dwExStyle
& WS_EX_CONTEXTHELP
))
1258 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
1260 if (pWindowObject
->pcls
->style
& CS_NOCLOSE
)
1262 bti
->rgstate
[5] = STATE_SYSTEM_UNAVAILABLE
;
1267 bti
->rgstate
[2] = STATE_SYSTEM_INVISIBLE
;
1268 bti
->rgstate
[3] = STATE_SYSTEM_INVISIBLE
;
1269 bti
->rgstate
[4] = STATE_SYSTEM_INVISIBLE
;
1270 bti
->rgstate
[5] = STATE_SYSTEM_INVISIBLE
;
1275 bti
->rgstate
[0] |= STATE_SYSTEM_INVISIBLE
;
1280 EngSetLastError(ERROR_INVALID_PARAMETER
);
1292 LPCMENUITEMINFOW UnsafeItemInfo
,
1293 PUNICODE_STRING lpstr
)
1296 ROSMENUITEMINFO ItemInfo
;
1298 /* Try to copy the whole MENUITEMINFOW structure */
1299 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, sizeof(MENUITEMINFOW
));
1300 if (NT_SUCCESS(Status
))
1302 if (sizeof(MENUITEMINFOW
) != ItemInfo
.cbSize
1303 && FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
1305 EngSetLastError(ERROR_INVALID_PARAMETER
);
1308 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
1311 /* Try to copy without last field (not present in older versions) */
1312 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
));
1313 if (NT_SUCCESS(Status
))
1315 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != ItemInfo
.cbSize
)
1317 EngSetLastError(ERROR_INVALID_PARAMETER
);
1320 ItemInfo
.hbmpItem
= (HBITMAP
)0;
1321 return IntInsertMenuItem(Menu
, uItem
, fByPosition
, &ItemInfo
, lpstr
);
1324 SetLastNtError(Status
);
1328 UINT FASTCALL
IntGetMenuState( HMENU hMenu
, UINT uId
, UINT uFlags
)
1333 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
1338 if (!(pItem
= MENU_FindItem( &MenuObject
, &uId
, uFlags
))) return -1;
1340 if (pItem
->spSubMenu
)
1342 return (pItem
->spSubMenu
->cItems
<< 8) | ((pItem
->fState
|pItem
->fType
) & 0xff);
1345 return (pItem
->fType
| pItem
->fState
);
1348 HMENU FASTCALL
IntGetSubMenu( HMENU hMenu
, int nPos
)
1353 if (!(MenuObject
= UserGetMenuObject(hMenu
)))
1358 if (!(pItem
= MENU_FindItem( &MenuObject
, (UINT
*)&nPos
, MF_BYPOSITION
))) return NULL
;
1360 if (pItem
->spSubMenu
)
1362 HMENU hsubmenu
= UserHMGetHandle(pItem
->spSubMenu
);
1368 UINT FASTCALL
IntFindSubMenu(HMENU
*hMenu
, HMENU hSubTarget
)
1375 if (((*hMenu
)==(HMENU
)0xffff) ||(!(menu
= UserGetMenuObject(*hMenu
))))
1376 return NO_SELECTED_ITEM
;
1378 item
= menu
->rgItems
;
1379 for (i
= 0; i
< menu
->cItems
; i
++, item
++)
1381 if (!item
->spSubMenu
)
1385 hSubMenu
= UserHMGetHandle(item
->spSubMenu
);
1386 if (hSubMenu
== hSubTarget
)
1392 HMENU hsubmenu
= hSubMenu
;
1393 UINT pos
= IntFindSubMenu( &hsubmenu
, hSubTarget
);
1394 if (pos
!= NO_SELECTED_ITEM
)
1402 return NO_SELECTED_ITEM
;
1406 HMENU FASTCALL
UserCreateMenu(BOOL PopupMenu
)
1408 PWINSTATION_OBJECT WinStaObject
;
1412 PEPROCESS CurrentProcess
= PsGetCurrentProcess();
1414 if (gpepCSRSS
!= CurrentProcess
)
1417 * gpepCSRSS does not have a Win32WindowStation
1420 Status
= IntValidateWindowStationHandle(CurrentProcess
->Win32WindowStation
,
1425 if (!NT_SUCCESS(Status
))
1427 ERR("Validation of window station handle (%p) failed\n",
1428 CurrentProcess
->Win32WindowStation
);
1429 SetLastNtError(Status
);
1432 Menu
= IntCreateMenu(&Handle
, !PopupMenu
);
1433 if (Menu
->head
.rpdesk
->rpwinstaParent
!= WinStaObject
)
1435 ERR("Desktop Window Station does not match Process one!\n");
1437 ObDereferenceObject(WinStaObject
);
1441 Menu
= IntCreateMenu(&Handle
, !PopupMenu
);
1444 if (Menu
) UserDereferenceObject(Menu
);
1445 return (HMENU
)Handle
;
1453 PROSMENUITEMINFO ItemInfo
,
1455 PUNICODE_STRING lpstr
)
1460 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
1462 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
1467 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, ItemInfo
, lpstr
);
1471 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, ItemInfo
);
1481 PROSMENUITEMINFO UnsafeItemInfo
,
1483 PUNICODE_STRING lpstr
)
1486 ROSMENUITEMINFO ItemInfo
;
1491 Status
= MmCopyFromCaller(&Size
, &UnsafeItemInfo
->cbSize
, sizeof(UINT
));
1492 if (! NT_SUCCESS(Status
))
1494 SetLastNtError(Status
);
1497 if (sizeof(MENUITEMINFOW
) != Size
1498 && FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) != Size
1499 && sizeof(ROSMENUITEMINFO
) != Size
)
1501 EngSetLastError(ERROR_INVALID_PARAMETER
);
1504 Status
= MmCopyFromCaller(&ItemInfo
, UnsafeItemInfo
, Size
);
1505 if (! NT_SUCCESS(Status
))
1507 SetLastNtError(Status
);
1510 /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't
1512 if (FIELD_OFFSET(MENUITEMINFOW
, hbmpItem
) == Size
1513 && 0 != (ItemInfo
.fMask
& MIIM_BITMAP
))
1515 EngSetLastError(ERROR_INVALID_PARAMETER
);
1519 if (!(MenuItem
= MENU_FindItem( &Menu
, &Item
, (ByPosition
? MF_BYPOSITION
: MF_BYCOMMAND
) )))
1521 EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND
);
1527 Ret
= IntSetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
, lpstr
);
1531 Ret
= IntGetMenuItemInfo(Menu
, MenuItem
, &ItemInfo
);
1534 Status
= MmCopyToCaller(UnsafeItemInfo
, &ItemInfo
, Size
);
1535 if (! NT_SUCCESS(Status
))
1537 SetLastNtError(Status
);
1549 PROSMENUINFO UnsafeMenuInfo
,
1555 ROSMENUINFO MenuInfo
;
1557 Status
= MmCopyFromCaller(&Size
, &UnsafeMenuInfo
->cbSize
, sizeof(DWORD
));
1558 if (! NT_SUCCESS(Status
))
1560 SetLastNtError(Status
);
1563 if(Size
< sizeof(MENUINFO
) || sizeof(ROSMENUINFO
) < Size
)
1565 EngSetLastError(ERROR_INVALID_PARAMETER
);
1568 Status
= MmCopyFromCaller(&MenuInfo
, UnsafeMenuInfo
, Size
);
1569 if (! NT_SUCCESS(Status
))
1571 SetLastNtError(Status
);
1578 Res
= IntSetMenuInfo(Menu
, &MenuInfo
);
1583 Res
= IntGetMenuInfo(Menu
, &MenuInfo
);
1586 Status
= MmCopyToCaller(UnsafeMenuInfo
, &MenuInfo
, Size
);
1587 if (! NT_SUCCESS(Status
))
1589 SetLastNtError(Status
);
1599 MENU_AdjustMenuItemRect(PMENU menu
, PRECTL rect
)
1601 if (menu
->dwArrowsOn
)
1603 UINT arrow_bitmap_height
;
1605 //GetObjectW(get_up_arrow_bitmap(), sizeof(bmp), &bmp);
1606 arrow_bitmap_height
= gpsi
->oembmi
[65].cy
; ///// Menu up arrow! OBM_UPARROW DFCS_MENUARROWUP
1607 //arrow_bitmap_height = bmp.bmHeight;
1608 rect
->top
+= arrow_bitmap_height
- menu
->iTop
;
1609 rect
->bottom
+= arrow_bitmap_height
- menu
->iTop
;
1625 HWND hWnd
= Menu
->hWnd
;
1626 if (!(pWnd
= UserGetWindowObject(hWnd
))) return FALSE
;
1629 if ((MenuItem
= MENU_FindItem (&Menu
, &uItem
, MF_BYPOSITION
)))
1631 Rect
->left
= MenuItem
->xItem
;
1632 Rect
->top
= MenuItem
->yItem
;
1633 Rect
->right
= MenuItem
->cxItem
; // Do this for now......
1634 Rect
->bottom
= MenuItem
->cyItem
;
1638 ERR("Failed Item Lookup! %d\n", uItem
);
1642 if (Menu
->fFlags
& MNF_POPUP
)
1644 XMove
= pWnd
->rcClient
.left
;
1645 YMove
= pWnd
->rcClient
.top
;
1649 XMove
= pWnd
->rcWindow
.left
;
1650 YMove
= pWnd
->rcWindow
.top
;
1653 Rect
->left
+= XMove
;
1655 Rect
->right
+= XMove
;
1656 Rect
->bottom
+= YMove
;
1661 /* FUNCTIONS *****************************************************************/
1667 NtUserCheckMenuItem(
1673 DECLARE_RETURN(DWORD
);
1675 TRACE("Enter NtUserCheckMenuItem\n");
1676 UserEnterExclusive();
1678 if(!(Menu
= UserGetMenuObject(hMenu
)))
1683 RETURN( IntCheckMenuItem(Menu
, uIDCheckItem
, uCheck
));
1686 TRACE("Leave NtUserCheckMenuItem, ret=%lu\n",_ret_
);
1701 DECLARE_RETURN(BOOL
);
1703 TRACE("Enter NtUserDeleteMenu\n");
1704 UserEnterExclusive();
1706 if(!(Menu
= UserGetMenuObject(hMenu
)))
1711 RETURN( IntRemoveMenuItem(Menu
, uPosition
, uFlags
, TRUE
));
1714 TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_
);
1723 NtUserGetTitleBarInfo(
1728 TITLEBARINFO bartitleinfo
;
1729 DECLARE_RETURN(BOOLEAN
);
1730 BOOLEAN retValue
= TRUE
;
1732 TRACE("Enter NtUserGetTitleBarInfo\n");
1733 UserEnterExclusive();
1735 /* Vaildate the windows handle */
1736 if (!(WindowObject
= UserGetWindowObject(hwnd
)))
1738 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
1744 /* Copy our usermode buffer bti to local buffer bartitleinfo */
1745 ProbeForRead(bti
, sizeof(TITLEBARINFO
), 1);
1746 RtlCopyMemory(&bartitleinfo
, bti
, sizeof(TITLEBARINFO
));
1748 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1750 /* Fail copy the data */
1751 EngSetLastError(ERROR_INVALID_PARAMETER
);
1756 /* Get the tile bar info */
1759 retValue
= intGetTitleBarInfo(WindowObject
, &bartitleinfo
);
1764 /* Copy our buffer to user mode buffer bti */
1765 ProbeForWrite(bti
, sizeof(TITLEBARINFO
), 1);
1766 RtlCopyMemory(bti
, &bartitleinfo
, sizeof(TITLEBARINFO
));
1768 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1770 /* Fail copy the data */
1771 EngSetLastError(ERROR_INVALID_PARAMETER
);
1781 TRACE("Leave NtUserGetTitleBarInfo, ret=%u\n",_ret_
);
1789 BOOL FASTCALL
UserDestroyMenu(HMENU hMenu
)
1792 PTHREADINFO pti
= PsGetCurrentThreadWin32Thread();
1794 if(!(Menu
= UserGetMenuObject(hMenu
)))
1799 if (Menu
->head
.rpdesk
!= pti
->rpdesk
)
1801 EngSetLastError(ERROR_ACCESS_DENIED
);
1804 return IntDestroyMenuObject(Menu
, FALSE
, TRUE
);
1815 DECLARE_RETURN(BOOL
);
1817 TRACE("Enter NtUserDestroyMenu\n");
1818 UserEnterExclusive();
1820 if(!(Menu
= UserGetMenuObject(hMenu
)))
1824 if (Menu
->head
.rpdesk
!= gptiCurrent
->rpdesk
)
1826 EngSetLastError(ERROR_ACCESS_DENIED
);
1829 RETURN( IntDestroyMenuObject(Menu
, TRUE
, TRUE
));
1832 TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_
);
1841 NtUserEnableMenuItem(
1847 DECLARE_RETURN(UINT
);
1849 TRACE("Enter NtUserEnableMenuItem\n");
1850 UserEnterExclusive();
1852 if(!(Menu
= UserGetMenuObject(hMenu
)))
1857 RETURN( IntEnableMenuItem(Menu
, uIDEnableItem
, uEnable
));
1860 TRACE("Leave NtUserEnableMenuItem, ret=%u\n",_ret_
);
1869 NtUserGetMenuBarInfo(
1879 NTSTATUS Status
= STATUS_SUCCESS
;
1881 DECLARE_RETURN(BOOL
);
1883 TRACE("Enter NtUserGetMenuBarInfo\n");
1886 if (!(pWnd
= UserGetWindowObject(hwnd
)))
1888 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
1895 if (!pWnd
->pcls
->fnid
)
1897 if (pWnd
->pcls
->fnid
!= FNID_MENU
)
1899 WARN("called on invalid window: %d\n", pWnd
->pcls
->fnid
);
1900 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
1903 // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW.
1904 hMenu
= (HMENU
)co_IntSendMessage(hwnd
, MN_GETHMENU
, 0, 0);
1907 hMenu
= UlongToHandle(pWnd
->IDMenu
);
1910 if (!(pWnd
->style
& WS_SYSMENU
)) RETURN(FALSE
);
1911 Menu
= IntGetSystemMenu(pWnd
, FALSE
, FALSE
);
1912 hMenu
= Menu
->head
.h
;
1923 kmbi
.cbSize
= pmbi
->cbSize
;
1925 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1931 if (kmbi
.cbSize
!= sizeof(MENUBARINFO
))
1933 EngSetLastError(ERROR_INVALID_PARAMETER
);
1937 if (!Menu
) Menu
= UserGetMenuObject(hMenu
);
1941 if (idItem
< 0 || idItem
> Menu
->cItems
)
1944 RECTL_vSetEmptyRect(&kmbi
.rcBar
);
1948 Ret
= IntGetMenuItemRect(pWnd
, Menu
, 0, &kmbi
.rcBar
);
1949 kmbi
.rcBar
.right
= kmbi
.rcBar
.left
+ Menu
->cxMenu
;
1950 kmbi
.rcBar
.bottom
= kmbi
.rcBar
.top
+ Menu
->cyMenu
;
1951 TRACE("idItem 0 %d\n",Ret
);
1955 Ret
= IntGetMenuItemRect(pWnd
, Menu
, idItem
-1, &kmbi
.rcBar
);
1956 TRACE("idItem X %d\n", Ret
);
1960 kmbi
.hwndMenu
= NULL
;
1961 kmbi
.fBarFocused
= FALSE
;
1962 kmbi
.fFocused
= FALSE
;
1963 //kmbi.fBarFocused = top_popup_hmenu == hMenu;
1966 kmbi
.fFocused
= Menu
->iItem
== idItem
-1;
1967 if (kmbi
.fFocused
&& (Menu
->rgItems
[idItem
- 1].spSubMenu
))
1969 kmbi
.hwndMenu
= Menu
->rgItems
[idItem
- 1].spSubMenu
->hWnd
;
1974 kmbi.fFocused = kmbi.fBarFocused;
1979 RtlCopyMemory(pmbi
, &kmbi
, sizeof(MENUBARINFO
));
1981 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1983 Status
= _SEH2_GetExceptionCode();
1987 if (!NT_SUCCESS(Status
))
1989 SetLastNtError(Status
);
1996 TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_
);
2009 PMENU Menu
, SubMenu
;
2012 DECLARE_RETURN(UINT
);
2014 TRACE("Enter NtUserGetMenuIndex\n");
2017 if ( !(Menu
= UserGetMenuObject(hMenu
)) ||
2018 !(SubMenu
= UserGetMenuObject(hSubMenu
)) )
2021 MenuItem
= Menu
->rgItems
;
2022 for (i
= 0; i
< Menu
->cItems
; i
++, MenuItem
++)
2024 if (MenuItem
->spSubMenu
== SubMenu
)
2025 RETURN(MenuItem
->wID
);
2030 TRACE("Leave NtUserGetMenuIndex, ret=%u\n",_ret_
);
2039 NtUserGetMenuItemRect(
2050 NTSTATUS Status
= STATUS_SUCCESS
;
2051 DECLARE_RETURN(BOOL
);
2053 TRACE("Enter NtUserGetMenuItemRect\n");
2056 if (!(Menu
= UserGetMenuObject(hMenu
)))
2061 if ((MenuItem
= MENU_FindItem (&Menu
, &uItem
, MF_BYPOSITION
)))
2063 Rect
.left
= MenuItem
->xItem
;
2064 Rect
.top
= MenuItem
->yItem
;
2065 Rect
.right
= MenuItem
->cxItem
; // Do this for now......
2066 Rect
.bottom
= MenuItem
->cyItem
;
2076 if (lprcItem
== NULL
) RETURN( FALSE
);
2078 if (!(ReferenceWnd
= UserGetWindowObject(hWnd
))) RETURN( FALSE
);
2080 if (Menu
->fFlags
& MNF_POPUP
)
2082 XMove
= ReferenceWnd
->rcClient
.left
;
2083 YMove
= ReferenceWnd
->rcClient
.top
;
2087 XMove
= ReferenceWnd
->rcWindow
.left
;
2088 YMove
= ReferenceWnd
->rcWindow
.top
;
2093 Rect
.right
+= XMove
;
2094 Rect
.bottom
+= YMove
;
2098 RtlCopyMemory(lprcItem
, &Rect
, sizeof(RECTL
));
2100 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
2102 Status
= _SEH2_GetExceptionCode();
2106 if (!NT_SUCCESS(Status
))
2108 SetLastNtError(Status
);
2114 TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_
);
2123 NtUserHiliteMenuItem(
2131 DECLARE_RETURN(BOOLEAN
);
2133 TRACE("Enter NtUserHiliteMenuItem\n");
2134 UserEnterExclusive();
2136 if(!(Window
= UserGetWindowObject(hWnd
)))
2138 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE
);
2142 if(!(Menu
= UserGetMenuObject(hMenu
)))
2144 EngSetLastError(ERROR_INVALID_MENU_HANDLE
);
2148 RETURN( IntHiliteMenuItem(Window
, Menu
, uItemHilite
, uHilite
));
2151 TRACE("Leave NtUserHiliteMenuItem, ret=%u\n",_ret_
);
2161 NtUserMenuItemFromPoint(
2171 DECLARE_RETURN(int);
2173 TRACE("Enter NtUserMenuItemFromPoint\n");
2174 UserEnterExclusive();
2176 if (!(Menu
= UserGetMenuObject(hMenu
)))
2181 if (!(Window
= UserGetWindowObject(Menu
->hWnd
)))
2186 X
-= Window
->rcWindow
.left
;
2187 Y
-= Window
->rcWindow
.top
;
2190 for (i
= 0; i
< Menu
->cItems
; i
++, mi
++)
2193 Rect
.left
= mi
->xItem
;
2194 Rect
.top
= mi
->yItem
;
2195 Rect
.right
= mi
->cxItem
; // Do this for now......
2196 Rect
.bottom
= mi
->cyItem
;
2197 //MENU_AdjustMenuItemRect(Menu, &Rect); Need gpsi OBMI via callback!
2198 if (RECTL_bPointInRect(&Rect
, X
, Y
))
2204 RETURN( (mi
? i
: NO_SELECTED_ITEM
));
2207 TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_
);
2223 DECLARE_RETURN(BOOL
);
2225 TRACE("Enter NtUserRemoveMenu\n");
2226 UserEnterExclusive();
2228 if(!(Menu
= UserGetMenuObject(hMenu
)))
2233 RETURN(IntRemoveMenuItem(Menu
, uPosition
, uFlags
, FALSE
));
2236 TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_
);
2246 NtUserSetMenuContextHelpId(
2248 DWORD dwContextHelpId
)
2251 DECLARE_RETURN(BOOL
);
2253 TRACE("Enter NtUserSetMenuContextHelpId\n");
2254 UserEnterExclusive();
2256 if(!(Menu
= UserGetMenuObject(hMenu
)))
2261 RETURN(IntSetMenuContextHelpId(Menu
, dwContextHelpId
));
2264 TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_
);
2273 NtUserSetMenuDefaultItem(
2279 DECLARE_RETURN(BOOL
);
2281 TRACE("Enter NtUserSetMenuDefaultItem\n");
2282 UserEnterExclusive();
2284 if(!(Menu
= UserGetMenuObject(hMenu
)))
2289 RETURN( UserSetMenuDefaultItem(Menu
, uItem
, fByPos
));
2292 TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_
);
2301 NtUserSetMenuFlagRtoL(
2305 DECLARE_RETURN(BOOL
);
2307 TRACE("Enter NtUserSetMenuFlagRtoL\n");
2308 UserEnterExclusive();
2310 if(!(Menu
= UserGetMenuObject(hMenu
)))
2315 RETURN(IntSetMenuFlagRtoL(Menu
));
2318 TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_
);
2327 NtUserThunkedMenuInfo(
2332 DECLARE_RETURN(BOOL
);
2334 TRACE("Enter NtUserThunkedMenuInfo\n");
2335 UserEnterExclusive();
2337 if (!(Menu
= UserGetMenuObject(hMenu
)))
2342 RETURN(UserMenuInfo(Menu
, (PROSMENUINFO
)lpcmi
, TRUE
));
2345 TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_
);
2354 NtUserThunkedMenuItemInfo(
2359 LPMENUITEMINFOW lpmii
,
2360 PUNICODE_STRING lpszCaption
)
2364 UNICODE_STRING lstrCaption
;
2365 DECLARE_RETURN(BOOL
);
2367 TRACE("Enter NtUserThunkedMenuItemInfo\n");
2368 UserEnterExclusive();
2370 /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString()
2371 if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */
2373 if (!(Menu
= UserGetMenuObject(hMenu
)))
2378 RtlInitUnicodeString(&lstrCaption
, 0);
2380 /* Check if we got a Caption */
2381 if (lpszCaption
&& lpszCaption
->Buffer
)
2383 /* Copy the string to kernel mode */
2384 Status
= ProbeAndCaptureUnicodeString( &lstrCaption
,
2387 if (!NT_SUCCESS(Status
))
2389 ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status
);
2390 SetLastNtError(Status
);
2395 if (bInsert
) RETURN( UserInsertMenuItem(Menu
, uItem
, fByPosition
, lpmii
, &lstrCaption
));
2397 RETURN( UserMenuItemInfo(Menu
, uItem
, fByPosition
, (PROSMENUITEMINFO
)lpmii
, TRUE
, &lstrCaption
));
2400 TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_
);