#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 *********************************************************************/
-typedef struct _MENUITEM
-{
- UINT Type;
- UINT State;
- UINT Id;
- HMENU SubMenu;
- HBITMAP CheckBit;
- HBITMAP UnCheckBit;
- LPWSTR Text;
- DWORD ItemData;
- DWORD TypeData;
- HBITMAP BmpItem;
- RECT Rect;
- UINT XTab;
-} MENUITEM, *PMENUITEM;
+#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
-typedef struct _POPUP_MENU
+#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 =
{
- MENUITEM* Items;
- WORD NrItems;
-} POPUP_MENU, *PPOPUP_MENU;
+ POPUPMENU_CLASS_ATOMW, /* name */
+ CS_GLOBALCLASS | CS_SAVEBITS | CS_DBLCLKS, /* style */
+ (WNDPROC) NULL, /* FIXME - procW */
+ sizeof(MENUINFO *), /* extra */
+ (LPCWSTR) IDC_ARROW, /* cursor */
+ (HBRUSH)COLOR_MENU /* brush */
+};
-/* FUNCTIONS *****************************************************************/
-static PPOPUP_MENU
-MenuGetMenu(HMENU hMenu)
+/* 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 )
{
- PPOPUP_MENU Menu;
- Menu = (PPOPUP_MENU)hMenu;
- return(Menu);
+ 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 MENUITEM*
-MenuFindItem(HMENU* hMenu, UINT* nPos, UINT wFlags)
+static inline WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
{
- POPUP_MENU* Menu;
- ULONG i;
+ WCHAR *p = dst;
+ while ((*p++ = *src++));
+ return dst;
+}
- if ((ULONG)(*hMenu) == 0xFFFF || (Menu = MenuGetMenu(*hMenu)) == NULL)
- {
- return(NULL);
- }
- if (wFlags & MF_BYPOSITION)
+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
{
- if ((*nPos) >= Menu->NrItems)
+ 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? */
{
- return(NULL);
+ /* 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;
}
- return(&Menu->Items[*nPos]);
+ 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;
+
+ 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)
{
- MENUITEM* Item = Menu->Items;
- for (i = 0; i < Menu->NrItems; i++)
- {
- if (Item->Id == (*nPos))
- {
- *nPos = i;
- return(Item);
- }
- else if (Item->Type & MF_POPUP)
- {
- HMENU SubMenu = Item->SubMenu;
- MENUITEM* SubItem = MenuFindItem(&SubMenu, nPos, wFlags);
- if (SubItem)
- {
- *hMenu = SubMenu;
- return(SubItem);
- }
- }
- }
+ 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--;
}
- return(NULL);
+ 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)
{
- DPRINT("AppendMenuA(hMenu 0x%X, uFlags 0x%X, uIDNewItem %d, "
- "lpNewItem %s\n", hMenu, uFlags, uIDNewItem, lpNewItem);
return(InsertMenuA(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem,
lpNewItem));
}
+
+/*
+ * @implemented
+ */
WINBOOL STDCALL
AppendMenuW(HMENU hMenu,
UINT uFlags,
UINT_PTR uIDNewItem,
LPCWSTR lpNewItem)
{
- DPRINT("AppendMenuW(hMenu 0x%X, uFlags 0x%X, uIDNewItem %d, "
- "lpNewItem %S\n", hMenu, uFlags, uIDNewItem, lpNewItem);
return(InsertMenuW(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem,
lpNewItem));
}
+
+/*
+ * @implemented
+ */
DWORD STDCALL
CheckMenuItem(HMENU hmenu,
UINT uIDCheckItem,
UINT uCheck)
{
- MENUITEM* Item;
- DWORD Ret;
-
- DPRINT("CheckMenuItem(hmenu 0x%X, uIDCheckItem %d, uCheck %d",
- hmenu, uIDCheckItem, uCheck);
- if ((Item = MenuFindItem(&hmenu, &uIDCheckItem, uCheck)) == NULL)
- {
- return(-1);
- }
- Ret = Item->State & MF_CHECKED;
- if (uCheck & MF_CHECKED)
- {
- Item->State |= MF_CHECKED;
- }
- else
- {
- Item->State &= ~MF_CHECKED;
- }
- return(Ret);
+ return NtUserCheckMenuItem(hmenu, uIDCheckItem, uCheck);
}
-WINBOOL
-STDCALL
-CheckMenuRadioItem(
- HMENU hmenu,
- UINT idFirst,
- UINT idLast,
- UINT idCheck,
- UINT uFlags)
+
+/*
+ * @unimplemented
+ */
+WINBOOL STDCALL
+CheckMenuRadioItem(HMENU hmenu,
+ UINT idFirst,
+ UINT idLast,
+ UINT idCheck,
+ UINT uFlags)
{
+ UNIMPLEMENTED;
return FALSE;
}
-HMENU
-STDCALL
+
+
+/*
+ * @implemented
+ */
+HMENU STDCALL
CreateMenu(VOID)
{
- return (HMENU)0;
+ return NtUserCreateMenu();
}
-HMENU
-STDCALL
+
+/*
+ * @implemented
+ */
+HMENU STDCALL
CreatePopupMenu(VOID)
{
- return (HMENU)0;
+ /* FIXME - add MF_POPUP style? */
+ return NtUserCreateMenu();
}
-WINBOOL
-STDCALL
-DeleteMenu(
- HMENU hMenu,
- UINT uPosition,
- UINT uFlags)
+
+
+/*
+ * @implemented
+ */
+WINBOOL STDCALL
+DeleteMenu(HMENU hMenu,
+ UINT uPosition,
+ UINT uFlags)
{
- return FALSE;
+ return NtUserDeleteMenu(hMenu, uPosition, uFlags);
}
-WINBOOL
-STDCALL
-DestroyMenu(
- HMENU hMenu)
+
+
+/*
+ * @implemented
+ */
+WINBOOL STDCALL
+DestroyMenu(HMENU hMenu)
{
- return FALSE;
+ return NtUserDestroyMenu(hMenu);
}
-WINBOOL
-STDCALL
-DrawMenuBar(
- HWND hWnd)
+
+
+/*
+ * @unimplemented
+ */
+WINBOOL STDCALL
+DrawMenuBar(HWND hWnd)
{
+ UNIMPLEMENTED
+ /* FIXME - return NtUserCallHwndLock(hWnd, 0x55); */
return FALSE;
}
-WINBOOL
-STDCALL
-EnableMenuItem(
- HMENU hMenu,
- UINT uIDEnableItem,
- UINT uEnable)
+
+
+/*
+ * @implemented
+ */
+UINT STDCALL
+EnableMenuItem(HMENU hMenu,
+ UINT uIDEnableItem,
+ UINT uEnable)
{
- return FALSE;
+ return NtUserEnableMenuItem(hMenu, uIDEnableItem, uEnable);
}
-WINBOOL
-STDCALL
+
+/*
+ * @unimplemented
+ */
+WINBOOL STDCALL
EndMenu(VOID)
{
+ UNIMPLEMENTED;
+ /* FIXME - return NtUserEndMenu(); */
return FALSE;
}
-HMENU
-STDCALL
-GetMenu(
- HWND hWnd)
+
+
+/*
+ * @implemented
+ */
+HMENU STDCALL
+GetMenu(HWND hWnd)
{
- return (HMENU)0;
+ return (HMENU)NtUserCallOneParam((DWORD)hWnd, ONEPARAM_ROUTINE_GETMENU);
}
-WINBOOL
-STDCALL
-GetMenuBarInfo(
- HWND hwnd,
- LONG idObject,
- LONG idItem,
- PMENUBARINFO pmbi)
+
+/*
+ * @unimplemented
+ */
+WINBOOL STDCALL
+GetMenuBarInfo(HWND hwnd,
+ LONG idObject,
+ LONG idItem,
+ PMENUBARINFO pmbi)
{
+ UNIMPLEMENTED;
return FALSE;
}
-LONG
-STDCALL
+
+/*
+ * @implemented
+ */
+LONG STDCALL
GetMenuCheckMarkDimensions(VOID)
{
- return 0;
+ return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK),
+ GetSystemMetrics(SM_CYMENUCHECK)));
}
-UINT
-STDCALL
-GetMenuDefaultItem(
- HMENU hMenu,
- UINT fByPos,
- UINT gmdiFlags)
+
+/*
+ * @implemented
+ */
+UINT STDCALL
+GetMenuDefaultItem(HMENU hMenu,
+ UINT fByPos,
+ UINT gmdiFlags)
{
- return 0;
+ return NtUserGetMenuDefaultItem(hMenu, fByPos, gmdiFlags);
}
-WINBOOL
-STDCALL
-GetMenuInfo(
- HMENU hmenu,
- LPCMENUINFO lpcmi)
+
+/*
+ * @implemented
+ */
+WINBOOL STDCALL
+GetMenuInfo(HMENU hmenu,
+ LPMENUINFO lpcmi)
{
- return FALSE;
+ 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;
}
-int
-STDCALL
-GetMenuItemCount(
- HMENU hMenu)
+
+/*
+ * @implemented
+ */
+int STDCALL
+GetMenuItemCount(HMENU hMenu)
{
- return 0;
+ return NtUserBuildMenuItemList(hMenu, NULL, 0, 0);
}
-UINT
-STDCALL
-GetMenuItemID(
- HMENU hMenu,
- int nPos)
+
+/*
+ * @implemented
+ */
+UINT STDCALL
+GetMenuItemID(HMENU hMenu,
+ int nPos)
{
- return 0;
+ 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;
}
-WINBOOL
-STDCALL
+
+/*
+ * @unimplemented
+ */
+WINBOOL STDCALL
GetMenuItemInfoA(
HMENU hMenu,
UINT uItem,
WINBOOL fByPosition,
- LPMENUITEMINFO lpmii)
+ LPMENUITEMINFOA lpmii)
{
+ UNIMPLEMENTED;
return FALSE;
}
+
+/*
+ * @unimplemented
+ */
WINBOOL
STDCALL
GetMenuItemInfoW(
HMENU hMenu,
UINT uItem,
WINBOOL fByPosition,
- LPMENUITEMINFO lpmii)
+ LPMENUITEMINFOW lpmii)
{
+ UNIMPLEMENTED;
return FALSE;
}
-WINBOOL
-STDCALL
-GetMenuItemRect(
- HWND hWnd,
- HMENU hMenu,
- UINT uItem,
- LPRECT lprcItem)
+
+/*
+ * @unimplemented
+ */
+WINBOOL STDCALL
+GetMenuItemRect(HWND hWnd,
+ HMENU hMenu,
+ UINT uItem,
+ LPRECT lprcItem)
{
- return FALSE;
+ UNIMPLEMENTED;
+ return(FALSE);
}
+
+/*
+ * @implemented
+ */
UINT
STDCALL
GetMenuState(
UINT uId,
UINT uFlags)
{
- return 0;
+ 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(
int nMaxCount,
UINT uFlag)
{
+ UNIMPLEMENTED;
return 0;
}
+
+/*
+ * @unimplemented
+ */
int
STDCALL
GetMenuStringW(
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(
UINT uItemHilite,
UINT uHilite)
{
- return FALSE;
+ return NtUserHiliteMenuItem(hwnd, hmenu, uItemHilite, uHilite);
}
+
+
+/*
+ * @implemented
+ */
WINBOOL
STDCALL
InsertMenuA(
UINT_PTR uIDNewItem,
LPCSTR lpNewItem)
{
- return FALSE;
+ 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,
- LPCMENUITEMINFO lpmii)
+ LPCMENUITEMINFOA lpmii)
{
- return FALSE;
+ 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,
- LPCMENUITEMINFO lpmii)
+ LPCMENUITEMINFOW lpmii)
{
- return FALSE;
+ 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(
UINT_PTR uIDNewItem,
LPCWSTR lpNewItem)
{
- return FALSE;
+ 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)
{
- return FALSE;
+ DWORD ret;
+ SetLastError(ERROR_SUCCESS);
+ ret = NtUserBuildMenuItemList(hMenu, NULL, 0, 0);
+ return ((ret == (DWORD)-1) || (GetLastError() == ERROR_INVALID_MENU_HANDLE));
}
-HMENU
-STDCALL
-LoadMenuA(
- HINSTANCE hInstance,
- LPCSTR lpMenuName)
+
+
+/*
+ * @implemented
+ */
+HMENU STDCALL
+LoadMenuA(HINSTANCE hInstance,
+ LPCSTR lpMenuName)
{
- return (HMENU)0;
+ HANDLE Resource = FindResourceA(hInstance, lpMenuName, MAKEINTRESOURCEA(4));
+ if (Resource == NULL)
+ {
+ return(NULL);
+ }
+ return(LoadMenuIndirectA((PVOID)LoadResource(hInstance, Resource)));
}
-HMENU
-STDCALL
-LoadMenuIndirectA(
- CONST MENUTEMPLATE *lpMenuTemplate)
+
+/*
+ * @implemented
+ */
+HMENU STDCALL
+LoadMenuIndirectA(CONST MENUTEMPLATE *lpMenuTemplate)
{
- return (HMENU)0;
+ return(LoadMenuIndirectW(lpMenuTemplate));
}
-HMENU
-STDCALL
-LoadMenuIndirectW(
- CONST MENUTEMPLATE *lpMenuTemplate)
+
+/*
+ * @implemented
+ */
+HMENU STDCALL
+LoadMenuIndirectW(CONST MENUTEMPLATE *lpMenuTemplate)
{
- return (HMENU)0;
+ 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;
+ }
}
-HMENU
-STDCALL
-LoadMenuW(
- HINSTANCE hInstance,
- LPCWSTR lpMenuName)
+
+/*
+ * @implemented
+ */
+HMENU STDCALL
+LoadMenuW(HINSTANCE hInstance,
+ LPCWSTR lpMenuName)
{
- return (HMENU)0;
+ HANDLE Resource = FindResourceW(hInstance, lpMenuName, RT_MENU);
+ if (Resource == NULL)
+ {
+ return(NULL);
+ }
+ return(LoadMenuIndirectW((PVOID)LoadResource(hInstance, Resource)));
}
+
+
+/*
+ * @unimplemented
+ */
int
STDCALL
MenuItemFromPoint(
HMENU hMenu,
POINT ptScreen)
{
+ UNIMPLEMENTED;
return 0;
}
+
+
+/*
+ * @unimplemented
+ */
WINBOOL
STDCALL
ModifyMenuA(
UINT_PTR uIDNewItem,
LPCSTR lpNewItem)
{
+ UNIMPLEMENTED;
return FALSE;
}
+
+/*
+ * @unimplemented
+ */
WINBOOL
STDCALL
ModifyMenuW(
UINT_PTR uIDNewItem,
LPCWSTR lpNewItem)
{
+ UNIMPLEMENTED;
return FALSE;
}
+
+
+/*
+ * @implemented
+ */
WINBOOL
STDCALL
RemoveMenu(
UINT uPosition,
UINT uFlags)
{
- return FALSE;
+ return NtUserRemoveMenu(hMenu, uPosition, uFlags);
}
-WINBOOL
-STDCALL
-SetMenu(
- HWND hWnd,
- HMENU hMenu)
+
+
+/*
+ * @implemented
+ */
+WINBOOL STDCALL
+SetMenu(HWND hWnd,
+ HMENU hMenu)
{
- return FALSE;
+ return NtUserSetMenu(hWnd, hMenu, TRUE);
}
+
+/*
+ * @implemented
+ */
WINBOOL
STDCALL
SetMenuDefaultItem(
UINT uItem,
UINT fByPos)
{
- return FALSE;
+ return NtUserSetMenuDefaultItem(hMenu, uItem, fByPos);
}
+
+/*
+ * @implemented
+ */
WINBOOL
STDCALL
SetMenuInfo(
HMENU hmenu,
LPCMENUINFO lpcmi)
{
- return FALSE;
+ 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(
HBITMAP hBitmapUnchecked,
HBITMAP hBitmapChecked)
{
+ UNIMPLEMENTED;
return FALSE;
}
+
+/*
+ * @unimplemented
+ */
WINBOOL
STDCALL
SetMenuItemInfoA(
HMENU hMenu,
UINT uItem,
WINBOOL fByPosition,
- LPMENUITEMINFO lpmii)
+ LPMENUITEMINFOA lpmii)
{
+ UNIMPLEMENTED;
return FALSE;
}
+
+/*
+ * @unimplemented
+ */
WINBOOL
STDCALL
SetMenuItemInfoW(
HMENU hMenu,
UINT uItem,
WINBOOL fByPosition,
- LPMENUITEMINFO lpmii)
+ LPMENUITEMINFOW lpmii)
{
+ UNIMPLEMENTED;
return FALSE;
}
+
+/*
+ * @unimplemented
+ */
WINBOOL
STDCALL
TrackPopupMenu(
HWND hWnd,
CONST RECT *prcRect)
{
+ UNIMPLEMENTED;
return FALSE;
}
+
+/*
+ * @unimplemented
+ */
WINBOOL
STDCALL
TrackPopupMenuEx(
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;
+}
+