X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=reactos%2Fwin32ss%2Fuser%2Fuser32%2Fwindows%2Fmenu.c;h=f1ef54089da4efd817be11beae5e6a8bd849f495;hp=c5a2766c6318d25a1a2b59b2eec5c1d5f86e6db3;hb=5e23122314c33684d26c6e86fe6399be5b193e59;hpb=599a7affa308ee89291a8c11db08406e672aa856 diff --git a/reactos/win32ss/user/user32/windows/menu.c b/reactos/win32ss/user/user32/windows/menu.c index c5a2766c631..f1ef54089da 100644 --- a/reactos/win32ss/user/user32/windows/menu.c +++ b/reactos/win32ss/user/user32/windows/menu.c @@ -14,6 +14,9 @@ #include LRESULT DefWndNCPaint(HWND hWnd, HRGN hRgn, BOOL Active); +BOOL WINAPI GdiValidateHandle(HGDIOBJ hobj); +LRESULT DefWndNCHitTest(HWND hWnd, POINT Point); +void FASTCALL NcGetSysPopupPos(HWND Wnd, RECT *Rect); WINE_DEFAULT_DEBUG_CHANNEL(menu); @@ -36,20 +39,38 @@ WINE_DEFAULT_DEBUG_CHANNEL(menu); #define TPM_BUTTONDOWN 0x40000000 /* menu was clicked before tracking */ #define TPM_POPUPMENU 0x20000000 /* menu is a popup menu */ +/* top and bottom margins for popup menus */ +#define MENU_TOP_MARGIN 3 +#define MENU_BOTTOM_MARGIN 2 #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)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU)) + (0 == ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN)) #define IS_SYSTEM_POPUP(MenuInfo) \ - (0 != ((MenuInfo)->Flags & MF_POPUP) && 0 != ((MenuInfo)->Flags & MF_SYSMENU)) + (0 != ((MenuInfo)->fFlags & MNF_POPUP) && 0 != ((MenuInfo)->fFlags & MNF_SYSDESKMN)) #define IS_BITMAP_ITEM(flags) (MF_BITMAP == MENU_ITEM_TYPE(flags)) @@ -105,6 +126,248 @@ static HBITMAP BmpSysMenu = NULL; static SIZE MenuCharSize; + +/*********************************************************************** + * MENU_GetMenu + * + * Validate the given menu handle and returns the menu structure pointer. + */ +FORCEINLINE PMENU MENU_GetMenu(HMENU hMenu) +{ + return ValidateHandleNoErr(hMenu, TYPE_MENU); +} + +/*********************************************************************** + * get_win_sys_menu + * + * Get the system menu of a window + */ +static HMENU get_win_sys_menu( HWND hwnd ) +{ + HMENU ret = 0; + WND *win = ValidateHwnd( hwnd ); + if (win) + { + ret = win->SystemMenu; + } + return ret; +} + +/*********************************************************************** + * 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; +} + +#define MAX_GOINTOSUBMENU (0x10) +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 ( (Item->fType & MF_POPUP) && (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) 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)) ) + { + lpmii->cch = 0; + if( unicode) + *((WCHAR *)lpmii->dwTypeData) = 0; + else + *((CHAR *)lpmii->dwTypeData) = 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; +} + /*********************************************************************** * MenuGetRosMenuInfo * @@ -113,10 +376,31 @@ static SIZE MenuCharSize; static BOOL FASTCALL MenuGetRosMenuInfo(PROSMENUINFO MenuInfo, HMENU Menu) { - MenuInfo->cbSize = sizeof(ROSMENUINFO); - MenuInfo->fMask = MIM_BACKGROUND | MIM_HELPID | MIM_MAXHEIGHT | MIM_MENUDATA | MIM_STYLE; - - return NtUserMenuInfo(Menu, MenuInfo, FALSE); + PMENU pMenu; + if (!(pMenu = ValidateHandleNoErr(Menu, TYPE_MENU))) return FALSE; + + MenuInfo->hbrBack = pMenu->hbrBack; + MenuInfo->dwContextHelpID = pMenu->dwContextHelpId; + MenuInfo->cyMax = pMenu->cyMax; + MenuInfo->dwMenuData = pMenu->dwMenuData; + MenuInfo->dwStyle = pMenu->fFlags & MNS_STYLE_MASK; + + MenuInfo->cItems = pMenu->cItems; + + MenuInfo->iItem = pMenu->iItem; + MenuInfo->cxMenu = pMenu->cxMenu; + MenuInfo->cyMenu = pMenu->cyMenu; + MenuInfo->spwndNotify = pMenu->spwndNotify; + MenuInfo->cxTextAlign = pMenu->cxTextAlign; + MenuInfo->iTop = pMenu->iMaxTop; + MenuInfo->iMaxTop = pMenu->iMaxTop; + MenuInfo->dwArrowsOn = pMenu->dwArrowsOn; + + MenuInfo->fFlags = pMenu->fFlags; + MenuInfo->Self = pMenu->head.h; + MenuInfo->TimeToHide = pMenu->TimeToHide; + MenuInfo->Wnd = pMenu->hWnd; + return TRUE; } /*********************************************************************** @@ -130,7 +414,7 @@ MenuSetRosMenuInfo(PROSMENUINFO MenuInfo) MenuInfo->cbSize = sizeof(ROSMENUINFO); MenuInfo->fMask = MIM_BACKGROUND | MIM_HELPID | MIM_MAXHEIGHT | MIM_MENUDATA | MIM_STYLE; - return NtUserMenuInfo(MenuInfo->Self, MenuInfo, TRUE); + return NtUserThunkedMenuInfo(MenuInfo->Self, (LPCMENUINFO)MenuInfo); } /*********************************************************************** @@ -153,41 +437,68 @@ MenuInitRosMenuItemInfo(PROSMENUITEMINFO ItemInfo) static BOOL FASTCALL MenuGetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo) { + PITEM pItem; UINT Save_Mask = ItemInfo->fMask; /* Save the org mask bits. */ if (ItemInfo->dwTypeData != NULL) - { + { HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData); - } - + } - ItemInfo->fMask = MIIM_BITMAP | MIIM_CHECKMARKS | MIIM_DATA | MIIM_FTYPE - | MIIM_ID | MIIM_STATE | MIIM_STRING | MIIM_SUBMENU | MIIM_TYPE; ItemInfo->dwTypeData = NULL; - if (! NtUserMenuItemInfo(Menu, Index, TRUE, ItemInfo, FALSE)) - { + if (!(pItem = MENU_FindItem(&Menu, &Index, MF_BYPOSITION))) + { ItemInfo->fType = 0; return FALSE; - } + } + + ItemInfo->fType = pItem->fType; + ItemInfo->hbmpItem = pItem->hbmp; + ItemInfo->hbmpChecked = pItem->hbmpChecked; + ItemInfo->hbmpUnchecked = pItem->hbmpUnchecked; + ItemInfo->dwItemData = pItem->dwItemData; + ItemInfo->wID = pItem->wID; + ItemInfo->fState = pItem->fState; + + if (pItem->spSubMenu) + { + PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu); + HMENU hSubMenu = UserHMGetHandle(pSubMenu); + ItemInfo->hSubMenu = hSubMenu; + } + else + ItemInfo->hSubMenu = NULL; if (MENU_ITEM_TYPE(ItemInfo->fType) == MF_STRING) - { - ItemInfo->cch++; - ItemInfo->dwTypeData = HeapAlloc(GetProcessHeap(), 0, - ItemInfo->cch * sizeof(WCHAR)); - if (NULL == ItemInfo->dwTypeData) + { + LPWSTR lpstr = pItem->lpstr.Buffer ? DesktopPtrToUser(pItem->lpstr.Buffer) : NULL; + if (lpstr) + { + ItemInfo->cch = pItem->lpstr.Length / sizeof(WCHAR); + ItemInfo->cch++; + ItemInfo->dwTypeData = HeapAlloc(GetProcessHeap(), 0, ItemInfo->cch * sizeof(WCHAR)); + if (ItemInfo->dwTypeData == NULL) { - return FALSE; + return FALSE; } + RtlCopyMemory(ItemInfo->dwTypeData, lpstr, min(ItemInfo->cch * sizeof(WCHAR), pItem->lpstr.MaximumLength)); + } + else + { + ItemInfo->cch = 0; + } + } + + ItemInfo->Rect.left = pItem->xItem; + ItemInfo->Rect.top = pItem->yItem; + ItemInfo->Rect.right = pItem->cxItem; // Do this for now...... + ItemInfo->Rect.bottom = pItem->cyItem; + ItemInfo->dxTab = pItem->dxTab; + ItemInfo->lpstr = pItem->lpstr.Buffer; + ItemInfo->maxBmpSize.cx = pItem->cxBmp; + ItemInfo->maxBmpSize.cy = pItem->cyBmp; - if (! NtUserMenuItemInfo(Menu, Index, TRUE, ItemInfo, FALSE)) - { - ItemInfo->fType = 0; - return FALSE; - } - ItemInfo->dwTypeData[ItemInfo->cch - 1] = UNICODE_NULL; - } ItemInfo->fMask = Save_Mask; return TRUE; } @@ -207,8 +518,11 @@ MenuSetRosMenuItemInfo(HMENU Menu, UINT Index, PROSMENUITEMINFO ItemInfo) { ItemInfo->cch = strlenW(ItemInfo->dwTypeData); } - Ret = NtUserMenuItemInfo(Menu, Index, TRUE, ItemInfo, TRUE); - + if (ItemInfo->hSubMenu) + { + if (!IsMenu(ItemInfo->hSubMenu)) ItemInfo->hSubMenu = NULL; + } + Ret = NtUserThunkedMenuItemInfo(Menu, Index, TRUE, FALSE, (LPMENUITEMINFOW)ItemInfo, NULL); return Ret; } @@ -221,45 +535,10 @@ static VOID FASTCALL MenuCleanupRosMenuItemInfo(PROSMENUITEMINFO ItemInfo) { if (ItemInfo->dwTypeData != NULL) - { + { HeapFree(GetProcessHeap(), 0, ItemInfo->dwTypeData); ItemInfo->dwTypeData = NULL; - } -} - -/*********************************************************************** - * MenuGetAllRosMenuItemInfo - * - * Get full information about all menu items - */ -static INT FASTCALL -MenuGetAllRosMenuItemInfo(HMENU Menu, PROSMENUITEMINFO *ItemInfo) -{ - DWORD BufSize; - - BufSize = NtUserBuildMenuItemList(Menu, (VOID *) 1, 0, 0); - if (BufSize == (DWORD) -1 || BufSize == 0) - { - return -1; - } - *ItemInfo = HeapAlloc(GetProcessHeap(), 0, BufSize); - if (NULL == *ItemInfo) - { - return -1; - } - - return NtUserBuildMenuItemList(Menu, *ItemInfo, BufSize, 0); -} - -/*********************************************************************** - * MenuCleanupAllRosMenuItemInfo - * - * Cleanup after use of MenuGetAllRosMenuItemInfo - */ -static VOID FASTCALL -MenuCleanupAllRosMenuItemInfo(PROSMENUITEMINFO ItemInfo) -{ - HeapFree(GetProcessHeap(), 0, ItemInfo); + } } /*********************************************************************** @@ -310,22 +589,27 @@ void FASTCALL MenuInitSysMenuPopup(HMENU hmenu, DWORD style, DWORD clsStyle, LON * PROSMENUINFO MenuInfo) * *****************************************************************************/ -static UINT MenuGetStartOfNextColumn( - PROSMENUINFO MenuInfo) + +static UINT MENU_GetStartOfNextColumn( + HMENU hMenu ) { - PROSMENUITEMINFO MenuItems; + MENU *menu = MENU_GetMenu(hMenu); + PITEM pItem; UINT i; - i = MenuInfo->FocusedItem; - if ( i == NO_SELECTED_ITEM ) - return i; + if(!menu) + return NO_SELECTED_ITEM; - if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &MenuItems) <= 0) - return NO_SELECTED_ITEM; + i = menu->iItem + 1; + if( i == NO_SELECTED_ITEM ) + return i; - for (i++ ; i < MenuInfo->MenuItemCount; i++) - if (0 != (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK))) - return i; + pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL; + if (!pItem) return NO_SELECTED_ITEM; + for( ; i < menu->cItems; ++i ) { + if (pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)) + return i; + } return NO_SELECTED_ITEM; } @@ -336,43 +620,112 @@ static UINT MenuGetStartOfNextColumn( * PROSMENUINFO MenuInfo) * *****************************************************************************/ - -static UINT FASTCALL MenuGetStartOfPrevColumn( - PROSMENUINFO MenuInfo) +static UINT MENU_GetStartOfPrevColumn( + HMENU hMenu ) { - PROSMENUITEMINFO MenuItems; - UINT i; + MENU *menu = MENU_GetMenu(hMenu); + UINT i; + PITEM pItem; - if (!MenuInfo->FocusedItem || MenuInfo->FocusedItem == NO_SELECTED_ITEM) - return NO_SELECTED_ITEM; + if( !menu ) + return NO_SELECTED_ITEM; - if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &MenuItems) <= 0) - return NO_SELECTED_ITEM; + if( menu->iItem == 0 || menu->iItem == NO_SELECTED_ITEM ) + return NO_SELECTED_ITEM; + + pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL; + if (!pItem) return NO_SELECTED_ITEM; /* Find the start of the column */ - for (i = MenuInfo->FocusedItem; - 0 != i && 0 == (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)); - --i) - { - ; /* empty */ + + for(i = menu->iItem; i != 0 && + !(pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)); + --i); /* empty */ + + if(i == 0) + return NO_SELECTED_ITEM; + + for(--i; i != 0; --i) { + if (pItem[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)) + break; } - if (i == 0) + TRACE("ret %d.\n", i ); + + return i; +} + +/*********************************************************************** + * MenuLoadBitmaps + * + * Load the arrow bitmap. We can't do this from MenuInit since user32 + * can also be used (and thus initialized) from text-mode. + */ +static void FASTCALL +MenuLoadBitmaps(VOID) +{ + /* Load system buttons bitmaps */ + if (NULL == BmpSysMenu) { - MenuCleanupAllRosMenuItemInfo(MenuItems); - return NO_SELECTED_ITEM; + BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE)); } +} +/////////// Make gpsi OBMI via callback ////////////// +/*********************************************************************** + * get_arrow_bitmap + */ +HBITMAP get_arrow_bitmap(void) +{ + static HBITMAP arrow_bitmap; - for (--i; 0 != i; --i) - if (MenuItems[i].fType & (MF_MENUBREAK | MF_MENUBARBREAK)) - break; + if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_MNARROW)); + return arrow_bitmap; +} - MenuCleanupAllRosMenuItemInfo(MenuItems); - TRACE("ret %d.\n", i ); +/*********************************************************************** + * get_down_arrow_bitmap DFCS_MENUARROWDOWN + */ +HBITMAP get_down_arrow_bitmap(void) +{ + static HBITMAP arrow_bitmap; - return i; + if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROW)); + return arrow_bitmap; +} + +/*********************************************************************** + * get_down_arrow_inactive_bitmap DFCS_MENUARROWDOWN | DFCS_INACTIVE + */ +HBITMAP get_down_arrow_inactive_bitmap(void) +{ + static HBITMAP arrow_bitmap; + + if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_DNARROWI)); + return arrow_bitmap; +} + +/*********************************************************************** + * get_up_arrow_bitmap DFCS_MENUARROWUP + */ +HBITMAP get_up_arrow_bitmap(void) +{ + static HBITMAP arrow_bitmap; + + if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROW)); + return arrow_bitmap; } +/*********************************************************************** + * get_up_arrow_inactive_bitmap DFCS_MENUARROWUP | DFCS_INACTIVE + */ +static HBITMAP get_up_arrow_inactive_bitmap(void) +{ + static HBITMAP arrow_bitmap; + + if (!arrow_bitmap) arrow_bitmap = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_UPARROWI)); + return arrow_bitmap; +} +//////////////// /*********************************************************************** * MenuFindSubMenu * @@ -382,51 +735,59 @@ static UINT FASTCALL MenuGetStartOfPrevColumn( */ static UINT FASTCALL MenuFindSubMenu(HMENU *hmenu, HMENU hSubTarget ) { - ROSMENUINFO menu; + PMENU menu, pSubMenu; + HMENU hSubMenu; UINT i; - ROSMENUITEMINFO item; - if (((*hmenu)==(HMENU)0xffff) || - (!MenuGetRosMenuInfo(&menu, *hmenu))) + PITEM item; + + if (((*hmenu)==(HMENU)0xffff) ||(!(menu = MENU_GetMenu(*hmenu)))) return NO_SELECTED_ITEM; - MenuInitRosMenuItemInfo(&item); - for (i = 0; i < menu.MenuItemCount; i++) { - if (! MenuGetRosMenuItemInfo(menu.Self, i, &item)) + item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL; + for (i = 0; i < menu->cItems; i++, item++) + { + if (!item->spSubMenu) + continue; + else { - MenuCleanupRosMenuItemInfo(&item); - return NO_SELECTED_ITEM; - } - if (!(item.fType & MF_POPUP)) continue; - if (item.hSubMenu == hSubTarget) { - MenuCleanupRosMenuItemInfo(&item); - return i; - } - else { - HMENU hsubmenu = item.hSubMenu; - UINT pos = MenuFindSubMenu(&hsubmenu, hSubTarget ); - if (pos != NO_SELECTED_ITEM) { - *hmenu = hsubmenu; - return pos; + pSubMenu = DesktopPtrToUser(item->spSubMenu); + hSubMenu = UserHMGetHandle(pSubMenu); + if (hSubMenu == hSubTarget) + { + return i; + } + else + { + HMENU hsubmenu = hSubMenu; + UINT pos = MenuFindSubMenu( &hsubmenu, hSubTarget ); + if (pos != NO_SELECTED_ITEM) + { + *hmenu = hsubmenu; + return pos; + } } } } - MenuCleanupRosMenuItemInfo(&item); return NO_SELECTED_ITEM; } /*********************************************************************** - * MenuLoadBitmaps + * MENU_AdjustMenuItemRect * - * Load the arrow bitmap. We can't do this from MenuInit since user32 - * can also be used (and thus initialized) from text-mode. + * Adjust menu item rectangle according to scrolling state. */ -static void FASTCALL -MenuLoadBitmaps(VOID) +static void +MENU_AdjustMenuItemRect(PROSMENUINFO menu, LPRECT rect) { - /* Load system buttons bitmaps */ - if (NULL == BmpSysMenu) + if (menu->dwArrowsOn) { - BmpSysMenu = LoadBitmapW(0, MAKEINTRESOURCEW(OBM_CLOSE)); + UINT arrow_bitmap_height; + BITMAP bmp; + + GetObjectW(get_up_arrow_bitmap(), sizeof(bmp), &bmp); + arrow_bitmap_height = bmp.bmHeight; + rect->top += arrow_bitmap_height - menu->iTop; + rect->bottom += arrow_bitmap_height - menu->iTop; } } @@ -500,54 +861,48 @@ MenuDrawPopupGlyph(HDC dc, LPRECT r, INT_PTR popupMagic, BOOL inactive, BOOL hil * Find the menu item selected by a key press. * Return item id, -1 if none, -2 if we should close the menu. */ -static UINT FASTCALL MenuFindItemByKey(HWND WndOwner, PROSMENUINFO MenuInfo, +static UINT FASTCALL MENU_FindItemByKey(HWND WndOwner, HMENU hmenu, WCHAR Key, BOOL ForceMenuChar) { - ROSMENUINFO SysMenuInfo; - PROSMENUITEMINFO Items, ItemInfo; LRESULT MenuChar; - UINT i; + WORD Flags = 0; - TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char) Key, Key, MenuInfo); + TRACE("\tlooking for '%c' (0x%02x) in [%p]\n", (char)Key, Key, hmenu ); - if (NULL == MenuInfo || ! IsMenu(MenuInfo->Self)) - { - if (MenuGetRosMenuInfo(&SysMenuInfo, GetSystemMenu(WndOwner, FALSE))) - { - MenuInfo = &SysMenuInfo; - } - else - { - MenuInfo = NULL; - } - } + if (!IsMenu( hmenu )) hmenu = GetSubMenu( get_win_sys_menu(WndOwner), 0); + if (hmenu) + { + MENU *menu = MENU_GetMenu( hmenu ); + ITEM *item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL; - if (NULL != MenuInfo) - { - if (MenuGetAllRosMenuItemInfo(MenuInfo->Self, &Items) <= 0) - { - return -1; - } - if ( !ForceMenuChar ) - { - ItemInfo = Items; - for (i = 0; i < MenuInfo->MenuItemCount; i++, ItemInfo++) - { - if ((ItemInfo->lpstr) && NULL != ItemInfo->dwTypeData) - { - WCHAR *p = (WCHAR *) ItemInfo->dwTypeData - 2; - do - { - p = strchrW (p + 2, '&'); - } - while (p != NULL && p [1] == '&'); - if (p && (toupperW(p[1]) == toupperW(Key))) return i; - } - } - } + if( !ForceMenuChar ) + { + UINT i; + BOOL cjk = GetSystemMetrics( SM_DBCSENABLED ); + + for (i = 0; i < menu->cItems; i++, item++) + { + LPWSTR text = item->Xlpstr ? DesktopPtrToUser(item->Xlpstr) : NULL; + if( text) + { + const WCHAR *p = text - 2; + do + { + const WCHAR *q = p + 2; + p = strchrW (q, '&'); + if (!p && cjk) p = strchrW (q, '\036'); /* Japanese Win16 */ + } + while (p != NULL && p [1] == '&'); + if (p && (toupperW(p[1]) == toupperW(Key))) return i; + } + } + } + + Flags |= menu->fFlags & MNF_POPUP ? MF_POPUP : 0; + Flags |= menu->fFlags & MNF_SYSDESKMN ? MF_SYSMENU : 0; MenuChar = SendMessageW(WndOwner, WM_MENUCHAR, - MAKEWPARAM(Key, MenuInfo->Flags), (LPARAM) MenuInfo->Self); + MAKEWPARAM(Key, Flags), (LPARAM) hmenu); if (HIWORD(MenuChar) == MNC_EXECUTE) return LOWORD(MenuChar); if (HIWORD(MenuChar) == MNC_CLOSE) return (UINT)(-2); } @@ -624,7 +979,7 @@ static void FASTCALL MenuGetBitmapItemSize(PROSMENUITEMINFO lpitem, SIZE *size, * Draw a bitmap item. */ static void FASTCALL MenuDrawBitmapItem(HDC hdc, PROSMENUITEMINFO lpitem, const RECT *rect, - HMENU hmenu, HWND WndOwner, UINT odaction, BOOL MenuBar) + PROSMENUINFO MenuInfo, HWND WndOwner, UINT odaction, BOOL MenuBar) { BITMAP bm; DWORD rop; @@ -692,7 +1047,9 @@ static void FASTCALL MenuDrawBitmapItem(HDC hdc, PROSMENUITEMINFO lpitem, const drawItem.itemState |= (lpitem->fState & MF_DISABLED)?ODS_DISABLED:0; drawItem.itemState |= (lpitem->fState & MF_GRAYED)?ODS_GRAYED|ODS_DISABLED:0; drawItem.itemState |= (lpitem->fState & MF_HILITE)?ODS_SELECTED:0; - drawItem.hwndItem = (HWND)hmenu; + //drawItem.itemState |= (!(MenuInfo->fFlags & MNF_UNDERLINE))?ODS_NOACCEL:0; + //drawItem.itemState |= (MenuInfo->fFlags & MNF_INACTIVE)?ODS_INACTIVE:0; + drawItem.hwndItem = (HWND)MenuInfo->Self; drawItem.hDC = hdc; drawItem.rcItem = *rect; drawItem.itemData = lpitem->dwItemData; @@ -743,14 +1100,19 @@ static void FASTCALL MenuDrawBitmapItem(HDC hdc, PROSMENUITEMINFO lpitem, const * Calculate the size of the menu item and store it in lpitem->rect. */ static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMENUINFO MenuInfo, HWND hwndOwner, - INT orgX, INT orgY, BOOL menuBar) + INT orgX, INT orgY, BOOL menuBar, BOOL textandbmp) { WCHAR *p; UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK ); + UINT arrow_bitmap_width; + BITMAP bm; INT itemheight = 0; TRACE("dc=%x owner=%x (%d,%d)\n", hdc, hwndOwner, orgX, orgY); + GetObjectW( get_arrow_bitmap(), sizeof(bm), &bm ); + arrow_bitmap_width = bm.bmWidth; + MenuCharSize.cx = GdiGetCharDimensions( hdc, NULL, &MenuCharSize.cy ); SetRect( &lpitem->Rect, orgX, orgY, orgX, orgY ); @@ -769,24 +1131,26 @@ static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMEN * width of a menufont character to the width of an owner-drawn menu. */ lpitem->Rect.right += mis.itemWidth + 2 * MenuCharSize.cx; - if (menuBar) { /* under at least win95 you seem to be given a standard height for the menu and the height value is ignored */ lpitem->Rect.bottom += GetSystemMetrics(SM_CYMENUSIZE); } else lpitem->Rect.bottom += mis.itemHeight; - + // Or this, + //Item->cxBmp = mis.itemWidth; + //Item->cyBmp = mis.itemHeight; TRACE("id=%04lx size=%dx%d\n", - lpitem->wID, mis.itemWidth, mis.itemHeight); + lpitem->wID, lpitem->Rect.right-lpitem->Rect.left, + lpitem->Rect.bottom-lpitem->Rect.top); return; } if (lpitem->fType & MF_SEPARATOR) { - lpitem->Rect.bottom += SEPARATOR_HEIGHT; + lpitem->Rect.bottom += GetSystemMetrics( SM_CYMENUSIZE)/2;//SEPARATOR_HEIGHT; if( !menuBar) - lpitem->Rect.right += check_bitmap_width + MenuCharSize.cx; + lpitem->Rect.right += arrow_bitmap_width/*check_bitmap_width*/ + MenuCharSize.cx; return; } @@ -800,21 +1164,17 @@ static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMEN MenuGetBitmapItemSize(lpitem, &size, hwndOwner ); /* Keep the size of the bitmap in callback mode to be able * to draw it correctly */ - lpitem->Rect.right = lpitem->Rect.left + size.cx; - if (MenuInfo->maxBmpSize.cx < abs(size.cx) + MENU_ITEM_HBMP_SPACE || - MenuInfo->maxBmpSize.cy < abs(size.cy)) - { - MenuInfo->maxBmpSize.cx = abs(size.cx) + MENU_ITEM_HBMP_SPACE; - MenuInfo->maxBmpSize.cy = abs(size.cy); - } + lpitem->maxBmpSize = size; + MenuInfo->cxTextAlign = max(MenuInfo->cxTextAlign, size.cx); MenuSetRosMenuInfo(MenuInfo); + lpitem->Rect.right += size.cx + 2; itemheight = size.cy + 2; if( !(MenuInfo->dwStyle & MNS_NOCHECK)) lpitem->Rect.right += 2 * check_bitmap_width; lpitem->Rect.right += 4 + MenuCharSize.cx; lpitem->dxTab = lpitem->Rect.right; - lpitem->Rect.right += check_bitmap_width; + lpitem->Rect.right += arrow_bitmap_width;//check_bitmap_width; } else /* hbmpItem & MenuBar */ { MenuGetBitmapItemSize(lpitem, &size, hwndOwner ); lpitem->Rect.right += size.cx; @@ -887,6 +1247,17 @@ static void FASTCALL MenuCalcItemSize( HDC hdc, PROSMENUITEMINFO lpitem, PROSMEN TRACE("(%ld,%ld)-(%ld,%ld)\n", lpitem->Rect.left, lpitem->Rect.top, lpitem->Rect.right, lpitem->Rect.bottom); } +/*********************************************************************** + * MENU_GetMaxPopupHeight + */ +static UINT +MENU_GetMaxPopupHeight(PROSMENUINFO lppop) +{ + if (lppop->cyMax) + return lppop->cyMax; + return GetSystemMetrics(SM_CYSCREEN) - GetSystemMetrics(SM_CYBORDER); +} + /*********************************************************************** * MenuPopupMenuCalcSize * @@ -897,10 +1268,11 @@ static void FASTCALL MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner) ROSMENUITEMINFO lpitem; HDC hdc; int start, i; - int orgX, orgY, maxX, maxTab, maxTabWidth; + int orgX, orgY, maxX, maxTab, maxTabWidth, maxHeight; + BOOL textandbmp = FALSE; - MenuInfo->Width = MenuInfo->Height = 0; - if (MenuInfo->MenuItemCount == 0) + MenuInfo->cxMenu = MenuInfo->cyMenu = 0; + if (MenuInfo->cItems == 0) { MenuSetRosMenuInfo(MenuInfo); return; @@ -912,11 +1284,10 @@ static void FASTCALL MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner) start = 0; maxX = 2 + 1; - MenuInfo->maxBmpSize.cx = 0; - MenuInfo->maxBmpSize.cy = 0; + MenuInfo->cxTextAlign = 0; MenuInitRosMenuItemInfo(&lpitem); - while (start < MenuInfo->MenuItemCount) + while (start < MenuInfo->cItems) { orgX = maxX; orgY = 2; @@ -924,7 +1295,7 @@ static void FASTCALL MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner) maxTab = maxTabWidth = 0; /* Parse items until column break or end of menu */ - for (i = start; i < MenuInfo->MenuItemCount; i++) + for (i = start; i < MenuInfo->cItems; i++) { if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i, &lpitem)) { @@ -935,7 +1306,9 @@ static void FASTCALL MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner) if (i != start && (lpitem.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break; - MenuCalcItemSize(hdc, &lpitem, MenuInfo, WndOwner, orgX, orgY, FALSE); + if( lpitem.lpstr && lpitem.hbmpItem) textandbmp = TRUE; + + MenuCalcItemSize(hdc, &lpitem, MenuInfo, WndOwner, orgX, orgY, FALSE, textandbmp); if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &lpitem)) { MenuCleanupRosMenuItemInfo(&lpitem); @@ -950,7 +1323,7 @@ static void FASTCALL MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner) maxX = max(maxX, lpitem.Rect.right); orgY = lpitem.Rect.bottom; if ((lpitem.lpstr) && lpitem.dxTab ) - { + { maxTab = max( maxTab, lpitem.dxTab ); maxTabWidth = max(maxTabWidth, lpitem.Rect.right - lpitem.dxTab); } @@ -971,14 +1344,33 @@ static void FASTCALL MenuPopupMenuCalcSize(PROSMENUINFO MenuInfo, HWND WndOwner) } start++; } - MenuInfo->Height = max(MenuInfo->Height, orgY); + MenuInfo->cyMenu = max(MenuInfo->cyMenu, orgY); } - MenuInfo->Width = maxX; + MenuInfo->cxMenu = maxX; + /* if none of the items have both text and bitmap then + * the text and bitmaps are all aligned on the left. If there is at + * least one item with both text and bitmap then bitmaps are + * on the left and texts left aligned with the right hand side + * of the bitmaps */ + if( !textandbmp) MenuInfo->cxTextAlign = 0; /* space for 3d border */ - MenuInfo->Height += 2; - MenuInfo->Width += 2; + MenuInfo->cyMenu += MENU_BOTTOM_MARGIN; + MenuInfo->cxMenu += 2; + + /* Adjust popup height if it exceeds maximum */ + maxHeight = MENU_GetMaxPopupHeight(MenuInfo); + MenuInfo->iMaxTop = MenuInfo->cyMenu - MENU_TOP_MARGIN; + if (MenuInfo->cyMenu >= maxHeight) + { + MenuInfo->cyMenu = maxHeight; + MenuInfo->dwArrowsOn = 1; + } + else + { + MenuInfo->dwArrowsOn = 0; + } MenuCleanupRosMenuItemInfo(&lpitem); MenuSetRosMenuInfo(MenuInfo); @@ -1001,19 +1393,18 @@ static void FASTCALL MenuMenuBarCalcSize( HDC hdc, LPRECT lprect, int start, i, orgX, orgY, maxY, helpPos; if ((lprect == NULL) || (MenuInfo == NULL)) return; - if (MenuInfo->MenuItemCount == 0) return; - TRACE("left=%ld top=%ld right=%ld bottom=%ld\n", lprect->left, lprect->top, lprect->right, lprect->bottom); - MenuInfo->Width = lprect->right - lprect->left; - MenuInfo->Height = 0; + if (MenuInfo->cItems == 0) return; + TRACE("lprect %p %s\n", lprect, wine_dbgstr_rect( lprect)); + MenuInfo->cxMenu = lprect->right - lprect->left; + MenuInfo->cyMenu = 0; maxY = lprect->top + 1; start = 0; helpPos = -1; - MenuInfo->maxBmpSize.cx = 0; - MenuInfo->maxBmpSize.cy = 0; + MenuInfo->cxTextAlign = 0; MenuInitRosMenuItemInfo(&ItemInfo); - while (start < MenuInfo->MenuItemCount) + while (start < MenuInfo->cItems) { if (! MenuGetRosMenuItemInfo(MenuInfo->Self, start, &ItemInfo)) { @@ -1024,14 +1415,14 @@ static void FASTCALL MenuMenuBarCalcSize( HDC hdc, LPRECT lprect, orgY = maxY; /* Parse items until line break or end of menu */ - for (i = start; i < MenuInfo->MenuItemCount; i++) + for (i = start; i < MenuInfo->cItems; i++) { if ((helpPos == -1) && (ItemInfo.fType & MF_RIGHTJUSTIFY)) helpPos = i; if ((i != start) && (ItemInfo.fType & (MF_MENUBREAK | MF_MENUBARBREAK))) break; TRACE("calling MENU_CalcItemSize org=(%d, %d)\n", orgX, orgY); - MenuCalcItemSize(hdc, &ItemInfo, MenuInfo, hwndOwner, orgX, orgY, TRUE); + MenuCalcItemSize(hdc, &ItemInfo, MenuInfo, hwndOwner, orgX, orgY, TRUE, FALSE); if (! MenuSetRosMenuItemInfo(MenuInfo->Self, i, &ItemInfo)) { MenuCleanupRosMenuItemInfo(&ItemInfo); @@ -1045,7 +1436,7 @@ static void FASTCALL MenuMenuBarCalcSize( HDC hdc, LPRECT lprect, } maxY = max( maxY, ItemInfo.Rect.bottom ); orgX = ItemInfo.Rect.right; - if (i + 1 < MenuInfo->MenuItemCount) + if (i + 1 < MenuInfo->cItems) { if (! MenuGetRosMenuItemInfo(MenuInfo->Self, i + 1, &ItemInfo)) { @@ -1074,21 +1465,21 @@ HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */ } lprect->bottom = maxY; - MenuInfo->Height = lprect->bottom - lprect->top; + MenuInfo->cyMenu = lprect->bottom - lprect->top; MenuSetRosMenuInfo(MenuInfo); if (helpPos != -1) { /* Flush right all items between the MF_RIGHTJUSTIFY and */ /* the last item (if several lines, only move the last line) */ - if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->MenuItemCount - 1, &ItemInfo)) + if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->cItems - 1, &ItemInfo)) { MenuCleanupRosMenuItemInfo(&ItemInfo); return; } orgY = ItemInfo.Rect.top; orgX = lprect->right; - for (i = MenuInfo->MenuItemCount - 1; helpPos <= i; i--) + for (i = MenuInfo->cItems - 1; helpPos <= i; i--) { if (i < helpPos) { @@ -1118,6 +1509,50 @@ HBMMENU_MBAR_CLOSE, MINIMIZE & RESTORE, look the same size as the menu bar! */ MenuCleanupRosMenuItemInfo(&ItemInfo); } +/*********************************************************************** + * MENU_DrawScrollArrows + * + * Draw scroll arrows. + */ +static void +MENU_DrawScrollArrows(PROSMENUINFO lppop, HDC hdc) +{ + HDC hdcMem = CreateCompatibleDC(hdc); + HBITMAP hOrigBitmap; + UINT arrow_bitmap_width, arrow_bitmap_height; + BITMAP bmp; + RECT rect; + + GetObjectW(get_down_arrow_bitmap(), sizeof(bmp), &bmp); + arrow_bitmap_width = bmp.bmWidth; + arrow_bitmap_height = bmp.bmHeight; + + + if (lppop->iTop) + hOrigBitmap = SelectObject(hdcMem, get_up_arrow_bitmap()); + else + hOrigBitmap = SelectObject(hdcMem, get_up_arrow_inactive_bitmap()); + rect.left = 0; + rect.top = 0; + rect.right = lppop->cxMenu; + rect.bottom = arrow_bitmap_height; + FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENU)); + BitBlt(hdc, (lppop->cxMenu - arrow_bitmap_width) / 2, 0, + arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY); + rect.top = lppop->cyMenu - arrow_bitmap_height; + rect.bottom = lppop->cyMenu; + FillRect(hdc, &rect, GetSysColorBrush(COLOR_MENU)); + if (lppop->iTop < lppop->iMaxTop - (MENU_GetMaxPopupHeight(lppop) - 2 * arrow_bitmap_height)) + SelectObject(hdcMem, get_down_arrow_bitmap()); + else + SelectObject(hdcMem, get_down_arrow_inactive_bitmap()); + BitBlt(hdc, (lppop->cxMenu - arrow_bitmap_width) / 2, + lppop->cyMenu - arrow_bitmap_height, + arrow_bitmap_width, arrow_bitmap_height, hdcMem, 0, 0, SRCCOPY); + SelectObject(hdcMem, hOrigBitmap); + DeleteDC(hdcMem); +} + /*********************************************************************** * MenuDrawMenuItem * @@ -1130,7 +1565,7 @@ static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND Wnd PWCHAR Text; BOOL flat_menu = FALSE; int bkgnd; - PWND Wnd = ValidateHwnd(hWnd); + PWND Wnd = ValidateHwndNoErr(hWnd); if (!Wnd) return; @@ -1140,9 +1575,8 @@ static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND Wnd if ( (Wnd->style & WS_MINIMIZE)) { UserGetInsideRectNC(Wnd, &rect); - UserDrawSysMenuButton(hWnd, hdc, &rect, - lpitem->fState & (MF_HILITE | MF_MOUSESELECT)); - } + UserDrawSysMenuButton(hWnd, hdc, &rect, lpitem->fState & (MF_HILITE | MF_MOUSESELECT)); + } return; } @@ -1173,7 +1607,9 @@ static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND Wnd SetBkColor( hdc, GetSysColor( bkgnd ) ); } + TRACE("rect=%s\n", wine_dbgstr_rect( &lpitem->Rect)); rect = lpitem->Rect; + MENU_AdjustMenuItemRect(MenuInfo, &rect); if (lpitem->fType & MF_OWNERDRAW) { @@ -1193,9 +1629,13 @@ static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND Wnd dis.itemID = lpitem->wID; dis.itemData = (DWORD)lpitem->dwItemData; dis.itemState = 0; - if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED; - if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED | ODS_DISABLED; - if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED; + if (lpitem->fState & MF_CHECKED) dis.itemState |= ODS_CHECKED; + if (lpitem->fState & MF_DEFAULT) dis.itemState |= ODS_DEFAULT; + if (lpitem->fState & MF_DISABLED) dis.itemState |= ODS_DISABLED; + if (lpitem->fState & MF_GRAYED) dis.itemState |= ODS_GRAYED | ODS_DISABLED; + if (lpitem->fState & MF_HILITE) dis.itemState |= ODS_SELECTED; + //if (!(MenuInfo->fFlags & MNF_UNDERLINE)) dis.itemState |= ODS_NOACCEL; + //if (MenuInfo->fFlags & MNF_INACTIVE) dis.itemState |= ODS_INACTIVE; dis.itemAction = odaction; /* ODA_DRAWENTIRE | ODA_SELECT | ODA_FOCUS; */ dis.hwndItem = (HWND) MenuInfo->Self; dis.hDC = hdc; @@ -1207,7 +1647,7 @@ static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND Wnd dis.rcItem.bottom); SendMessageW(WndOwner, WM_DRAWITEM, 0, (LPARAM) &dis); /* Draw the popup-menu arrow */ - if (lpitem->fType & MF_POPUP) + if (lpitem->hSubMenu) { RECT rectTemp; CopyRect(&rectTemp, &rect); @@ -1299,7 +1739,7 @@ static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND Wnd HBITMAP bm; INT y = rect.top + rect.bottom; RECT rc = rect; - int checked = FALSE; + BOOL checked = FALSE; UINT check_bitmap_width = GetSystemMetrics( SM_CXMENUCHECK ); UINT check_bitmap_height = GetSystemMetrics( SM_CYMENUCHECK ); /* Draw the check mark @@ -1340,12 +1780,12 @@ static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND Wnd bmpRect.left += check_bitmap_width + 2; if (!(checked && (MenuInfo->dwStyle & MNS_CHECKORBMP))) { - bmpRect.right = bmpRect.left + MenuInfo->maxBmpSize.cx; - MenuDrawBitmapItem(hdc, lpitem, &bmpRect, MenuInfo->Self, WndOwner, odaction, menuBar); + bmpRect.right = bmpRect.left + lpitem->maxBmpSize.cx; + MenuDrawBitmapItem(hdc, lpitem, &bmpRect, MenuInfo, WndOwner, odaction, menuBar); } } /* Draw the popup-menu arrow */ - if (lpitem->fType & MF_POPUP) + if (lpitem->hSubMenu) { RECT rectTemp; CopyRect(&rectTemp, &rect); @@ -1359,7 +1799,7 @@ static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND Wnd } else if( lpitem->hbmpItem) { /* Draw the bitmap */ - MenuDrawBitmapItem(hdc, lpitem, &rect, MenuInfo->Self, WndOwner, odaction, menuBar); + MenuDrawBitmapItem(hdc, lpitem, &rect, MenuInfo, WndOwner, odaction, menuBar); } /* process text if present */ @@ -1368,13 +1808,14 @@ static void FASTCALL MenuDrawMenuItem(HWND hWnd, PROSMENUINFO MenuInfo, HWND Wnd register int i = 0; HFONT hfontOld = 0; - UINT uFormat = menuBar ? DT_CENTER | DT_VCENTER | DT_SINGLELINE - : DT_LEFT | DT_VCENTER | DT_SINGLELINE; + UINT uFormat = menuBar ? + DT_CENTER | DT_VCENTER | DT_SINGLELINE : + DT_LEFT | DT_VCENTER | DT_SINGLELINE; - if(MenuInfo->dwStyle & MNS_CHECKORBMP) - rect.left += max(0, MenuInfo->maxBmpSize.cx - GetSystemMetrics(SM_CXMENUCHECK)); + if((MenuInfo->dwStyle & MNS_CHECKORBMP)) + rect.left += max(0, (int)(MenuInfo->cxTextAlign - GetSystemMetrics(SM_CXMENUCHECK))); else - rect.left += MenuInfo->maxBmpSize.cx; + rect.left += MenuInfo->cxTextAlign; if ( lpitem->fState & MFS_DEFAULT ) { @@ -1476,21 +1917,27 @@ static void FASTCALL MenuDrawPopupMenu(HWND hwnd, HDC hdc, HMENU hmenu ) DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT); /* draw menu items */ - if (MenuGetRosMenuInfo(&MenuInfo, hmenu) && MenuInfo.MenuItemCount) + //TRACE("hmenu %p Style %08x\n", hmenu, menu->dwStyle); + if (MenuGetRosMenuInfo(&MenuInfo, hmenu) && MenuInfo.cItems) { UINT u; - - MenuInitRosMenuItemInfo(&ItemInfo); + MenuInitRosMenuItemInfo(&ItemInfo); - for (u = 0; u < MenuInfo.MenuItemCount; u++) + for (u = 0; u < MenuInfo.cItems; u++) { if (MenuGetRosMenuItemInfo(MenuInfo.Self, u, &ItemInfo)) { - MenuDrawMenuItem(hwnd, &MenuInfo, MenuInfo.WndOwner, hdc, &ItemInfo, - MenuInfo.Height, FALSE, ODA_DRAWENTIRE); + HWND WndOwner = MenuInfo.spwndNotify ? MenuInfo.spwndNotify->head.h : NULL; + MenuDrawMenuItem(hwnd, &MenuInfo, WndOwner, hdc, &ItemInfo, + MenuInfo.cyMenu, FALSE, ODA_DRAWENTIRE); } } + /* draw scroll arrows */ + if (MenuInfo.dwArrowsOn) + MENU_DrawScrollArrows(&MenuInfo, hdc); + + MenuSetRosMenuInfo(&MenuInfo); MenuCleanupRosMenuItemInfo(&ItemInfo); } } else @@ -1524,15 +1971,54 @@ UINT MenuDrawMenuBar( HDC hDC, LPRECT lprect, HWND hwnd, MenuMenuBarCalcSize(hDC, lprect, &lppop, hwnd); - lprect->bottom = lprect->top + lppop.Height; + lprect->bottom = lprect->top + lppop.cyMenu; if (hfontOld) SelectObject( hDC, hfontOld); - return lppop.Height; + return lppop.cyMenu; } else return DrawMenuBarTemp(hwnd, hDC, lprect, hMenu, NULL); } +/*********************************************************************** + * MENU_InitPopup + * + * Popup menu initialization before WM_ENTERMENULOOP. + */ +static BOOL MENU_InitPopup( HWND hwndOwner, HMENU hmenu, UINT flags ) +{ + MENU *menu; + DWORD ex_style = 0; + ROSMENUINFO MenuInfo; + + TRACE("owner=%p hmenu=%p\n", hwndOwner, hmenu); + + if (!(menu = MENU_GetMenu( hmenu ))) return FALSE; + + /* store the owner for DrawItem */ + if (!IsWindow( hwndOwner )) + { + SetLastError( ERROR_INVALID_WINDOW_HANDLE ); + return FALSE; + } + MenuGetRosMenuInfo(&MenuInfo, menu->head.h); + //menu->hwndOwner = hwndOwner; + MenuInfo.spwndNotify = ValidateHwndNoErr( hwndOwner ); + + if (flags & TPM_LAYOUTRTL) + ex_style = WS_EX_LAYOUTRTL; + + /* NOTE: In Windows, top menu popup is not owned. */ + //menu->hWnd = CreateWindowExW( ex_style, WC_MENU, NULL, + MenuInfo.Wnd = CreateWindowExW( ex_style, WC_MENU, NULL, + WS_POPUP, 0, 0, 0, 0, + hwndOwner, 0, (HINSTANCE)GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE), + (LPVOID)hmenu ); + MenuSetRosMenuInfo(&MenuInfo); + if( !menu->hWnd ) return FALSE; + return TRUE; +} + /*********************************************************************** * MenuShowPopup * @@ -1552,34 +2038,28 @@ static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT fl hwndOwner, hmenu, id, x, y, xanchor, yanchor); if (! MenuGetRosMenuInfo(&MenuInfo, hmenu)) return FALSE; - if (MenuInfo.FocusedItem != NO_SELECTED_ITEM) + if (MenuInfo.iItem != NO_SELECTED_ITEM) { MenuInitRosMenuItemInfo(&ItemInfo); - if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo)) + if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.iItem, &ItemInfo)) { ItemInfo.fMask |= MIIM_STATE; ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT); - MenuSetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo); + MenuSetRosMenuItemInfo(MenuInfo.Self, MenuInfo.iItem, &ItemInfo); } MenuCleanupRosMenuItemInfo(&ItemInfo); - MenuInfo.FocusedItem = NO_SELECTED_ITEM; + MenuInfo.iItem = NO_SELECTED_ITEM; } - /* store the owner for DrawItem */ - if (!IsWindow(hwndOwner)) - { - SetLastError( ERROR_INVALID_WINDOW_HANDLE ); - return FALSE; - } - MenuInfo.WndOwner = hwndOwner; + //menu->dwArrowsOn = 0; + MenuInfo.dwArrowsOn = 0; MenuSetRosMenuInfo(&MenuInfo); - MenuPopupMenuCalcSize(&MenuInfo, hwndOwner); /* adjust popup menu pos so that it fits within the desktop */ - width = MenuInfo.Width + GetSystemMetrics(SM_CXBORDER); - height = MenuInfo.Height + GetSystemMetrics(SM_CYBORDER); + width = MenuInfo.cxMenu + GetSystemMetrics(SM_CXBORDER); + height = MenuInfo.cyMenu + GetSystemMetrics(SM_CYBORDER); /* FIXME: should use item rect */ pt.x = x; @@ -1588,6 +2068,9 @@ static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT fl info.cbSize = sizeof(info); GetMonitorInfoW( monitor, &info ); + if (flags & TPM_LAYOUTRTL) + flags ^= TPM_RIGHTALIGN; + if( flags & TPM_RIGHTALIGN ) x -= width; if( flags & TPM_CENTERALIGN ) x -= width / 2; @@ -1614,27 +2097,59 @@ static BOOL FASTCALL MenuShowPopup(HWND hwndOwner, HMENU hmenu, UINT id, UINT fl } if( y < info.rcMonitor.top ) y = info.rcMonitor.top; - /* NOTE: In Windows, top menu popup is not owned. */ - MenuInfo.Wnd = CreateWindowExW( 0, WC_MENU, NULL, - WS_POPUP, x, y, width, height, - hwndOwner, 0, (HINSTANCE) GetWindowLongPtrW(hwndOwner, GWLP_HINSTANCE), - (LPVOID) MenuInfo.Self); - if ( !MenuInfo.Wnd || ! MenuSetRosMenuInfo(&MenuInfo)) return FALSE; if (!top_popup) { top_popup = MenuInfo.Wnd; top_popup_hmenu = hmenu; } - - IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, MenuInfo.Wnd, OBJID_CLIENT, CHILDID_SELF, 0); - /* Display the window */ - SetWindowPos( MenuInfo.Wnd, HWND_TOPMOST, 0, 0, 0, 0, - SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE | SWP_NOACTIVATE); + SetWindowPos( MenuInfo.Wnd, HWND_TOPMOST, x, y, width, height, + SWP_SHOWWINDOW | SWP_NOACTIVATE); UpdateWindow( MenuInfo.Wnd ); + + IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPSTART, MenuInfo.Wnd, OBJID_CLIENT, CHILDID_SELF, 0); + return TRUE; } +/*********************************************************************** + * MENU_EnsureMenuItemVisible + */ +void +MENU_EnsureMenuItemVisible(PROSMENUINFO lppop, PROSMENUITEMINFO item, HDC hdc) +{ + if (lppop->dwArrowsOn) + { + //ITEM *item = &lppop->items[wIndex]; + UINT nMaxHeight = MENU_GetMaxPopupHeight(lppop); + UINT nOldPos = lppop->iTop; + RECT rc; + UINT arrow_bitmap_height; + BITMAP bmp; + + GetClientRect(lppop->Wnd, &rc); + + GetObjectW(get_down_arrow_bitmap(), sizeof(bmp), &bmp); + arrow_bitmap_height = bmp.bmHeight; + + rc.top += arrow_bitmap_height; + rc.bottom -= arrow_bitmap_height + MENU_BOTTOM_MARGIN; + + nMaxHeight -= GetSystemMetrics(SM_CYBORDER) + 2 * arrow_bitmap_height; + if (item->Rect.bottom > lppop->iTop + nMaxHeight) + { + lppop->iTop = item->Rect.bottom - nMaxHeight; + ScrollWindow(lppop->Wnd, 0, nOldPos - lppop->iTop, &rc, &rc); + MENU_DrawScrollArrows(lppop, hdc); + } + else if (item->Rect.top - MENU_TOP_MARGIN < lppop->iTop) + { + lppop->iTop = item->Rect.top - MENU_TOP_MARGIN; + ScrollWindow(lppop->Wnd, 0, nOldPos - lppop->iTop, &rc, &rc); + MENU_DrawScrollArrows(lppop, hdc); + } + } +} /*********************************************************************** * MenuSelectItem @@ -1648,9 +2163,9 @@ static void FASTCALL MenuSelectItem(HWND hwndOwner, PROSMENUINFO hmenu, UINT wIn TRACE("owner=%p menu=%p index=0x%04x select=0x%04x\n", hwndOwner, hmenu, wIndex, sendMenuSelect); - if (!hmenu || !hmenu->MenuItemCount || !hmenu->Wnd) return; - if (hmenu->FocusedItem == wIndex) return; - if (hmenu->Flags & MF_POPUP) hdc = GetDC(hmenu->Wnd); + if (!hmenu || !hmenu->cItems || !hmenu->Wnd) return; + if (hmenu->iItem == wIndex) return; + if (hmenu->fFlags & MNF_POPUP) hdc = GetDC(hmenu->Wnd); else hdc = GetDCEx(hmenu->Wnd, 0, DCX_CACHE | DCX_WINDOW); if (!top_popup) { top_popup = hmenu->Wnd; @@ -1662,46 +2177,51 @@ static void FASTCALL MenuSelectItem(HWND hwndOwner, PROSMENUINFO hmenu, UINT wIn MenuInitRosMenuItemInfo(&ItemInfo); /* Clear previous highlighted item */ - if (hmenu->FocusedItem != NO_SELECTED_ITEM) + if (hmenu->iItem != NO_SELECTED_ITEM) { - if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->FocusedItem, &ItemInfo)) + if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo)) { ItemInfo.fMask |= MIIM_STATE; ItemInfo.fState &= ~(MF_HILITE|MF_MOUSESELECT); - MenuSetRosMenuItemInfo(hmenu->Self, hmenu->FocusedItem, &ItemInfo); + MenuSetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo); } + //MENU_EnsureMenuItemVisible(hmenu, &ItemInfo, hdc); MenuDrawMenuItem(hmenu->Wnd, hmenu, hwndOwner, hdc, &ItemInfo, - hmenu->Height, ! (hmenu->Flags & MF_POPUP), + hmenu->cyMenu, !(hmenu->fFlags & MNF_POPUP), ODA_SELECT); } /* Highlight new item (if any) */ - hmenu->FocusedItem = wIndex; + hmenu->iItem = wIndex; MenuSetRosMenuInfo(hmenu); - if (hmenu->FocusedItem != NO_SELECTED_ITEM) + if (hmenu->iItem != NO_SELECTED_ITEM) { - if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->FocusedItem, &ItemInfo)) + if (MenuGetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo)) { if (!(ItemInfo.fType & MF_SEPARATOR)) { ItemInfo.fMask |= MIIM_STATE; ItemInfo.fState |= MF_HILITE; - MenuSetRosMenuItemInfo(hmenu->Self, hmenu->FocusedItem, &ItemInfo); + MenuSetRosMenuItemInfo(hmenu->Self, hmenu->iItem, &ItemInfo); MenuDrawMenuItem(hmenu->Wnd, hmenu, hwndOwner, hdc, - &ItemInfo, hmenu->Height, ! (hmenu->Flags & MF_POPUP), + &ItemInfo, hmenu->cyMenu, !(hmenu->fFlags & MNF_POPUP), ODA_SELECT); } if (sendMenuSelect) { - SendMessageW(hwndOwner, WM_MENUSELECT, - MAKELONG(ItemInfo.fType & MF_POPUP ? wIndex : ItemInfo.wID, - ItemInfo.fType | ItemInfo.fState | MF_MOUSESELECT | - (hmenu->Flags & MF_SYSMENU)), (LPARAM) hmenu->Self); + WPARAM wParam = MAKEWPARAM( ItemInfo.hSubMenu ? wIndex : ItemInfo.wID, + ItemInfo.fType | ItemInfo.fState | + (ItemInfo.hSubMenu ? MF_POPUP : 0) | + (hmenu->fFlags & MNF_SYSDESKMN ? MF_SYSMENU : 0 ) ); + + SendMessageW(hwndOwner, WM_MENUSELECT, wParam, (LPARAM) hmenu->Self); } } } - else if (sendMenuSelect) { - if(topmenu) { + else if (sendMenuSelect) + { + if(topmenu) + { int pos; pos = MenuFindSubMenu(&topmenu, hmenu->Self); if (pos != NO_SELECTED_ITEM) @@ -1709,11 +2229,11 @@ static void FASTCALL MenuSelectItem(HWND hwndOwner, PROSMENUINFO hmenu, UINT wIn if (MenuGetRosMenuInfo(&TopMenuInfo, topmenu) && MenuGetRosMenuItemInfo(topmenu, pos, &ItemInfo)) { - SendMessageW(hwndOwner, WM_MENUSELECT, - MAKELONG(Pos, ItemInfo.fType | ItemInfo.fState - | MF_MOUSESELECT - | (TopMenuInfo.Flags & MF_SYSMENU)), - (LPARAM) topmenu); + WPARAM wParam = MAKEWPARAM( Pos, ItemInfo.fType | ItemInfo.fState | + (ItemInfo.hSubMenu ? MF_POPUP : 0) | + (TopMenuInfo.fFlags & MNF_SYSDESKMN ? MF_SYSMENU : 0 ) ); + + SendMessageW(hwndOwner, WM_MENUSELECT, wParam, (LPARAM) topmenu); } } } @@ -1739,7 +2259,7 @@ MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset) TRACE("hwnd=%x menu=%x off=0x%04x\n", WndOwner, MenuInfo, Offset); /* Prevent looping */ - if (0 == MenuInfo->MenuItemCount || 0 == Offset) + if (0 == MenuInfo->cItems || 0 == Offset) return; else if (Offset < -1) Offset = -1; @@ -1748,7 +2268,7 @@ MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset) MenuInitRosMenuItemInfo(&ItemInfo); - OrigPos = MenuInfo->FocusedItem; + OrigPos = MenuInfo->iItem; if (OrigPos == NO_SELECTED_ITEM) /* NO_SELECTED_ITEM is not -1 ! */ { OrigPos = 0; @@ -1756,7 +2276,7 @@ MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset) } else { - i = MenuInfo->FocusedItem; + i = MenuInfo->iItem; } do @@ -1766,9 +2286,9 @@ MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset) /* Clip and wrap around */ if (i < 0) { - i = MenuInfo->MenuItemCount - 1; + i = MenuInfo->cItems - 1; } - else if (i >= MenuInfo->MenuItemCount) + else if (i >= MenuInfo->cItems) { i = 0; } @@ -1786,20 +2306,27 @@ MenuMoveSelection(HWND WndOwner, PROSMENUINFO MenuInfo, INT Offset) MenuCleanupRosMenuItemInfo(&ItemInfo); } -// -// This breaks some test results. Should handle A2U if called! -// -LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) +#if 0 +LRESULT WINAPI +PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) { -#ifdef __REACTOS__ +#ifdef __REACTOS__ // Do this now, remove after Server side is fixed. PWND pWnd; + PPOPUPMENU pPopupMenu; - pWnd = ValidateHwnd(Wnd); + pWnd = ValidateHwndNoErr(Wnd); if (pWnd) { if (!pWnd->fnid) { + if (Message != WM_NCCREATE) + { + return DefWindowProcW(Wnd, Message, wParam, lParam); + } NtUserSetWindowFNID(Wnd, FNID_MENU); + pPopupMenu = HeapAlloc( GetProcessHeap(), 0, sizeof(POPUPMENU) ); + pPopupMenu->spwndPopupMenu = pWnd; + SetWindowLongPtrW(Wnd, 0, (LONG_PTR)pPopupMenu); } else { @@ -1808,18 +2335,19 @@ LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM l ERR("Wrong window class for Menu!\n"); return 0; } + pPopupMenu = ((PMENUWND)pWnd)->ppopupmenu; } } #endif - TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam); + TRACE("hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam); switch(Message) { case WM_CREATE: { - CREATESTRUCTA *cs = (CREATESTRUCTA *) lParam; - SetWindowLongPtrA(Wnd, 0, (LONG_PTR)cs->lpCreateParams); + CREATESTRUCTW *cs = (CREATESTRUCTW *) lParam; + pPopupMenu->spmenu = ValidateHandle(cs->lpCreateParams, TYPE_MENU); return 0; } @@ -1830,16 +2358,15 @@ LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM l { PAINTSTRUCT ps; BeginPaint(Wnd, &ps); - MenuDrawPopupMenu(Wnd, ps.hdc, (HMENU)GetWindowLongPtrA(Wnd, 0)); + MenuDrawPopupMenu(Wnd, ps.hdc, pPopupMenu->spmenu->head.h); EndPaint(Wnd, &ps); return 0; } case WM_PRINTCLIENT: { - MenuDrawPopupMenu( Wnd, (HDC)wParam, - (HMENU)GetWindowLongPtrW( Wnd, 0 ) ); - return 0; + MenuDrawPopupMenu( Wnd, (HDC)wParam, pPopupMenu->spmenu->head.h); + return 0; } case WM_ERASEBKGND: @@ -1854,39 +2381,51 @@ LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM l } break; -#ifdef __REACTOS__ case WM_NCDESTROY: + { + HeapFree( GetProcessHeap(), 0, pPopupMenu ); + SetWindowLongPtrW(Wnd, 0, 0); NtUserSetWindowFNID(Wnd, FNID_DESTROY); break; -#endif + } case WM_SHOWWINDOW: if (0 != wParam) - { - if (0 == GetWindowLongPtrA(Wnd, 0)) - { + { + if (!pPopupMenu || !pPopupMenu->spmenu) + { OutputDebugStringA("no menu to display\n"); - } - } - else - { - SetWindowLongPtrA(Wnd, 0, 0); - } + } + } + /*else + { + pPopupMenu->spmenu = NULL; ///// WTF? + }*/ break; case MM_SETMENUHANDLE: - SetWindowLongPtrA(Wnd, 0, wParam); - break; + { + PMENU pmenu = ValidateHandle((HMENU)wParam, TYPE_MENU); + if (!pmenu) + { + ERR("Bad Menu Handle\n"); + break; + } + pPopupMenu->spmenu = pmenu; + break; + } case MM_GETMENUHANDLE: - case MN_GETHMENU: - return GetWindowLongPtrA(Wnd, 0); + case MN_GETHMENU: + return (LRESULT)(pPopupMenu ? (pPopupMenu->spmenu ? pPopupMenu->spmenu->head.h : NULL) : NULL); default: - return DefWindowProcA(Wnd, Message, wParam, lParam); + return DefWindowProcW(Wnd, Message, wParam, lParam); } + return 0; } +#endif LRESULT WINAPI PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) @@ -1958,6 +2497,12 @@ PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) } break; +#ifdef __REACTOS__ + case WM_NCDESTROY: + NtUserSetWindowFNID(Wnd, FNID_DESTROY); + break; +#endif + case WM_SHOWWINDOW: if (0 != wParam) { @@ -1987,6 +2532,42 @@ PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) return 0; } +// +// This breaks some test results. Should handle A2U if called! +// +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_GETHMENU: + return PopupMenuWndProcW(Wnd, Message, wParam, lParam); + + default: + return DefWindowProcA(Wnd, Message, wParam, lParam); + } + return 0; +} + /********************************************************************** * MENU_ParseResource * @@ -1995,11 +2576,11 @@ PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) * * NOTE: flags is equivalent to the mtOption field */ -static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode ) +static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu) { WORD flags, id = 0; HMENU hSubMenu; - LPCSTR str; + LPCWSTR str; BOOL end = FALSE; do @@ -2016,52 +2597,24 @@ static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode ) id = GET_WORD(res); res += sizeof(WORD); } - str = res; - if(!unicode) - res += strlen(str) + 1; - else - res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR); + 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, unicode))) - return NULL; - if(!unicode) - AppendMenuA(hMenu, flags, (UINT)hSubMenu, str); - else - AppendMenuW(hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str); + if(!(res = MENU_ParseResource(res, hSubMenu))) return NULL; + AppendMenuW(hMenu, flags, (UINT_PTR)hSubMenu, (LPCWSTR)str); } else /* Not a popup */ { - if(!unicode) - { - if (*str == 0) - flags = MF_SEPARATOR; - } - else - { - if (*(LPCWSTR)str == 0) - flags = MF_SEPARATOR; - } - - if (flags & MF_SEPARATOR) - { - if (!(flags & (MF_GRAYED | MF_DISABLED))) - flags |= MF_GRAYED | MF_DISABLED; - } - - if(!unicode) - AppendMenuA(hMenu, flags, id, *str ? str : NULL); - else - AppendMenuW(hMenu, flags, id, - *(LPCWSTR)str ? (LPCWSTR)str : NULL); + AppendMenuW(hMenu, flags, id, *(LPCWSTR)str ? (LPCWSTR)str : NULL); } } while(!end); return res; } - /********************************************************************** * MENUEX_ParseResource * @@ -2071,10 +2624,10 @@ static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode ) static LPCSTR MENUEX_ParseResource(LPCSTR res, HMENU hMenu) { WORD resinfo; - MENUITEMINFOW mii; - do { + MENUITEMINFOW mii; + mii.cbSize = sizeof(mii); mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE; mii.fType = GET_DWORD(res); @@ -2114,148 +2667,64 @@ static LPCSTR MENUEX_ParseResource(LPCSTR res, HMENU hMenu) return NULL; } mii.fMask |= MIIM_SUBMENU; - mii.fType |= MF_POPUP; - mii.wID = (UINT)mii.hSubMenu; } - else if (!mii.dwTypeData[0]) + else if (!mii.dwTypeData[0] && !(mii.fType & MF_SEPARATOR)) + { mii.fType |= MF_SEPARATOR; - - if (!InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii)) - ERR("InsertMenuItemW failed\n"); + } + InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii); } while (!(resinfo & MF_END)); return res; } -NTSTATUS WINAPI -User32LoadSysMenuTemplateForKernel(PVOID Arguments, ULONG ArgumentLength) + +/*********************************************************************** + * DrawMenuBarTemp (USER32.@) + * + * UNDOCUMENTED !! + * + * called by W98SE desk.cpl Control Panel Applet + * + * Not 100% sure about the param names, but close. + * + * @implemented + */ +DWORD WINAPI +DrawMenuBarTemp(HWND Wnd, HDC DC, LPRECT Rect, HMENU Menu, HFONT Font) { - HMENU hmenu = LoadMenuW(User32Instance, L"SYSMENU"); - LRESULT Result = (LRESULT)hmenu; - MENUINFO menuinfo = {0}; - MENUITEMINFOW info = {0}; + ROSMENUINFO MenuInfo; + ROSMENUITEMINFO ItemInfo; + UINT i; + HFONT FontOld = NULL; + BOOL flat_menu = FALSE; - // removing space for checkboxes from menu - menuinfo.cbSize = sizeof(menuinfo); - menuinfo.fMask = MIM_STYLE; - GetMenuInfo(hmenu, &menuinfo); - menuinfo.dwStyle |= MNS_NOCHECK; - SetMenuInfo(hmenu, &menuinfo); + SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0); - // adding bitmaps to menu items - info.cbSize = sizeof(info); - info.fMask |= MIIM_BITMAP; - info.hbmpItem = HBMMENU_POPUP_MINIMIZE; - SetMenuItemInfoW(hmenu, SC_MINIMIZE, FALSE, &info); - info.hbmpItem = HBMMENU_POPUP_RESTORE; - SetMenuItemInfoW(hmenu, SC_RESTORE, FALSE, &info); - info.hbmpItem = HBMMENU_POPUP_MAXIMIZE; - SetMenuItemInfoW(hmenu, SC_MAXIMIZE, FALSE, &info); - info.hbmpItem = HBMMENU_POPUP_CLOSE; - SetMenuItemInfoW(hmenu, SC_CLOSE, FALSE, &info); + if (NULL == Menu) + { + Menu = GetMenu(Wnd); + } - return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS)); -} + if (NULL == Font) + { + Font = hMenuFont; + } - -BOOL -MenuInit(VOID) -{ - NONCLIENTMETRICSW ncm; - - /* get the menu font */ - if(!hMenuFont || !hMenuFontBold) - { - ncm.cbSize = sizeof(ncm); - if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)) - { - ERR("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n"); - return FALSE; - } - - hMenuFont = CreateFontIndirectW(&ncm.lfMenuFont); - if(hMenuFont == NULL) - { - ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n"); - return FALSE; - } - - ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000); - hMenuFontBold = CreateFontIndirectW(&ncm.lfMenuFont); - if(hMenuFontBold == NULL) - { - ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n"); - DeleteObject(hMenuFont); - hMenuFont = NULL; - return FALSE; - } - } - - return TRUE; -} - -VOID -MenuCleanup(VOID) -{ - if (hMenuFont) - { - DeleteObject(hMenuFont); - hMenuFont = NULL; - } - - if (hMenuFontBold) - { - DeleteObject(hMenuFontBold); - hMenuFontBold = NULL; - } -} - -/*********************************************************************** - * DrawMenuBarTemp (USER32.@) - * - * UNDOCUMENTED !! - * - * called by W98SE desk.cpl Control Panel Applet - * - * Not 100% sure about the param names, but close. - * - * @implemented - */ -DWORD WINAPI -DrawMenuBarTemp(HWND Wnd, HDC DC, LPRECT Rect, HMENU Menu, HFONT Font) -{ - ROSMENUINFO MenuInfo; - ROSMENUITEMINFO ItemInfo; - UINT i; - HFONT FontOld = NULL; - BOOL flat_menu = FALSE; - - SystemParametersInfoW (SPI_GETFLATMENU, 0, &flat_menu, 0); - - if (NULL == Menu) - { - Menu = GetMenu(Wnd); - } - - if (NULL == Font) - { - Font = hMenuFont; - } - - if (NULL == Rect || ! MenuGetRosMenuInfo(&MenuInfo, Menu)) - { - return GetSystemMetrics(SM_CYMENU); - } + if (NULL == Rect || ! MenuGetRosMenuInfo(&MenuInfo, Menu)) + { + return GetSystemMetrics(SM_CYMENU); + } TRACE("(%x, %x, %p, %x, %x)\n", Wnd, DC, Rect, Menu, Font); FontOld = SelectObject(DC, Font); - if (0 == MenuInfo.Height) + if (0 == MenuInfo.cyMenu) { MenuMenuBarCalcSize(DC, Rect, &MenuInfo, Wnd); } - Rect->bottom = Rect->top + MenuInfo.Height; + Rect->bottom = Rect->top + MenuInfo.cyMenu; FillRect(DC, Rect, GetSysColorBrush(flat_menu ? COLOR_MENUBAR : COLOR_MENU)); @@ -2264,28 +2733,29 @@ DrawMenuBarTemp(HWND Wnd, HDC DC, LPRECT Rect, HMENU Menu, HFONT Font) MoveToEx(DC, Rect->left, Rect->bottom - 1, NULL); LineTo(DC, Rect->right, Rect->bottom - 1); - if (0 == MenuInfo.MenuItemCount) + if (0 == MenuInfo.cItems) { SelectObject(DC, FontOld); return GetSystemMetrics(SM_CYMENU); } MenuInitRosMenuItemInfo(&ItemInfo); - for (i = 0; i < MenuInfo.MenuItemCount; i++) + for (i = 0; i < MenuInfo.cItems; i++) { if (MenuGetRosMenuItemInfo(MenuInfo.Self, i, &ItemInfo)) { MenuDrawMenuItem(Wnd, &MenuInfo, Wnd, DC, &ItemInfo, - MenuInfo.Height, TRUE, ODA_DRAWENTIRE); + MenuInfo.cyMenu, TRUE, ODA_DRAWENTIRE); } } MenuCleanupRosMenuItemInfo(&ItemInfo); SelectObject(DC, FontOld); - return MenuInfo.Height; + return MenuInfo.cyMenu; } + /*********************************************************************** * MenuShowSubPopup * @@ -2295,7 +2765,6 @@ DrawMenuBarTemp(HWND Wnd, HDC DC, LPRECT Rect, HMENU Menu, HFONT Font) static HMENU FASTCALL MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Flags) { - extern void FASTCALL NcGetSysPopupPos(HWND Wnd, RECT *Rect); RECT Rect; ROSMENUITEMINFO ItemInfo; ROSMENUINFO SubMenuInfo; @@ -2304,18 +2773,18 @@ MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Fl TRACE("owner=%x menu=%p 0x%04x\n", WndOwner, MenuInfo, SelectFirst); - if (NO_SELECTED_ITEM == MenuInfo->FocusedItem) + if (NO_SELECTED_ITEM == MenuInfo->iItem) { return MenuInfo->Self; } MenuInitRosMenuItemInfo(&ItemInfo); - if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo)) + if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo)) { MenuCleanupRosMenuItemInfo(&ItemInfo); return MenuInfo->Self; } - if (0 == (ItemInfo.fType & MF_POPUP) || 0 != (ItemInfo.fState & (MF_GRAYED | MF_DISABLED))) + if (0 == (ItemInfo.hSubMenu) || 0 != (ItemInfo.fState & (MF_GRAYED | MF_DISABLED))) { MenuCleanupRosMenuItemInfo(&ItemInfo); return MenuInfo->Self; @@ -2328,10 +2797,10 @@ MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Fl if (0 == (Flags & TPM_NONOTIFY)) { SendMessageW(WndOwner, WM_INITMENUPOPUP, (WPARAM) ItemInfo.hSubMenu, - MAKELONG(MenuInfo->FocusedItem, IS_SYSTEM_MENU(MenuInfo))); + MAKELPARAM(MenuInfo->iItem, IS_SYSTEM_MENU(MenuInfo))); } - if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo)) + if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo)) { MenuCleanupRosMenuItemInfo(&ItemInfo); return MenuInfo->Self; @@ -2341,7 +2810,7 @@ MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Fl /* correct item if modified as a reaction to WM_INITMENUPOPUP message */ if (0 == (ItemInfo.fState & MF_HILITE)) { - if (0 != (MenuInfo->Flags & MF_POPUP)) + if (0 != (MenuInfo->fFlags & MNF_POPUP)) { Dc = GetDC(MenuInfo->Wnd); } @@ -2353,9 +2822,9 @@ MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Fl SelectObject(Dc, hMenuFont); ItemInfo.fMask |= MIIM_STATE; ItemInfo.fState |= MF_HILITE; - MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo); - MenuDrawMenuItem(MenuInfo->Wnd, MenuInfo, WndOwner, Dc, &ItemInfo, MenuInfo->Height, - ! (MenuInfo->Flags & MF_POPUP), ODA_DRAWENTIRE); + MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo); + MenuDrawMenuItem(MenuInfo->Wnd, MenuInfo, WndOwner, Dc, &ItemInfo, MenuInfo->cyMenu, + !(MenuInfo->fFlags & MNF_POPUP), ODA_DRAWENTIRE); ReleaseDC(MenuInfo->Wnd, Dc); } @@ -2367,44 +2836,60 @@ MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Fl ItemInfo.fMask |= MIIM_STATE; ItemInfo.fState |= MF_MOUSESELECT; - MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo); + MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo); if (IS_SYSTEM_MENU(MenuInfo)) - { + { + ERR("Right click on window bar and Draw system menu!\n"); MenuInitSysMenuPopup(ItemInfo.hSubMenu, GetWindowLongPtrW(MenuInfo->Wnd, GWL_STYLE), GetClassLongPtrW(MenuInfo->Wnd, GCL_STYLE), HTSYSMENU); - + if (Flags & TPM_LAYOUTRTL) Rect.left; NcGetSysPopupPos(MenuInfo->Wnd, &Rect); Rect.top = Rect.bottom; Rect.right = GetSystemMetrics(SM_CXSIZE); Rect.bottom = GetSystemMetrics(SM_CYSIZE); - } + } else - { + { GetWindowRect(MenuInfo->Wnd, &Rect); - if (0 != (MenuInfo->Flags & MF_POPUP)) - { - Rect.left += ItemInfo.Rect.right - GetSystemMetrics(SM_CXBORDER); - Rect.top += ItemInfo.Rect.top - 3; - Rect.right = ItemInfo.Rect.left - ItemInfo.Rect.right + GetSystemMetrics(SM_CXBORDER); - Rect.bottom = ItemInfo.Rect.top - ItemInfo.Rect.bottom - 3 - 2 - - GetSystemMetrics(SM_CYBORDER); - } + if (0 != (MenuInfo->fFlags & MNF_POPUP)) + { + RECT rc = ItemInfo.Rect; + + MENU_AdjustMenuItemRect(MenuInfo, &rc); + + if(Flags & TPM_LAYOUTRTL) + Rect.left += GetSystemMetrics(SM_CXBORDER); + else + Rect.left += ItemInfo.Rect.right- GetSystemMetrics(SM_CXBORDER); + Rect.top += rc.top - MENU_TOP_MARGIN;//3; + Rect.right = rc.left - rc.right + GetSystemMetrics(SM_CXBORDER); + Rect.bottom = rc.top - rc.bottom - MENU_TOP_MARGIN - MENU_BOTTOM_MARGIN/*2*/ + - GetSystemMetrics(SM_CYBORDER); + } else - { - Rect.left += ItemInfo.Rect.left; + { + if(Flags & TPM_LAYOUTRTL) + Rect.left += Rect.right - ItemInfo.Rect.left; + else + Rect.left += ItemInfo.Rect.left; Rect.top += ItemInfo.Rect.bottom; Rect.right = ItemInfo.Rect.right - ItemInfo.Rect.left; Rect.bottom = ItemInfo.Rect.bottom - ItemInfo.Rect.top; - } - } + } + } + + /* use default alignment for submenus */ + Flags &= ~(TPM_CENTERALIGN | TPM_RIGHTALIGN | TPM_VCENTERALIGN | TPM_BOTTOMALIGN); + + MENU_InitPopup( WndOwner, ItemInfo.hSubMenu, Flags ); - MenuShowPopup(WndOwner, ItemInfo.hSubMenu, MenuInfo->FocusedItem, Flags, + MenuShowPopup(WndOwner, ItemInfo.hSubMenu, MenuInfo->iItem, Flags, Rect.left, Rect.top, Rect.right, Rect.bottom ); if (SelectFirst && MenuGetRosMenuInfo(&SubMenuInfo, ItemInfo.hSubMenu)) - { + { MenuMoveSelection(WndOwner, &SubMenuInfo, ITEM_NEXT); - } + } Ret = ItemInfo.hSubMenu; MenuCleanupRosMenuItemInfo(&ItemInfo); @@ -2421,11 +2906,10 @@ MenuShowSubPopup(HWND WndOwner, PROSMENUINFO MenuInfo, BOOL SelectFirst, UINT Fl */ void MENU_EndMenu( HWND hwnd ) { - ROSMENUINFO MenuInfo; - BOOL Ret = FALSE; - if (top_popup_hmenu) - Ret = MenuGetRosMenuInfo(&MenuInfo, top_popup_hmenu); - if (Ret && hwnd == MenuInfo.WndOwner) EndMenu(); + MENU *menu; + menu = top_popup_hmenu ? MENU_GetMenu( top_popup_hmenu ) : NULL; + if (menu && ( hwnd == menu->hWnd || hwnd == (menu->spwndNotify ? menu->spwndNotify->head.h : NULL)) ) + EndMenu(); } /*********************************************************************** @@ -2442,12 +2926,12 @@ MenuHideSubPopups(HWND WndOwner, PROSMENUINFO MenuInfo, TRACE("owner=%x menu=%x 0x%04x\n", WndOwner, MenuInfo, SendMenuSelect); - if (NULL != MenuInfo && NULL != top_popup && NO_SELECTED_ITEM != MenuInfo->FocusedItem) + if (NULL != MenuInfo && NULL != top_popup && NO_SELECTED_ITEM != MenuInfo->iItem) { MenuInitRosMenuItemInfo(&ItemInfo); ItemInfo.fMask |= MIIM_FTYPE | MIIM_STATE; - if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo) - || 0 == (ItemInfo.fType & MF_POPUP) + if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo) + || 0 == (ItemInfo.hSubMenu) || 0 == (ItemInfo.fState & MF_MOUSESELECT)) { MenuCleanupRosMenuItemInfo(&ItemInfo); @@ -2455,7 +2939,7 @@ MenuHideSubPopups(HWND WndOwner, PROSMENUINFO MenuInfo, } ItemInfo.fState &= ~MF_MOUSESELECT; ItemInfo.fMask |= MIIM_STATE; - MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo); + MenuSetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo); if (MenuGetRosMenuInfo(&SubMenuInfo, ItemInfo.hSubMenu)) { MenuHideSubPopups(WndOwner, &SubMenuInfo, FALSE, wFlags); @@ -2485,7 +2969,7 @@ MenuSwitchTracking(MTRACKER* Mt, PROSMENUINFO PtMenuInfo, UINT Index, UINT wFlag if (MenuGetRosMenuInfo(&TopMenuInfo, Mt->TopMenu) && Mt->TopMenu != PtMenuInfo->Self && - 0 == ((PtMenuInfo->Flags | TopMenuInfo.Flags) & MF_POPUP)) + 0 == ((PtMenuInfo->fFlags | TopMenuInfo.fFlags) & MNF_POPUP)) { /* both are top level menus (system and menu-bar) */ MenuHideSubPopups(Mt->OwnerWnd, &TopMenuInfo, FALSE, wFlags); @@ -2518,13 +3002,13 @@ MenuExecFocusedItem(MTRACKER *Mt, PROSMENUINFO MenuInfo, UINT Flags) TRACE("%p menu=%p\n", Mt, MenuInfo); - if (0 == MenuInfo->MenuItemCount || NO_SELECTED_ITEM == MenuInfo->FocusedItem) + if (0 == MenuInfo->cItems || NO_SELECTED_ITEM == MenuInfo->iItem) { return -1; } MenuInitRosMenuItemInfo(&ItemInfo); - if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->FocusedItem, &ItemInfo)) + if (! MenuGetRosMenuItemInfo(MenuInfo->Self, MenuInfo->iItem, &ItemInfo)) { MenuCleanupRosMenuItemInfo(&ItemInfo); return -1; @@ -2532,7 +3016,7 @@ MenuExecFocusedItem(MTRACKER *Mt, PROSMENUINFO MenuInfo, UINT Flags) TRACE("%p %08x %p\n", MenuInfo, ItemInfo.wID, ItemInfo.hSubMenu); - if (0 == (ItemInfo.fType & MF_POPUP)) + if (0 == (ItemInfo.hSubMenu)) { if (0 == (ItemInfo.fState & (MF_GRAYED | MF_DISABLED)) && 0 == (ItemInfo.fType & MF_SEPARATOR)) @@ -2541,17 +3025,19 @@ MenuExecFocusedItem(MTRACKER *Mt, PROSMENUINFO MenuInfo, UINT Flags) do not send a message to the owner */ if (0 == (Flags & TPM_RETURNCMD)) { - if (0 != (MenuInfo->Flags & MF_SYSMENU)) + if (0 != (MenuInfo->fFlags & MNF_SYSDESKMN)) { PostMessageW(Mt->OwnerWnd, WM_SYSCOMMAND, ItemInfo.wID, MAKELPARAM((SHORT) Mt->Pt.x, (SHORT) Mt->Pt.y)); } else { - if (MenuInfo->dwStyle & MNS_NOTIFYBYPOS) - PostMessageW(Mt->OwnerWnd, WM_MENUCOMMAND, - MenuInfo->FocusedItem, - (LPARAM)MenuInfo->Self); + ROSMENUINFO topmenuI; + BOOL ret = MenuGetRosMenuInfo(&topmenuI, Mt->TopMenu); + DWORD dwStyle = MenuInfo->dwStyle | (ret ? topmenuI.dwStyle : 0); + + if (dwStyle & MNS_NOTIFYBYPOS) + PostMessageW(Mt->OwnerWnd, WM_MENUCOMMAND, MenuInfo->iItem, (LPARAM)MenuInfo->Self); else PostMessageW(Mt->OwnerWnd, WM_COMMAND, ItemInfo.wID, 0); } @@ -2576,7 +3062,7 @@ MenuExecFocusedItem(MTRACKER *Mt, PROSMENUINFO MenuInfo, UINT Flags) * Return TRUE if we can go on with menu tracking. */ static BOOL FASTCALL -MenuButtonDown(MTRACKER* Mt, HMENU PtMenu, UINT Flags) +MENU_ButtonDown(MTRACKER* Mt, HMENU PtMenu, UINT Flags) { int Index; ROSMENUINFO MenuInfo; @@ -2608,7 +3094,7 @@ MenuButtonDown(MTRACKER* Mt, HMENU PtMenu, UINT Flags) if (!(Item.fType & MF_SEPARATOR) && !(Item.fState & (MFS_DISABLED | MFS_GRAYED)) ) { - if (MenuInfo.FocusedItem != Index) + if (MenuInfo.iItem != Index) { MenuSwitchTracking(Mt, &MenuInfo, Index, Flags); } @@ -2639,9 +3125,9 @@ MenuButtonDown(MTRACKER* Mt, HMENU PtMenu, UINT Flags) * */ static INT FASTCALL -MenuButtonUp(MTRACKER *Mt, HMENU PtMenu, UINT Flags) +MENU_ButtonUp(MTRACKER *Mt, HMENU PtMenu, UINT Flags) { - UINT Id; + INT Id; ROSMENUINFO MenuInfo; ROSMENUITEMINFO ItemInfo; @@ -2661,9 +3147,9 @@ MenuButtonUp(MTRACKER *Mt, HMENU PtMenu, UINT Flags) } MenuInitRosMenuItemInfo(&ItemInfo); if (0 <= Id && MenuGetRosMenuItemInfo(MenuInfo.Self, Id, &ItemInfo) && - MenuInfo.FocusedItem == Id) + MenuInfo.iItem == Id) { - if (0 == (ItemInfo.fType & MF_POPUP)) + if (0 == (ItemInfo.hSubMenu)) { INT ExecutedMenuId = MenuExecFocusedItem(Mt, &MenuInfo, Flags); MenuCleanupRosMenuItemInfo(&ItemInfo); @@ -2694,56 +3180,41 @@ MenuButtonUp(MTRACKER *Mt, HMENU PtMenu, UINT Flags) * Walks menu chain trying to find a menu pt maps to. */ static HMENU FASTCALL -MenuPtMenu(HMENU Menu, POINT Pt) +MENU_PtMenu(HMENU hMenu, POINT pt) { - extern LRESULT DefWndNCHitTest(HWND hWnd, POINT Point); - ROSMENUINFO MenuInfo; - ROSMENUITEMINFO ItemInfo; - HMENU Ret = NULL; - INT Ht; + MENU *menu; + PITEM pItem; + HMENU ret = NULL; - if (! MenuGetRosMenuInfo(&MenuInfo, Menu)) - { - return NULL; - } + menu = MENU_GetMenu( hMenu ); + if (!menu) return NULL; /* try subpopup first (if any) */ - if (NO_SELECTED_ITEM != MenuInfo.FocusedItem) - { - MenuInitRosMenuItemInfo(&ItemInfo); - if (MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo) && - 0 != (ItemInfo.fType & MF_POPUP) && - 0 != (ItemInfo.fState & MF_MOUSESELECT)) - { - Ret = MenuPtMenu(ItemInfo.hSubMenu, Pt); - if (NULL != Ret) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return Ret; - } - } - MenuCleanupRosMenuItemInfo(&ItemInfo); - } + if (menu->iItem != NO_SELECTED_ITEM) + { + pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL; + if ( pItem ) pItem = &pItem[menu->iItem]; + if ( pItem && pItem->spSubMenu && pItem->fState & MF_MOUSESELECT) + { + PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu); + ret = MENU_PtMenu( UserHMGetHandle(pSubMenu), pt); + } + } /* check the current window (avoiding WM_HITTEST) */ - Ht = DefWndNCHitTest(MenuInfo.Wnd, Pt); - if (0 != (MenuInfo.Flags & MF_POPUP)) - { - if (HTNOWHERE != Ht && HTERROR != Ht) - { - Ret = Menu; - } - } - else if (HTSYSMENU == Ht) - { - Ret = NtUserGetSystemMenu(MenuInfo.Wnd, FALSE); - } - else if (HTMENU == Ht) - { - Ret = GetMenu(MenuInfo.Wnd); - } - - return Ret; + if (!ret) + { + INT ht = DefWndNCHitTest(menu->hWnd, pt); + if ( menu->fFlags & MNF_POPUP ) + { + if (ht != HTNOWHERE && ht != HTERROR) ret = hMenu; + } + else if (ht == HTSYSMENU) + ret = NtUserGetSystemMenu(menu->hWnd, FALSE); + else if (ht == HTMENU) + ret = GetMenu( menu->hWnd ); + } + return ret; } /*********************************************************************** @@ -2754,7 +3225,7 @@ MenuPtMenu(HMENU Menu, POINT Pt) static BOOL FASTCALL MenuMouseMove(MTRACKER *Mt, HMENU PtMenu, UINT Flags) { - UINT Index; + INT Index; ROSMENUINFO MenuInfo; ROSMENUITEMINFO ItemInfo; @@ -2787,7 +3258,7 @@ MenuMouseMove(MTRACKER *Mt, HMENU PtMenu, UINT Flags) TRUE, Mt->TopMenu); } } - else if (MenuInfo.FocusedItem != Index) + else if (MenuInfo.iItem != Index) { MenuInitRosMenuItemInfo(&ItemInfo); if (MenuGetRosMenuItemInfo(MenuInfo.Self, Index, &ItemInfo) && @@ -2808,32 +3279,25 @@ MenuMouseMove(MTRACKER *Mt, HMENU PtMenu, UINT Flags) * * Return the handle of the selected sub-popup menu (if any). */ -static HMENU FASTCALL -MenuGetSubPopup(HMENU Menu) +static +HMENU MENU_GetSubPopup( HMENU hmenu ) { - ROSMENUINFO MenuInfo; - ROSMENUITEMINFO ItemInfo; + MENU *menu; + ITEM *item; - if (! MenuGetRosMenuInfo(&MenuInfo, Menu) - || NO_SELECTED_ITEM == MenuInfo.FocusedItem) - { - return NULL; - } + menu = MENU_GetMenu( hmenu ); - MenuInitRosMenuItemInfo(&ItemInfo); - if (! MenuGetRosMenuItemInfo(MenuInfo.Self, MenuInfo.FocusedItem, &ItemInfo)) - { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return NULL; - } - if (0 != (ItemInfo.fType & MF_POPUP) && 0 != (ItemInfo.fState & MF_MOUSESELECT)) + if ((!menu) || (menu->iItem == NO_SELECTED_ITEM)) return 0; + + //item = &menu->rgItems[menu->iItem]; + item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL; + if (item) item = &item[menu->iItem]; + if (item && (item->spSubMenu) && (item->fState & MF_MOUSESELECT)) { - MenuCleanupRosMenuItemInfo(&ItemInfo); - return ItemInfo.hSubMenu; + PMENU pSubMenu = DesktopPtrToUser(item->spSubMenu); + return UserHMGetHandle(pSubMenu); } - - MenuCleanupRosMenuItemInfo(&ItemInfo); - return NULL; + return 0; } /*********************************************************************** @@ -2852,8 +3316,8 @@ MenuDoNextMenu(MTRACKER* Mt, UINT Vk, UINT wFlags) return (LRESULT) FALSE; } - if ((VK_LEFT == Vk && 0 == TopMenuInfo.FocusedItem) - || (VK_RIGHT == Vk && TopMenuInfo.FocusedItem == TopMenuInfo.MenuItemCount - 1)) + if ((VK_LEFT == Vk && 0 == TopMenuInfo.iItem) + || (VK_RIGHT == Vk && TopMenuInfo.iItem == TopMenuInfo.cItems - 1)) { MDINEXTMENU NextMenu; HMENU NewMenu; @@ -2888,7 +3352,7 @@ MenuDoNextMenu(MTRACKER* Mt, UINT Vk, UINT wFlags) { return FALSE; } - Id = MenuInfo.MenuItemCount - 1; + Id = MenuInfo.cItems - 1; } } else if (0 != (Style & WS_SYSMENU)) @@ -2978,20 +3442,20 @@ MenuSuspendPopup(MTRACKER* Mt, UINT uMsg) switch( uMsg ) { - case WM_KEYDOWN: - PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE); - if( msg.message == WM_KEYUP || msg.message == WM_PAINT ) - { - PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE); - PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE); - if( msg.message == WM_KEYDOWN && - (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT)) - { - Mt->TrackFlags |= TF_SUSPENDPOPUP; - return TRUE; - } - } - break; + case WM_KEYDOWN: + PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE); + if( msg.message == WM_KEYUP || msg.message == WM_PAINT ) + { + PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_REMOVE); + PeekMessageW( &msg, 0, 0, 0, PM_NOYIELD | PM_NOREMOVE); + if( msg.message == WM_KEYDOWN && + (msg.wParam == VK_LEFT || msg.wParam == VK_RIGHT)) + { + Mt->TrackFlags |= TF_SUSPENDPOPUP; + return TRUE; + } + } + break; } /* failures go through this */ Mt->TrackFlags &= ~TF_SUSPENDPOPUP; @@ -3013,7 +3477,7 @@ MenuKeyEscape(MTRACKER *Mt, UINT Flags) if (Mt->CurrentMenu != Mt->TopMenu) { if (MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu) - && 0 != (MenuInfo.Flags & MF_POPUP)) + && 0 != (MenuInfo.fFlags & MNF_POPUP)) { MenuPrev = MenuTmp = Mt->TopMenu; @@ -3021,7 +3485,7 @@ MenuKeyEscape(MTRACKER *Mt, UINT Flags) while (MenuTmp != Mt->CurrentMenu) { MenuPrev = MenuTmp; - MenuTmp = MenuGetSubPopup(MenuPrev); + MenuTmp = MENU_GetSubPopup(MenuPrev); } if (MenuGetRosMenuInfo(&MenuInfo, MenuPrev)) @@ -3052,13 +3516,8 @@ MenuKeyLeft(MTRACKER* Mt, UINT Flags) MenuPrev = MenuTmp = Mt->TopMenu; - if (! MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu)) - { - return; - } - /* Try to move 1 column left (if possible) */ - if ( (PrevCol = MenuGetStartOfPrevColumn(&MenuInfo)) != NO_SELECTED_ITEM) + if ( (PrevCol = MENU_GetStartOfPrevColumn(Mt->CurrentMenu)) != NO_SELECTED_ITEM) { if (MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu)) { @@ -3071,7 +3530,7 @@ MenuKeyLeft(MTRACKER* Mt, UINT Flags) while (MenuTmp != Mt->CurrentMenu) { MenuPrev = MenuTmp; - MenuTmp = MenuGetSubPopup(MenuPrev); + MenuTmp = MENU_GetSubPopup(MenuPrev); } if (! MenuGetRosMenuInfo(&PrevMenuInfo, MenuPrev)) @@ -3085,7 +3544,7 @@ MenuKeyLeft(MTRACKER* Mt, UINT Flags) { return; } - if ((MenuPrev == Mt->TopMenu) && !(TopMenuInfo.Flags & MF_POPUP)) + if ((MenuPrev == Mt->TopMenu) && !(TopMenuInfo.fFlags & MNF_POPUP)) { /* move menu bar selection if no more popups are left */ @@ -3125,7 +3584,7 @@ static void FASTCALL MenuKeyRight(MTRACKER *Mt, UINT Flags) Mt->CurrentMenu, Mt->TopMenu); if (! MenuGetRosMenuInfo(&MenuInfo, Mt->TopMenu)) return; - if ((MenuInfo.Flags & MF_POPUP) || (Mt->CurrentMenu != Mt->TopMenu)) + if ((MenuInfo.fFlags & MNF_POPUP) || (Mt->CurrentMenu != Mt->TopMenu)) { /* If already displaying a popup, try to display sub-popup */ @@ -3139,13 +3598,8 @@ static void FASTCALL MenuKeyRight(MTRACKER *Mt, UINT Flags) if (hmenutmp != Mt->CurrentMenu) return; } - if (! MenuGetRosMenuInfo(&CurrentMenuInfo, Mt->CurrentMenu)) - { - return; - } - /* Check to see if there's another column */ - if ( (NextCol = MenuGetStartOfNextColumn(&CurrentMenuInfo)) != NO_SELECTED_ITEM) + if ( (NextCol = MENU_GetStartOfNextColumn(Mt->CurrentMenu)) != NO_SELECTED_ITEM) { TRACE("Going to %d.\n", NextCol); if (MenuGetRosMenuInfo(&MenuInfo, Mt->CurrentMenu)) @@ -3155,7 +3609,7 @@ static void FASTCALL MenuKeyRight(MTRACKER *Mt, UINT Flags) return; } - if (!(MenuInfo.Flags & MF_POPUP)) /* menu bar tracking */ + if (!(MenuInfo.fFlags & MNF_POPUP)) /* menu bar tracking */ { if (Mt->CurrentMenu != Mt->TopMenu) { @@ -3194,6 +3648,7 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, MSG msg; ROSMENUINFO MenuInfo; ROSMENUITEMINFO ItemInfo; + PMENU menu; BOOL fRemove; INT executedMenuId = -1; MTRACKER mt; @@ -3213,12 +3668,10 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, if (!IsMenu(hmenu)) { - WARN("Invalid menu handle %p\n", hmenu); - SetLastError( ERROR_INVALID_MENU_HANDLE ); + WARN("Invalid menu handle %p\n", hmenu); // Error already set in IsMenu. return FALSE; } - fEndMenu = FALSE; if (! MenuGetRosMenuInfo(&MenuInfo, hmenu)) { return FALSE; @@ -3227,7 +3680,7 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, if (wFlags & TPM_BUTTONDOWN) { /* Get the result in order to start the tracking or not */ - fRemove = MenuButtonDown( &mt, hmenu, wFlags ); + fRemove = MENU_ButtonDown( &mt, hmenu, wFlags ); fEndMenu = !fRemove; } @@ -3238,10 +3691,10 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, NtUserxSetGUIThreadHandle(MSQ_STATE_MENUOWNER, capture_win); // 1 SetCapture(capture_win); // 2 - while (! fEndMenu) + while (!fEndMenu) { BOOL ErrorExit = FALSE; - PVOID menu = ValidateHandle(mt.CurrentMenu, TYPE_MENU); + menu = MENU_GetMenu( mt.CurrentMenu ); if (!menu) /* sometimes happens if I do a window manager close */ break; @@ -3259,14 +3712,14 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, else { /* ReactOS Check */ - if (!ValidateHwnd(mt.OwnerWnd) || !ValidateHwnd(MenuInfo.Wnd)) + if (!ValidateHwndNoErr(mt.OwnerWnd) || !ValidateHwndNoErr(MenuInfo.Wnd)) { ErrorExit = TRUE; // Do not wait on dead windows, now test_capture_4 works. break; } if (!enterIdleSent) { - HWND win = MenuInfo.Flags & MF_POPUP ? MenuInfo.Wnd : NULL; + HWND win = MenuInfo.fFlags & MNF_POPUP ? MenuInfo.Wnd : NULL; enterIdleSent = TRUE; SendMessageW( mt.OwnerWnd, WM_ENTERIDLE, MSGF_MENU, (LPARAM) win); } @@ -3307,7 +3760,7 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, mt.Pt.y = (short)HIWORD(msg.lParam); /* Find a menu for this mouse event */ - hmenu = MenuPtMenu(mt.TopMenu, mt.Pt); + hmenu = MENU_PtMenu(mt.TopMenu, mt.Pt); switch(msg.message) { @@ -3321,7 +3774,7 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, case WM_LBUTTONDOWN: /* If the message belongs to the menu, removes it from the queue */ /* Else, end menu tracking */ - fRemove = MenuButtonDown(&mt, hmenu, wFlags); + fRemove = MENU_ButtonDown(&mt, hmenu, wFlags); fEndMenu = !fRemove; break; @@ -3332,7 +3785,7 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, /* Check if a menu was selected by the mouse */ if (hmenu) { - executedMenuId = MenuButtonUp( &mt, hmenu, wFlags); + executedMenuId = MENU_ButtonUp( &mt, hmenu, wFlags); TRACE("executedMenuId %d\n", executedMenuId); /* End the loop if executedMenuId is an item ID */ @@ -3374,10 +3827,8 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, case VK_END: if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) { - MenuSelectItem(mt.OwnerWnd, &MenuInfo, - NO_SELECTED_ITEM, FALSE, 0 ); - MenuMoveSelection(mt.OwnerWnd, &MenuInfo, - VK_HOME == msg.wParam ? ITEM_NEXT : ITEM_PREV); + MenuSelectItem(mt.OwnerWnd, &MenuInfo, NO_SELECTED_ITEM, FALSE, 0 ); + MenuMoveSelection(mt.OwnerWnd, &MenuInfo, VK_HOME == msg.wParam ? ITEM_NEXT : ITEM_PREV); } break; @@ -3385,14 +3836,13 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, case VK_DOWN: /* If on menu bar, pull-down the menu */ if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) { - if (!(MenuInfo.Flags & MF_POPUP)) + if (!(MenuInfo.fFlags & MNF_POPUP)) { if (MenuGetRosMenuInfo(&MenuInfo, mt.TopMenu)) mt.CurrentMenu = MenuShowSubPopup(mt.OwnerWnd, &MenuInfo, TRUE, wFlags); } else /* otherwise try to move selection */ - MenuMoveSelection(mt.OwnerWnd, &MenuInfo, - (msg.wParam == VK_UP)? ITEM_PREV : ITEM_NEXT ); + MenuMoveSelection(mt.OwnerWnd, &MenuInfo, (msg.wParam == VK_UP)? ITEM_PREV : ITEM_NEXT ); } break; @@ -3415,13 +3865,13 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, hi.iContextType = HELPINFO_MENUITEM; if (MenuGetRosMenuInfo(&MenuInfo, mt.CurrentMenu)) { - if (MenuInfo.FocusedItem == NO_SELECTED_ITEM) + if (MenuInfo.iItem == NO_SELECTED_ITEM) hi.iCtrlId = 0; else { MenuInitRosMenuItemInfo(&ItemInfo); if (MenuGetRosMenuItemInfo(MenuInfo.Self, - MenuInfo.FocusedItem, + MenuInfo.iItem, &ItemInfo)) { hi.iCtrlId = ItemInfo.wID; @@ -3462,14 +3912,12 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, /* We will find a better way real soon... */ if (msg.wParam < 32) break; - pos = MenuFindItemByKey(mt.OwnerWnd, &MenuInfo, - LOWORD(msg.wParam), FALSE); + pos = MENU_FindItemByKey(mt.OwnerWnd, mt.CurrentMenu, LOWORD(msg.wParam), FALSE); if (pos == (UINT)-2) fEndMenu = TRUE; else if (pos == (UINT)-1) MessageBeep(0); else { - MenuSelectItem(mt.OwnerWnd, &MenuInfo, pos, - TRUE, 0); + MenuSelectItem(mt.OwnerWnd, &MenuInfo, pos, TRUE, 0); executedMenuId = MenuExecFocusedItem(&mt, &MenuInfo, wFlags); fEndMenu = (executedMenuId != -2); } @@ -3508,16 +3956,15 @@ static INT FASTCALL MenuTrackMenu(HMENU hmenu, UINT wFlags, INT x, INT y, { MenuHideSubPopups(mt.OwnerWnd, &MenuInfo, FALSE, wFlags); - if (MenuInfo.Flags & MF_POPUP) + if (MenuInfo.fFlags & MNF_POPUP) { IntNotifyWinEvent(EVENT_SYSTEM_MENUPOPUPEND, MenuInfo.Wnd, OBJID_CLIENT, CHILDID_SELF, 0); DestroyWindow(MenuInfo.Wnd); MenuInfo.Wnd = NULL; - if (!(MenuInfo.Flags & TPM_NONOTIFY)) + if (!(wFlags & TPM_NONOTIFY)) SendMessageW( mt.OwnerWnd, WM_UNINITMENUPOPUP, (WPARAM)mt.TopMenu, MAKELPARAM(0, IS_SYSTEM_MENU(&MenuInfo)) ); - } MenuSelectItem( mt.OwnerWnd, &MenuInfo, NO_SELECTED_ITEM, FALSE, 0 ); } @@ -3554,11 +4001,19 @@ static BOOL FASTCALL MenuInitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT * It also enables menus to be displayed in more than one window, * but there are some bugs left that need to be fixed in this case. */ - if (MenuGetRosMenuInfo(&MenuInfo, hMenu)) + if (!bPopup && (MenuGetRosMenuInfo(&MenuInfo, hMenu))) { MenuInfo.Wnd = hWnd; MenuSetRosMenuInfo(&MenuInfo); } + //if (!bPopup) menu->hWnd = hWnd; + if (!top_popup) + { + top_popup = MenuInfo.Wnd;//menu->hWnd; + top_popup_hmenu = hMenu; + } + + fEndMenu = FALSE; /* Send WM_ENTERMENULOOP and WM_INITMENU message only if TPM_NONOTIFY flag is not specified */ if (!(wFlags & TPM_NONOTIFY)) @@ -3573,7 +4028,7 @@ static BOOL FASTCALL MenuInitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT * menu sizes will be recalculated once the menu created/shown. */ - if (!MenuInfo.Height) + if (!MenuInfo.cyMenu) { /* app changed/recreated menu bar entries in WM_INITMENU Recalculate menu sizes else clicks will not work */ @@ -3585,10 +4040,11 @@ static BOOL FASTCALL MenuInitTracking(HWND hWnd, HMENU hMenu, BOOL bPopup, UINT IntNotifyWinEvent( EVENT_SYSTEM_MENUSTART, hWnd, - MenuInfo.Flags & MF_SYSMENU ? OBJID_SYSMENU : OBJID_MENU, + MenuInfo.fFlags & MNF_SYSDESKMN ? OBJID_SYSMENU : OBJID_MENU, CHILDID_SELF, 0); return TRUE; } + /*********************************************************************** * MenuExitTracking */ @@ -3616,6 +4072,7 @@ VOID MenuTrackMouseMenuBar( HWND hWnd, ULONG ht, POINT pt) TRACE("wnd=%p ht=0x%04x (%ld,%ld)\n", hWnd, ht, pt.x, pt.y); + if (GetWindowLongW( hWnd, GWL_EXSTYLE ) & WS_EX_LAYOUTRTL) wFlags |= TPM_LAYOUTRTL; if (IsMenu(hMenu)) { /* map point to parent client coordinates */ @@ -3631,7 +4088,6 @@ VOID MenuTrackMouseMenuBar( HWND hWnd, ULONG ht, POINT pt) } } - /*********************************************************************** * MenuTrackKbdMenuBar * @@ -3667,6 +4123,9 @@ VOID MenuTrackKbdMenuBar(HWND hwnd, UINT wParam, WCHAR wChar) MenuInitTracking( hwnd, hTrackMenu, FALSE, wFlags ); + /* fetch the window menu again, it may have changed */ + hTrackMenu = (wParam & HTSYSMENU) ? get_win_sys_menu( hwnd ) : GetMenu( hwnd ); + if (! MenuGetRosMenuInfo(&MenuInfo, hTrackMenu)) { goto track_menu; @@ -3674,7 +4133,7 @@ VOID MenuTrackKbdMenuBar(HWND hwnd, UINT wParam, WCHAR wChar) if( wChar && wChar != ' ' ) { - uItem = MenuFindItemByKey( hwnd, &MenuInfo, wChar, (wParam & HTSYSMENU) ); + uItem = MENU_FindItemByKey( hwnd, hTrackMenu, wChar, (wParam & HTSYSMENU) ); if ( uItem >= (UINT)(-2) ) { if( uItem == (UINT)(-1) ) MessageBeep(0); @@ -3702,41 +4161,59 @@ track_menu: /********************************************************************** * TrackPopupMenuEx (USER32.@) */ -BOOL WINAPI TrackPopupMenuEx( HMENU Menu, UINT Flags, int x, int y, - HWND Wnd, LPTPMPARAMS Tpm) +BOOL WINAPI TrackPopupMenuEx( HMENU hMenu, UINT wFlags, int x, int y, + HWND hWnd, LPTPMPARAMS lpTpm) { BOOL ret = FALSE; - ROSMENUINFO MenuInfo; + MENU *menu; - if (!IsMenu(Menu)) + TRACE("hmenu %p flags %04x (%d,%d) hwnd %p lpTpm %p rect %s\n", + hMenu, wFlags, x, y, hWnd, lpTpm, + lpTpm ? wine_dbgstr_rect( &lpTpm->rcExclude) : "-" ); + + /* Parameter check */ + /* FIXME: this check is performed several times, here and in the called + functions. That could be optimized */ + if (!(menu = MENU_GetMenu( hMenu ))) { SetLastError( ERROR_INVALID_MENU_HANDLE ); return FALSE; } - /* ReactOS Check */ - if (!ValidateHwnd(Wnd)) - { - return FALSE; - } - - MenuGetRosMenuInfo(&MenuInfo, Menu); - if (IsWindow(MenuInfo.Wnd)) + if (IsWindow(menu->hWnd)) { SetLastError( ERROR_POPUP_ALREADY_ACTIVE ); return FALSE; } - MenuInitTracking(Wnd, Menu, TRUE, Flags); + if (MENU_InitPopup( hWnd, hMenu, wFlags )) + { + MenuInitTracking(hWnd, hMenu, TRUE, wFlags); + + /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */ + if (!(wFlags & TPM_NONOTIFY)) + SendMessageW(hWnd, WM_INITMENUPOPUP, (WPARAM) hMenu, 0); - /* Send WM_INITMENUPOPUP message only if TPM_NONOTIFY flag is not specified */ - if (!(Flags & TPM_NONOTIFY)) - SendMessageW(Wnd, WM_INITMENUPOPUP, (WPARAM) Menu, 0); + if (MenuShowPopup(hWnd, hMenu, 0, wFlags, x, y, 0, 0 )) + ret = MenuTrackMenu(hMenu, wFlags | TPM_POPUPMENU, 0, 0, hWnd, + lpTpm ? &lpTpm->rcExclude : NULL); + MenuExitTracking(hWnd, TRUE); - if (MenuShowPopup(Wnd, Menu, 0, Flags, x, y, 0, 0 )) - ret = MenuTrackMenu(Menu, Flags | TPM_POPUPMENU, 0, 0, Wnd, - Tpm ? &Tpm->rcExclude : NULL); - MenuExitTracking(Wnd, TRUE); + if (menu->hWnd) + { + ROSMENUINFO MenuInfo; + if (IsWindow( menu->hWnd )) // wine hack around this with their destroy function. + DestroyWindow( menu->hWnd ); // Fix wrong error return. + //menu->hWnd = 0; + MenuGetRosMenuInfo(&MenuInfo, menu->head.h); + MenuInfo.Wnd = 0; + MenuSetRosMenuInfo(&MenuInfo); + + if (!(wFlags & TPM_NONOTIFY)) + SendMessageW( hWnd, WM_UNINITMENUPOPUP, (WPARAM)hMenu, + MAKELPARAM(0, IS_SYSTEM_MENU(menu)) ); + } + } return ret; } @@ -3749,162 +4226,209 @@ BOOL WINAPI TrackPopupMenu( HMENU Menu, UINT Flags, int x, int y, return TrackPopupMenuEx( Menu, Flags, x, y, Wnd, NULL); } -/* - * From MSDN: - * The MFT_BITMAP, MFT_SEPARATOR, and MFT_STRING values cannot be combined - * with one another. Also MFT_OWNERDRAW. Set fMask to MIIM_TYPE to use fType. - * - * Windows 2K/XP: fType is used only if fMask has a value of MIIM_FTYPE. - * - * MIIM_TYPE: Retrieves or sets the fType and dwTypeData members. Windows - * 2K/XP: MIIM_TYPE is replaced by MIIM_BITMAP, MIIM_FTYPE, and MIIM_STRING. - * MFT_STRING is replaced by MIIM_STRING. - * (So, I guess we should use MIIM_STRING only for strings?) - * - * MIIM_FTYPE: Windows 2K/Windows XP: Retrieves or sets the fType member. - * - * Based on wine, SetMenuItemInfo_common: - * 1) set MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP any one with MIIM_TYPE, - * it will result in a error. - * 2) set menu mask to MIIM_FTYPE and MFT_BITMAP ftype it will result in a error. - * These conditions are addressed in Win32k IntSetMenuItemInfo. +/********************************************************************** + * MENU_mnu2mnuii * + * Uses flags, id and text ptr, passed by InsertMenu() and + * ModifyMenu() to setup a MenuItemInfo structure. */ -static -BOOL -FASTCALL -MenuSetItemData( - LPMENUITEMINFOW mii, - UINT Flags, - UINT_PTR IDNewItem, - LPCWSTR NewItem, - BOOL Unicode) +static void MENU_mnu2mnuii( UINT flags, UINT_PTR id, LPCWSTR str, LPMENUITEMINFOW pmii, BOOL Unicode) { -/* - * Let us assume MIIM_FTYPE is set and building a new menu item structure. - */ - if(Flags & MF_BITMAP) - { - mii->fMask |= MIIM_BITMAP; /* Use the new way of seting hbmpItem.*/ - mii->hbmpItem = (HBITMAP) NewItem; - - if (Flags & MF_HELP) - { - /* increase ident */ - mii->fType |= MF_HELP; - } - } - else if(Flags & MF_OWNERDRAW) - { - mii->fType |= MFT_OWNERDRAW; - mii->fMask |= MIIM_DATA; - mii->dwItemData = (DWORD_PTR) NewItem; - } - else if (Flags & MF_SEPARATOR) - { - mii->fType |= MFT_SEPARATOR; - if (!(Flags & (MF_GRAYED|MF_DISABLED))) - Flags |= MF_GRAYED|MF_DISABLED; - } - else /* Default action MF_STRING. */ - { - /* Item beginning with a backspace is a help item */ - if (NewItem != NULL) - { - if (Unicode) - { - if (*NewItem == '\b') - { - mii->fType |= MF_HELP; - NewItem++; - } - } - else - { - LPCSTR NewItemA = (LPCSTR) NewItem; - if (*NewItemA == '\b') - { - mii->fType |= MF_HELP; - NewItemA++; - NewItem = (LPCWSTR) NewItemA; - } - } + 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; +} - if (Flags & MF_HELP) - mii->fType |= MF_HELP; - mii->fMask |= MIIM_STRING; - mii->fType |= MFT_STRING; /* Zero */ - mii->dwTypeData = (LPWSTR)NewItem; - if (Unicode) - mii->cch = (NULL == NewItem ? 0 : strlenW(NewItem)); - else - mii->cch = (NULL == NewItem ? 0 : strlen((LPCSTR)NewItem)); +/********************************************************************** + * 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; } - else + /* 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 ) { - mii->fType |= MFT_SEPARATOR; - if (!(Flags & (MF_GRAYED|MF_DISABLED))) - Flags |= MF_GRAYED|MF_DISABLED; + pmii_out->fType &= ~MENUITEMINFO_TYPE_MASK; + pmii_out->fType |= pmii_in->fType & MENUITEMINFO_TYPE_MASK; } - } - - if(Flags & MF_RIGHTJUSTIFY) /* Same as MF_HELP */ - { - mii->fType |= MFT_RIGHTJUSTIFY; - } + 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(Flags & MF_MENUBREAK) - { - mii->fType |= MFT_MENUBREAK; - } - else if(Flags & MF_MENUBARBREAK) - { - mii->fType |= MFT_MENUBARBREAK; - } + return TRUE; +} - if(Flags & MF_GRAYED || Flags & MF_DISABLED) - { - if (Flags & MF_GRAYED) - mii->fState |= MF_GRAYED; - - if (Flags & MF_DISABLED) - mii->fState |= MF_DISABLED; +BOOL +MenuInit(VOID) +{ + NONCLIENTMETRICSW ncm; - mii->fMask |= MIIM_STATE; - } - else if (Flags & MF_HILITE) - { - mii->fState |= MF_HILITE; - mii->fMask |= MIIM_STATE; - } - else /* default state */ + /* get the menu font */ + if(!hMenuFont || !hMenuFontBold) { - mii->fState |= MFS_ENABLED; - mii->fMask |= MIIM_STATE; + ncm.cbSize = sizeof(ncm); + if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0)) + { + ERR("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n"); + return FALSE; + } + + hMenuFont = CreateFontIndirectW(&ncm.lfMenuFont); + if(hMenuFont == NULL) + { + ERR("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n"); + return FALSE; + } + + ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000); + hMenuFontBold = CreateFontIndirectW(&ncm.lfMenuFont); + if(hMenuFontBold == NULL) + { + ERR("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n"); + DeleteObject(hMenuFont); + hMenuFont = NULL; + return FALSE; + } } - if(Flags & MF_POPUP) + return TRUE; +} + +VOID +MenuCleanup(VOID) +{ + if (hMenuFont) { - mii->fType |= MF_POPUP; - mii->fMask |= MIIM_SUBMENU; - mii->hSubMenu = (HMENU)IDNewItem; + DeleteObject(hMenuFont); + hMenuFont = NULL; } - else + + if (hMenuFontBold) { - mii->fMask |= MIIM_ID; - mii->wID = (UINT)IDNewItem; + DeleteObject(hMenuFontBold); + hMenuFontBold = NULL; } - return TRUE; +} + +NTSTATUS WINAPI +User32LoadSysMenuTemplateForKernel(PVOID Arguments, ULONG ArgumentLength) +{ + HMENU hmenu = LoadMenuW(User32Instance, L"SYSMENU"); + LRESULT Result = (LRESULT)hmenu; + MENUINFO menuinfo = {0}; + MENUITEMINFOW info = {0}; + + // removing space for checkboxes from menu + menuinfo.cbSize = sizeof(menuinfo); + menuinfo.fMask = MIM_STYLE; + GetMenuInfo(hmenu, &menuinfo); + menuinfo.dwStyle |= MNS_CHECKORBMP; // test_menu_bmp_and_string MNS_CHECKORBMP + SetMenuInfo(hmenu, &menuinfo); + + // adding bitmaps to menu items + info.cbSize = sizeof(info); + info.fMask |= MIIM_BITMAP; + info.hbmpItem = HBMMENU_POPUP_MINIMIZE; + SetMenuItemInfoW(hmenu, SC_MINIMIZE, FALSE, &info); + info.hbmpItem = HBMMENU_POPUP_RESTORE; + SetMenuItemInfoW(hmenu, SC_RESTORE, FALSE, &info); + info.hbmpItem = HBMMENU_POPUP_MAXIMIZE; + SetMenuItemInfoW(hmenu, SC_MAXIMIZE, FALSE, &info); + info.hbmpItem = HBMMENU_POPUP_CLOSE; + SetMenuItemInfoW(hmenu, SC_CLOSE, FALSE, &info); + + return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS)); } NTSTATUS WINAPI User32CallLoadMenuFromKernel(PVOID Arguments, ULONG ArgumentLength) { PLOADMENU_CALLBACK_ARGUMENTS Common; - LRESULT Result; + LRESULT Result; Common = (PLOADMENU_CALLBACK_ARGUMENTS) Arguments; - + Result = (LRESULT)LoadMenuW( Common->hModule, IS_INTRESOURCE(Common->MenuName[0]) ? MAKEINTRESOURCE(Common->MenuName[0]) : @@ -3916,13 +4440,6 @@ User32CallLoadMenuFromKernel(PVOID Arguments, ULONG ArgumentLength) /* FUNCTIONS *****************************************************************/ -/*static BOOL -MenuIsStringItem(ULONG TypeData) -{ - return(MF_STRING == MENU_ITEM_TYPE(ItemInfo->fType)); -}*/ - - /* * @implemented */ @@ -3932,10 +4449,34 @@ AppendMenuA(HMENU hMenu, UINT_PTR uIDNewItem, LPCSTR lpNewItem) { - return(InsertMenuA(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem, - lpNewItem)); -} + MENUITEMINFOW mii; + UNICODE_STRING UnicodeString; + BOOL res; + + RtlInitUnicodeString(&UnicodeString, 0); + MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE); + + /* copy the text string, it wll 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 @@ -3946,10 +4487,24 @@ AppendMenuW(HMENU hMenu, UINT_PTR uIDNewItem, LPCWSTR lpNewItem) { - return(InsertMenuW(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem, - lpNewItem)); -} + MENUITEMINFOW mii; + UNICODE_STRING MenuText; + BOOL res; + + RtlInitUnicodeString(&MenuText, 0); + MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE); + + /* copy the text string, it wll 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 @@ -3959,141 +4514,85 @@ CheckMenuItem(HMENU hmenu, UINT uIDCheckItem, UINT uCheck) { - return NtUserCheckMenuItem(hmenu, uIDCheckItem, uCheck); -} - -static -BOOL -MenuCheckMenuRadioItem(HMENU hMenu, UINT idFirst, UINT idLast, UINT idCheck, UINT uFlags, BOOL bCheck, PUINT pChecked, PUINT pUnchecked, PUINT pMenuChanged) -{ - UINT ItemCount, i; - PROSMENUITEMINFO Items = NULL; - UINT cChecked, cUnchecked; - BOOL bRet = TRUE; - //ROSMENUINFO mi; - - if(idFirst > idLast) - return FALSE; - - ItemCount = GetMenuItemCount(hMenu); - - //mi.cbSize = sizeof(ROSMENUINFO); - //if(!NtUserMenuInfo(hmenu, &mi, FALSE)) return ret; - - - if(MenuGetAllRosMenuItemInfo(hMenu, &Items) <= 0) - { - ERR("MenuGetAllRosMenuItemInfo failed\n"); - return FALSE; - } - - cChecked = cUnchecked = 0; - - for (i = 0 ; i < ItemCount; i++) - { - BOOL check = FALSE; - if (0 != (Items[i].fType & MF_MENUBARBREAK)) continue; - if (0 != (Items[i].fType & MF_SEPARATOR)) continue; - - if ((Items[i].fType & MF_POPUP) && (uFlags == MF_BYCOMMAND)) - { - MenuCheckMenuRadioItem(Items[i].hSubMenu, idFirst, idLast, idCheck, uFlags, bCheck, pChecked, pUnchecked, pMenuChanged); - continue; - } - if (uFlags & MF_BYPOSITION) - { - if (i < idFirst || i > idLast) - continue; + PMENU pMenu; + PITEM item; + DWORD Ret; - if (i == idCheck) - { - cChecked++; - check = TRUE; - } - else - { - cUnchecked++; - } - } - else - { - if (Items[i].wID < idFirst || Items[i].wID > idLast) - continue; + if (!(pMenu = ValidateHandle(hmenu, TYPE_MENU))) + return -1; - if (Items[i].wID == idCheck) - { - cChecked++; - check = TRUE; - } - else - { - cUnchecked++; - } - } + if (!(item = MENU_FindItem( &hmenu, &uIDCheckItem, uCheck ))) return -1; - if (!bCheck) - continue; + Ret = item->fState & MFS_CHECKED; + if ( Ret == (uCheck & MFS_CHECKED)) return Ret; // Already Checked... - Items[i].fMask = MIIM_STATE | MIIM_FTYPE; - if (check) - { - Items[i].fType |= MFT_RADIOCHECK; - Items[i].fState |= MFS_CHECKED; - } - else - { - Items[i].fState &= ~MFS_CHECKED; - } - - if(!MenuSetRosMenuItemInfo(hMenu, i ,&Items[i])) - { - ERR("MenuSetRosMenuItemInfo failed\n"); - bRet = FALSE; - break; - } - } - HeapFree(GetProcessHeap(), 0, Items); - - *pChecked += cChecked; - *pUnchecked += cUnchecked; - - if (cChecked || cUnchecked) - (*pMenuChanged)++; - - return bRet; + return NtUserCheckMenuItem(hmenu, uIDCheckItem, uCheck); } /* * @implemented */ BOOL WINAPI -CheckMenuRadioItem(HMENU hmenu, - UINT idFirst, - UINT idLast, - UINT idCheck, - UINT uFlags) +CheckMenuRadioItem(HMENU hMenu, + UINT first, + UINT last, + UINT check, + UINT bypos) { - UINT cChecked = 0; - UINT cUnchecked = 0; - UINT cMenuChanged = 0; - - if (!MenuCheckMenuRadioItem(hmenu, idFirst, idLast, idCheck, uFlags, FALSE, &cChecked, &cUnchecked, &cMenuChanged)) - return FALSE; + BOOL done = FALSE; + UINT i; + PITEM mi_first = NULL, mi_check; + HMENU m_first, m_check; + MENUITEMINFOW mii; + mii.cbSize = sizeof( mii); - if (cMenuChanged > 1) - return FALSE; + for (i = first; i <= last; i++) + { + UINT pos = i; - cMenuChanged = 0; - cChecked = 0; - cUnchecked = 0; + 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 (!MenuCheckMenuRadioItem(hmenu, idFirst, idLast, idCheck, uFlags, TRUE, &cChecked, &cUnchecked, &cMenuChanged)) - return FALSE; + if (m_first != m_check) continue; + if (mi_check->fType == MFT_SEPARATOR) continue; - return (cChecked != 0); + 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 */ @@ -4104,7 +4603,6 @@ CreateMenu(VOID) return NtUserxCreateMenu(); } - /* * @implemented */ @@ -4115,26 +4613,13 @@ CreatePopupMenu(VOID) return NtUserxCreatePopupMenu(); } - /* * @implemented */ BOOL WINAPI DrawMenuBar(HWND hWnd) { -// return NtUserxDrawMenuBar(hWnd); - ROSMENUINFO MenuInfo; - HMENU hMenu; - hMenu = GetMenu(hWnd); - if (!hMenu) - return FALSE; - MenuGetRosMenuInfo(&MenuInfo, hMenu); - MenuInfo.Height = 0; // make sure to recalc size - MenuSetRosMenuInfo(&MenuInfo); - - SetWindowPos( hWnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | - SWP_NOZORDER | SWP_FRAMECHANGED ); - return TRUE; + return NtUserxDrawMenuBar(hWnd); } /* @@ -4178,27 +4663,26 @@ EndMenu(VOID) /* don't end up with an orphaned menu */ PostMessageW( top_popup, WM_CANCELMODE, 0, 0); } - return TRUE; + return fEndMenu; } -// So this one maybe one day it will be a callback! BOOL WINAPI HiliteMenuItem( HWND hWnd, HMENU hMenu, UINT wItemID, UINT wHilite ) { ROSMENUINFO MenuInfo; - ROSMENUITEMINFO mii; TRACE("(%p, %p, %04x, %04x);\n", hWnd, hMenu, wItemID, wHilite); - if (!hWnd) + // Force bits to be set call server side.... + // This alone works and passes all the menu test_menu_hilitemenuitem tests. + if (!NtUserHiliteMenuItem(hWnd, hMenu, wItemID, wHilite)) return FALSE; + // Without the above call we fail 3 out of the wine failed todo tests, see CORE-7967 + // Now redraw menu. + if (MenuGetRosMenuInfo(&MenuInfo, hMenu)) { - SetLastError(ERROR_INVALID_WINDOW_HANDLE); - return FALSE; - } - if (!NtUserMenuItemInfo(hMenu, wItemID, wHilite, &mii, FALSE)) return FALSE; - if (!NtUserMenuInfo(hMenu, &MenuInfo, FALSE)) return FALSE; - if (MenuInfo.FocusedItem == wItemID) return TRUE; - MenuHideSubPopups( hWnd, &MenuInfo, FALSE, 0 ); - MenuSelectItem( hWnd, &MenuInfo, wItemID, TRUE, 0 ); - return TRUE; + if (MenuInfo.iItem == wItemID) return TRUE; + MenuHideSubPopups( hWnd, &MenuInfo, FALSE, 0 ); + MenuSelectItem( hWnd, &MenuInfo, wItemID, TRUE, 0 ); + } + return TRUE; // Always returns TRUE! } /* @@ -4215,7 +4699,6 @@ GetMenu(HWND hWnd) return UlongToHandle(Wnd->IDMenu); } - /* * @implemented */ @@ -4235,7 +4718,6 @@ BOOL WINAPI GetMenuBarInfo( HWND hwnd, LONG idObject, LONG idItem, PMENUBARINFO return TRUE; } - /* * @implemented */ @@ -4246,236 +4728,152 @@ GetMenuCheckMarkDimensions(VOID) GetSystemMetrics(SM_CYMENUCHECK))); } - -/* - * @implemented - */ -UINT WINAPI -GetMenuDefaultItem(HMENU hMenu, - UINT fByPos, - UINT gmdiFlags) -{ - return NtUserGetMenuDefaultItem(hMenu, fByPos, gmdiFlags); -} - - /* * @implemented */ -BOOL WINAPI -GetMenuInfo(HMENU hmenu, - LPMENUINFO lpcmi) -{ - ROSMENUINFO 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 WINAPI -GetMenuItemCount(HMENU Menu) +DWORD +WINAPI +GetMenuContextHelpId(HMENU hmenu) { - ROSMENUINFO MenuInfo; - - return MenuGetRosMenuInfo(&MenuInfo, Menu) ? MenuInfo.MenuItemCount : 0; + PMENU pMenu; + if ((pMenu = ValidateHandle(hmenu, TYPE_MENU))) + return pMenu->dwContextHelpId; + return 0; } - /* * @implemented */ UINT WINAPI -GetMenuItemID(HMENU hMenu, - int nPos) +GetMenuDefaultItem(HMENU hMenu, + UINT fByPos, + UINT gmdiFlags) { - ROSMENUITEMINFO mii; - - mii.cbSize = sizeof(MENUITEMINFOW); - mii.fMask = MIIM_ID | MIIM_SUBMENU; - - if (! NtUserMenuItemInfo(hMenu, nPos, MF_BYPOSITION, &mii, FALSE)) - { - return -1; - } - - if (NULL != mii.hSubMenu) - { - return -1; - } - if (0 == mii.wID) - { - return -1; - } + PMENU pMenu; + DWORD gismc = 0; + if (!(pMenu = ValidateHandle(hMenu, TYPE_MENU))) + return (UINT)-1; - return mii.wID; + return IntGetMenuDefaultItem( pMenu, (BOOL)fByPos, gmdiFlags, &gismc); } - /* * @implemented */ BOOL WINAPI -GetMenuItemInfoA( - HMENU Menu, - UINT Item, - BOOL ByPosition, - LPMENUITEMINFOA mii) +GetMenuInfo(HMENU hmenu, + LPMENUINFO lpcmi) { - MENUITEMINFOW miiW; - LPSTR AnsiBuffer; - INT Count; - - if (mii->cbSize != sizeof(MENUITEMINFOA) && - mii->cbSize != sizeof(MENUITEMINFOA) - sizeof(HBITMAP)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } - - if(!(mii->fMask & (MIIM_TYPE | MIIM_STRING))) - { - /* No text requested, just pass on */ - return NtUserMenuItemInfo(Menu, Item, ByPosition, (PROSMENUITEMINFO) mii, FALSE); - } - - AnsiBuffer = mii->dwTypeData; - Count = miiW.cch = mii->cch; - RtlCopyMemory(&miiW, mii, mii->cbSize); - miiW.dwTypeData = 0; + PMENU pMenu; - if (AnsiBuffer) - { - miiW.dwTypeData = RtlAllocateHeap(GetProcessHeap(), 0, - miiW.cch * sizeof(WCHAR)); - if (miiW.dwTypeData == NULL) return FALSE; - miiW.dwTypeData[0] = 0; - } - - if (!NtUserMenuItemInfo(Menu, Item, ByPosition, (PROSMENUITEMINFO)&miiW, FALSE)) - { - if (miiW.dwTypeData) RtlFreeHeap(GetProcessHeap(), 0, miiW.dwTypeData); - return FALSE; - } - - RtlCopyMemory(mii, &miiW, miiW.cbSize); - - if (!AnsiBuffer || !Count) - { - if (miiW.dwTypeData) RtlFreeHeap(GetProcessHeap(), 0, miiW.dwTypeData); - mii->dwTypeData = AnsiBuffer; - mii->cch = miiW.cch; - return TRUE; - } - - if ((miiW.fMask & MIIM_STRING) || (IS_STRING_ITEM(miiW.fType))) - { - if (miiW.cch) - { - if (!WideCharToMultiByte(CP_ACP, 0, miiW.dwTypeData, miiW.cch, AnsiBuffer, mii->cch, NULL, NULL)) - { - AnsiBuffer[0] = 0; - } - if (Count > miiW.cch) - { - AnsiBuffer[miiW.cch] = 0; - } - mii->cch = miiW.cch; - } - } - else - { - AnsiBuffer[0] = 0; - } + if (!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO))) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } - RtlFreeHeap(GetProcessHeap(), 0, miiW.dwTypeData); - mii->dwTypeData = AnsiBuffer; + if (!(pMenu = ValidateHandle(hmenu, TYPE_MENU))) + return FALSE; - return TRUE; -} + 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 */ -BOOL WINAPI -GetMenuItemInfoW( - HMENU Menu, - UINT Item, - BOOL ByPosition, - LPMENUITEMINFOW mii) +int WINAPI +GetMenuItemCount(HMENU hmenu) { - MENUITEMINFOW miiW; - LPWSTR String; - INT Count; - - if (mii->cbSize != sizeof(MENUITEMINFOW) && - mii->cbSize != sizeof(MENUITEMINFOW) - sizeof(HBITMAP)) - { - SetLastError(ERROR_INVALID_PARAMETER); - return FALSE; - } + PMENU pMenu; + if ((pMenu = ValidateHandle(hmenu, TYPE_MENU))) + return pMenu->cItems; + return -1; +} - if(!(mii->fMask & (MIIM_TYPE | MIIM_STRING))) - { - /* No text requested, just pass on */ - return NtUserMenuItemInfo(Menu, Item, ByPosition, (PROSMENUITEMINFO) mii, FALSE); - } +/* + * @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; +} - String = mii->dwTypeData; - Count = mii->cch; - RtlCopyMemory(&miiW, mii, mii->cbSize); - miiW.dwTypeData = 0; +/* + * @implemented + */ +BOOL WINAPI +GetMenuItemInfoA( + HMENU hmenu, + UINT item, + BOOL bypos, + LPMENUITEMINFOA lpmii) +{ + BOOL ret; + MENUITEMINFOA mii; - if (String) - { - miiW.dwTypeData = RtlAllocateHeap(GetProcessHeap(), 0, - miiW.cch * sizeof(WCHAR)); - if (miiW.dwTypeData == NULL) return FALSE; - miiW.dwTypeData[0] = 0; - } + 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; +} - if (!NtUserMenuItemInfo(Menu, Item, ByPosition, (PROSMENUITEMINFO) &miiW, FALSE)) +/* + * @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)) { - if (miiW.dwTypeData) RtlFreeHeap(GetProcessHeap(), 0, miiW.dwTypeData); + SetLastError( ERROR_INVALID_PARAMETER); return FALSE; } - - RtlCopyMemory(mii, &miiW, miiW.cbSize); // Okay to over write user data. - - if (!String || !Count) - { - if (miiW.dwTypeData) RtlFreeHeap(GetProcessHeap(), 0, miiW.dwTypeData); - mii->dwTypeData = String; // may not be zero. - mii->cch = miiW.cch; - return TRUE; - } - - if ((miiW.fMask & MIIM_STRING) || (IS_STRING_ITEM(miiW.fType))) - { - lstrcpynW( String, miiW.dwTypeData, Count ); - } - - RtlFreeHeap(GetProcessHeap(), 0, miiW.dwTypeData); - mii->dwTypeData = String; - mii->cch = strlenW(String); - return TRUE; + 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 */ @@ -4486,39 +4884,24 @@ GetMenuState( UINT uId, UINT uFlags) { - ROSMENUINFO MenuInfo; - ROSMENUITEMINFO mii; - memset( &mii, 0, sizeof(mii) ); - mii.cbSize = sizeof(MENUITEMINFOW); - mii.fMask = MIIM_STATE | MIIM_FTYPE | MIIM_SUBMENU; - - SetLastError(0); - if(NtUserMenuItemInfo(hMenu, uId, uFlags, &mii, FALSE)) - { - UINT nSubItems = 0; - if(mii.hSubMenu) - { - if (! MenuGetRosMenuInfo(&MenuInfo, mii.hSubMenu)) - { - return (UINT) -1; - } - nSubItems = MenuInfo.MenuItemCount; + 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; - /* FIXME - ported from wine, does that work (0xff)? */ - if(GetLastError() != ERROR_INVALID_MENU_HANDLE) - return (nSubItems << 8) | ((mii.fState | mii.fType) & 0xff); + if (!pItem->Xlpstr && pItem->hbmp) Type = MFT_BITMAP; - return (UINT)-1; /* Invalid submenu */ - } - - /* FIXME - ported from wine, does that work? */ - return (mii.fType | mii.fState); - } - - return (UINT)-1; + if (pItem->spSubMenu) + { + PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu); + HMENU hsubmenu = UserHMGetHandle(pSubMenu); + 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 */ @@ -4531,20 +4914,28 @@ GetMenuStringA( int nMaxCount, UINT uFlag) { - MENUITEMINFOA mii; - memset( &mii, 0, sizeof(mii) ); - mii.dwTypeData = lpString; - mii.fMask = MIIM_STRING | MIIM_FTYPE; - mii.fType = MFT_STRING; - mii.cbSize = sizeof(MENUITEMINFOA); - mii.cch = nMaxCount; - - if(!(GetMenuItemInfoA( hMenu, uIDItem, (BOOL)(MF_BYPOSITION & uFlag),&mii))) - return 0; - else - return mii.cch; -} + 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 @@ -4558,20 +4949,31 @@ GetMenuStringW( int nMaxCount, UINT uFlag) { - MENUITEMINFOW miiW; - memset( &miiW, 0, sizeof(miiW) ); - miiW.dwTypeData = lpString; - miiW.fMask = MIIM_STRING | MIIM_FTYPE; - miiW.fType = MFT_STRING; - miiW.cbSize = sizeof(MENUITEMINFOW); - miiW.cch = nMaxCount; - - if(!(GetMenuItemInfoW( hMenu, uIDItem, (BOOL)(MF_BYPOSITION & uFlag),&miiW))) - return 0; - else - return miiW.cch; -} + 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 @@ -4582,16 +4984,15 @@ GetSubMenu( HMENU hMenu, int nPos) { - ROSMENUITEMINFO mi; - - mi.cbSize = sizeof(MENUITEMINFOW); - mi.fMask = MIIM_SUBMENU; - - if (NtUserMenuItemInfo(hMenu, (UINT)nPos, MF_BYPOSITION, &mi, FALSE)) - { - return IsMenu(mi.hSubMenu) ? mi.hSubMenu : NULL; - } + 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; } @@ -4611,7 +5012,6 @@ GetSystemMenu( return NULL == TopMenu ? NULL : GetSubMenu(TopMenu, 0); } - /* * @implemented */ @@ -4624,21 +5024,33 @@ InsertMenuA( UINT_PTR uIDNewItem, LPCSTR lpNewItem) { - MENUITEMINFOA mii; - memset( &mii, 0, sizeof(mii) ); - mii.cbSize = sizeof(MENUITEMINFOA); - mii.fMask = MIIM_FTYPE; - - MenuSetItemData((LPMENUITEMINFOW) &mii, - uFlags, - uIDNewItem, - (LPCWSTR) lpNewItem, - FALSE); - - return InsertMenuItemA(hMenu, uPosition, (BOOL)((MF_BYPOSITION & uFlags) > 0), &mii); -} + MENUITEMINFOW mii; + UNICODE_STRING UnicodeString; + BOOL res; + RtlInitUnicodeString(&UnicodeString, 0); + MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE); + + /* copy the text string, it wll 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 @@ -4651,43 +5063,38 @@ InsertMenuItemA( BOOL fByPosition, LPCMENUITEMINFOA lpmii) { - MENUITEMINFOW mi; - UNICODE_STRING MenuText; - BOOL res = FALSE; - BOOL CleanHeap = FALSE; + MENUITEMINFOW mii; + UNICODE_STRING UnicodeString; + BOOL res; - if((lpmii->cbSize == sizeof(MENUITEMINFOA)) || - (lpmii->cbSize == sizeof(MENUITEMINFOA) - sizeof(HBITMAP))) - { - RtlCopyMemory ( &mi, lpmii, lpmii->cbSize ); + TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii); - if( lpmii->cbSize != sizeof( MENUITEMINFOW)) - { - mi.cbSize = sizeof( MENUITEMINFOW); - mi.hbmpItem = NULL; - } - /* copy the text string */ - if (((mi.fMask & MIIM_STRING) || - ((mi.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mi.fType) == MF_STRING))) - && mi.dwTypeData != NULL) - { - if (!RtlCreateUnicodeStringFromAsciiz(&MenuText, (LPSTR)mi.dwTypeData)) + 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; } - mi.dwTypeData = MenuText.Buffer; - mi.cch = MenuText.Length / sizeof(WCHAR); - CleanHeap = TRUE; - } - res = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, TRUE, &mi, NULL); - - if ( CleanHeap ) RtlFreeUnicodeString ( &MenuText ); + 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 */ @@ -4699,7 +5106,7 @@ InsertMenuItemW( BOOL fByPosition, LPCMENUITEMINFOW lpmii) { - MENUITEMINFOW mi; + MENUITEMINFOW mii; UNICODE_STRING MenuText; BOOL res = FALSE; @@ -4707,31 +5114,25 @@ InsertMenuItemW( 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))) - { - RtlCopyMemory(&mi, lpmii, lpmii->cbSize); + TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii); - if( lpmii->cbSize != sizeof( MENUITEMINFOW)) - { - mi.cbSize = sizeof( MENUITEMINFOW); - mi.hbmpItem = NULL; - } - /* copy the text string */ - if (((mi.fMask & MIIM_STRING) || - ((mi.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mi.fType) == MF_STRING))) - && mi.dwTypeData != NULL) - { - RtlInitUnicodeString(&MenuText, (PWSTR)lpmii->dwTypeData); - mi.dwTypeData = MenuText.Buffer; - mi.cch = MenuText.Length / sizeof(WCHAR); - } - res = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, TRUE, &mi, NULL); + 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 */ @@ -4745,19 +5146,23 @@ InsertMenuW( LPCWSTR lpNewItem) { MENUITEMINFOW mii; - memset( &mii, 0, sizeof(mii) ); - mii.cbSize = sizeof(MENUITEMINFOW); - mii.fMask = MIIM_FTYPE; + UNICODE_STRING MenuText; + BOOL res; - MenuSetItemData( &mii, - uFlags, - uIDNewItem, - lpNewItem, - TRUE); + RtlInitUnicodeString(&MenuText, 0); - return InsertMenuItemW(hMenu, uPosition, (BOOL)((MF_BYPOSITION & uFlags) > 0), &mii); -} + MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE); + /* copy the text string, it wll 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 @@ -4771,7 +5176,6 @@ IsMenu( return FALSE; } - /* * @implemented */ @@ -4787,7 +5191,6 @@ LoadMenuA(HINSTANCE hInstance, return(LoadMenuIndirectA((PVOID)LoadResource(hInstance, Resource))); } - /* * @implemented */ @@ -4797,7 +5200,6 @@ LoadMenuIndirectA(CONST MENUTEMPLATE *lpMenuTemplate) return(LoadMenuIndirectW(lpMenuTemplate)); } - /* * @implemented */ @@ -4817,7 +5219,7 @@ LoadMenuIndirectW(CONST MENUTEMPLATE *lpMenuTemplate) offset = GET_WORD(p); p += sizeof(WORD) + offset; if (!(hMenu = CreateMenu())) return 0; - if (!MENU_ParseResource(p, hMenu, TRUE)) + if (!MENU_ParseResource(p, hMenu)) { DestroyMenu(hMenu); return 0; @@ -4839,7 +5241,6 @@ LoadMenuIndirectW(CONST MENUTEMPLATE *lpMenuTemplate) } } - /* * @implemented */ @@ -4855,7 +5256,6 @@ LoadMenuW(HINSTANCE hInstance, return(LoadMenuIndirectW((PVOID)LoadResource(hInstance, Resource))); } - /* * @implemented */ @@ -4869,103 +5269,81 @@ MenuItemFromPoint( return NtUserMenuItemFromPoint(hWnd, hMenu, ptScreen.x, ptScreen.y); } - /* * @implemented */ BOOL WINAPI ModifyMenuA( - HMENU hMnu, + HMENU hMenu, UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem, LPCSTR lpNewItem) { - ROSMENUINFO mi; - ROSMENUITEMINFO rmii; - MENUITEMINFOA mii; - memset( &mii, 0, sizeof(mii) ); - mii.cbSize = sizeof(MENUITEMINFOA); - mii.fMask = MIIM_FTYPE; - - if (!MenuGetRosMenuInfo( &mi, hMnu )) return FALSE; - - mi.Height = 0; - - if (!MenuSetRosMenuInfo( &mi )) return FALSE; - - MenuInitRosMenuItemInfo( &rmii ); - - if(!MenuGetRosMenuItemInfo( hMnu, uPosition, &rmii)) return FALSE; - - if ((rmii.fType & MF_POPUP) && (uFlags & MF_POPUP) && (rmii.hSubMenu != (HMENU)uIDNewItem)) - NtUserDestroyMenu( rmii.hSubMenu ); /* ModifyMenu() spec */ + MENUITEMINFOW mii; + UNICODE_STRING UnicodeString; + BOOL res; - MenuCleanupRosMenuItemInfo( &rmii ); + RtlInitUnicodeString(&UnicodeString, 0); - MenuSetItemData((LPMENUITEMINFOW) &mii, - uFlags, - uIDNewItem, - (LPCWSTR) lpNewItem, - FALSE); + MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE); - return SetMenuItemInfoA( hMnu, - uPosition, - (BOOL)(MF_BYPOSITION & uFlags), - &mii); + /* copy the text string, it wll 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 hMnu, + HMENU hMenu, UINT uPosition, UINT uFlags, UINT_PTR uIDNewItem, LPCWSTR lpNewItem) { - ROSMENUINFO mi; - ROSMENUITEMINFO rmii; MENUITEMINFOW mii; - memset ( &mii, 0, sizeof(mii) ); - mii.cbSize = sizeof(MENUITEMINFOW); - mii.fMask = MIIM_FTYPE; - - if (!MenuGetRosMenuInfo( &mi, hMnu )) return FALSE; - - mi.Height = 0; // Force size recalculation. - - if (!MenuSetRosMenuInfo( &mi )) return FALSE; - - MenuInitRosMenuItemInfo( &rmii ); - - if(!MenuGetRosMenuItemInfo( hMnu, uPosition, &rmii)) return FALSE; - - if ((rmii.fType & MF_POPUP) && (uFlags & MF_POPUP) && (rmii.hSubMenu != (HMENU)uIDNewItem)) - NtUserDestroyMenu( rmii.hSubMenu ); /* ModifyMenu() spec */ + UNICODE_STRING MenuText; + BOOL res; - MenuCleanupRosMenuItemInfo( &rmii ); + RtlInitUnicodeString(&MenuText, 0); - /* Init new data for this menu item */ - MenuSetItemData( &mii, - uFlags, - uIDNewItem, - lpNewItem, - TRUE); + MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE); - /* Now, make Win32k IntSetMenuItemInfo handle the changes to this menu item. */ - return SetMenuItemInfoW( hMnu, - uPosition, - (BOOL)(MF_BYPOSITION & uFlags), - &mii); + /* copy the text string, it wll 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 */ @@ -4976,7 +5354,6 @@ SetMenu(HWND hWnd, return NtUserSetMenu(hWnd, hMenu, TRUE); } - /* * @implemented */ @@ -4996,10 +5373,9 @@ SetMenuInfo( } memcpy(&mi, lpcmi, sizeof(MENUINFO)); - return NtUserMenuInfo(hmenu, &mi, TRUE); + return NtUserThunkedMenuInfo(hmenu, (LPCMENUINFO)&mi); } - /* * @implemented */ @@ -5012,90 +5388,63 @@ SetMenuItemBitmaps( HBITMAP hBitmapUnchecked, HBITMAP hBitmapChecked) { - ROSMENUITEMINFO uItem; + MENUITEMINFOW uItem; memset ( &uItem, 0, sizeof(uItem) ); - uItem.fMask = MIIM_STATE | MIIM_BITMAP; - - if(!(NtUserMenuItemInfo(hMenu, uPosition, - (BOOL)(MF_BYPOSITION & uFlags), &uItem, FALSE))) return FALSE; - - if (!hBitmapChecked && !hBitmapUnchecked) - { - uItem.fState &= ~MF_USECHECKBITMAPS; - } - else /* Install new bitmaps */ - { - uItem.hbmpChecked = hBitmapChecked; - uItem.hbmpUnchecked = hBitmapUnchecked; - uItem.fState |= MF_USECHECKBITMAPS; - } - return NtUserMenuItemInfo(hMenu, uPosition, - (BOOL)(MF_BYPOSITION & uFlags), &uItem, TRUE); + 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 uItem, - BOOL fByPosition, + HMENU hmenu, + UINT item, + BOOL bypos, LPCMENUITEMINFOA lpmii) { - MENUITEMINFOW MenuItemInfoW; + MENUITEMINFOW mii; UNICODE_STRING UnicodeString; - NTSTATUS Status; - ULONG Result = FALSE; + BOOL Ret; - RtlCopyMemory(&MenuItemInfoW, lpmii, min(lpmii->cbSize, sizeof(MENUITEMINFOW))); + TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu, item, bypos, lpmii); - if( lpmii->cbSize != sizeof( MENUITEMINFOW)) - { - MenuItemInfoW.cbSize = sizeof( MENUITEMINFOW); - MenuItemInfoW.hbmpItem = NULL; - } + 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_OWNERSRAW == good + * MIIM_STRING & MFT_OWNERDRAW == good */ - if (((MenuItemInfoW.fMask & MIIM_STRING) || - ((MenuItemInfoW.fMask & MIIM_TYPE) && - (MENU_ITEM_TYPE(MenuItemInfoW.fType) == MF_STRING))) - && MenuItemInfoW.dwTypeData != NULL) + 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. */ - Status = RtlCreateUnicodeStringFromAsciiz(&UnicodeString, - (LPSTR)MenuItemInfoW.dwTypeData); - if (!NT_SUCCESS (Status)) - { - SetLastError (RtlNtStatusToDosError(Status)); - return FALSE; - } - MenuItemInfoW.dwTypeData = UnicodeString.Buffer; - MenuItemInfoW.cch = UnicodeString.Length / sizeof(WCHAR); + /* 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; - } - - Result = NtUserMenuItemInfo(hMenu, uItem, fByPosition, - (PROSMENUITEMINFO)&MenuItemInfoW, TRUE); - - if (UnicodeString.Buffer != NULL) - { - RtlFreeUnicodeString(&UnicodeString); + UnicodeString.Buffer = NULL; } - - return Result; + Ret = NtUserThunkedMenuItemInfo(hmenu, item, bypos, FALSE, &mii, &UnicodeString); + if (UnicodeString.Buffer != NULL) RtlFreeUnicodeString(&UnicodeString); + return Ret; } - /* * @implemented */ @@ -5108,27 +5457,26 @@ SetMenuItemInfoW( LPCMENUITEMINFOW lpmii) { MENUITEMINFOW MenuItemInfoW; - ULONG Result; + UNICODE_STRING UnicodeString; + BOOL Ret; - RtlCopyMemory(&MenuItemInfoW, lpmii, min(lpmii->cbSize, sizeof(MENUITEMINFOW))); + TRACE("hmenu %p, item %u, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii); - if( lpmii->cbSize != sizeof( MENUITEMINFOW)) - { - MenuItemInfoW.cbSize = sizeof( MENUITEMINFOW); - MenuItemInfoW.hbmpItem = NULL; - } + 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 != NULL) + && MenuItemInfoW.dwTypeData && !(GdiValidateHandle((HGDIOBJ)MenuItemInfoW.dwTypeData)) ) { - MenuItemInfoW.cch = strlenW(MenuItemInfoW.dwTypeData); + RtlInitUnicodeString(&UnicodeString, (PCWSTR)MenuItemInfoW.dwTypeData); + MenuItemInfoW.cch = strlenW(MenuItemInfoW.dwTypeData); } - Result = NtUserMenuItemInfo(hMenu, uItem, fByPosition, - (PROSMENUITEMINFO)&MenuItemInfoW, TRUE); + Ret = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, FALSE, &MenuItemInfoW, &UnicodeString); - return Result; + return Ret; } /* @@ -5177,25 +5525,6 @@ NEWTrackPopupMenu( NULL); // LPTPMPARAMS is null } - -/* - * @implemented - */ -DWORD -WINAPI -GetMenuContextHelpId(HMENU hmenu) -{ - ROSMENUINFO mi; - mi.cbSize = sizeof(ROSMENUINFO); - mi.fMask = MIM_HELPID; - - if(NtUserMenuInfo(hmenu, &mi, FALSE)) - { - return mi.dwContextHelpID; - } - return 0; -} - /* * @unimplemented */ @@ -5221,7 +5550,6 @@ MenuWindowProcA( return FALSE; } return NtUserMessageCall(hWnd, Msg, wParam, lParam, Result, FNID_MENU, TRUE); - } /* @@ -5327,7 +5655,3 @@ ChangeMenuA( }; } - - - -