reactos/win32ss/user/user32/windows/menu.c

1785 lines
44 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS user32.dll
* FILE: win32ss/user/user32/windows/menu.c
* PURPOSE: Menus
*
* PROGRAMMERS: Casper S. Hornstrup
* James Tabor
*/
#include <user32.h>
BOOL WINAPI GdiValidateHandle(HGDIOBJ hobj);
WINE_DEFAULT_DEBUG_CHANNEL(menu);
/* internal popup menu window messages */
#define MM_SETMENUHANDLE (WM_USER + 0)
#define MM_GETMENUHANDLE (WM_USER + 1)
#define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR)
#define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK)
#define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP)
#define MENUITEMINFO_TYPE_MASK \
(MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \
MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \
MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ )
#define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU)
#define STATE_MASK (~TYPE_MASK)
#define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT))
#define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT)
/* macro to test that flags do not indicate bitmap, ownerdraw or separator */
#define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags))
#define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1))
#define IS_SYSTEM_MENU(MenuInfo) \
(0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
#define IS_SYSTEM_POPUP(MenuInfo) \
(0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSMENU))
#define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags))
/*********************************************************************
* PopupMenu class descriptor
*/
const struct builtin_class_descr POPUPMENU_builtin_class =
{
WC_MENU, /* name */
CS_SAVEBITS | CS_DBLCLKS, /* style */
NULL, /* FIXME - procA */
PopupMenuWndProcW, /* FIXME - procW */
sizeof(MENUINFO *), /* extra */
(LPCWSTR) IDC_ARROW, /* cursor */
(HBRUSH)(COLOR_MENU + 1) /* brush */
};
#ifndef GET_WORD
#define GET_WORD(ptr) (*(WORD *)(ptr))
#endif
#ifndef GET_DWORD
#define GET_DWORD(ptr) (*(DWORD *)(ptr))
#endif
/***********************************************************************
* MENU_GetMenu
*
* Validate the given menu handle and returns the menu structure pointer.
*/
FORCEINLINE PMENU MENU_GetMenu(HMENU hMenu)
{
return ValidateHandleNoErr(hMenu, TYPE_MENU);
}
/***********************************************************************
* MENU_FindItem
*
* Find a menu item. Return a pointer on the item, and modifies *hmenu
* in case the item was in a sub-menu.
*/
ITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags )
{
MENU *menu;
ITEM *fallback = NULL;
UINT fallback_pos = 0;
UINT i;
PITEM pItem;
if ((*hmenu == (HMENU)0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL;
if (wFlags & MF_BYPOSITION)
{
if (*nPos >= menu->cItems) return NULL;
pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
if (pItem) pItem = &pItem[*nPos];
return pItem;
}
else
{
PITEM item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL;
for (i = 0; item && (i < menu->cItems); i++, item++)
{
if (item->spSubMenu)
{
PMENU pSubMenu = DesktopPtrToUser(item->spSubMenu);
HMENU hsubmenu = UserHMGetHandle(pSubMenu);
ITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags );
if (subitem)
{
*hmenu = hsubmenu;
return subitem;
}
else if (item->wID == *nPos)
{
/* fallback to this item if nothing else found */
fallback_pos = i;
fallback = item;
}
}
else if (item->wID == *nPos)
{
*nPos = i;
return item;
}
}
}
if (fallback)
*nPos = fallback_pos;
return fallback;
}
UINT FASTCALL
IntGetMenuDefaultItem(PMENU Menu, BOOL fByPos, UINT gmdiFlags, DWORD *gismc)
{
UINT i = 0;
PITEM Item = Menu->rgItems ? DesktopPtrToUser(Menu->rgItems) : NULL;
/* empty menu */
if (!Item) return -1;
while ( !( Item->fState & MFS_DEFAULT ) )
{
i++; Item++;
if (i >= Menu->cItems ) return -1;
}
/* default: don't return disabled items */
if ( (!(GMDI_USEDISABLED & gmdiFlags)) && (Item->fState & MFS_DISABLED )) return -1;
/* search rekursiv when needed */
if ( (gmdiFlags & GMDI_GOINTOPOPUPS) && Item->spSubMenu )
{
UINT ret;
(*gismc)++;
ret = IntGetMenuDefaultItem( DesktopPtrToUser(Item->spSubMenu), fByPos, gmdiFlags, gismc );
(*gismc)--;
if ( -1 != ret ) return ret;
/* when item not found in submenu, return the popup item */
}
return ( fByPos ) ? i : Item->wID;
}
static BOOL GetMenuItemInfo_common ( HMENU hmenu,
UINT item,
BOOL bypos,
LPMENUITEMINFOW lpmii,
BOOL unicode)
{
ITEM *pItem = MENU_FindItem (&hmenu, &item, bypos ? MF_BYPOSITION : 0);
//debug_print_menuitem("GetMenuItemInfo_common: ", pItem, "");
if (!pItem)
{
SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
return FALSE;
}
if( lpmii->fMask & MIIM_TYPE)
{
if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP))
{
ERR("invalid combination of fMask bits used\n");
/* this does not happen on Win9x/ME */
SetLastError( ERROR_INVALID_PARAMETER);
return FALSE;
}
lpmii->fType = pItem->fType & MENUITEMINFO_TYPE_MASK;
if (pItem->hbmp && !IS_MAGIC_BITMAP(pItem->hbmp))
lpmii->fType |= MFT_BITMAP;
lpmii->hbmpItem = pItem->hbmp; /* not on Win9x/ME */
if( lpmii->fType & MFT_BITMAP)
{
lpmii->dwTypeData = (LPWSTR) pItem->hbmp;
lpmii->cch = 0;
}
else if( lpmii->fType & (MFT_OWNERDRAW | MFT_SEPARATOR))
{
/* this does not happen on Win9x/ME */
lpmii->dwTypeData = 0;
lpmii->cch = 0;
}
}
/* copy the text string */
if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING)))
{
if( !pItem->Xlpstr )
{ // Very strange this fixes a wine test with a crash.
if(lpmii->dwTypeData && lpmii->cch && !(GdiValidateHandle((HGDIOBJ)lpmii->dwTypeData)) )
{
if( unicode)
*((WCHAR *)lpmii->dwTypeData) = 0;
else
*((CHAR *)lpmii->dwTypeData) = 0;
}
lpmii->cch = 0;
}
else
{
int len;
LPWSTR text = DesktopPtrToUser(pItem->Xlpstr);
if (unicode)
{
len = strlenW(text);
if(lpmii->dwTypeData && lpmii->cch)
lstrcpynW(lpmii->dwTypeData, text, lpmii->cch);
}
else
{
len = WideCharToMultiByte( CP_ACP, 0, text, -1, NULL, 0, NULL, NULL ) - 1;
if(lpmii->dwTypeData && lpmii->cch)
if (!WideCharToMultiByte( CP_ACP, 0, text, -1,
(LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL ))
((LPSTR)lpmii->dwTypeData)[lpmii->cch - 1] = 0;
}
/* if we've copied a substring we return its length */
if(lpmii->dwTypeData && lpmii->cch)
if (lpmii->cch <= len + 1)
lpmii->cch--;
else
lpmii->cch = len;
else
{
/* return length of string */
/* not on Win9x/ME if fType & MFT_BITMAP */
lpmii->cch = len;
}
}
}
if (lpmii->fMask & MIIM_FTYPE)
lpmii->fType = pItem->fType & MENUITEMINFO_TYPE_MASK;
if (lpmii->fMask & MIIM_BITMAP)
lpmii->hbmpItem = pItem->hbmp;
if (lpmii->fMask & MIIM_STATE)
lpmii->fState = pItem->fState & MENUITEMINFO_STATE_MASK;
if (lpmii->fMask & MIIM_ID)
lpmii->wID = pItem->wID;
if (lpmii->fMask & MIIM_SUBMENU && pItem->spSubMenu )
{
PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
HMENU hSubMenu = UserHMGetHandle(pSubMenu);
lpmii->hSubMenu = hSubMenu;
}
else
{
/* hSubMenu is always cleared
* (not on Win9x/ME ) */
lpmii->hSubMenu = 0;
}
if (lpmii->fMask & MIIM_CHECKMARKS)
{
lpmii->hbmpChecked = pItem->hbmpChecked;
lpmii->hbmpUnchecked = pItem->hbmpUnchecked;
}
if (lpmii->fMask & MIIM_DATA)
lpmii->dwItemData = pItem->dwItemData;
return TRUE;
}
//
// User side Menu Class Proc.
//
LRESULT WINAPI
PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
LRESULT lResult;
PWND pWnd;
TRACE("PMWPW : hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
pWnd = ValidateHwnd(Wnd);
if (pWnd)
{
if (!pWnd->fnid)
{
if (Message != WM_NCCREATE)
{
return DefWindowProcW(Wnd, Message, wParam, lParam);
}
}
else
{
if (pWnd->fnid != FNID_MENU)
{
ERR("Wrong window class for Menu!\n");
return 0;
}
}
}
switch(Message)
{
case WM_DESTROY:
case WM_NCDESTROY:
case WM_NCCREATE:
case WM_CREATE:
case MM_SETMENUHANDLE:
case MM_GETMENUHANDLE:
case MN_SETHMENU:
case MN_GETHMENU:
case WM_PAINT:
case WM_PRINTCLIENT:
{
TRACE("Menu Class ProcW\n");
NtUserMessageCall( Wnd, Message, wParam, lParam, (ULONG_PTR)&lResult, FNID_MENU, FALSE);
return lResult;
}
case WM_MOUSEACTIVATE: /* We don't want to be activated */
return MA_NOACTIVATE;
case WM_ERASEBKGND:
return 1;
case WM_SHOWWINDOW: // Not sure what this does....
if (0 != wParam)
{
if (0 == GetWindowLongPtrW(Wnd, 0))
{
OutputDebugStringA("no menu to display\n");
}
}
else
{
//SetWindowLongPtrW(Wnd, 0, 0);
}
break;
default:
return DefWindowProcW(Wnd, Message, wParam, lParam);
}
return 0;
}
LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
PWND pWnd;
pWnd = ValidateHwnd(Wnd);
if (pWnd && !pWnd->fnid && Message != WM_NCCREATE)
{
return DefWindowProcA(Wnd, Message, wParam, lParam);
}
TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam);
switch(Message)
{
case WM_NCCREATE:
case WM_CREATE:
case WM_MOUSEACTIVATE:
case WM_PAINT:
case WM_PRINTCLIENT:
case WM_ERASEBKGND:
case WM_DESTROY:
case WM_NCDESTROY:
case WM_SHOWWINDOW:
case MM_SETMENUHANDLE:
case MM_GETMENUHANDLE:
case MN_SETHMENU:
case MN_GETHMENU:
return PopupMenuWndProcW(Wnd, Message, wParam, lParam);
default:
return DefWindowProcA(Wnd, Message, wParam, lParam);
}
return 0;
}
/**********************************************************************
* MENU_ParseResource
*
* Parse a standard menu resource and add items to the menu.
* Return a pointer to the end of the resource.
*
* NOTE: flags is equivalent to the mtOption field
*/
static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu)
{
WORD flags, id = 0;
HMENU hSubMenu;
LPCWSTR str;
BOOL end = FALSE;
do
{
flags = GET_WORD(res);
/* remove MF_END flag before passing it to AppendMenu()! */
end = (flags & MF_END);
if(end) flags ^= MF_END;
res += sizeof(WORD);
if(!(flags & MF_POPUP))
{
id = GET_WORD(res);
res += sizeof(WORD);
}
str = (LPCWSTR)res;
res += (strlenW(str) + 1) * sizeof(WCHAR);
if (flags & MF_POPUP)
{
hSubMenu = CreatePopupMenu();
if(!hSubMenu) return NULL;
if(!(res = MENU_ParseResource(res, hSubMenu))) return NULL;
AppendMenuW(hMenu, flags, (UINT_PTR)hSubMenu, (LPCWSTR)str);
}
else /* Not a popup */
{
AppendMenuW(hMenu, flags, id, *(LPCWSTR)str ? (LPCWSTR)str : NULL);
}
} while(!end);
return res;
}
/**********************************************************************
* MENUEX_ParseResource
*
* Parse an extended menu resource and add items to the menu.
* Return a pointer to the end of the resource.
*/
static LPCSTR MENUEX_ParseResource(LPCSTR res, HMENU hMenu)
{
WORD resinfo;
do
{
MENUITEMINFOW mii;
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
mii.fType = GET_DWORD(res);
res += sizeof(DWORD);
mii.fState = GET_DWORD(res);
res += sizeof(DWORD);
mii.wID = GET_DWORD(res);
res += sizeof(DWORD);
resinfo = GET_WORD(res);
res += sizeof(WORD);
/* Align the text on a word boundary. */
res += (~((UINT_PTR)res - 1)) & 1;
mii.dwTypeData = (LPWSTR)res;
mii.cch = strlenW(mii.dwTypeData);
res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
/* Align the following fields on a dword boundary. */
res += (~((UINT_PTR)res - 1)) & 3;
TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n",
mii.fType, mii.fState, mii.wID, resinfo, mii.dwTypeData);
if (resinfo & 1) /* Pop-up? */
{
/* DWORD helpid = GET_DWORD(res); FIXME: use this. */
res += sizeof(DWORD);
mii.hSubMenu = CreatePopupMenu();
if (!mii.hSubMenu)
{
ERR("CreatePopupMenu failed\n");
return NULL;
}
if (!(res = MENUEX_ParseResource(res, mii.hSubMenu)))
{
ERR("MENUEX_ParseResource failed\n");
DestroyMenu(mii.hSubMenu);
return NULL;
}
mii.fMask |= MIIM_SUBMENU;
mii.fType |= MF_POPUP;
}
else if (!mii.dwTypeData[0] && !(mii.fType & MF_SEPARATOR))
{
WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n",
mii.wID, mii.fType);
mii.fType |= MF_SEPARATOR;
}
InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
} while (!(resinfo & MF_END));
return res;
}
/**********************************************************************
* MENU_mnu2mnuii
*
* Uses flags, id and text ptr, passed by InsertMenu() and
* ModifyMenu() to setup a MenuItemInfo structure.
*/
static void MENU_mnu2mnuii( UINT flags, UINT_PTR id, LPCWSTR str, LPMENUITEMINFOW pmii, BOOL Unicode)
{
RtlZeroMemory( pmii, sizeof( MENUITEMINFOW));
pmii->cbSize = sizeof( MENUITEMINFOW);
pmii->fMask = MIIM_STATE | MIIM_ID | MIIM_FTYPE;
/* setting bitmap clears text and vice versa */
if( IS_STRING_ITEM(flags)) {
pmii->fMask |= MIIM_STRING | MIIM_BITMAP;
if( !str)
flags |= MF_SEPARATOR;
/* Item beginning with a backspace is a help item */
/* FIXME: wrong place, this is only true in win16 */
else
{
if (Unicode)
{
if (*str == '\b')
{
flags |= MF_HELP;
str++;
}
}
else
{
LPCSTR NewItemA = (LPCSTR) str;
if (*NewItemA == '\b')
{
flags |= MF_HELP;
NewItemA++;
str = (LPCWSTR) NewItemA;
}
TRACE("A cch %d\n",strlen(NewItemA));
}
}
pmii->dwTypeData = (LPWSTR)str;
} else if( flags & MFT_BITMAP){
pmii->fMask |= MIIM_BITMAP | MIIM_STRING;
pmii->hbmpItem = (HBITMAP)str;
}
if( flags & MF_OWNERDRAW){
pmii->fMask |= MIIM_DATA;
pmii->dwItemData = (ULONG_PTR) str;
}
if( flags & MF_POPUP && MENU_GetMenu((HMENU)id)) {
pmii->fMask |= MIIM_SUBMENU;
pmii->hSubMenu = (HMENU)id;
}
if( flags & MF_SEPARATOR) flags |= MF_GRAYED | MF_DISABLED;
pmii->fState = flags & MENUITEMINFO_STATE_MASK & ~MFS_DEFAULT;
pmii->fType = flags & MENUITEMINFO_TYPE_MASK;
pmii->wID = (UINT)id;
}
/**********************************************************************
* MENU_NormalizeMenuItemInfoStruct
*
* Helper for SetMenuItemInfo and InsertMenuItemInfo:
* check, copy and extend the MENUITEMINFO struct from the version that the application
* supplied to the version used by wine source. */
static BOOL MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW *pmii_in,
MENUITEMINFOW *pmii_out )
{
/* do we recognize the size? */
if( !pmii_in || (pmii_in->cbSize != sizeof( MENUITEMINFOW) &&
pmii_in->cbSize != sizeof( MENUITEMINFOW) - sizeof( pmii_in->hbmpItem)) ) {
SetLastError( ERROR_INVALID_PARAMETER);
return FALSE;
}
/* copy the fields that we have */
memcpy( pmii_out, pmii_in, pmii_in->cbSize);
/* if the hbmpItem member is missing then extend */
if( pmii_in->cbSize != sizeof( MENUITEMINFOW)) {
pmii_out->cbSize = sizeof( MENUITEMINFOW);
pmii_out->hbmpItem = NULL;
}
/* test for invalid bit combinations */
if( (pmii_out->fMask & MIIM_TYPE &&
pmii_out->fMask & (MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) ||
(pmii_out->fMask & MIIM_FTYPE && pmii_out->fType & MFT_BITMAP)) {
ERR("invalid combination of fMask bits used\n");
/* this does not happen on Win9x/ME */
SetLastError( ERROR_INVALID_PARAMETER);
return FALSE;
}
/* convert old style (MIIM_TYPE) to the new and keep the old one too */
if( pmii_out->fMask & MIIM_TYPE){
pmii_out->fMask |= MIIM_FTYPE;
if( IS_STRING_ITEM(pmii_out->fType)){
pmii_out->fMask |= MIIM_STRING;
} else if( (pmii_out->fType) & MFT_BITMAP){
pmii_out->fMask |= MIIM_BITMAP;
pmii_out->hbmpItem = UlongToHandle(LOWORD(pmii_out->dwTypeData));
}
}
if (pmii_out->fMask & MIIM_FTYPE )
{
pmii_out->fType &= ~MENUITEMINFO_TYPE_MASK;
pmii_out->fType |= pmii_in->fType & MENUITEMINFO_TYPE_MASK;
}
if (pmii_out->fMask & MIIM_STATE)
/* Other menu items having MFS_DEFAULT are not converted
to normal items */
pmii_out->fState = pmii_in->fState & MENUITEMINFO_STATE_MASK;
if (pmii_out->fMask & MIIM_SUBMENU)
{
if ((pmii_out->hSubMenu != NULL) && !IsMenu(pmii_out->hSubMenu))
return FALSE;
}
return TRUE;
}
BOOL
MenuInit(VOID)
{
return TRUE;
}
VOID
MenuCleanup(VOID)
{
}
NTSTATUS WINAPI
User32LoadSysMenuTemplateForKernel(PVOID Arguments, ULONG ArgumentLength)
{
LRESULT Result = 0;
// Use this for Menu Ole!!
return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
}
NTSTATUS WINAPI
User32CallLoadMenuFromKernel(PVOID Arguments, ULONG ArgumentLength)
{
PLOADMENU_CALLBACK_ARGUMENTS Common;
LRESULT Result;
Common = (PLOADMENU_CALLBACK_ARGUMENTS) Arguments;
Result = (LRESULT)LoadMenuW(Common->hModule, Common->InterSource ? MAKEINTRESOURCEW(Common->InterSource) : (LPCWSTR)&Common->MenuName);
return ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS);
}
/* FUNCTIONS *****************************************************************/
/*
* @implemented
*/
BOOL WINAPI
AppendMenuA(HMENU hMenu,
UINT uFlags,
UINT_PTR uIDNewItem,
LPCSTR lpNewItem)
{
MENUITEMINFOW mii;
UNICODE_STRING UnicodeString;
BOOL res;
RtlInitUnicodeString(&UnicodeString, 0);
MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE);
/* copy the text string, it will be one or the other */
if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
{
if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
{
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
mii.dwTypeData = UnicodeString.Buffer;
mii.cch = UnicodeString.Length / sizeof(WCHAR);
}
else
{
TRACE("AMA Handle bitmaps\n");
}
////// Answer a question, why a -1? To hunt for the end of the item list. Get it, to Append?
res = NtUserThunkedMenuItemInfo(hMenu, -1, TRUE, TRUE, &mii, &UnicodeString);
if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
return res;
}
/*
* @implemented
*/
BOOL WINAPI
AppendMenuW(HMENU hMenu,
UINT uFlags,
UINT_PTR uIDNewItem,
LPCWSTR lpNewItem)
{
MENUITEMINFOW mii;
UNICODE_STRING MenuText;
BOOL res;
RtlInitUnicodeString(&MenuText, 0);
MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE);
/* copy the text string, it will be one or the other */
if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
{
RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData);
mii.dwTypeData = MenuText.Buffer;
mii.cch = MenuText.Length / sizeof(WCHAR);
}
res = NtUserThunkedMenuItemInfo(hMenu, -1, TRUE, TRUE, &mii, &MenuText);
return res;
}
/*
* @implemented
*/
DWORD WINAPI
CheckMenuItem(HMENU hmenu,
UINT uIDCheckItem,
UINT uCheck)
{
PITEM item;
DWORD Ret;
UINT uID = uIDCheckItem;
if (!ValidateHandle(hmenu, TYPE_MENU))
return -1;
if (!(item = MENU_FindItem( &hmenu, &uID, uCheck ))) return -1;
Ret = item->fState & MFS_CHECKED;
if ( Ret == (uCheck & MFS_CHECKED)) return Ret; // Already Checked...
return NtUserCheckMenuItem(hmenu, uIDCheckItem, uCheck);
}
/*
* @implemented
*/
BOOL WINAPI
CheckMenuRadioItem(HMENU hMenu,
UINT first,
UINT last,
UINT check,
UINT bypos)
{
BOOL done = FALSE;
UINT i;
PITEM mi_first = NULL, mi_check;
HMENU m_first, m_check;
MENUITEMINFOW mii;
mii.cbSize = sizeof( mii);
for (i = first; i <= last; i++)
{
UINT pos = i;
if (!mi_first)
{
m_first = hMenu;
mi_first = MENU_FindItem(&m_first, &pos, bypos);
if (!mi_first) continue;
mi_check = mi_first;
m_check = m_first;
}
else
{
m_check = hMenu;
mi_check = MENU_FindItem(&m_check, &pos, bypos);
if (!mi_check) continue;
}
if (m_first != m_check) continue;
if (mi_check->fType == MFT_SEPARATOR) continue;
if (i == check)
{
if (!(mi_check->fType & MFT_RADIOCHECK) || !(mi_check->fState & MFS_CHECKED))
{
mii.fMask = MIIM_FTYPE | MIIM_STATE;
mii.fType = (mi_check->fType & MENUITEMINFO_TYPE_MASK) | MFT_RADIOCHECK;
mii.fState = (mi_check->fState & MII_STATE_MASK) | MFS_CHECKED;
NtUserThunkedMenuItemInfo(m_check, i, bypos, FALSE, &mii, NULL);
}
done = TRUE;
}
else
{
/* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */
if (mi_check->fState & MFS_CHECKED)
{
mii.fMask = MIIM_STATE;
mii.fState = (mi_check->fState & MII_STATE_MASK) & ~MFS_CHECKED;
NtUserThunkedMenuItemInfo(m_check, i, bypos, FALSE, &mii, NULL);
}
}
}
return done;
}
/*
* @implemented
*/
HMENU WINAPI
CreateMenu(VOID)
{
return NtUserxCreateMenu();
}
/*
* @implemented
*/
HMENU WINAPI
CreatePopupMenu(VOID)
{
return NtUserxCreatePopupMenu();
}
/*
* @implemented
*/
BOOL WINAPI
DrawMenuBar(HWND hWnd)
{
return NtUserxDrawMenuBar(hWnd);
}
/*
* @implemented
*/
BOOL WINAPI
EnableMenuItem(HMENU hMenu,
UINT uIDEnableItem,
UINT uEnable)
{
return NtUserEnableMenuItem(hMenu, uIDEnableItem, uEnable);
}
/*
* @implemented
*/
HMENU WINAPI
GetMenu(HWND hWnd)
{
PWND Wnd = ValidateHwnd(hWnd);
if (!Wnd)
return NULL;
return UlongToHandle(Wnd->IDMenu);
}
/*
* @implemented
*/
LONG WINAPI
GetMenuCheckMarkDimensions(VOID)
{
return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK),
GetSystemMetrics(SM_CYMENUCHECK)));
}
/*
* @implemented
*/
DWORD
WINAPI
GetMenuContextHelpId(HMENU hmenu)
{
PMENU pMenu;
if ((pMenu = ValidateHandle(hmenu, TYPE_MENU)))
return pMenu->dwContextHelpId;
return 0;
}
/*
* @implemented
*/
UINT WINAPI
GetMenuDefaultItem(HMENU hMenu,
UINT fByPos,
UINT gmdiFlags)
{
PMENU pMenu;
DWORD gismc = 0;
if (!(pMenu = ValidateHandle(hMenu, TYPE_MENU)))
return (UINT)-1;
return IntGetMenuDefaultItem( pMenu, (BOOL)fByPos, gmdiFlags, &gismc);
}
/*
* @implemented
*/
BOOL WINAPI
GetMenuInfo(HMENU hmenu,
LPMENUINFO lpcmi)
{
PMENU pMenu;
if (!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO)))
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (!(pMenu = ValidateHandle(hmenu, TYPE_MENU)))
return FALSE;
if (lpcmi->fMask & MIM_BACKGROUND)
lpcmi->hbrBack = pMenu->hbrBack;
if (lpcmi->fMask & MIM_HELPID)
lpcmi->dwContextHelpID = pMenu->dwContextHelpId;
if (lpcmi->fMask & MIM_MAXHEIGHT)
lpcmi->cyMax = pMenu->cyMax;
if (lpcmi->fMask & MIM_MENUDATA)
lpcmi->dwMenuData = pMenu->dwMenuData;
if (lpcmi->fMask & MIM_STYLE)
lpcmi->dwStyle = pMenu->fFlags & MNS_STYLE_MASK;
return TRUE;
}
/*
* @implemented
*/
int WINAPI
GetMenuItemCount(HMENU hmenu)
{
PMENU pMenu;
if ((pMenu = ValidateHandle(hmenu, TYPE_MENU)))
return pMenu->cItems;
return -1;
}
/*
* @implemented
*/
UINT WINAPI
GetMenuItemID(HMENU hMenu,
int nPos)
{
ITEM * lpmi;
if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) return -1;
if (lpmi->spSubMenu) return -1;
return lpmi->wID;
}
/*
* @implemented
*/
BOOL WINAPI
GetMenuItemInfoA(
HMENU hmenu,
UINT item,
BOOL bypos,
LPMENUITEMINFOA lpmii)
{
BOOL ret;
MENUITEMINFOA mii;
if( lpmii->cbSize != sizeof( mii) &&
lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem))
{
SetLastError( ERROR_INVALID_PARAMETER);
return FALSE;
}
memcpy( &mii, lpmii, lpmii->cbSize);
mii.cbSize = sizeof( mii);
ret = GetMenuItemInfo_common (hmenu,
item,
bypos,
(LPMENUITEMINFOW)&mii,
FALSE);
mii.cbSize = lpmii->cbSize;
memcpy( lpmii, &mii, mii.cbSize);
return ret;
}
/*
* @implemented
*/
BOOL WINAPI
GetMenuItemInfoW(
HMENU hMenu,
UINT Item,
BOOL bypos,
LPMENUITEMINFOW lpmii)
{
BOOL ret;
MENUITEMINFOW mii;
if( lpmii->cbSize != sizeof( mii) && lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem))
{
SetLastError( ERROR_INVALID_PARAMETER);
return FALSE;
}
memcpy( &mii, lpmii, lpmii->cbSize);
mii.cbSize = sizeof( mii);
ret = GetMenuItemInfo_common (hMenu, Item, bypos, &mii, TRUE);
mii.cbSize = lpmii->cbSize;
memcpy( lpmii, &mii, mii.cbSize);
return ret;
}
/*
* @implemented
*/
UINT
WINAPI
GetMenuState(
HMENU hMenu,
UINT uId,
UINT uFlags)
{
PITEM pItem;
UINT Type = 0;
TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu, uId, uFlags);
if (!(pItem = MENU_FindItem( &hMenu, &uId, uFlags ))) return -1;
if (!pItem->Xlpstr && pItem->hbmp) Type = MFT_BITMAP;
if (pItem->spSubMenu)
{
PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
HMENU hsubmenu = UserHMGetHandle(pSubMenu);
Type |= MF_POPUP; // Fix CORE-9269
if (!IsMenu(hsubmenu)) return (UINT)-1;
else return (pSubMenu->cItems << 8) | ((pItem->fState|pItem->fType|Type) & 0xff);
}
else
return (pItem->fType | pItem->fState | Type);
}
/*
* @implemented
*/
int
WINAPI
GetMenuStringA(
HMENU hMenu,
UINT uIDItem,
LPSTR lpString,
int nMaxCount,
UINT uFlag)
{
ITEM *item;
LPWSTR text;
////// wine Code, seems to be faster.
TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, uIDItem, lpString, nMaxCount, uFlag );
if (lpString && nMaxCount) lpString[0] = '\0';
if (!(item = MENU_FindItem( &hMenu, &uIDItem, uFlag )))
{
SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
return 0;
}
text = item->Xlpstr ? DesktopPtrToUser(item->Xlpstr) : NULL;
if (!text) return 0;
if (!lpString || !nMaxCount) return WideCharToMultiByte( CP_ACP, 0, text, -1, NULL, 0, NULL, NULL );
if (!WideCharToMultiByte( CP_ACP, 0, text, -1, lpString, nMaxCount, NULL, NULL ))
lpString[nMaxCount-1] = 0;
TRACE("A returning %s\n", lpString);
return strlen(lpString);
}
/*
* @implemented
*/
int
WINAPI
GetMenuStringW(
HMENU hMenu,
UINT uIDItem,
LPWSTR lpString,
int nMaxCount,
UINT uFlag)
{
ITEM *item;
LPWSTR text;
TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, uIDItem, lpString, nMaxCount, uFlag );
if (lpString && nMaxCount) lpString[0] = '\0';
if (!(item = MENU_FindItem( &hMenu, &uIDItem, uFlag )))
{
SetLastError( ERROR_MENU_ITEM_NOT_FOUND);
return 0;
}
text = item->Xlpstr ? DesktopPtrToUser(item->Xlpstr) : NULL;
if (!lpString || !nMaxCount) return text ? strlenW(text) : 0;
if( !(text))
{
lpString[0] = 0;
return 0;
}
lstrcpynW( lpString, text, nMaxCount );
TRACE("W returning %S\n", lpString);
return strlenW(lpString);
}
/*
* @implemented
*/
HMENU
WINAPI
GetSubMenu(
HMENU hMenu,
int nPos)
{
PITEM pItem;
if (!(pItem = MENU_FindItem( &hMenu, (UINT*)&nPos, MF_BYPOSITION ))) return NULL;
if (pItem->spSubMenu)
{
PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu);
HMENU hsubmenu = UserHMGetHandle(pSubMenu);
if (IsMenu(hsubmenu)) return hsubmenu;
}
return NULL;
}
/*
* @implemented
*/
HMENU
WINAPI
GetSystemMenu(HWND hWnd, BOOL bRevert)
{
return NtUserGetSystemMenu(hWnd, bRevert);
}
/*
* @implemented
*/
BOOL
WINAPI
InsertMenuA(
HMENU hMenu,
UINT uPosition,
UINT uFlags,
UINT_PTR uIDNewItem,
LPCSTR lpNewItem)
{
MENUITEMINFOW mii;
UNICODE_STRING UnicodeString;
BOOL res;
RtlInitUnicodeString(&UnicodeString, 0);
MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE);
/* copy the text string, it will be one or the other */
if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
{
if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
{
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
mii.dwTypeData = UnicodeString.Buffer;
mii.cch = UnicodeString.Length / sizeof(WCHAR);
}
else
{
TRACE("Handle bitmaps\n");
}
res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), TRUE, &mii, &UnicodeString);
if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
return res;
}
/*
* @implemented
*/
BOOL
WINAPI
InsertMenuItemA(
HMENU hMenu,
UINT uItem,
BOOL fByPosition,
LPCMENUITEMINFOA lpmii)
{
MENUITEMINFOW mii;
UNICODE_STRING UnicodeString;
BOOL res;
TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii);
RtlInitUnicodeString(&UnicodeString, 0);
if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
/* copy the text string */
if (((mii.fMask & MIIM_STRING) ||
((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING)))
&& mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) )
{
if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
{
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
mii.dwTypeData = UnicodeString.Buffer;
mii.cch = UnicodeString.Length / sizeof(WCHAR);
}
else
{
TRACE("Handle bitmaps\n");
}
res = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, TRUE, &mii, &UnicodeString);
if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
return res;
}
/*
* @implemented
*/
BOOL
WINAPI
InsertMenuItemW(
HMENU hMenu,
UINT uItem,
BOOL fByPosition,
LPCMENUITEMINFOW lpmii)
{
MENUITEMINFOW mii;
UNICODE_STRING MenuText;
BOOL res = FALSE;
/* while we could just pass 'lpmii' to win32k, we make a copy so that
if a bad user passes bad data, we crash his process instead of the
entire kernel */
TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii);
RtlInitUnicodeString(&MenuText, 0);
if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
/* copy the text string */
if (((mii.fMask & MIIM_STRING) ||
((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING)))
&& mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) )
{
RtlInitUnicodeString(&MenuText, (PWSTR)lpmii->dwTypeData);
mii.dwTypeData = MenuText.Buffer;
mii.cch = MenuText.Length / sizeof(WCHAR);
}
res = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, TRUE, &mii, &MenuText);
return res;
}
/*
* @implemented
*/
BOOL
WINAPI
InsertMenuW(
HMENU hMenu,
UINT uPosition,
UINT uFlags,
UINT_PTR uIDNewItem,
LPCWSTR lpNewItem)
{
MENUITEMINFOW mii;
UNICODE_STRING MenuText;
BOOL res;
RtlInitUnicodeString(&MenuText, 0);
MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE);
/* copy the text string, it will be one or the other */
if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
{
RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData);
mii.dwTypeData = MenuText.Buffer;
mii.cch = MenuText.Length / sizeof(WCHAR);
}
res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), TRUE, &mii, &MenuText);
return res;
}
/*
* @implemented
*/
BOOL
WINAPI
IsMenu(
HMENU Menu)
{
if (ValidateHandle(Menu, TYPE_MENU)) return TRUE;
return FALSE;
}
/*
* @implemented
*/
HMENU WINAPI
LoadMenuA(HINSTANCE hInstance,
LPCSTR lpMenuName)
{
HANDLE Resource = FindResourceA(hInstance, lpMenuName, MAKEINTRESOURCEA(4));
if (Resource == NULL)
{
return(NULL);
}
return(LoadMenuIndirectA((PVOID)LoadResource(hInstance, Resource)));
}
/*
* @implemented
*/
HMENU WINAPI
LoadMenuIndirectA(CONST MENUTEMPLATE *lpMenuTemplate)
{
return(LoadMenuIndirectW(lpMenuTemplate));
}
/*
* @implemented
*/
HMENU WINAPI
LoadMenuIndirectW(CONST MENUTEMPLATE *lpMenuTemplate)
{
HMENU hMenu;
WORD version, offset;
LPCSTR p = (LPCSTR)lpMenuTemplate;
version = GET_WORD(p);
p += sizeof(WORD);
switch (version)
{
case 0: /* standard format is version of 0 */
offset = GET_WORD(p);
p += sizeof(WORD) + offset;
if (!(hMenu = CreateMenu())) return 0;
if (!MENU_ParseResource(p, hMenu))
{
DestroyMenu(hMenu);
return 0;
}
return hMenu;
case 1: /* extended format is version of 1 */
offset = GET_WORD(p);
p += sizeof(WORD) + offset;
if (!(hMenu = CreateMenu())) return 0;
if (!MENUEX_ParseResource(p, hMenu))
{
DestroyMenu( hMenu );
return 0;
}
return hMenu;
default:
ERR("Menu template version %d not supported.\n", version);
return 0;
}
}
/*
* @implemented
*/
HMENU WINAPI
LoadMenuW(HINSTANCE hInstance,
LPCWSTR lpMenuName)
{
HANDLE Resource = FindResourceW(hInstance, lpMenuName, RT_MENU);
if (Resource == NULL)
{
return(NULL);
}
return(LoadMenuIndirectW((PVOID)LoadResource(hInstance, Resource)));
}
/*
* @implemented
*/
BOOL
WINAPI
ModifyMenuA(
HMENU hMenu,
UINT uPosition,
UINT uFlags,
UINT_PTR uIDNewItem,
LPCSTR lpNewItem)
{
MENUITEMINFOW mii;
UNICODE_STRING UnicodeString;
BOOL res;
RtlInitUnicodeString(&UnicodeString, 0);
MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE);
/* copy the text string, it will be one or the other */
if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
{
if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
{
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
mii.dwTypeData = UnicodeString.Buffer;
mii.cch = UnicodeString.Length / sizeof(WCHAR);
}
else
{
TRACE("Handle bitmaps\n");
}
res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), FALSE, &mii, &UnicodeString);
if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString );
return res;
}
/*
* @implemented
*/
BOOL
WINAPI
ModifyMenuW(
HMENU hMenu,
UINT uPosition,
UINT uFlags,
UINT_PTR uIDNewItem,
LPCWSTR lpNewItem)
{
MENUITEMINFOW mii;
UNICODE_STRING MenuText;
BOOL res;
RtlInitUnicodeString(&MenuText, 0);
MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE);
/* copy the text string, it will be one or the other */
if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData)
{
RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData);
mii.dwTypeData = MenuText.Buffer;
mii.cch = MenuText.Length / sizeof(WCHAR);
}
else
{
TRACE("Handle bitmaps\n");
}
res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), FALSE, &mii, &MenuText);
return res;
}
/*
* @implemented
*/
BOOL WINAPI
SetMenu(HWND hWnd,
HMENU hMenu)
{
return NtUserSetMenu(hWnd, hMenu, TRUE);
}
/*
* @implemented
*/
BOOL
WINAPI
SetMenuInfo(
HMENU hmenu,
LPCMENUINFO lpcmi)
{
MENUINFO mi;
BOOL res = FALSE;
if (!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO)))
{
SetLastError(ERROR_INVALID_PARAMETER);
return res;
}
memcpy(&mi, lpcmi, sizeof(MENUINFO));
return NtUserThunkedMenuInfo(hmenu, (LPCMENUINFO)&mi);
}
/*
* @implemented
*/
BOOL
WINAPI
SetMenuItemBitmaps(
HMENU hMenu,
UINT uPosition,
UINT uFlags,
HBITMAP hBitmapUnchecked,
HBITMAP hBitmapChecked)
{
MENUITEMINFOW uItem;
memset ( &uItem, 0, sizeof(uItem) );
uItem.cbSize = sizeof(MENUITEMINFOW);
uItem.fMask = MIIM_CHECKMARKS;
uItem.hbmpUnchecked = hBitmapUnchecked;
uItem.hbmpChecked = hBitmapChecked;
return SetMenuItemInfoW(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), &uItem);
}
/*
* @implemented
*/
BOOL
WINAPI
SetMenuItemInfoA(
HMENU hmenu,
UINT item,
BOOL bypos,
LPCMENUITEMINFOA lpmii)
{
MENUITEMINFOW mii;
UNICODE_STRING UnicodeString;
BOOL Ret;
TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu, item, bypos, lpmii);
RtlInitUnicodeString(&UnicodeString, 0);
if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE;
/*
* MIIM_STRING == good
* MIIM_TYPE & MFT_STRING == good
* MIIM_STRING & MFT_STRING == good
* MIIM_STRING & MFT_OWNERDRAW == good
*/
if (((mii.fMask & MIIM_STRING) ||
((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING)))
&& mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) )
{
/* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */
if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData))
{
SetLastError (ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
mii.dwTypeData = UnicodeString.Buffer;
mii.cch = UnicodeString.Length / sizeof(WCHAR);
}
else
{
UnicodeString.Buffer = NULL;
}
Ret = NtUserThunkedMenuItemInfo(hmenu, item, bypos, FALSE, &mii, &UnicodeString);
if (UnicodeString.Buffer != NULL) RtlFreeUnicodeString(&UnicodeString);
return Ret;
}
/*
* @implemented
*/
BOOL
WINAPI
SetMenuItemInfoW(
HMENU hMenu,
UINT uItem,
BOOL fByPosition,
LPCMENUITEMINFOW lpmii)
{
MENUITEMINFOW MenuItemInfoW;
UNICODE_STRING UnicodeString;
BOOL Ret;
TRACE("hmenu %p, item %u, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii);
RtlInitUnicodeString(&UnicodeString, 0);
if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &MenuItemInfoW )) return FALSE;
if (((MenuItemInfoW.fMask & MIIM_STRING) ||
((MenuItemInfoW.fMask & MIIM_TYPE) &&
(MENU_ITEM_TYPE(MenuItemInfoW.fType) == MF_STRING)))
&& MenuItemInfoW.dwTypeData && !(GdiValidateHandle((HGDIOBJ)MenuItemInfoW.dwTypeData)) )
{
RtlInitUnicodeString(&UnicodeString, (PCWSTR)MenuItemInfoW.dwTypeData);
MenuItemInfoW.cch = strlenW(MenuItemInfoW.dwTypeData);
}
Ret = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, FALSE, &MenuItemInfoW, &UnicodeString);
return Ret;
}
/*
* @implemented
*/
BOOL
WINAPI
SetSystemMenu (
HWND hwnd,
HMENU hMenu)
{
if(!hwnd)
{
SetLastError(ERROR_INVALID_WINDOW_HANDLE);
return FALSE;
}
if(!hMenu)
{
SetLastError(ERROR_INVALID_MENU_HANDLE);
return FALSE;
}
return NtUserSetSystemMenu(hwnd, hMenu);
}
BOOL
WINAPI
TrackPopupMenu(
HMENU Menu,
UINT Flags,
int x,
int y,
int Reserved,
HWND Wnd,
CONST RECT *Rect)
{
return NtUserTrackPopupMenuEx( Menu,
Flags,
x,
y,
Wnd,
NULL); // LPTPMPARAMS is null
}
/*
* @unimplemented
*/
LRESULT
WINAPI
MenuWindowProcA(
HWND hWnd,
ULONG_PTR Result,
UINT Msg,
WPARAM wParam,
LPARAM lParam
)
{
if ( Msg < WM_USER)
{
return PopupMenuWndProcA(hWnd, Msg, wParam, lParam );
}
return NtUserMessageCall(hWnd, Msg, wParam, lParam, Result, FNID_MENU, TRUE);
}
/*
* @unimplemented
*/
LRESULT
WINAPI
MenuWindowProcW(
HWND hWnd,
ULONG_PTR Result,
UINT Msg,
WPARAM wParam,
LPARAM lParam
)
{
if ( Msg < WM_USER)
{
return PopupMenuWndProcW(hWnd, Msg, wParam, lParam );
}
return NtUserMessageCall(hWnd, Msg, wParam, lParam, Result, FNID_MENU, FALSE);
}
/*
* @implemented
*/
BOOL
WINAPI
ChangeMenuW(
HMENU hMenu,
UINT cmd,
LPCWSTR lpszNewItem,
UINT cmdInsert,
UINT flags)
{
/*
FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
for MF_DELETE. We should check the parameters for all others
MF_* actions also (anybody got a doc on ChangeMenu?).
*/
switch(flags & (MF_APPEND | MF_DELETE | MF_CHANGE | MF_REMOVE | MF_INSERT))
{
case MF_APPEND :
return AppendMenuW(hMenu, flags &~ MF_APPEND, cmdInsert, lpszNewItem);
case MF_DELETE :
return DeleteMenu(hMenu, cmd, flags &~ MF_DELETE);
case MF_CHANGE :
return ModifyMenuW(hMenu, cmd, flags &~ MF_CHANGE, cmdInsert, lpszNewItem);
case MF_REMOVE :
return RemoveMenu(hMenu, flags & MF_BYPOSITION ? cmd : cmdInsert,
flags &~ MF_REMOVE);
default : /* MF_INSERT */
return InsertMenuW(hMenu, cmd, flags, cmdInsert, lpszNewItem);
};
}
/*
* @implemented
*/
BOOL
WINAPI
ChangeMenuA(
HMENU hMenu,
UINT cmd,
LPCSTR lpszNewItem,
UINT cmdInsert,
UINT flags)
{
/*
FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert
for MF_DELETE. We should check the parameters for all others
MF_* actions also (anybody got a doc on ChangeMenu?).
*/
switch(flags & (MF_APPEND | MF_DELETE | MF_CHANGE | MF_REMOVE | MF_INSERT))
{
case MF_APPEND :
return AppendMenuA(hMenu, flags &~ MF_APPEND, cmdInsert, lpszNewItem);
case MF_DELETE :
return DeleteMenu(hMenu, cmd, flags &~ MF_DELETE);
case MF_CHANGE :
return ModifyMenuA(hMenu, cmd, flags &~ MF_CHANGE, cmdInsert, lpszNewItem);
case MF_REMOVE :
return RemoveMenu(hMenu, flags & MF_BYPOSITION ? cmd : cmdInsert,
flags &~ MF_REMOVE);
default : /* MF_INSERT */
return InsertMenuA(hMenu, cmd, flags, cmdInsert, lpszNewItem);
};
}