You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
451 lines
12 KiB
451 lines
12 KiB
/****************************** Module Header ******************************\
|
|
* Module Name: menuc.c
|
|
*
|
|
* Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
*
|
|
* This module contains
|
|
*
|
|
* History:
|
|
* 01-11-93 DavidPe Created
|
|
\***************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
FUNCLOG3(LOG_GENERAL, DWORD, DUMMYCALLINGTYPE, CheckMenuItem, HMENU, hMenu, UINT, uIDCheckItem, UINT, uCheck)
|
|
DWORD CheckMenuItem(
|
|
HMENU hMenu,
|
|
UINT uIDCheckItem,
|
|
UINT uCheck)
|
|
{
|
|
PMENU pMenu;
|
|
PITEM pItem;
|
|
|
|
pMenu = VALIDATEHMENU(hMenu);
|
|
if (pMenu == NULL) {
|
|
return (DWORD)-1;
|
|
}
|
|
|
|
/*
|
|
* Get a pointer the the menu item
|
|
*/
|
|
if ((pItem = MNLookUpItem(pMenu, uIDCheckItem, (BOOL) (uCheck & MF_BYPOSITION), NULL)) == NULL)
|
|
return (DWORD)-1;
|
|
|
|
/*
|
|
* If the item is already in the state we're
|
|
* trying to set, just return.
|
|
*/
|
|
if ((pItem->fState & MFS_CHECKED) == (uCheck & MFS_CHECKED)) {
|
|
return pItem->fState & MF_CHECKED;
|
|
}
|
|
|
|
return NtUserCheckMenuItem(hMenu, uIDCheckItem, uCheck);
|
|
}
|
|
|
|
|
|
FUNCLOG3(LOG_GENERAL, UINT, DUMMYCALLINGTYPE, GetMenuDefaultItem, HMENU, hMenu, UINT, fByPosition, UINT, uFlags)
|
|
UINT GetMenuDefaultItem(HMENU hMenu, UINT fByPosition, UINT uFlags)
|
|
{
|
|
PMENU pMenu;
|
|
|
|
pMenu = VALIDATEHMENU(hMenu);
|
|
if (pMenu == NULL) {
|
|
return (DWORD)-1;
|
|
}
|
|
|
|
return _GetMenuDefaultItem(pMenu, (BOOL)fByPosition, uFlags);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* SetMenuItemInfoStruct
|
|
*
|
|
* History:
|
|
* 07-22-96 GerardoB - Added header and Fixed up for 5.0
|
|
\***************************************************************************/
|
|
void SetMenuItemInfoStruct(HMENU hMenu, UINT wFlags, UINT_PTR wIDNew, LPWSTR pwszNew, LPMENUITEMINFO pmii)
|
|
{
|
|
PMENU pMenu;
|
|
PITEM pItem;
|
|
|
|
UserAssert(sizeof(MENUITEMINFOW) == sizeof(MENUITEMINFOA));
|
|
|
|
RtlZeroMemory(pmii, sizeof(*pmii));
|
|
|
|
pmii->fMask = MIIM_STATE | MIIM_ID | MIIM_FTYPE;
|
|
|
|
/*
|
|
* For compatibility, setting the bitmap drops the string and
|
|
* viceversa; new apps that want to have sting and bitmaps
|
|
* must use the MENUITEMINFO APIs
|
|
*/
|
|
if (wFlags & MFT_BITMAP) {
|
|
pmii->fMask |= MIIM_BITMAP | MIIM_STRING;
|
|
pmii->hbmpItem = (HBITMAP)pwszNew;
|
|
pmii->dwTypeData = 0;
|
|
} else if (!(wFlags & MFT_NONSTRING)) {
|
|
pmii->fMask |= MIIM_BITMAP | MIIM_STRING;
|
|
pmii->dwTypeData = pwszNew;
|
|
pmii->hbmpItem = NULL;
|
|
}
|
|
|
|
if (wFlags & MF_POPUP) {
|
|
pmii->fMask |= MIIM_SUBMENU;
|
|
pmii->hSubMenu = (HMENU)wIDNew;
|
|
}
|
|
|
|
if (wFlags & MF_OWNERDRAW) {
|
|
pmii->fMask |= MIIM_DATA;
|
|
pmii->dwItemData = (ULONG_PTR) pwszNew;
|
|
}
|
|
|
|
pmii->fState = wFlags & MFS_OLDAPI_MASK;
|
|
pmii->fType = wFlags & MFT_OLDAPI_MASK;
|
|
pMenu = VALIDATEHMENU(hMenu);
|
|
if (pMenu && pMenu->cItems) {
|
|
pItem = &((PITEM)REBASEALWAYS(pMenu, rgItems))[0];
|
|
if (pItem && TestMFT(pItem, MFT_RIGHTORDER)) {
|
|
pmii->fType |= MFT_RIGHTORDER;
|
|
}
|
|
}
|
|
pmii->wID = (UINT)wIDNew;
|
|
}
|
|
/***************************************************************************\
|
|
* SetMenuItemInfo
|
|
*
|
|
* History:
|
|
* 07-22-96 GerardoB - Added header
|
|
\***************************************************************************/
|
|
|
|
FUNCLOG2(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, SetMenuInfo, HMENU, hMenu, LPCMENUINFO, lpmi)
|
|
BOOL SetMenuInfo(HMENU hMenu, LPCMENUINFO lpmi)
|
|
{
|
|
if (!ValidateMENUINFO(lpmi, MENUAPI_SET)) {
|
|
return FALSE;
|
|
}
|
|
|
|
return NtUserThunkedMenuInfo(hMenu, (LPCMENUINFO)lpmi);
|
|
}
|
|
/***************************************************************************\
|
|
* ChangeMenu
|
|
*
|
|
* Stub routine for compatibility with version < 3.0
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG5(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, ChangeMenuW, HMENU, hMenu, UINT, cmd, LPCWSTR, lpNewItem, UINT, IdItem, UINT, flags)
|
|
BOOL ChangeMenuW(
|
|
HMENU hMenu,
|
|
UINT cmd,
|
|
LPCWSTR lpNewItem,
|
|
UINT IdItem,
|
|
UINT flags)
|
|
{
|
|
/*
|
|
* These next two statements take care of sleazyness needed for
|
|
* compatability with old changemenu.
|
|
*/
|
|
if ((flags & MF_SEPARATOR) && cmd == MFMWFP_OFFMENU && !(flags & MF_CHANGE))
|
|
flags |= MF_APPEND;
|
|
|
|
if (lpNewItem == NULL)
|
|
flags |= MF_SEPARATOR;
|
|
|
|
|
|
|
|
/*
|
|
* MUST be MF_BYPOSITION for Win2.x compatability.
|
|
*/
|
|
if (flags & MF_REMOVE)
|
|
return(NtUserRemoveMenu(hMenu, cmd,
|
|
(DWORD)((flags & ~MF_REMOVE) | MF_BYPOSITION)));
|
|
|
|
if (flags & MF_DELETE)
|
|
return(NtUserDeleteMenu(hMenu, cmd, (DWORD)(flags & ~MF_DELETE)));
|
|
|
|
if (flags & MF_CHANGE)
|
|
return(ModifyMenuW(hMenu, cmd, (DWORD)((flags & ~MF_CHANGE) &
|
|
(0x07F | MF_HELP | MF_BYPOSITION | MF_BYCOMMAND |
|
|
MF_SEPARATOR)), IdItem, lpNewItem));
|
|
|
|
if (flags & MF_APPEND)
|
|
return(AppendMenuW(hMenu, (UINT)(flags & ~MF_APPEND),
|
|
IdItem, lpNewItem));
|
|
|
|
/*
|
|
* Default is insert
|
|
*/
|
|
return(InsertMenuW(hMenu, cmd, (DWORD)(flags & ~MF_INSERT),
|
|
IdItem, lpNewItem));
|
|
}
|
|
|
|
|
|
FUNCLOG5(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, ChangeMenuA, HMENU, hMenu, UINT, cmd, LPCSTR, lpNewItem, UINT, IdItem, UINT, flags)
|
|
BOOL ChangeMenuA(
|
|
HMENU hMenu,
|
|
UINT cmd,
|
|
LPCSTR lpNewItem,
|
|
UINT IdItem,
|
|
UINT flags)
|
|
{
|
|
/*
|
|
* These next two statements take care of sleazyness needed for
|
|
* compatability with old changemenu.
|
|
*/
|
|
if ((flags & MF_SEPARATOR) && cmd == MFMWFP_OFFMENU && !(flags & MF_CHANGE))
|
|
flags |= MF_APPEND;
|
|
|
|
if (lpNewItem == NULL)
|
|
flags |= MF_SEPARATOR;
|
|
|
|
|
|
|
|
/*
|
|
* MUST be MF_BYPOSITION for Win2.x compatability.
|
|
*/
|
|
if (flags & MF_REMOVE)
|
|
return(NtUserRemoveMenu(hMenu, cmd,
|
|
(DWORD)((flags & ~MF_REMOVE) | MF_BYPOSITION)));
|
|
|
|
if (flags & MF_DELETE)
|
|
return(NtUserDeleteMenu(hMenu, cmd, (DWORD)(flags & ~MF_DELETE)));
|
|
|
|
if (flags & MF_CHANGE)
|
|
return(ModifyMenuA(hMenu, cmd, (DWORD)((flags & ~MF_CHANGE) &
|
|
(0x07F | MF_HELP | MF_BYPOSITION | MF_BYCOMMAND |
|
|
MF_SEPARATOR)), IdItem, lpNewItem));
|
|
|
|
if (flags & MF_APPEND)
|
|
return(AppendMenuA(hMenu, (UINT)(flags & ~MF_APPEND),
|
|
IdItem, lpNewItem));
|
|
|
|
/*
|
|
* Default is insert
|
|
*/
|
|
return(InsertMenuA(hMenu, cmd, (DWORD)(flags & ~MF_INSERT),
|
|
IdItem, lpNewItem));
|
|
}
|
|
|
|
LONG GetMenuCheckMarkDimensions()
|
|
{
|
|
return((DWORD)MAKELONG(SYSMET(CXMENUCHECK), SYSMET(CYMENUCHECK)));
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetMenuContextHelpId
|
|
*
|
|
* Return the help id of a menu.
|
|
*
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG1(LOG_GENERAL, WINUSERAPI DWORD, WINAPI, GetMenuContextHelpId, HMENU, hMenu)
|
|
WINUSERAPI DWORD WINAPI GetMenuContextHelpId(
|
|
HMENU hMenu)
|
|
{
|
|
PMENU pMenu;
|
|
|
|
pMenu = VALIDATEHMENU(hMenu);
|
|
|
|
if (pMenu == NULL)
|
|
return 0;
|
|
|
|
return pMenu->dwContextHelpId;
|
|
}
|
|
|
|
BOOL TrackPopupMenu(
|
|
HMENU hMenu,
|
|
UINT fuFlags,
|
|
int x,
|
|
int y,
|
|
int nReserved,
|
|
HWND hwnd,
|
|
CONST RECT *prcRect)
|
|
{
|
|
UNREFERENCED_PARAMETER(nReserved);
|
|
UNREFERENCED_PARAMETER(prcRect);
|
|
|
|
return NtUserTrackPopupMenuEx(hMenu, fuFlags, x, y, hwnd, NULL);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* GetSysMenuHandle
|
|
*
|
|
* Returns a handle to the system menu of the given window. NULL if
|
|
* the window doesn't have a system menu.
|
|
*
|
|
* History:
|
|
\***************************************************************************/
|
|
|
|
PMENU xxxGetSysMenuHandle(
|
|
PWND pwnd)
|
|
{
|
|
PMENU pMenu;
|
|
|
|
if (TestWF(pwnd, WFSYSMENU)) {
|
|
pMenu = pwnd->spmenuSys;
|
|
|
|
/*
|
|
* If the window doesn't have a System Menu, use the default one.
|
|
*/
|
|
if (pMenu == NULL) {
|
|
|
|
/*
|
|
* Change owner so this app can access this menu.
|
|
*/
|
|
pMenu = (PMENU)NtUserCallHwndLock(HWq(pwnd), SFI_XXXGETSYSMENUHANDLE);
|
|
}
|
|
} else {
|
|
pMenu = NULL;
|
|
}
|
|
|
|
return pMenu;
|
|
}
|
|
|
|
BOOL WINAPI SetMenuItemBitmaps
|
|
(
|
|
HMENU hMenu,
|
|
UINT nPosition,
|
|
UINT uFlags,
|
|
HBITMAP hbmpUnchecked,
|
|
HBITMAP hbmpChecked
|
|
)
|
|
{
|
|
MENUITEMINFO mii;
|
|
mii.cbSize = sizeof(MENUITEMINFO);
|
|
mii.fMask = MIIM_CHECKMARKS;
|
|
mii.hbmpChecked = hbmpChecked;
|
|
mii.hbmpUnchecked = hbmpUnchecked;
|
|
|
|
return(SetMenuItemInfo(hMenu, nPosition, (BOOL) (uFlags & MF_BYPOSITION), &mii));
|
|
}
|
|
|
|
|
|
FUNCLOG5(LOG_GENERAL, int, WINAPI, DrawMenuBarTemp, HWND, hwnd, HDC, hdc, LPCRECT, lprc, HMENU, hMenu, HFONT, hFont)
|
|
int WINAPI DrawMenuBarTemp(
|
|
HWND hwnd,
|
|
HDC hdc,
|
|
LPCRECT lprc,
|
|
HMENU hMenu,
|
|
HFONT hFont)
|
|
{
|
|
HDC hdcr;
|
|
|
|
if (IsMetaFile(hdc))
|
|
return -1;
|
|
|
|
hdcr = GdiConvertAndCheckDC(hdc);
|
|
if (hdcr == (HDC)0)
|
|
return -1;
|
|
|
|
if (!hMenu)
|
|
return -1;
|
|
|
|
return NtUserDrawMenuBarTemp(
|
|
hwnd,
|
|
hdc,
|
|
lprc,
|
|
hMenu,
|
|
hFont);
|
|
}
|
|
|
|
/***************************************************************************\
|
|
*
|
|
* CheckMenuRadioItem() -
|
|
*
|
|
* Checks one menu item in a range, unchecking the others. This can be
|
|
* done either MF_BYCOMMAND or MF_BYPOSITION. It works similarly to
|
|
* CheckRadioButton().
|
|
*
|
|
* The return value is TRUE if the given item was checked, FALSE if not.
|
|
*
|
|
* History
|
|
* 04/04/97 GerardoB Moved to the client side
|
|
\***************************************************************************/
|
|
|
|
|
|
FUNCLOG5(LOG_GENERAL, BOOL, DUMMYCALLINGTYPE, CheckMenuRadioItem, HMENU, hMenu, UINT, wIDFirst, UINT, wIDLast, UINT, wIDCheck, UINT, flags)
|
|
BOOL CheckMenuRadioItem(HMENU hMenu, UINT wIDFirst, UINT wIDLast,
|
|
UINT wIDCheck, UINT flags)
|
|
{
|
|
BOOL fByPosition = (BOOL) (flags & MF_BYPOSITION);
|
|
PMENU pMenu, pMenuItemIsOn;
|
|
PITEM pItem;
|
|
UINT wIDCur;
|
|
BOOL fChecked = FALSE;
|
|
BOOL fFirst = TRUE;
|
|
MENUITEMINFO mii;
|
|
|
|
pMenu = VALIDATEHMENU(hMenu);
|
|
if (pMenu == NULL) {
|
|
return FALSE;
|
|
}
|
|
|
|
mii.cbSize = sizeof(mii);
|
|
/*
|
|
* Make sure we won't loop for ever
|
|
*/
|
|
wIDLast = min(wIDLast, (UINT)0xFFFFFFFE);
|
|
|
|
for (wIDCur = wIDFirst; wIDCur <= wIDLast; wIDCur++) {
|
|
pItem = MNLookUpItem(pMenu, wIDCur, fByPosition, &pMenuItemIsOn);
|
|
/*
|
|
* Continue searching if it didn't find the item or it's a separator
|
|
*/
|
|
if ((pItem == NULL) || TestMFT(pItem, MFT_SEPARATOR)) {
|
|
continue;
|
|
}
|
|
/*
|
|
* If this is the first one, rememeber what menu it's on because
|
|
* all items are supposed to be in the same menu.
|
|
*/
|
|
if (fFirst) {
|
|
pMenu = pMenuItemIsOn;
|
|
hMenu = PtoHq(pMenu);
|
|
fFirst = FALSE;
|
|
}
|
|
/*
|
|
* If this item is on a different menu, don't touch it
|
|
*/
|
|
if (pMenu != pMenuItemIsOn) {
|
|
continue;
|
|
}
|
|
/*
|
|
* Set the new check state. Avoid the trip to the kernel if possible
|
|
*/
|
|
if (wIDCur == wIDCheck) {
|
|
/*
|
|
* Check it.
|
|
*/
|
|
if (!TestMFT(pItem, MFT_RADIOCHECK) || !TestMFS(pItem, MFS_CHECKED)) {
|
|
mii.fMask = MIIM_FTYPE | MIIM_STATE;
|
|
mii.fType = (pItem->fType & MFT_MASK) | MFT_RADIOCHECK;
|
|
mii.fState = (pItem->fState & MFS_MASK) | MFS_CHECKED;
|
|
NtUserThunkedMenuItemInfo(hMenu, wIDCheck, fByPosition, FALSE, &mii, NULL);
|
|
}
|
|
fChecked = TRUE;
|
|
} else {
|
|
/*
|
|
* Uncheck it
|
|
* NOTE: don't remove MFT_RADIOCHECK type
|
|
*/
|
|
if (TestMFS(pItem, MFS_CHECKED)) {
|
|
mii.fMask = MIIM_STATE;
|
|
mii.fState = (pItem->fState & MFS_MASK) & ~MFS_CHECKED;
|
|
NtUserThunkedMenuItemInfo(hMenu, wIDCur, fByPosition, FALSE, &mii, NULL);
|
|
}
|
|
}
|
|
} /* for */
|
|
|
|
if (fFirst) {
|
|
/*
|
|
* No item was ever found.
|
|
*/
|
|
RIPERR0(ERROR_MENU_ITEM_NOT_FOUND, RIP_VERBOSE, "CheckMenuRadioItem, no items found\n");
|
|
|
|
}
|
|
return(fChecked);
|
|
}
|