Files
reactos/reactos/lib/user32/windows/menu.c
Filip Navara ea251a9fb2 - Moved GetFocus, DrawCaptionTemp[AW], DrawMenuBarTemp, SetTaskmanWindow, SetProgmanWindow, GetProgmanWindow, GetTaskmanWindow, MenuWindowProc[AW], SetWindowsHook[AW], RegisterShellHookWindow, DeregisterShellHookWindow,
ChangeMenu[AW], UnhookWindowsHook, NotifyWinEvent, SetWinEventHook, UnhookWinEvent, IsWinEventHookInstalled, SetWindowStationUser, LockWindowStation, UnlockWindowStation, SetWindowStationUser, SetWindowsHookEx[AW] from stubs.c to appropriate files.
- Changed EditWndProc in user32.edf to point to EditWndProcA.

svn path=/trunk/; revision=6592
2003-11-09 13:50:04 +00:00

1468 lines
27 KiB
C

/*
* ReactOS kernel
* Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/* $Id: menu.c,v 1.36 2003/11/09 13:50:04 navaraf Exp $
*
* PROJECT: ReactOS user32.dll
* FILE: lib/user32/windows/menu.c
* PURPOSE: Menus
* PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
* UPDATE HISTORY:
* 09-05-2001 CSH Created
*/
/* INCLUDES ******************************************************************/
#include <windows.h>
#include <user32.h>
#include <debug.h>
#include <string.h>
#include <draw.h>
#include <window.h>
#include <strpool.h>
#include <user32/callback.h>
#include "user32/regcontrol.h"
#include "../controls/controls.h"
/* TYPES *********************************************************************/
#define MENU_TYPE_MASK ((MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
#define MENU_ITEM_TYPE(flags) \
((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
#define MENU_BAR_ITEMS_SPACE (12)
#define SEPARATOR_HEIGHT (5)
#define MENU_TAB_SPACE (8)
#ifndef MF_END
#define MF_END (0x0080)
#endif
#ifndef MIIM_STRING
#define MIIM_STRING (0x00000040)
#endif
#define MAKEINTATOMA(atom) ((LPCSTR)((ULONG_PTR)((WORD)(atom))))
#define MAKEINTATOMW(atom) ((LPCWSTR)((ULONG_PTR)((WORD)(atom))))
#define POPUPMENU_CLASS_ATOMA MAKEINTATOMA(32768) /* PopupMenu */
#define POPUPMENU_CLASS_ATOMW MAKEINTATOMW(32768) /* PopupMenu */
/*********************************************************************
* PopupMenu class descriptor
*/
const struct builtin_class_descr POPUPMENU_builtin_class =
{
POPUPMENU_CLASS_ATOMW, /* name */
CS_GLOBALCLASS | CS_SAVEBITS | CS_DBLCLKS, /* style */
(WNDPROC) NULL, /* FIXME - procW */
(WNDPROC) NULL, /* FIXME - procA */
sizeof(MENUINFO *), /* extra */
(LPCWSTR) IDC_ARROW, /* cursor */
(HBRUSH)COLOR_MENU /* brush */
};
/* INTERNAL FUNCTIONS ********************************************************/
/* Rip the fun and easy to use and fun WINE unicode string manipulation routines.
* Of course I didnt copy the ASM code because we want this to be portable
* and it needs to go away.
*/
static inline unsigned int strlenW( const WCHAR *str )
{
const WCHAR *s = str;
while (*s) s++;
return s - str;
}
static inline WCHAR *strncpyW( WCHAR *str1, const WCHAR *str2, int n )
{
WCHAR *ret = str1;
while (n-- > 0) if (!(*str1++ = *str2++)) break;
while (n-- > 0) *str1++ = 0;
return ret;
}
static inline WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
{
WCHAR *p = dst;
while ((*p++ = *src++));
return dst;
}
static inline WCHAR *strcatW( WCHAR *dst, const WCHAR *src )
{
strcpyW( dst + strlenW(dst), src );
return dst;
}
#ifndef GET_WORD
#define GET_WORD(ptr) (*(WORD *)(ptr))
#endif
#ifndef GET_DWORD
#define GET_DWORD(ptr) (*(DWORD *)(ptr))
#endif
HFONT hMenuFont = NULL;
HFONT hMenuFontBold = NULL;
/**********************************************************************
* MENUEX_ParseResource
*
* Parse an extended menu resource and add items to the menu.
* Return a pointer to the end of the resource.
*
* FIXME - should we be passing an LPCSTR to a predominantly UNICODE function?
*/
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 += (~((int)res - 1)) & 1;
mii.dwTypeData = (LPWSTR) res;
res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
/* Align the following fields on a dword boundary. */
res += (~((int)res - 1)) & 3;
if (resinfo & 1) /* Pop-up? */
{
/* DWORD helpid = GET_DWORD(res); FIXME: use this. */
res += sizeof(DWORD);
mii.hSubMenu = CreatePopupMenu();
if (!mii.hSubMenu)
return NULL;
if (!(res = MENUEX_ParseResource(res, mii.hSubMenu)))
{
DestroyMenu(mii.hSubMenu);
return NULL;
}
mii.fMask |= MIIM_SUBMENU;
mii.fType |= MF_POPUP;
}
else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR))
{
DbgPrint("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_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, BOOL unicode )
{
WORD flags, id = 0;
HMENU hSubMenu;
LPCSTR 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 = res;
if(!unicode)
res += strlen(str) + 1;
else
res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
if (flags & MF_POPUP)
{
hSubMenu = CreatePopupMenu();
if(!hSubMenu) return NULL;
if(!(res = MENU_ParseResource(res, hSubMenu, unicode)))
return NULL;
if(!unicode)
AppendMenuA(hMenu, flags, (UINT)hSubMenu, str);
else
AppendMenuW(hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str);
}
else /* Not a popup */
{
if(!unicode)
AppendMenuA(hMenu, flags, id, *str ? str : NULL);
else
AppendMenuW(hMenu, flags, id,
*(LPCWSTR)str ? (LPCWSTR)str : NULL);
}
} while(!end);
return res;
}
NTSTATUS STDCALL
User32LoadSysMenuTemplateForKernel(PVOID Arguments, ULONG ArgumentLength)
{
LRESULT Result;
HMODULE hUser32;
hUser32 = GetModuleHandleW(L"USER32");
Result = (LRESULT)LoadMenuW(hUser32, L"SYSMENU");
return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
}
BOOL
MenuInit(VOID)
{
NONCLIENTMETRICSW ncm;
/* get the menu font */
if(!hMenuFont || !hMenuFontBold)
{
ncm.cbSize = sizeof(ncm);
if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
{
DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
return FALSE;
}
hMenuFont = CreateFontIndirectW(&ncm.lfMenuFont);
if(hMenuFont == NULL)
{
DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
return FALSE;
}
ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
hMenuFontBold = CreateFontIndirectW(&ncm.lfMenuFont);
if(hMenuFontBold == NULL)
{
DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
return FALSE;
}
}
return TRUE;
}
ULONG
MenuGetMenuBarHeight(HWND hWnd, ULONG MenuBarWidth, LONG OrgX, LONG OrgY)
{
/*ULONG MenuId;
PPOPUP_MENU Menu;
RECT Rect;
HDC hDC;
MenuId = GetWindowLong(hWnd, GWL_ID);
Menu = MenuGetMenu((HMENU)MenuId);
if (Menu == NULL)
{
return(0);
}
hDC = GetDCEx(hWnd, 0, DCX_CACHE | DCX_WINDOW);
SelectObject(hDC, hMenuFont);
SetRect(&Rect, OrgX, OrgY, OrgX + MenuBarWidth,
OrgY + GetSystemMetrics(SM_CYMENU));
MenuMenuBarCalcSize(hDC, &Rect, Menu, hWnd);
ReleaseDC(hWnd, hDC);*/
return(GetSystemMetrics(SM_CYMENU));
}
static BOOL
MeasureMenuItem(HWND hWnd, HMENU mnu, HDC hDC, MENUITEMINFOW *mii, RECT *mir, LPWSTR str)
{
BOOL res = FALSE;
MEASUREITEMSTRUCT mis;
SIZE sz;
if(mii->fType & MFT_OWNERDRAW)
{
/* send WM_MEASUREITEM message to window */
mis.CtlType = ODT_MENU;
mis.CtlID = 0;
mis.itemID = mii->wID;
mis.itemWidth = 0;
mis.itemHeight = 0;
mis.itemData = mii->dwItemData;
res = (BOOL)SendMessageW(hWnd, WM_MEASUREITEM, 0, (LPARAM)&mis);
if(res)
{
mir->right = mir->left + mis.itemWidth;
mir->bottom = mir->top + mis.itemHeight;
}
else
{
/* FIXME calculate size internally assuming the menu item is empty */
mir->right = mir->left + 1;
mir->bottom = mir->top + 1;
}
return res;
}
else
{
GetTextExtentPoint32W(hDC, str, mii->cch, &sz);
/* FIXME calculate the size of the menu item */
mir->right = mir->left + sz.cx + 6;
mir->bottom = mir->top + max(sz.cy, GetSystemMetrics(SM_CYMENU));
return TRUE;
}
}
static BOOL
DrawMenuItem(HWND hWnd, HMENU mnu, HDC hDC, MENUITEMINFOW *mii, RECT *mir, LPWSTR str)
{
BOOL res = FALSE;
DRAWITEMSTRUCT dis;
if(mii->fType & MFT_OWNERDRAW)
{
/* send WM_DRAWITEM message to window */
dis.CtlType = ODT_MENU;
dis.CtlID = 0;
dis.itemID = mii->wID;
dis.itemAction = ODA_DRAWENTIRE; /* FIXME */
dis.itemState = 0; /* FIXME */
dis.hwndItem = (HWND)mnu;
dis.hDC = hDC;
RtlCopyMemory(&dis.rcItem, mir, sizeof(RECT));
dis.itemData = mii->dwItemData;
res = (BOOL)SendMessageW(hWnd, WM_DRAWITEM, 0, (LPARAM)&dis);
return res;
}
else
{
/* FIXME draw the menu item */
SetTextColor(hDC, COLOR_MENUTEXT);
DrawTextW(hDC, str, mii->cch, mir, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
}
return res;
}
UINT
MenuDrawMenuBar(HDC hDC, LPRECT Rect, HWND hWnd, BOOL Draw)
{
UINT height;
HMENU mnu;
HANDLE hHeap;
PVOID Buf, hBuf;
DWORD BufSize, Items, Items2;
MENUITEMINFOW *mii;
RECT *omir, *mir = NULL;
LPWSTR str;
FillRect(hDC, Rect, GetSysColorBrush(COLOR_MENU));
height = Rect->bottom - Rect->top;
mnu = GetMenu(hWnd); /* Fixme - pass menu handle as parameter */
/* get menu item list size */
BufSize = NtUserBuildMenuItemList(mnu, (VOID*)1, 0, 0);
if(BufSize)
{
/* FIXME cache menu bar items using NtUserDrawMenuBarTemp()
instead of allocating and deallocating memory everytime */
hHeap = GetProcessHeap();
hBuf = HeapAlloc(hHeap, 0, BufSize);
if(!hBuf)
return(Rect->bottom - Rect->top);
Buf = hBuf;
/* copy menu items into buffer */
Items = Items2 = NtUserBuildMenuItemList(mnu, Buf, BufSize, 0);
/* calculate menu item rectangles */
while(Items > 0)
{
omir = mir;
mii = (LPMENUITEMINFOW)Buf;
Buf += sizeof(MENUITEMINFOW);
mir = (LPRECT)Buf;
Buf += sizeof(RECT);
if(mii->cch)
{
str = (LPWSTR)Buf;
Buf += (mii->cch + 1) * sizeof(WCHAR);
}
else
str = NULL;
if(omir)
{
mir->left = omir->right + 1;
mir->top = omir->top;
mir->right += mir->left;
mir->bottom += mir->top;
}
else
{
mir->left = Rect->left;
mir->top = Rect->top;
}
MeasureMenuItem(hWnd, mnu, hDC, mii, mir, str);
height = max(height, mir->top + mir->bottom);
/* DbgPrint("Measure menu item %ws: (%d, %d, %d, %d)\n", str, mir->left, mir->top, mir->right, mir->bottom); */
Items--;
}
height = max(height, GetSystemMetrics(SM_CYMENU));
Buf = hBuf;
/* draw menu items */
while (Items2 > 0)
{
mii = (LPMENUITEMINFOW)Buf;
Buf += sizeof(MENUITEMINFOW);
mir = (LPRECT)Buf;
Buf += sizeof(RECT);
if(mii->cch)
{
str = (LPWSTR)Buf;
Buf += (mii->cch + 1) * sizeof(WCHAR);
}
else
str = NULL;
/* DbgPrint("Draw menu item %ws at (%d, %d, %d, %d)\n", str, mir->left, mir->top, mir->right, mir->bottom); */
DrawMenuItem(hWnd, mnu, hDC, mii, mir, str);
Items2--;
}
HeapFree(hHeap, 0, hBuf);
}
return height;
}
VOID
MenuTrackMouseMenuBar(HWND hWnd, ULONG Ht, POINT Pt)
{
}
VOID
MenuTrackKbdMenuBar(HWND hWnd, ULONG wParam, ULONG Key)
{
}
/* FUNCTIONS *****************************************************************/
/*static BOOL
MenuIsStringItem(ULONG TypeData)
{
return((TypeData & MENU_TYPE_MASK) == MF_STRING);
}*/
/*
* @implemented
*/
WINBOOL STDCALL
AppendMenuA(HMENU hMenu,
UINT uFlags,
UINT_PTR uIDNewItem,
LPCSTR lpNewItem)
{
return(InsertMenuA(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem,
lpNewItem));
}
/*
* @implemented
*/
WINBOOL STDCALL
AppendMenuW(HMENU hMenu,
UINT uFlags,
UINT_PTR uIDNewItem,
LPCWSTR lpNewItem)
{
return(InsertMenuW(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem,
lpNewItem));
}
/*
* @implemented
*/
DWORD STDCALL
CheckMenuItem(HMENU hmenu,
UINT uIDCheckItem,
UINT uCheck)
{
return NtUserCheckMenuItem(hmenu, uIDCheckItem, uCheck);
}
/*
* @unimplemented
*/
WINBOOL STDCALL
CheckMenuRadioItem(HMENU hmenu,
UINT idFirst,
UINT idLast,
UINT idCheck,
UINT uFlags)
{
UNIMPLEMENTED;
return FALSE;
}
/*
* @implemented
*/
HMENU STDCALL
CreateMenu(VOID)
{
return NtUserCreateMenu();
}
/*
* @implemented
*/
HMENU STDCALL
CreatePopupMenu(VOID)
{
/* FIXME - add MF_POPUP style? */
return NtUserCreateMenu();
}
/*
* @implemented
*/
WINBOOL STDCALL
DeleteMenu(HMENU hMenu,
UINT uPosition,
UINT uFlags)
{
return NtUserDeleteMenu(hMenu, uPosition, uFlags);
}
/*
* @implemented
*/
WINBOOL STDCALL
DestroyMenu(HMENU hMenu)
{
return NtUserDestroyMenu(hMenu);
}
/*
* @unimplemented
*/
WINBOOL STDCALL
DrawMenuBar(HWND hWnd)
{
UNIMPLEMENTED
/* FIXME - return NtUserCallHwndLock(hWnd, 0x55); */
return FALSE;
}
/*
* @implemented
*/
UINT STDCALL
EnableMenuItem(HMENU hMenu,
UINT uIDEnableItem,
UINT uEnable)
{
return NtUserEnableMenuItem(hMenu, uIDEnableItem, uEnable);
}
/*
* @unimplemented
*/
WINBOOL STDCALL
EndMenu(VOID)
{
UNIMPLEMENTED;
/* FIXME - return NtUserEndMenu(); */
return FALSE;
}
/*
* @implemented
*/
HMENU STDCALL
GetMenu(HWND hWnd)
{
return (HMENU)NtUserCallOneParam((DWORD)hWnd, ONEPARAM_ROUTINE_GETMENU);
}
/*
* @unimplemented
*/
WINBOOL STDCALL
GetMenuBarInfo(HWND hwnd,
LONG idObject,
LONG idItem,
PMENUBARINFO pmbi)
{
UNIMPLEMENTED;
return FALSE;
}
/*
* @implemented
*/
LONG STDCALL
GetMenuCheckMarkDimensions(VOID)
{
return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK),
GetSystemMetrics(SM_CYMENUCHECK)));
}
/*
* @implemented
*/
UINT STDCALL
GetMenuDefaultItem(HMENU hMenu,
UINT fByPos,
UINT gmdiFlags)
{
return NtUserGetMenuDefaultItem(hMenu, fByPos, gmdiFlags);
}
/*
* @implemented
*/
WINBOOL STDCALL
GetMenuInfo(HMENU hmenu,
LPMENUINFO lpcmi)
{
MENUINFO mi;
BOOL res = FALSE;
if(!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO)))
return FALSE;
RtlZeroMemory(&mi, sizeof(MENUINFO));
mi.cbSize = sizeof(MENUINFO);
mi.fMask = lpcmi->fMask;
res = NtUserMenuInfo(hmenu, &mi, FALSE);
memcpy(lpcmi, &mi, sizeof(MENUINFO));
return res;
}
/*
* @implemented
*/
int STDCALL
GetMenuItemCount(HMENU hMenu)
{
return NtUserBuildMenuItemList(hMenu, NULL, 0, 0);
}
/*
* @implemented
*/
UINT STDCALL
GetMenuItemID(HMENU hMenu,
int nPos)
{
MENUITEMINFOW mii;
mii.cbSize = sizeof(MENUITEMINFOW);
mii.fMask = MIIM_ID | MIIM_SUBMENU;
if(!NtUserMenuItemInfo(hMenu, nPos, MF_BYPOSITION, &mii, FALSE))
{
return -1;
}
if(mii.hSubMenu) return -1;
if(mii.wID == 0) return -1;
return mii.wID;
}
/*
* @unimplemented
*/
WINBOOL STDCALL
GetMenuItemInfoA(
HMENU hMenu,
UINT uItem,
WINBOOL fByPosition,
LPMENUITEMINFOA lpmii)
{
UNIMPLEMENTED;
return FALSE;
}
/*
* @unimplemented
*/
WINBOOL
STDCALL
GetMenuItemInfoW(
HMENU hMenu,
UINT uItem,
WINBOOL fByPosition,
LPMENUITEMINFOW lpmii)
{
UNIMPLEMENTED;
return FALSE;
}
/*
* @unimplemented
*/
WINBOOL STDCALL
GetMenuItemRect(HWND hWnd,
HMENU hMenu,
UINT uItem,
LPRECT lprcItem)
{
UNIMPLEMENTED;
return(FALSE);
}
/*
* @implemented
*/
UINT
STDCALL
GetMenuState(
HMENU hMenu,
UINT uId,
UINT uFlags)
{
MENUITEMINFOW mii;
mii.cbSize = sizeof(MENUITEMINFOW);
mii.fMask = MIIM_STATE | MIIM_TYPE | MIIM_SUBMENU;
SetLastError(0);
if(NtUserMenuItemInfo(hMenu, uId, uFlags, &mii, FALSE))
{
UINT nSubItems = 0;
if(mii.hSubMenu)
{
nSubItems = (UINT)NtUserBuildMenuItemList(mii.hSubMenu, NULL, 0, 0);
/* FIXME - ported from wine, does that work (0xff)? */
if(GetLastError() != ERROR_INVALID_MENU_HANDLE)
return (nSubItems << 8) | ((mii.fState | mii.fType) & 0xff);
return (UINT)-1; /* Invalid submenu */
}
/* FIXME - ported from wine, does that work? */
return (mii.fType | mii.fState);
}
return (UINT)-1;
}
/*
* @unimplemented
*/
int
STDCALL
GetMenuStringA(
HMENU hMenu,
UINT uIDItem,
LPSTR lpString,
int nMaxCount,
UINT uFlag)
{
UNIMPLEMENTED;
return 0;
}
/*
* @unimplemented
*/
int
STDCALL
GetMenuStringW(
HMENU hMenu,
UINT uIDItem,
LPWSTR lpString,
int nMaxCount,
UINT uFlag)
{
UNIMPLEMENTED;
return 0;
}
/*
* @implemented
*/
HMENU
STDCALL
GetSubMenu(
HMENU hMenu,
int nPos)
{
MENUITEMINFOW mi;
mi.cbSize = sizeof(mi);
mi.fMask = MIIM_SUBMENU;
if(NtUserMenuItemInfo(hMenu, (UINT)nPos, MF_BYPOSITION, &mi, FALSE))
{
return mi.hSubMenu;
}
return (HMENU)0;
}
/*
* @implemented
*/
WINBOOL
STDCALL
HiliteMenuItem(
HWND hwnd,
HMENU hmenu,
UINT uItemHilite,
UINT uHilite)
{
return NtUserHiliteMenuItem(hwnd, hmenu, uItemHilite, uHilite);
}
/*
* @implemented
*/
WINBOOL
STDCALL
InsertMenuA(
HMENU hMenu,
UINT uPosition,
UINT uFlags,
UINT_PTR uIDNewItem,
LPCSTR lpNewItem)
{
MENUITEMINFOA mii;
mii.cbSize = sizeof(MENUITEMINFOA);
mii.fMask = MIIM_FTYPE | MIIM_STRING;
mii.fType = 0;
if(uFlags & MF_BITMAP)
{
mii.fType |= MFT_BITMAP;
}
else if(uFlags & MF_OWNERDRAW)
{
mii.fType |= MFT_OWNERDRAW;
}
mii.dwTypeData = (LPSTR)lpNewItem;
if(uFlags & MF_POPUP)
{
mii.fMask |= MIIM_SUBMENU;
mii.hSubMenu = (HMENU)uIDNewItem;
}
else
{
mii.fMask |= MIIM_ID;
mii.wID = (UINT)uIDNewItem;
}
return InsertMenuItemA(hMenu, uPosition, (WINBOOL)!(MF_BYPOSITION & uFlags), &mii);
}
/*
* @implemented
*/
WINBOOL
STDCALL
InsertMenuItemA(
HMENU hMenu,
UINT uItem,
WINBOOL fByPosition,
LPCMENUITEMINFOA lpmii)
{
MENUITEMINFOW mi;
UNICODE_STRING MenuText;
WINBOOL res = FALSE;
BOOL CleanHeap = FALSE;
NTSTATUS Status;
if((lpmii->cbSize == sizeof(MENUITEMINFOA)) ||
(lpmii->cbSize == sizeof(MENUITEMINFOA) - sizeof(HBITMAP)))
{
RtlMoveMemory ( &mi, lpmii, lpmii->cbSize );
/* copy the text string */
if((mi.fMask & (MIIM_TYPE | MIIM_STRING)) &&
(MENU_ITEM_TYPE(mi.fType) == MF_STRING) && mi.dwTypeData)
{
Status = HEAP_strdupAtoW ( &mi.dwTypeData, (LPCSTR)mi.dwTypeData, &mi.cch );
if (!NT_SUCCESS (Status))
{
SetLastError (RtlNtStatusToDosError(Status));
return FALSE;
}
RtlInitUnicodeString(&MenuText, (PWSTR)mi.dwTypeData);
mi.dwTypeData = (LPWSTR)&MenuText;
CleanHeap = TRUE;
}
res = NtUserInsertMenuItem(hMenu, uItem, fByPosition, &mi);
if ( CleanHeap ) HEAP_free ( mi.dwTypeData );
}
return res;
}
/*
* @implemented
*/
WINBOOL
STDCALL
InsertMenuItemW(
HMENU hMenu,
UINT uItem,
WINBOOL fByPosition,
LPCMENUITEMINFOW lpmii)
{
MENUITEMINFOW mi;
UNICODE_STRING MenuText;
WINBOOL res = FALSE;
BOOL CleanHeap = FALSE;
HANDLE hHeap = RtlGetProcessHeap();
mi.hbmpItem = (HBITMAP)0;
// 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
if((lpmii->cbSize == sizeof(MENUITEMINFOW)) ||
(lpmii->cbSize == sizeof(MENUITEMINFOW) - sizeof(HBITMAP)))
{
memcpy(&mi, lpmii, lpmii->cbSize);
/* copy the text string */
if((mi.fMask & (MIIM_TYPE | MIIM_STRING)) &&
(MENU_ITEM_TYPE(mi.fType) == MF_STRING) && mi.dwTypeData)
{
if(lpmii->cch > 0)
{
if(!RtlCreateUnicodeString(&MenuText, (PWSTR)lpmii->dwTypeData))
{
SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY));
return FALSE;
}
mi.dwTypeData = (LPWSTR)&MenuText;
mi.cch = MenuText.Length / sizeof(WCHAR);
CleanHeap = TRUE;
}
};
res = NtUserInsertMenuItem(hMenu, uItem, fByPosition, &mi);
if(CleanHeap) RtlFreeHeap (hHeap, 0, mi.dwTypeData);
}
return res;
}
/*
* @implemented
*/
WINBOOL
STDCALL
InsertMenuW(
HMENU hMenu,
UINT uPosition,
UINT uFlags,
UINT_PTR uIDNewItem,
LPCWSTR lpNewItem)
{
MENUITEMINFOW mii;
mii.cbSize = sizeof(MENUITEMINFOW);
mii.fMask = MIIM_FTYPE | MIIM_STRING;
mii.fType = 0;
if(uFlags & MF_BITMAP)
{
mii.fType |= MFT_BITMAP;
}
else if(uFlags & MF_OWNERDRAW)
{
mii.fType |= MFT_OWNERDRAW;
}
mii.dwTypeData = (LPWSTR)lpNewItem;
if(uFlags & MF_POPUP)
{
mii.fMask |= MIIM_SUBMENU;
mii.hSubMenu = (HMENU)uIDNewItem;
}
else
{
mii.fMask |= MIIM_ID;
mii.wID = (UINT)uIDNewItem;
}
return InsertMenuItemW(hMenu, uPosition, (WINBOOL)!(MF_BYPOSITION & uFlags), &mii);
}
/*
* @implemented
*/
WINBOOL
STDCALL
IsMenu(
HMENU hMenu)
{
DWORD ret;
SetLastError(ERROR_SUCCESS);
ret = NtUserBuildMenuItemList(hMenu, NULL, 0, 0);
return ((ret == (DWORD)-1) || (GetLastError() == ERROR_INVALID_MENU_HANDLE));
}
/*
* @implemented
*/
HMENU STDCALL
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 STDCALL
LoadMenuIndirectA(CONST MENUTEMPLATE *lpMenuTemplate)
{
return(LoadMenuIndirectW(lpMenuTemplate));
}
/*
* @implemented
*/
HMENU STDCALL
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, TRUE))
{
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:
DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version);
return 0;
}
}
/*
* @implemented
*/
HMENU STDCALL
LoadMenuW(HINSTANCE hInstance,
LPCWSTR lpMenuName)
{
HANDLE Resource = FindResourceW(hInstance, lpMenuName, RT_MENU);
if (Resource == NULL)
{
return(NULL);
}
return(LoadMenuIndirectW((PVOID)LoadResource(hInstance, Resource)));
}
/*
* @unimplemented
*/
int
STDCALL
MenuItemFromPoint(
HWND hWnd,
HMENU hMenu,
POINT ptScreen)
{
UNIMPLEMENTED;
return 0;
}
/*
* @unimplemented
*/
WINBOOL
STDCALL
ModifyMenuA(
HMENU hMnu,
UINT uPosition,
UINT uFlags,
UINT_PTR uIDNewItem,
LPCSTR lpNewItem)
{
UNIMPLEMENTED;
return FALSE;
}
/*
* @unimplemented
*/
WINBOOL
STDCALL
ModifyMenuW(
HMENU hMnu,
UINT uPosition,
UINT uFlags,
UINT_PTR uIDNewItem,
LPCWSTR lpNewItem)
{
UNIMPLEMENTED;
return FALSE;
}
/*
* @implemented
*/
WINBOOL
STDCALL
RemoveMenu(
HMENU hMenu,
UINT uPosition,
UINT uFlags)
{
return NtUserRemoveMenu(hMenu, uPosition, uFlags);
}
/*
* @implemented
*/
WINBOOL STDCALL
SetMenu(HWND hWnd,
HMENU hMenu)
{
return NtUserSetMenu(hWnd, hMenu, TRUE);
}
/*
* @implemented
*/
WINBOOL
STDCALL
SetMenuDefaultItem(
HMENU hMenu,
UINT uItem,
UINT fByPos)
{
return NtUserSetMenuDefaultItem(hMenu, uItem, fByPos);
}
/*
* @implemented
*/
WINBOOL
STDCALL
SetMenuInfo(
HMENU hmenu,
LPCMENUINFO lpcmi)
{
MENUINFO mi;
BOOL res = FALSE;
if(lpcmi->cbSize != sizeof(MENUINFO))
return res;
memcpy(&mi, lpcmi, sizeof(MENUINFO));
return NtUserMenuInfo(hmenu, &mi, TRUE);
}
/*
* @unimplemented
*/
WINBOOL
STDCALL
SetMenuItemBitmaps(
HMENU hMenu,
UINT uPosition,
UINT uFlags,
HBITMAP hBitmapUnchecked,
HBITMAP hBitmapChecked)
{
UNIMPLEMENTED;
return FALSE;
}
/*
* @unimplemented
*/
WINBOOL
STDCALL
SetMenuItemInfoA(
HMENU hMenu,
UINT uItem,
WINBOOL fByPosition,
LPMENUITEMINFOA lpmii)
{
UNIMPLEMENTED;
return FALSE;
}
/*
* @unimplemented
*/
WINBOOL
STDCALL
SetMenuItemInfoW(
HMENU hMenu,
UINT uItem,
WINBOOL fByPosition,
LPMENUITEMINFOW lpmii)
{
UNIMPLEMENTED;
return FALSE;
}
/*
* @unimplemented
*/
WINBOOL
STDCALL
TrackPopupMenu(
HMENU hMenu,
UINT uFlags,
int x,
int y,
int nReserved,
HWND hWnd,
CONST RECT *prcRect)
{
UNIMPLEMENTED;
return FALSE;
}
/*
* @unimplemented
*/
WINBOOL
STDCALL
TrackPopupMenuEx(
HMENU hmenu,
UINT fuFlags,
int x,
int y,
HWND hwnd,
LPTPMPARAMS lptpm)
{
UNIMPLEMENTED;
return FALSE;
}
/*
* @implemented
*/
WINBOOL
STDCALL
SetMenuContextHelpId(HMENU hmenu,
DWORD dwContextHelpId)
{
return NtUserSetMenuContextHelpId(hmenu, dwContextHelpId);
}
/*
* @implemented
*/
DWORD
STDCALL
GetMenuContextHelpId(HMENU hmenu)
{
MENUINFO mi;
mi.cbSize = sizeof(MENUINFO);
mi.fMask = MIM_HELPID;
if(NtUserMenuInfo(hmenu, &mi, FALSE))
{
return mi.dwContextHelpID;
}
return 0;
}
/*
* @unimplemented
*/
DWORD
STDCALL
DrawMenuBarTemp(
HWND hwnd,
HDC hDC,
LPRECT lprect,
HMENU hMenu,
HFONT hFont
)
{
UNIMPLEMENTED;
return FALSE;
}
/*
* @unimplemented
*/
LRESULT
STDCALL
MenuWindowProcA(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
)
{
UNIMPLEMENTED;
return FALSE;
}
/*
* @unimplemented
*/
LRESULT
STDCALL
MenuWindowProcW(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
)
{
UNIMPLEMENTED;
return FALSE;
}
/*
* @unimplemented
*/
WINBOOL
STDCALL
ChangeMenuW(
HMENU hMenu,
UINT cmd,
LPCWSTR lpszNewItem,
UINT cmdInsert,
UINT flags)
{
UNIMPLEMENTED;
return FALSE;
}
/*
* @unimplemented
*/
WINBOOL
STDCALL
ChangeMenuA(
HMENU hMenu,
UINT cmd,
LPCSTR lpszNewItem,
UINT cmdInsert,
UINT flags)
{
UNIMPLEMENTED;
return FALSE;
}