From 66615a0c8a6c60a15a8e751efe739534700304c8 Mon Sep 17 00:00:00 2001 From: Thomas Bluemel Date: Fri, 1 Aug 2003 00:44:27 +0000 Subject: [PATCH] Implemented LoadMenuIndirectW() svn path=/trunk/; revision=5355 --- reactos/lib/user32/windows/menu.c | 191 +++++++++++++++++++++++++++++- 1 file changed, 187 insertions(+), 4 deletions(-) diff --git a/reactos/lib/user32/windows/menu.c b/reactos/lib/user32/windows/menu.c index c51eb864929..be1ba33cc40 100644 --- a/reactos/lib/user32/windows/menu.c +++ b/reactos/lib/user32/windows/menu.c @@ -16,7 +16,7 @@ * 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.12 2003/07/31 23:06:43 weiden Exp $ +/* $Id: menu.c,v 1.13 2003/08/01 00:44:27 weiden Exp $ * * PROJECT: ReactOS user32.dll * FILE: lib/user32/windows/menu.c @@ -94,6 +94,158 @@ HANDLE hMenuDefSysPopup = 0; #define NO_SELECTED_ITEM (0xffff) +#ifndef MF_END +#define MF_END 0x0080 +#endif + + +/* 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 + +/********************************************************************** + * 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 { + MENUITEMINFO 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; + 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) + { + HMENU 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; +} + + /* FUNCTIONS *****************************************************************/ static BOOL @@ -831,13 +983,44 @@ LoadMenuIndirectA(CONST MENUTEMPLATE *lpMenuTemplate) /* - * @unimplemented + * @implemented */ HMENU STDCALL LoadMenuIndirectW(CONST MENUTEMPLATE *lpMenuTemplate) { - UNIMPLEMENTED; - 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; + } }