/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * PURPOSE: Menus * FILE: subsys/win32k/ntuser/menu.c * PROGRAMER: Thomas Weidenmueller (w3seek@users.sourceforge.net) */ #include DBG_DEFAULT_CHANNEL(UserMenu); /* INTERNAL ******************************************************************/ /* Maximum number of menu items a menu can contain */ #define MAX_MENU_ITEMS (0x4000) #define MAX_GOINTOSUBMENU (0x10) #define UpdateMenuItemState(state, change) \ {\ if((change) & MFS_DISABLED) { \ (state) |= MFS_DISABLED; \ } else { \ (state) &= ~MFS_DISABLED; \ } \ if((change) & MFS_CHECKED) { \ (state) |= MFS_CHECKED; \ } else { \ (state) &= ~MFS_CHECKED; \ } \ if((change) & MFS_HILITE) { \ (state) |= MFS_HILITE; \ } else { \ (state) &= ~MFS_HILITE; \ } \ if((change) & MFS_DEFAULT) { \ (state) |= MFS_DEFAULT; \ } else { \ (state) &= ~MFS_DEFAULT; \ } \ if((change) & MF_MOUSESELECT) { \ (state) |= MF_MOUSESELECT; \ } else { \ (state) &= ~MF_MOUSESELECT; \ } \ } #define FreeMenuText(MenuItem) \ { \ if((MENU_ITEM_TYPE((MenuItem)->fType) == MF_STRING) && \ (MenuItem)->Text.Length) { \ ExFreePoolWithTag((MenuItem)->Text.Buffer, TAG_STRING); \ } \ } PMENU_OBJECT FASTCALL UserGetMenuObject(HMENU hMenu) { PMENU_OBJECT Menu; if (!hMenu) { EngSetLastError(ERROR_INVALID_MENU_HANDLE); return NULL; } Menu = (PMENU_OBJECT)UserGetObject(gHandleTable, hMenu, otMenu); if (!Menu) { EngSetLastError(ERROR_INVALID_MENU_HANDLE); return NULL; } return Menu; } #if 0 void FASTCALL DumpMenuItemList(PMENU_ITEM MenuItem) { UINT cnt = 0; while(MenuItem) { if(MenuItem->Text.Length) DbgPrint(" %d. %wZ\n", ++cnt, &MenuItem->Text); else DbgPrint(" %d. NO TEXT dwTypeData==%d\n", ++cnt, (DWORD)MenuItem->Text.Buffer); DbgPrint(" fType="); if(MFT_BITMAP & MenuItem->fType) DbgPrint("MFT_BITMAP "); if(MFT_MENUBARBREAK & MenuItem->fType) DbgPrint("MFT_MENUBARBREAK "); if(MFT_MENUBREAK & MenuItem->fType) DbgPrint("MFT_MENUBREAK "); if(MFT_OWNERDRAW & MenuItem->fType) DbgPrint("MFT_OWNERDRAW "); if(MFT_RADIOCHECK & MenuItem->fType) DbgPrint("MFT_RADIOCHECK "); if(MFT_RIGHTJUSTIFY & MenuItem->fType) DbgPrint("MFT_RIGHTJUSTIFY "); if(MFT_SEPARATOR & MenuItem->fType) DbgPrint("MFT_SEPARATOR "); if(MFT_STRING & MenuItem->fType) DbgPrint("MFT_STRING "); DbgPrint("\n fState="); if(MFS_DISABLED & MenuItem->fState) DbgPrint("MFS_DISABLED "); else DbgPrint("MFS_ENABLED "); if(MFS_CHECKED & MenuItem->fState) DbgPrint("MFS_CHECKED "); else DbgPrint("MFS_UNCHECKED "); if(MFS_HILITE & MenuItem->fState) DbgPrint("MFS_HILITE "); else DbgPrint("MFS_UNHILITE "); if(MFS_DEFAULT & MenuItem->fState) DbgPrint("MFS_DEFAULT "); if(MFS_GRAYED & MenuItem->fState) DbgPrint("MFS_GRAYED "); DbgPrint("\n wId=%d\n", MenuItem->wID); MenuItem = MenuItem->Next; } DbgPrint("Entries: %d\n", cnt); return; } #endif PMENU_OBJECT FASTCALL IntGetMenuObject(HMENU hMenu) { PMENU_OBJECT Menu = UserGetMenuObject(hMenu); if (Menu) Menu->head.cLockObj++; return Menu; } BOOL FASTCALL IntFreeMenuItem(PMENU_OBJECT Menu, PMENU_ITEM MenuItem, BOOL bRecurse) { FreeMenuText(MenuItem); if(bRecurse && MenuItem->hSubMenu) { PMENU_OBJECT SubMenu; SubMenu = UserGetMenuObject(MenuItem->hSubMenu ); if(SubMenu) { IntDestroyMenuObject(SubMenu, bRecurse, TRUE); } } /* Free memory */ ExFreePoolWithTag(MenuItem, TAG_MENUITEM); return TRUE; } BOOL FASTCALL IntRemoveMenuItem(PMENU_OBJECT Menu, UINT uPosition, UINT uFlags, BOOL bRecurse) { PMENU_ITEM PrevMenuItem, MenuItem; if(IntGetMenuItemByFlag(Menu, uPosition, uFlags, &Menu, &MenuItem, &PrevMenuItem) > -1) { if(MenuItem) { if(PrevMenuItem) PrevMenuItem->Next = MenuItem->Next; else { Menu->MenuItemList = MenuItem->Next; } Menu->MenuInfo.MenuItemCount--; return IntFreeMenuItem(Menu, MenuItem, bRecurse); } } return FALSE; } UINT FASTCALL IntDeleteMenuItems(PMENU_OBJECT Menu, BOOL bRecurse) { UINT res = 0; PMENU_ITEM NextItem; PMENU_ITEM CurItem = Menu->MenuItemList; while(CurItem) { NextItem = CurItem->Next; IntFreeMenuItem(Menu, CurItem, bRecurse); CurItem = NextItem; res++; } Menu->MenuInfo.MenuItemCount = 0; Menu->MenuItemList = NULL; return res; } BOOL FASTCALL IntDestroyMenuObject(PMENU_OBJECT Menu, BOOL bRecurse, BOOL RemoveFromProcess) { if(Menu) { PWND Window; PWINSTATION_OBJECT WindowStation; NTSTATUS Status; /* Remove all menu items */ IntDeleteMenuItems(Menu, bRecurse); /* Do not destroy submenus */ if(RemoveFromProcess) { RemoveEntryList(&Menu->ListEntry); } Status = ObReferenceObjectByHandle(Menu->Process->Win32WindowStation, 0, ExWindowStationObjectType, KernelMode, (PVOID*)&WindowStation, NULL); if(NT_SUCCESS(Status)) { BOOL ret; if (Menu->MenuInfo.Wnd) { Window = UserGetWindowObject(Menu->MenuInfo.Wnd); if (Window) { Window->IDMenu = 0; } } // UserDereferenceObject(Menu); ret = UserDeleteObject(Menu->MenuInfo.Self, otMenu); ObDereferenceObject(WindowStation); return ret; } } return FALSE; } PMENU_OBJECT FASTCALL IntCreateMenu(PHANDLE Handle, BOOL IsMenuBar) { PMENU_OBJECT Menu; PPROCESSINFO CurrentWin32Process; Menu = (PMENU_OBJECT)UserCreateObject( gHandleTable, NULL, NULL, Handle, otMenu, sizeof(MENU_OBJECT)); if(!Menu) { *Handle = 0; return NULL; } Menu->Process = PsGetCurrentProcess(); Menu->RtoL = FALSE; /* Default */ Menu->MenuInfo.cbSize = sizeof(MENUINFO); /* Not used */ Menu->MenuInfo.fMask = 0; /* Not used */ Menu->MenuInfo.dwStyle = 0; /* FIXME */ Menu->MenuInfo.cyMax = 0; /* Default */ Menu->MenuInfo.hbrBack = NULL; /* No brush */ Menu->MenuInfo.dwContextHelpID = 0; /* Default */ Menu->MenuInfo.dwMenuData = 0; /* Default */ Menu->MenuInfo.Self = *Handle; Menu->MenuInfo.FocusedItem = NO_SELECTED_ITEM; Menu->MenuInfo.Flags = (IsMenuBar ? 0 : MF_POPUP); Menu->MenuInfo.Wnd = NULL; Menu->MenuInfo.WndOwner = NULL; Menu->MenuInfo.Height = 0; Menu->MenuInfo.Width = 0; Menu->MenuInfo.TimeToHide = FALSE; Menu->MenuInfo.MenuItemCount = 0; Menu->MenuItemList = NULL; /* Insert menu item into process menu handle list */ CurrentWin32Process = PsGetCurrentProcessWin32Process(); InsertTailList(&CurrentWin32Process->MenuListHead, &Menu->ListEntry); return Menu; } BOOL FASTCALL IntCloneMenuItems(PMENU_OBJECT Destination, PMENU_OBJECT Source) { PMENU_ITEM MenuItem, NewMenuItem = NULL; PMENU_ITEM Old = NULL; if(!Source->MenuInfo.MenuItemCount) return FALSE; MenuItem = Source->MenuItemList; while(MenuItem) { Old = NewMenuItem; if(NewMenuItem) NewMenuItem->Next = MenuItem; NewMenuItem = ExAllocatePoolWithTag(PagedPool, sizeof(MENU_ITEM), TAG_MENUITEM); if(!NewMenuItem) break; NewMenuItem->fType = MenuItem->fType; NewMenuItem->fState = MenuItem->fState; NewMenuItem->wID = MenuItem->wID; NewMenuItem->hSubMenu = MenuItem->hSubMenu; NewMenuItem->hbmpChecked = MenuItem->hbmpChecked; NewMenuItem->hbmpUnchecked = MenuItem->hbmpUnchecked; NewMenuItem->dwItemData = MenuItem->dwItemData; if((MENU_ITEM_TYPE(NewMenuItem->fType) == MF_STRING)) { if(MenuItem->Text.Length) { NewMenuItem->Text.Length = 0; NewMenuItem->Text.MaximumLength = MenuItem->Text.MaximumLength; NewMenuItem->Text.Buffer = (PWSTR)ExAllocatePoolWithTag(PagedPool, MenuItem->Text.MaximumLength, TAG_STRING); if(!NewMenuItem->Text.Buffer) { ExFreePoolWithTag(NewMenuItem, TAG_MENUITEM); break; } RtlCopyUnicodeString(&NewMenuItem->Text, &MenuItem->Text); } else { NewMenuItem->Text.Buffer = MenuItem->Text.Buffer; } } else { NewMenuItem->Text.Buffer = MenuItem->Text.Buffer; } NewMenuItem->hbmpItem = MenuItem->hbmpItem; NewMenuItem->Next = NULL; if(Old) Old->Next = NewMenuItem; else Destination->MenuItemList = NewMenuItem; Destination->MenuInfo.MenuItemCount++; MenuItem = MenuItem->Next; } return TRUE; } PMENU_OBJECT FASTCALL IntCloneMenu(PMENU_OBJECT Source) { PPROCESSINFO CurrentWin32Process; HANDLE hMenu; PMENU_OBJECT Menu; if(!Source) return NULL; Menu = (PMENU_OBJECT)UserCreateObject( gHandleTable, NULL, NULL, &hMenu, otMenu, sizeof(MENU_OBJECT)); if(!Menu) return NULL; Menu->Process = PsGetCurrentProcess(); Menu->RtoL = Source->RtoL; Menu->MenuInfo.cbSize = sizeof(MENUINFO); /* Not used */ Menu->MenuInfo.fMask = Source->MenuInfo.fMask; Menu->MenuInfo.dwStyle = Source->MenuInfo.dwStyle; Menu->MenuInfo.cyMax = Source->MenuInfo.cyMax; Menu->MenuInfo.hbrBack = Source->MenuInfo.hbrBack; Menu->MenuInfo.dwContextHelpID = Source->MenuInfo.dwContextHelpID; Menu->MenuInfo.dwMenuData = Source->MenuInfo.dwMenuData; Menu->MenuInfo.Self = hMenu; Menu->MenuInfo.FocusedItem = NO_SELECTED_ITEM; Menu->MenuInfo.Wnd = NULL; Menu->MenuInfo.WndOwner = NULL; Menu->MenuInfo.Height = 0; Menu->MenuInfo.Width = 0; Menu->MenuInfo.TimeToHide = FALSE; Menu->MenuInfo.MenuItemCount = 0; Menu->MenuItemList = NULL; /* Insert menu item into process menu handle list */ CurrentWin32Process = PsGetCurrentProcessWin32Process(); InsertTailList(&CurrentWin32Process->MenuListHead, &Menu->ListEntry); IntCloneMenuItems(Menu, Source); return Menu; } BOOL FASTCALL IntSetMenuFlagRtoL(PMENU_OBJECT Menu) { Menu->RtoL = TRUE; return TRUE; } BOOL FASTCALL IntSetMenuContextHelpId(PMENU_OBJECT Menu, DWORD dwContextHelpId) { Menu->MenuInfo.dwContextHelpID = dwContextHelpId; return TRUE; } BOOL FASTCALL IntGetMenuInfo(PMENU_OBJECT Menu, PROSMENUINFO lpmi) { if(lpmi->fMask & MIM_BACKGROUND) lpmi->hbrBack = Menu->MenuInfo.hbrBack; if(lpmi->fMask & MIM_HELPID) lpmi->dwContextHelpID = Menu->MenuInfo.dwContextHelpID; if(lpmi->fMask & MIM_MAXHEIGHT) lpmi->cyMax = Menu->MenuInfo.cyMax; if(lpmi->fMask & MIM_MENUDATA) lpmi->dwMenuData = Menu->MenuInfo.dwMenuData; if(lpmi->fMask & MIM_STYLE) lpmi->dwStyle = Menu->MenuInfo.dwStyle; if (sizeof(MENUINFO) < lpmi->cbSize) { RtlCopyMemory((char *) lpmi + sizeof(MENUINFO), (char *) &Menu->MenuInfo + sizeof(MENUINFO), lpmi->cbSize - sizeof(MENUINFO)); } if (sizeof(ROSMENUINFO) == lpmi->cbSize) { lpmi->maxBmpSize.cx = Menu->MenuInfo.maxBmpSize.cx; lpmi->maxBmpSize.cy = Menu->MenuInfo.maxBmpSize.cy; } return TRUE; } BOOL FASTCALL IntSetMenuInfo(PMENU_OBJECT Menu, PROSMENUINFO lpmi) { if(lpmi->fMask & MIM_BACKGROUND) Menu->MenuInfo.hbrBack = lpmi->hbrBack; if(lpmi->fMask & MIM_HELPID) Menu->MenuInfo.dwContextHelpID = lpmi->dwContextHelpID; if(lpmi->fMask & MIM_MAXHEIGHT) Menu->MenuInfo.cyMax = lpmi->cyMax; if(lpmi->fMask & MIM_MENUDATA) Menu->MenuInfo.dwMenuData = lpmi->dwMenuData; if(lpmi->fMask & MIM_STYLE) Menu->MenuInfo.dwStyle = lpmi->dwStyle; if(lpmi->fMask & MIM_APPLYTOSUBMENUS) { /* FIXME */ } if (sizeof(MENUINFO) < lpmi->cbSize) { Menu->MenuInfo.FocusedItem = lpmi->FocusedItem; Menu->MenuInfo.Height = lpmi->Height; Menu->MenuInfo.Width = lpmi->Width; Menu->MenuInfo.Wnd = lpmi->Wnd; Menu->MenuInfo.WndOwner = lpmi->WndOwner; Menu->MenuInfo.TimeToHide = lpmi->TimeToHide; } if (sizeof(ROSMENUINFO) == lpmi->cbSize) { Menu->MenuInfo.maxBmpSize.cx = lpmi->maxBmpSize.cx; Menu->MenuInfo.maxBmpSize.cy = lpmi->maxBmpSize.cy; } return TRUE; } int FASTCALL IntGetMenuItemByFlag(PMENU_OBJECT Menu, UINT uSearchBy, UINT fFlag, PMENU_OBJECT *SubMenu, PMENU_ITEM *MenuItem, PMENU_ITEM *PrevMenuItem) { PMENU_ITEM PrevItem = NULL; PMENU_ITEM CurItem = Menu->MenuItemList; int p; int ret; if(MF_BYPOSITION & fFlag) { p = uSearchBy; while(CurItem && (p > 0)) { PrevItem = CurItem; CurItem = CurItem->Next; p--; } if(CurItem) { if(MenuItem) *MenuItem = CurItem; if(PrevMenuItem) *PrevMenuItem = PrevItem; } else { if(MenuItem) *MenuItem = NULL; if(PrevMenuItem) *PrevMenuItem = NULL; /* ? */ return -1; } return uSearchBy - p; } else { p = 0; while(CurItem) { if(CurItem->wID == uSearchBy) { if(MenuItem) *MenuItem = CurItem; if(PrevMenuItem) *PrevMenuItem = PrevItem; if(SubMenu) *SubMenu = Menu; return p; } else { if(CurItem->fType & MF_POPUP) { PMENU_OBJECT NewMenu = UserGetMenuObject(CurItem->hSubMenu); if(NewMenu) { ret = IntGetMenuItemByFlag(NewMenu, uSearchBy, fFlag, SubMenu, MenuItem, PrevMenuItem); if(ret != -1) { return ret; } } } } PrevItem = CurItem; CurItem = CurItem->Next; p++; } } return -1; } int FASTCALL IntInsertMenuItemToList(PMENU_OBJECT Menu, PMENU_ITEM MenuItem, int pos) { PMENU_ITEM CurItem; PMENU_ITEM LastItem = NULL; UINT npos = 0; CurItem = Menu->MenuItemList; while(CurItem && (pos != 0)) { LastItem = CurItem; CurItem = CurItem->Next; pos--; npos++; } if(LastItem) { /* Insert the item after LastItem */ LastItem->Next = MenuItem; } else { /* Insert at the beginning */ Menu->MenuItemList = MenuItem; } MenuItem->Next = CurItem; Menu->MenuInfo.MenuItemCount++; return npos; } BOOL FASTCALL IntGetMenuItemInfo(PMENU_OBJECT Menu, /* UNUSED PARAM!! */ PMENU_ITEM MenuItem, PROSMENUITEMINFO lpmii) { NTSTATUS Status; if(lpmii->fMask & (MIIM_FTYPE | MIIM_TYPE)) { lpmii->fType = MenuItem->fType; } if(lpmii->fMask & MIIM_BITMAP) { lpmii->hbmpItem = MenuItem->hbmpItem; } if(lpmii->fMask & MIIM_CHECKMARKS) { lpmii->hbmpChecked = MenuItem->hbmpChecked; lpmii->hbmpUnchecked = MenuItem->hbmpUnchecked; } if(lpmii->fMask & MIIM_DATA) { lpmii->dwItemData = MenuItem->dwItemData; } if(lpmii->fMask & MIIM_ID) { lpmii->wID = MenuItem->wID; } if(lpmii->fMask & MIIM_STATE) { lpmii->fState = MenuItem->fState; } if(lpmii->fMask & MIIM_SUBMENU) { lpmii->hSubMenu = MenuItem->hSubMenu; } if ((lpmii->fMask & MIIM_STRING) || ((lpmii->fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(lpmii->fType) == MF_STRING))) { if (lpmii->dwTypeData == NULL) { lpmii->cch = MenuItem->Text.Length / sizeof(WCHAR); } else { Status = MmCopyToCaller(lpmii->dwTypeData, MenuItem->Text.Buffer, min(lpmii->cch * sizeof(WCHAR), MenuItem->Text.MaximumLength)); if (! NT_SUCCESS(Status)) { SetLastNtError(Status); return FALSE; } } } if (sizeof(ROSMENUITEMINFO) == lpmii->cbSize) { lpmii->Rect = MenuItem->Rect; lpmii->dxTab = MenuItem->dxTab; lpmii->lpstr = MenuItem->Text.Buffer; // Use DesktopHeap! } return TRUE; } BOOL FASTCALL IntSetMenuItemInfo(PMENU_OBJECT MenuObject, PMENU_ITEM MenuItem, PROSMENUITEMINFO lpmii) { PMENU_OBJECT SubMenuObject; UINT fTypeMask = (MFT_BITMAP | MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_OWNERDRAW | MFT_RADIOCHECK | MFT_RIGHTJUSTIFY | MFT_SEPARATOR | MF_POPUP); if(!MenuItem || !MenuObject || !lpmii) { return FALSE; } if (lpmii->fType & ~fTypeMask) { ERR("IntSetMenuItemInfo invalid fType flags %x\n", lpmii->fType & ~fTypeMask); lpmii->fMask &= ~(MIIM_TYPE | MIIM_FTYPE); } if (lpmii->fMask & MIIM_TYPE) { if (lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) { ERR("IntSetMenuItemInfo: Invalid combination of fMask bits used\n"); /* This does not happen on Win9x/ME */ SetLastNtError( ERROR_INVALID_PARAMETER); return FALSE; } /* * Delete the menu item type when changing type from * MF_STRING. */ if (MenuItem->fType != lpmii->fType && MENU_ITEM_TYPE(MenuItem->fType) == MFT_STRING) { FreeMenuText(MenuItem); RtlInitUnicodeString(&MenuItem->Text, NULL); } if(lpmii->fType & MFT_BITMAP) { if(lpmii->hbmpItem) MenuItem->hbmpItem = lpmii->hbmpItem; else { /* Win 9x/Me stuff */ MenuItem->hbmpItem = (HBITMAP)((ULONG_PTR)(LOWORD(lpmii->dwTypeData))); } } MenuItem->fType |= lpmii->fType; } if (lpmii->fMask & MIIM_FTYPE ) { if(( lpmii->fType & MFT_BITMAP)) { ERR("IntSetMenuItemInfo: Can not use FTYPE and MFT_BITMAP.\n"); SetLastNtError( ERROR_INVALID_PARAMETER); return FALSE; } MenuItem->fType |= lpmii->fType; /* Need to save all the flags, this fixed MFT_RIGHTJUSTIFY */ } if(lpmii->fMask & MIIM_BITMAP) { MenuItem->hbmpItem = lpmii->hbmpItem; } if(lpmii->fMask & MIIM_CHECKMARKS) { MenuItem->hbmpChecked = lpmii->hbmpChecked; MenuItem->hbmpUnchecked = lpmii->hbmpUnchecked; } if(lpmii->fMask & MIIM_DATA) { MenuItem->dwItemData = lpmii->dwItemData; } if(lpmii->fMask & MIIM_ID) { MenuItem->wID = lpmii->wID; } if(lpmii->fMask & MIIM_STATE) { /* Remove MFS_DEFAULT flag from all other menu items if this item has the MFS_DEFAULT state */ if(lpmii->fState & MFS_DEFAULT) UserSetMenuDefaultItem(MenuObject, -1, 0); /* Update the menu item state flags */ UpdateMenuItemState(MenuItem->fState, lpmii->fState); } if(lpmii->fMask & MIIM_SUBMENU) { MenuItem->hSubMenu = lpmii->hSubMenu; /* Make sure the submenu is marked as a popup menu */ if (MenuItem->hSubMenu) { SubMenuObject = UserGetMenuObject(MenuItem->hSubMenu); if (SubMenuObject != NULL) { SubMenuObject->MenuInfo.Flags |= MF_POPUP; MenuItem->fType |= MF_POPUP; } else { MenuItem->fType &= ~MF_POPUP; } } else { MenuItem->fType &= ~MF_POPUP; } } if ((lpmii->fMask & MIIM_STRING) || ((lpmii->fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(lpmii->fType) == MF_STRING))) { FreeMenuText(MenuItem); if(lpmii->dwTypeData && lpmii->cch) { UNICODE_STRING Source; Source.Length = Source.MaximumLength = lpmii->cch * sizeof(WCHAR); Source.Buffer = lpmii->dwTypeData; MenuItem->Text.Buffer = (PWSTR)ExAllocatePoolWithTag( PagedPool, Source.Length + sizeof(WCHAR), TAG_STRING); if(MenuItem->Text.Buffer != NULL) { MenuItem->Text.Length = 0; MenuItem->Text.MaximumLength = Source.Length + sizeof(WCHAR); RtlCopyUnicodeString(&MenuItem->Text, &Source); MenuItem->Text.Buffer[MenuItem->Text.Length / sizeof(WCHAR)] = 0; } else { RtlInitUnicodeString(&MenuItem->Text, NULL); } } else { if (0 == (MenuObject->MenuInfo.Flags & MF_SYSMENU)) { MenuItem->fType |= MF_SEPARATOR; } RtlInitUnicodeString(&MenuItem->Text, NULL); } } if (sizeof(ROSMENUITEMINFO) == lpmii->cbSize) { MenuItem->Rect = lpmii->Rect; MenuItem->dxTab = lpmii->dxTab; lpmii->lpstr = MenuItem->Text.Buffer; /* Use DesktopHeap! Send back new allocated string or zero */ } return TRUE; } BOOL FASTCALL IntInsertMenuItem(PMENU_OBJECT MenuObject, UINT uItem, BOOL fByPosition, PROSMENUITEMINFO ItemInfo) { int pos; PMENU_ITEM MenuItem; PMENU_OBJECT SubMenu = NULL; if (MAX_MENU_ITEMS <= MenuObject->MenuInfo.MenuItemCount) { EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } if (fByPosition) { SubMenu = MenuObject; /* calculate position */ pos = (int)uItem; if(uItem > MenuObject->MenuInfo.MenuItemCount) { pos = MenuObject->MenuInfo.MenuItemCount; } } else { pos = IntGetMenuItemByFlag(MenuObject, uItem, MF_BYCOMMAND, &SubMenu, NULL, NULL); } if (SubMenu == NULL) { /* Default to last position of menu */ SubMenu = MenuObject; pos = MenuObject->MenuInfo.MenuItemCount; } if (pos < -1) { pos = -1; } MenuItem = ExAllocatePoolWithTag(PagedPool, sizeof(MENU_ITEM), TAG_MENUITEM); if (NULL == MenuItem) { EngSetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } MenuItem->fType = MFT_STRING; MenuItem->fState = MFS_ENABLED | MFS_UNCHECKED; MenuItem->wID = 0; MenuItem->hSubMenu = (HMENU)0; MenuItem->hbmpChecked = (HBITMAP)0; MenuItem->hbmpUnchecked = (HBITMAP)0; MenuItem->dwItemData = 0; RtlInitUnicodeString(&MenuItem->Text, NULL); MenuItem->hbmpItem = (HBITMAP)0; if(!IntSetMenuItemInfo(SubMenu, MenuItem, ItemInfo)) { ExFreePoolWithTag(MenuItem, TAG_MENUITEM); return FALSE; } /* Force size recalculation! */ MenuObject->MenuInfo.Height = 0; pos = IntInsertMenuItemToList(SubMenu, MenuItem, pos); TRACE("IntInsertMenuItemToList = %i\n", pos); return (pos >= 0); } UINT FASTCALL IntEnableMenuItem(PMENU_OBJECT MenuObject, UINT uIDEnableItem, UINT uEnable) { PMENU_ITEM MenuItem; UINT res = IntGetMenuItemByFlag(MenuObject, uIDEnableItem, uEnable, NULL, &MenuItem, NULL); if(!MenuItem || (res == (UINT)-1)) { return (UINT)-1; } res = MenuItem->fState & (MF_GRAYED | MF_DISABLED); if(uEnable & MF_DISABLED) { MenuItem->fState |= MF_DISABLED; MenuItem->fState |= uEnable & MF_GRAYED; } else { if(uEnable & MF_GRAYED) { MenuItem->fState |= (MF_GRAYED | MF_DISABLED); } else { MenuItem->fState &= ~(MF_DISABLED | MF_GRAYED); } } return res; } DWORD FASTCALL IntBuildMenuItemList(PMENU_OBJECT MenuObject, PVOID Buffer, ULONG nMax) { DWORD res = 0; ROSMENUITEMINFO mii; PVOID Buf; PMENU_ITEM CurItem = MenuObject->MenuItemList; PWCHAR StrOut; NTSTATUS Status; WCHAR NulByte; if (0 != nMax) { if (nMax < MenuObject->MenuInfo.MenuItemCount * sizeof(ROSMENUITEMINFO)) { return 0; } StrOut = (PWCHAR)((char *) Buffer + MenuObject->MenuInfo.MenuItemCount * sizeof(ROSMENUITEMINFO)); nMax -= MenuObject->MenuInfo.MenuItemCount * sizeof(ROSMENUITEMINFO); Buf = Buffer; mii.cbSize = sizeof(ROSMENUITEMINFO); mii.fMask = 0; NulByte = L'\0'; while (NULL != CurItem) { mii.cch = CurItem->Text.Length / sizeof(WCHAR); mii.dwItemData = CurItem->dwItemData; if (0 != CurItem->Text.Length) { mii.dwTypeData = StrOut; } else { mii.dwTypeData = NULL; } mii.fState = CurItem->fState; mii.fType = CurItem->fType; mii.wID = CurItem->wID; mii.hbmpChecked = CurItem->hbmpChecked; mii.hbmpItem = CurItem->hbmpItem; mii.hbmpUnchecked = CurItem->hbmpUnchecked; mii.hSubMenu = CurItem->hSubMenu; mii.Rect = CurItem->Rect; mii.dxTab = CurItem->dxTab; mii.lpstr = CurItem->Text.Buffer; // Use DesktopHeap! Status = MmCopyToCaller(Buf, &mii, sizeof(ROSMENUITEMINFO)); if (! NT_SUCCESS(Status)) { SetLastNtError(Status); return 0; } Buf = (PVOID)((ULONG_PTR)Buf + sizeof(ROSMENUITEMINFO)); if (0 != CurItem->Text.Length && (nMax >= CurItem->Text.Length + sizeof(WCHAR))) { /* Copy string */ Status = MmCopyToCaller(StrOut, CurItem->Text.Buffer, CurItem->Text.Length); if (! NT_SUCCESS(Status)) { SetLastNtError(Status); return 0; } StrOut += CurItem->Text.Length / sizeof(WCHAR); Status = MmCopyToCaller(StrOut, &NulByte, sizeof(WCHAR)); if (! NT_SUCCESS(Status)) { SetLastNtError(Status); return 0; } StrOut++; nMax -= CurItem->Text.Length + sizeof(WCHAR); } else if (0 != CurItem->Text.Length) { break; } CurItem = CurItem->Next; res++; } } else { while (NULL != CurItem) { res += sizeof(ROSMENUITEMINFO) + CurItem->Text.Length + sizeof(WCHAR); CurItem = CurItem->Next; } } return res; } DWORD FASTCALL IntCheckMenuItem(PMENU_OBJECT MenuObject, UINT uIDCheckItem, UINT uCheck) { PMENU_ITEM MenuItem; int res = -1; if((IntGetMenuItemByFlag(MenuObject, uIDCheckItem, uCheck, NULL, &MenuItem, NULL) < 0) || !MenuItem) { return -1; } res = (DWORD)(MenuItem->fState & MF_CHECKED); if(uCheck & MF_CHECKED) { MenuItem->fState |= MF_CHECKED; } else { MenuItem->fState &= ~MF_CHECKED; } return (DWORD)res; } BOOL FASTCALL IntHiliteMenuItem(PWND WindowObject, PMENU_OBJECT MenuObject, UINT uItemHilite, UINT uHilite) { PMENU_ITEM MenuItem; BOOL res = IntGetMenuItemByFlag(MenuObject, uItemHilite, uHilite, NULL, &MenuItem, NULL); if(!MenuItem || !res) { return FALSE; } if(uHilite & MF_HILITE) { MenuItem->fState |= MF_HILITE; } else { MenuItem->fState &= ~MF_HILITE; } /* FIXME: Update the window's menu */ return TRUE; } BOOL FASTCALL UserSetMenuDefaultItem(PMENU_OBJECT MenuObject, UINT uItem, UINT fByPos) { BOOL ret = FALSE; PMENU_ITEM MenuItem = MenuObject->MenuItemList; if(uItem == (UINT)-1) { while(MenuItem) { MenuItem->fState &= ~MFS_DEFAULT; MenuItem = MenuItem->Next; } return TRUE; } if(fByPos) { UINT pos = 0; while(MenuItem) { if(pos == uItem) { MenuItem->fState |= MFS_DEFAULT; ret = TRUE; } else { MenuItem->fState &= ~MFS_DEFAULT; } pos++; MenuItem = MenuItem->Next; } } else { while(MenuItem) { if(!ret && (MenuItem->wID == uItem)) { MenuItem->fState |= MFS_DEFAULT; ret = TRUE; } else { MenuItem->fState &= ~MFS_DEFAULT; } MenuItem = MenuItem->Next; } } return ret; } UINT FASTCALL IntGetMenuDefaultItem(PMENU_OBJECT MenuObject, UINT fByPos, UINT gmdiFlags, DWORD *gismc) { UINT x = 0; UINT res = -1; UINT sres; PMENU_OBJECT SubMenuObject; PMENU_ITEM MenuItem = MenuObject->MenuItemList; while(MenuItem) { if(MenuItem->fState & MFS_DEFAULT) { if(!(gmdiFlags & GMDI_USEDISABLED) && (MenuItem->fState & MFS_DISABLED)) break; if(fByPos) res = x; else res = MenuItem->wID; if((*gismc < MAX_GOINTOSUBMENU) && (gmdiFlags & GMDI_GOINTOPOPUPS) && MenuItem->hSubMenu) { SubMenuObject = UserGetMenuObject(MenuItem->hSubMenu); if(!SubMenuObject || (SubMenuObject == MenuObject)) break; (*gismc)++; sres = IntGetMenuDefaultItem(SubMenuObject, fByPos, gmdiFlags, gismc); (*gismc)--; if(sres > (UINT)-1) res = sres; } break; } MenuItem = MenuItem->Next; x++; } return res; } VOID FASTCALL co_IntInitTracking(PWND Window, PMENU_OBJECT Menu, BOOL Popup, UINT Flags) { /* FIXME: Hide caret */ if(!(Flags & TPM_NONOTIFY)) co_IntSendMessage(Window->head.h, WM_SETCURSOR, (WPARAM)Window->head.h, HTCAPTION); /* FIXME: Send WM_SETCURSOR message */ if(!(Flags & TPM_NONOTIFY)) co_IntSendMessage(Window->head.h, WM_INITMENU, (WPARAM)Menu->MenuInfo.Self, 0); } VOID FASTCALL co_IntExitTracking(PWND Window, PMENU_OBJECT Menu, BOOL Popup, UINT Flags) { if(!(Flags & TPM_NONOTIFY)) co_IntSendMessage(Window->head.h, WM_EXITMENULOOP, 0 /* FIXME */, 0); /* FIXME: Show caret again */ } INT FASTCALL IntTrackMenu(PMENU_OBJECT Menu, PWND Window, INT x, INT y, RECTL lprect) { return 0; } BOOL FASTCALL co_IntTrackPopupMenu(PMENU_OBJECT Menu, PWND Window, UINT Flags, POINT *Pos, UINT MenuPos, RECTL *ExcludeRect) { co_IntInitTracking(Window, Menu, TRUE, Flags); co_IntExitTracking(Window, Menu, TRUE, Flags); return FALSE; } /*! * Internal function. Called when the process is destroyed to free the remaining menu handles. */ BOOL FASTCALL IntCleanupMenus(struct _EPROCESS *Process, PPROCESSINFO Win32Process) { PEPROCESS CurrentProcess; PLIST_ENTRY LastHead = NULL; PMENU_OBJECT MenuObject; CurrentProcess = PsGetCurrentProcess(); if (CurrentProcess != Process) { KeAttachProcess(&Process->Pcb); } while (Win32Process->MenuListHead.Flink != &(Win32Process->MenuListHead) && Win32Process->MenuListHead.Flink != LastHead) { LastHead = Win32Process->MenuListHead.Flink; MenuObject = CONTAINING_RECORD(Win32Process->MenuListHead.Flink, MENU_OBJECT, ListEntry); IntDestroyMenuObject(MenuObject, FALSE, TRUE); } if (CurrentProcess != Process) { KeDetachProcess(); } return TRUE; } BOOLEAN APIENTRY intGetTitleBarInfo(PWND pWindowObject, PTITLEBARINFO bti) { DWORD dwStyle = 0; DWORD dwExStyle = 0; BOOLEAN retValue = TRUE; if (bti->cbSize == sizeof(TITLEBARINFO)) { RtlZeroMemory(&bti->rgstate[0],sizeof(DWORD)*(CCHILDREN_TITLEBAR+1)); bti->rgstate[0] = STATE_SYSTEM_FOCUSABLE; dwStyle = pWindowObject->style; dwExStyle = pWindowObject->ExStyle; bti->rcTitleBar.top = 0; bti->rcTitleBar.left = 0; bti->rcTitleBar.right = pWindowObject->rcWindow.right - pWindowObject->rcWindow.left; bti->rcTitleBar.bottom = pWindowObject->rcWindow.bottom - pWindowObject->rcWindow.top; /* Is it iconiced ? */ if ((dwStyle & WS_ICONIC)!=WS_ICONIC) { /* Remove frame from rectangle */ if (HAS_THICKFRAME( dwStyle, dwExStyle )) { /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXFRAME) and UserGetSystemMetrics(SM_CYFRAME) */ RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) ); } else if (HAS_DLGFRAME( dwStyle, dwExStyle )) { /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXDLGFRAME) and UserGetSystemMetrics(SM_CYDLGFRAME) */ RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME)); } else if (HAS_THINFRAME( dwStyle, dwExStyle)) { /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */ RECTL_vInflateRect( &bti->rcTitleBar, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER) ); } /* We have additional border information if the window * is a child (but not an MDI child) */ if ( (dwStyle & WS_CHILD) && ((dwExStyle & WS_EX_MDICHILD) == 0 ) ) { if (dwExStyle & WS_EX_CLIENTEDGE) { /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXEDGE) and UserGetSystemMetrics(SM_CYEDGE) */ RECTL_vInflateRect (&bti->rcTitleBar, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE)); } if (dwExStyle & WS_EX_STATICEDGE) { /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CXBORDER) and UserGetSystemMetrics(SM_CYBORDER) */ RECTL_vInflateRect (&bti->rcTitleBar, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER)); } } } bti->rcTitleBar.top += pWindowObject->rcWindow.top; bti->rcTitleBar.left += pWindowObject->rcWindow.left; bti->rcTitleBar.right += pWindowObject->rcWindow.left; bti->rcTitleBar.bottom = bti->rcTitleBar.top; if (dwExStyle & WS_EX_TOOLWINDOW) { /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYSMCAPTION) */ bti->rcTitleBar.bottom += UserGetSystemMetrics(SM_CYSMCAPTION); } else { /* FIXME: Note this value should exists in pWindowObject for UserGetSystemMetrics(SM_CYCAPTION) and UserGetSystemMetrics(SM_CXSIZE) */ bti->rcTitleBar.bottom += UserGetSystemMetrics(SM_CYCAPTION); bti->rcTitleBar.left += UserGetSystemMetrics(SM_CXSIZE); } if (dwStyle & WS_CAPTION) { bti->rgstate[1] = STATE_SYSTEM_INVISIBLE; if (dwStyle & WS_SYSMENU) { if (!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) { bti->rgstate[2] = STATE_SYSTEM_INVISIBLE; bti->rgstate[3] = STATE_SYSTEM_INVISIBLE; } else { if (!(dwStyle & WS_MINIMIZEBOX)) { bti->rgstate[2] = STATE_SYSTEM_UNAVAILABLE; } if (!(dwStyle & WS_MAXIMIZEBOX)) { bti->rgstate[3] = STATE_SYSTEM_UNAVAILABLE; } } if (!(dwExStyle & WS_EX_CONTEXTHELP)) { bti->rgstate[4] = STATE_SYSTEM_INVISIBLE; } if (pWindowObject->pcls->style & CS_NOCLOSE) { bti->rgstate[5] = STATE_SYSTEM_UNAVAILABLE; } } else { bti->rgstate[2] = STATE_SYSTEM_INVISIBLE; bti->rgstate[3] = STATE_SYSTEM_INVISIBLE; bti->rgstate[4] = STATE_SYSTEM_INVISIBLE; bti->rgstate[5] = STATE_SYSTEM_INVISIBLE; } } else { bti->rgstate[0] |= STATE_SYSTEM_INVISIBLE; } } else { EngSetLastError(ERROR_INVALID_PARAMETER); retValue = FALSE; } return retValue; } DWORD FASTCALL UserInsertMenuItem( PMENU_OBJECT Menu, UINT uItem, BOOL fByPosition, LPCMENUITEMINFOW UnsafeItemInfo) { NTSTATUS Status; ROSMENUITEMINFO ItemInfo; /* Try to copy the whole MENUITEMINFOW structure */ Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, sizeof(MENUITEMINFOW)); if (NT_SUCCESS(Status)) { if (sizeof(MENUITEMINFOW) != ItemInfo.cbSize && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize) { EngSetLastError(ERROR_INVALID_PARAMETER); return FALSE; } return IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo); } /* Try to copy without last field (not present in older versions) */ Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, FIELD_OFFSET(MENUITEMINFOW, hbmpItem)); if (NT_SUCCESS(Status)) { if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != ItemInfo.cbSize) { EngSetLastError(ERROR_INVALID_PARAMETER); return FALSE; } ItemInfo.hbmpItem = (HBITMAP)0; return IntInsertMenuItem(Menu, uItem, fByPosition, &ItemInfo); } SetLastNtError(Status); return FALSE; } UINT FASTCALL IntGetMenuState( HMENU hMenu, UINT uId, UINT uFlags) { PMENU_OBJECT MenuObject, SubMenu; PMENU_ITEM mi; if (!(MenuObject = UserGetMenuObject(hMenu))) { return (UINT)-1; } if (IntGetMenuItemByFlag(MenuObject, uId, uFlags, &SubMenu, &mi, NULL)) { if (mi->hSubMenu) { if (SubMenu) { UINT nSubItems = SubMenu->MenuInfo.MenuItemCount; return (nSubItems << 8) | ((mi->fState | mi->fType) & 0xff); } else return (UINT)-1; } return (mi->fType | mi->fState); } return (UINT)-1; } HMENU FASTCALL IntGetSubMenu( HMENU hMenu, int nPos) { PMENU_OBJECT MenuObject, SubMenu; if (!(MenuObject = UserGetMenuObject(hMenu))) { return NULL; } if (IntGetMenuItemByFlag(MenuObject, nPos, MF_BYPOSITION, &SubMenu, NULL, NULL)) { return SubMenu ? UserHMGetHandle(SubMenu) : NULL; } return NULL; } UINT FASTCALL IntFindSubMenu(HMENU *hMenu, HMENU hSubTarget ) { PMENU_OBJECT MenuObject; PMENU_ITEM mi; UINT i; if ( (*hMenu) == (HMENU)0xffff || !(MenuObject = UserGetMenuObject(*hMenu)) ) return NO_SELECTED_ITEM; for (i = 0; i < MenuObject->MenuInfo.MenuItemCount; i++) { if (!IntGetMenuItemByFlag(MenuObject, i, MF_BYPOSITION, NULL, &mi, NULL)) { return NO_SELECTED_ITEM; } if (!(mi->fType & MF_POPUP)) continue; if (mi->hSubMenu == hSubTarget) { return i; } else { HMENU hsubmenu = mi->hSubMenu; UINT pos = IntFindSubMenu(&hsubmenu, hSubTarget ); if (pos != NO_SELECTED_ITEM) { *hMenu = hsubmenu; return pos; } } } return NO_SELECTED_ITEM; } /* FUNCTIONS *****************************************************************/ /* * @implemented */ DWORD APIENTRY NtUserCheckMenuItem( HMENU hMenu, UINT uIDCheckItem, UINT uCheck) { PMENU_OBJECT Menu; DECLARE_RETURN(DWORD); TRACE("Enter NtUserCheckMenuItem\n"); UserEnterExclusive(); if(!(Menu = UserGetMenuObject(hMenu))) { RETURN( (DWORD)-1); } RETURN( IntCheckMenuItem(Menu, uIDCheckItem, uCheck)); CLEANUP: TRACE("Leave NtUserCheckMenuItem, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } HMENU FASTCALL UserCreateMenu(BOOL PopupMenu) { PWINSTATION_OBJECT WinStaObject; HANDLE Handle; PMENU_OBJECT Menu; NTSTATUS Status; PEPROCESS CurrentProcess = PsGetCurrentProcess(); if (CsrProcess != CurrentProcess) { /* * CsrProcess does not have a Win32WindowStation * */ Status = IntValidateWindowStationHandle(PsGetCurrentProcess()->Win32WindowStation, KernelMode, 0, &WinStaObject); if (!NT_SUCCESS(Status)) { ERR("Validation of window station handle (0x%X) failed\n", CurrentProcess->Win32WindowStation); SetLastNtError(Status); return (HMENU)0; } Menu = IntCreateMenu(&Handle, !PopupMenu); ObDereferenceObject(WinStaObject); } else { Menu = IntCreateMenu(&Handle, !PopupMenu); } if (Menu) UserDereferenceObject(Menu); return (HMENU)Handle; } /* * @implemented */ BOOL APIENTRY NtUserDeleteMenu( HMENU hMenu, UINT uPosition, UINT uFlags) { PMENU_OBJECT Menu; DECLARE_RETURN(BOOL); TRACE("Enter NtUserDeleteMenu\n"); UserEnterExclusive(); if(!(Menu = UserGetMenuObject(hMenu))) { RETURN( FALSE); } RETURN( IntRemoveMenuItem(Menu, uPosition, uFlags, TRUE)); CLEANUP: TRACE("Leave NtUserDeleteMenu, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } /* * @implemented */ BOOLEAN APIENTRY NtUserGetTitleBarInfo( HWND hwnd, PTITLEBARINFO bti) { PWND WindowObject; TITLEBARINFO bartitleinfo; DECLARE_RETURN(BOOLEAN); BOOLEAN retValue = TRUE; TRACE("Enter NtUserGetTitleBarInfo\n"); UserEnterExclusive(); /* Vaildate the windows handle */ if (!(WindowObject = UserGetWindowObject(hwnd))) { EngSetLastError(ERROR_INVALID_WINDOW_HANDLE); retValue = FALSE; } _SEH2_TRY { /* Copy our usermode buffer bti to local buffer bartitleinfo */ ProbeForRead(bti, sizeof(TITLEBARINFO), 1); RtlCopyMemory(&bartitleinfo, bti, sizeof(TITLEBARINFO)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Fail copy the data */ EngSetLastError(ERROR_INVALID_PARAMETER); retValue = FALSE; } _SEH2_END /* Get the tile bar info */ if (retValue) { retValue = intGetTitleBarInfo(WindowObject, &bartitleinfo); if (retValue) { _SEH2_TRY { /* Copy our buffer to user mode buffer bti */ ProbeForWrite(bti, sizeof(TITLEBARINFO), 1); RtlCopyMemory(bti, &bartitleinfo, sizeof(TITLEBARINFO)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { /* Fail copy the data */ EngSetLastError(ERROR_INVALID_PARAMETER); retValue = FALSE; } _SEH2_END } } RETURN( retValue ); CLEANUP: TRACE("Leave NtUserGetTitleBarInfo, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } /* * @implemented */ BOOL FASTCALL UserDestroyMenu(HMENU hMenu) { PMENU_OBJECT Menu; if(!(Menu = UserGetMenuObject(hMenu))) { return FALSE; } if(Menu->Process != PsGetCurrentProcess()) { EngSetLastError(ERROR_ACCESS_DENIED); return FALSE; } return IntDestroyMenuObject(Menu, FALSE, TRUE); } /* * @implemented */ BOOL APIENTRY NtUserDestroyMenu( HMENU hMenu) { PMENU_OBJECT Menu; DECLARE_RETURN(BOOL); TRACE("Enter NtUserDestroyMenu\n"); UserEnterExclusive(); if(!(Menu = UserGetMenuObject(hMenu))) { RETURN( FALSE); } if(Menu->Process != PsGetCurrentProcess()) { EngSetLastError(ERROR_ACCESS_DENIED); RETURN( FALSE); } RETURN( IntDestroyMenuObject(Menu, TRUE, TRUE)); CLEANUP: TRACE("Leave NtUserDestroyMenu, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } /* * @implemented */ UINT APIENTRY NtUserEnableMenuItem( HMENU hMenu, UINT uIDEnableItem, UINT uEnable) { PMENU_OBJECT Menu; DECLARE_RETURN(UINT); TRACE("Enter NtUserEnableMenuItem\n"); UserEnterExclusive(); if(!(Menu = UserGetMenuObject(hMenu))) { RETURN(-1); } RETURN( IntEnableMenuItem(Menu, uIDEnableItem, uEnable)); CLEANUP: TRACE("Leave NtUserEnableMenuItem, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } /* * @implemented */ BOOL APIENTRY NtUserGetMenuBarInfo( HWND hwnd, LONG idObject, LONG idItem, PMENUBARINFO pmbi) { BOOL Res = TRUE; PMENU_OBJECT MenuObject; PMENU_ITEM mi; PWND WindowObject; HMENU hMenu; POINT Offset; RECTL Rect; MENUBARINFO kmbi; DECLARE_RETURN(BOOL); TRACE("Enter NtUserGetMenuBarInfo\n"); UserEnterShared(); if (!(WindowObject = UserGetWindowObject(hwnd))) { EngSetLastError(ERROR_INVALID_WINDOW_HANDLE); RETURN(FALSE); } hMenu = (HMENU)(DWORD_PTR)WindowObject->IDMenu; if (!(MenuObject = UserGetMenuObject(hMenu))) { EngSetLastError(ERROR_INVALID_MENU_HANDLE); RETURN(FALSE); } if (pmbi->cbSize != sizeof(MENUBARINFO)) { EngSetLastError(ERROR_INVALID_PARAMETER); RETURN(FALSE); } kmbi.cbSize = sizeof(MENUBARINFO); kmbi.fBarFocused = FALSE; kmbi.fFocused = FALSE; kmbi.hwndMenu = NULL; switch (idObject) { case OBJID_MENU: { PMENU_OBJECT SubMenuObject; kmbi.hMenu = hMenu; if (idItem) /* Non-Zero-Based. */ { if (IntGetMenuItemByFlag(MenuObject, idItem-1, MF_BYPOSITION, NULL, &mi, NULL) > -1) kmbi.rcBar = mi->Rect; else { Res = FALSE; break; } } else { /* If items is zero we assume info for the menu itself. */ if (!(IntGetClientOrigin(WindowObject, &Offset))) { Res = FALSE; break; } Rect.left = Offset.x; Rect.right = Offset.x + MenuObject->MenuInfo.Width; Rect.bottom = Offset.y; Rect.top = Offset.y - MenuObject->MenuInfo.Height; kmbi.rcBar = Rect; TRACE("Rect top = %d bottom = %d left = %d right = %d \n", Rect.top, Rect.bottom, Rect.left, Rect.right); } if (idItem) { if (idItem-1 == MenuObject->MenuInfo.FocusedItem) kmbi.fFocused = TRUE; } if (MenuObject->MenuInfo.FocusedItem != NO_SELECTED_ITEM) kmbi.fBarFocused = TRUE; if (MenuObject->MenuItemList) { SubMenuObject = UserGetMenuObject(MenuObject->MenuItemList->hSubMenu); if(SubMenuObject) kmbi.hwndMenu = SubMenuObject->MenuInfo.Wnd; } TRACE("OBJID_MENU, idItem = %d\n",idItem); break; } case OBJID_CLIENT: { PMENU_OBJECT SubMenuObject, XSubMenuObject; HMENU hMenuChk; // Windows does this! Wine checks for Atom and uses GetWindowLongPtrW. hMenuChk = (HMENU)co_IntSendMessage(hwnd, MN_GETHMENU, 0, 0); if (!(MenuObject = UserGetMenuObject(hMenuChk))) { ERR("Window does not have a Popup Menu!\n"); EngSetLastError(ERROR_INVALID_MENU_HANDLE); RETURN(FALSE); } SubMenuObject = UserGetMenuObject(MenuObject->MenuItemList->hSubMenu); if(SubMenuObject) kmbi.hMenu = SubMenuObject->MenuInfo.Self; else { Res = FALSE; ERR("OBJID_CLIENT, No SubMenu!\n"); break; } if (idItem) { if (IntGetMenuItemByFlag(SubMenuObject, idItem-1, MF_BYPOSITION, NULL, &mi, NULL) > -1) kmbi.rcBar = mi->Rect; else { Res = FALSE; break; } } else { PWND SubWinObj; if (!(SubWinObj = UserGetWindowObject(SubMenuObject->MenuInfo.Wnd))) { Res = FALSE; break; } if (!(IntGetClientOrigin(SubWinObj, &Offset))) { Res = FALSE; break; } Rect.left = Offset.x; Rect.right = Offset.x + SubMenuObject->MenuInfo.Width; Rect.top = Offset.y; Rect.bottom = Offset.y + SubMenuObject->MenuInfo.Height; kmbi.rcBar = Rect; } if (idItem) { if (idItem-1 == SubMenuObject->MenuInfo.FocusedItem) kmbi.fFocused = TRUE; } if (SubMenuObject->MenuInfo.FocusedItem != NO_SELECTED_ITEM) kmbi.fBarFocused = TRUE; XSubMenuObject = UserGetMenuObject(SubMenuObject->MenuItemList->hSubMenu); if (XSubMenuObject) kmbi.hwndMenu = XSubMenuObject->MenuInfo.Wnd; TRACE("OBJID_CLIENT, idItem = %d\n",idItem); break; } case OBJID_SYSMENU: { PMENU_OBJECT SysMenuObject, SubMenuObject; if(!(SysMenuObject = IntGetSystemMenu(WindowObject, FALSE, FALSE))) { Res = FALSE; break; } kmbi.hMenu = SysMenuObject->MenuInfo.Self; if (idItem) { if (IntGetMenuItemByFlag(SysMenuObject, idItem-1, MF_BYPOSITION, NULL, &mi, NULL) > -1) kmbi.rcBar = mi->Rect; else { Res = FALSE; break; } } else { PWND SysWinObj; if (!(SysWinObj = UserGetWindowObject(SysMenuObject->MenuInfo.Wnd))) { Res = FALSE; break; } if (!(IntGetClientOrigin(SysWinObj, &Offset))) { Res = FALSE; break; } Rect.left = Offset.x; Rect.right = Offset.x + SysMenuObject->MenuInfo.Width; Rect.top = Offset.y; Rect.bottom = Offset.y + SysMenuObject->MenuInfo.Height; kmbi.rcBar = Rect; } if (idItem) { if (idItem-1 == SysMenuObject->MenuInfo.FocusedItem) kmbi.fFocused = TRUE; } if (SysMenuObject->MenuInfo.FocusedItem != NO_SELECTED_ITEM) kmbi.fBarFocused = TRUE; SubMenuObject = UserGetMenuObject(SysMenuObject->MenuItemList->hSubMenu); if(SubMenuObject) kmbi.hwndMenu = SubMenuObject->MenuInfo.Wnd; TRACE("OBJID_SYSMENU, idItem = %d\n",idItem); break; } default: Res = FALSE; ERR("Unknown idObject = %d, idItem = %d\n",idObject,idItem); } if (Res) { NTSTATUS Status = MmCopyToCaller(pmbi, &kmbi, sizeof(MENUBARINFO)); if (! NT_SUCCESS(Status)) { SetLastNtError(Status); RETURN(FALSE); } } RETURN(Res); CLEANUP: TRACE("Leave NtUserGetMenuBarInfo, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } /* * @implemented */ UINT APIENTRY NtUserGetMenuIndex( HMENU hMenu, HMENU hSubMenu) { PMENU_OBJECT Menu, SubMenu; PMENU_ITEM MenuItem; DECLARE_RETURN(UINT); TRACE("Enter NtUserGetMenuIndex\n"); UserEnterShared(); if ( !(Menu = UserGetMenuObject(hMenu)) || !(SubMenu = UserGetMenuObject(hSubMenu)) ) RETURN(0xFFFFFFFF); MenuItem = Menu->MenuItemList; while(MenuItem) { if (MenuItem->hSubMenu == hSubMenu) RETURN(MenuItem->wID); MenuItem = MenuItem->Next; } RETURN(0xFFFFFFFF); CLEANUP: TRACE("Leave NtUserGetMenuIndex, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } /* * @implemented */ BOOL APIENTRY NtUserGetMenuItemRect( HWND hWnd, HMENU hMenu, UINT uItem, PRECTL lprcItem) { PWND ReferenceWnd; LONG XMove, YMove; RECTL Rect; NTSTATUS Status; PMENU_OBJECT Menu; PMENU_ITEM MenuItem; DECLARE_RETURN(BOOL); TRACE("Enter NtUserGetMenuItemRect\n"); UserEnterShared(); if (!(Menu = UserGetMenuObject(hMenu))) { RETURN(FALSE); } if (IntGetMenuItemByFlag(Menu, uItem, MF_BYPOSITION, NULL, &MenuItem, NULL) > -1) Rect = MenuItem->Rect; else RETURN(FALSE); if(!hWnd) { hWnd = Menu->MenuInfo.Wnd; } if (lprcItem == NULL) RETURN( FALSE); if (!(ReferenceWnd = UserGetWindowObject(hWnd))) RETURN( FALSE); if(MenuItem->fType & MF_POPUP) { XMove = ReferenceWnd->rcClient.left; YMove = ReferenceWnd->rcClient.top; } else { XMove = ReferenceWnd->rcWindow.left; YMove = ReferenceWnd->rcWindow.top; } Rect.left += XMove; Rect.top += YMove; Rect.right += XMove; Rect.bottom += YMove; Status = MmCopyToCaller(lprcItem, &Rect, sizeof(RECT)); if (! NT_SUCCESS(Status)) { SetLastNtError(Status); RETURN( FALSE); } RETURN( TRUE); CLEANUP: TRACE("Leave NtUserGetMenuItemRect, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } /* * @implemented */ BOOL APIENTRY NtUserHiliteMenuItem( HWND hWnd, HMENU hMenu, UINT uItemHilite, UINT uHilite) { PMENU_OBJECT Menu; PWND Window; DECLARE_RETURN(BOOLEAN); TRACE("Enter NtUserHiliteMenuItem\n"); UserEnterExclusive(); if(!(Window = UserGetWindowObject(hWnd))) { EngSetLastError(ERROR_INVALID_WINDOW_HANDLE); RETURN(FALSE); } if(!(Menu = UserGetMenuObject(hMenu))) { EngSetLastError(ERROR_INVALID_MENU_HANDLE); RETURN(FALSE); } if(Window->IDMenu == (UINT)(UINT_PTR)hMenu) { RETURN( IntHiliteMenuItem(Window, Menu, uItemHilite, uHilite)); } RETURN(FALSE); CLEANUP: TRACE("Leave NtUserHiliteMenuItem, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } static BOOL FASTCALL UserMenuInfo( PMENU_OBJECT Menu, PROSMENUINFO UnsafeMenuInfo, BOOL SetOrGet) { BOOL Res; DWORD Size; NTSTATUS Status; ROSMENUINFO MenuInfo; Status = MmCopyFromCaller(&Size, &UnsafeMenuInfo->cbSize, sizeof(DWORD)); if (! NT_SUCCESS(Status)) { SetLastNtError(Status); return( FALSE); } if(Size < sizeof(MENUINFO) || sizeof(ROSMENUINFO) < Size) { EngSetLastError(ERROR_INVALID_PARAMETER); return( FALSE); } Status = MmCopyFromCaller(&MenuInfo, UnsafeMenuInfo, Size); if (! NT_SUCCESS(Status)) { SetLastNtError(Status); return( FALSE); } if(SetOrGet) { /* Set MenuInfo */ Res = IntSetMenuInfo(Menu, &MenuInfo); } else { /* Get MenuInfo */ Res = IntGetMenuInfo(Menu, &MenuInfo); if (Res) { Status = MmCopyToCaller(UnsafeMenuInfo, &MenuInfo, Size); if (! NT_SUCCESS(Status)) { SetLastNtError(Status); return( FALSE); } } } return( Res); } /* * @implemented */ int APIENTRY NtUserMenuItemFromPoint( HWND hWnd, HMENU hMenu, DWORD X, DWORD Y) { PMENU_OBJECT Menu; PWND Window = NULL; PMENU_ITEM mi; int i; DECLARE_RETURN(int); TRACE("Enter NtUserMenuItemFromPoint\n"); UserEnterExclusive(); if (!(Menu = UserGetMenuObject(hMenu))) { RETURN( -1); } if (!(Window = UserGetWindowObject(Menu->MenuInfo.Wnd))) { RETURN( -1); } X -= Window->rcWindow.left; Y -= Window->rcWindow.top; mi = Menu->MenuItemList; for (i = 0; NULL != mi; i++) { if (RECTL_bPointInRect(&(mi->Rect), X, Y)) { break; } mi = mi->Next; } RETURN( (mi ? i : NO_SELECTED_ITEM)); CLEANUP: TRACE("Leave NtUserMenuItemFromPoint, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } static BOOL FASTCALL UserMenuItemInfo( PMENU_OBJECT Menu, UINT Item, BOOL ByPosition, PROSMENUITEMINFO UnsafeItemInfo, BOOL SetOrGet) { PMENU_ITEM MenuItem; ROSMENUITEMINFO ItemInfo; NTSTATUS Status; UINT Size; BOOL Ret; Status = MmCopyFromCaller(&Size, &UnsafeItemInfo->cbSize, sizeof(UINT)); if (! NT_SUCCESS(Status)) { SetLastNtError(Status); return( FALSE); } if (sizeof(MENUITEMINFOW) != Size && FIELD_OFFSET(MENUITEMINFOW, hbmpItem) != Size && sizeof(ROSMENUITEMINFO) != Size) { EngSetLastError(ERROR_INVALID_PARAMETER); return( FALSE); } Status = MmCopyFromCaller(&ItemInfo, UnsafeItemInfo, Size); if (! NT_SUCCESS(Status)) { SetLastNtError(Status); return( FALSE); } /* If this is a pre-0x0500 _WIN32_WINNT MENUITEMINFOW, you can't set/get hbmpItem */ if (FIELD_OFFSET(MENUITEMINFOW, hbmpItem) == Size && 0 != (ItemInfo.fMask & MIIM_BITMAP)) { EngSetLastError(ERROR_INVALID_PARAMETER); return( FALSE); } if (IntGetMenuItemByFlag(Menu, Item, (ByPosition ? MF_BYPOSITION : MF_BYCOMMAND), NULL, &MenuItem, NULL) < 0) { EngSetLastError(ERROR_INVALID_PARAMETER); // This will crash menu (line 80) correct_behavior test! // "NT4 and below can't handle a bigger MENUITEMINFO struct" //EngSetLastError(ERROR_MENU_ITEM_NOT_FOUND); return( FALSE); } if (SetOrGet) { Ret = IntSetMenuItemInfo(Menu, MenuItem, &ItemInfo); } else { Ret = IntGetMenuItemInfo(Menu, MenuItem, &ItemInfo); if (Ret) { Status = MmCopyToCaller(UnsafeItemInfo, &ItemInfo, Size); if (! NT_SUCCESS(Status)) { SetLastNtError(Status); return( FALSE); } } } return( Ret); } /* * @implemented */ BOOL APIENTRY NtUserRemoveMenu( HMENU hMenu, UINT uPosition, UINT uFlags) { PMENU_OBJECT Menu; DECLARE_RETURN(BOOL); TRACE("Enter NtUserRemoveMenu\n"); UserEnterExclusive(); if(!(Menu = UserGetMenuObject(hMenu))) { RETURN( FALSE); } RETURN(IntRemoveMenuItem(Menu, uPosition, uFlags, FALSE)); CLEANUP: TRACE("Leave NtUserRemoveMenu, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } /* * @implemented */ BOOL APIENTRY NtUserSetMenuContextHelpId( HMENU hMenu, DWORD dwContextHelpId) { PMENU_OBJECT Menu; DECLARE_RETURN(BOOL); TRACE("Enter NtUserSetMenuContextHelpId\n"); UserEnterExclusive(); if(!(Menu = UserGetMenuObject(hMenu))) { RETURN( FALSE); } RETURN(IntSetMenuContextHelpId(Menu, dwContextHelpId)); CLEANUP: TRACE("Leave NtUserSetMenuContextHelpId, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } /* * @implemented */ BOOL APIENTRY NtUserSetMenuDefaultItem( HMENU hMenu, UINT uItem, UINT fByPos) { PMENU_OBJECT Menu; DECLARE_RETURN(BOOL); TRACE("Enter NtUserSetMenuDefaultItem\n"); UserEnterExclusive(); if(!(Menu = UserGetMenuObject(hMenu))) { RETURN( FALSE); } RETURN( UserSetMenuDefaultItem(Menu, uItem, fByPos)); CLEANUP: TRACE("Leave NtUserSetMenuDefaultItem, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } /* * @implemented */ BOOL APIENTRY NtUserSetMenuFlagRtoL( HMENU hMenu) { PMENU_OBJECT Menu; DECLARE_RETURN(BOOL); TRACE("Enter NtUserSetMenuFlagRtoL\n"); UserEnterExclusive(); if(!(Menu = UserGetMenuObject(hMenu))) { RETURN( FALSE); } RETURN(IntSetMenuFlagRtoL(Menu)); CLEANUP: TRACE("Leave NtUserSetMenuFlagRtoL, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } /* * @implemented */ BOOL APIENTRY NtUserThunkedMenuInfo( HMENU hMenu, LPCMENUINFO lpcmi) { PMENU_OBJECT Menu; DECLARE_RETURN(BOOL); TRACE("Enter NtUserThunkedMenuInfo\n"); UserEnterExclusive(); if (!(Menu = UserGetMenuObject(hMenu))) { RETURN(FALSE); } RETURN(UserMenuInfo(Menu, (PROSMENUINFO)lpcmi, TRUE)); CLEANUP: TRACE("Leave NtUserThunkedMenuInfo, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } /* * @implemented */ BOOL APIENTRY NtUserThunkedMenuItemInfo( HMENU hMenu, UINT uItem, BOOL fByPosition, BOOL bInsert, LPMENUITEMINFOW lpmii, PUNICODE_STRING lpszCaption) { PMENU_OBJECT Menu; NTSTATUS Status; UNICODE_STRING lstrCaption; DECLARE_RETURN(BOOL); TRACE("Enter NtUserThunkedMenuItemInfo\n"); UserEnterExclusive(); /* lpszCaption may be NULL, check for it and call RtlInitUnicodeString() if bInsert == TRUE call UserInsertMenuItem() else UserSetMenuItemInfo() */ if (!(Menu = UserGetMenuObject(hMenu))) { RETURN(FALSE); } lstrCaption.Buffer = NULL; /* Check if we got a Caption */ if (lpszCaption) { /* Copy the string to kernel mode */ Status = ProbeAndCaptureUnicodeString( &lstrCaption, UserMode, lpszCaption); if (!NT_SUCCESS(Status)) { ERR("Failed to capture MenuItem Caption (status 0x%08x)\n",Status); SetLastNtError(Status); RETURN(FALSE); } } if (bInsert) RETURN( UserInsertMenuItem(Menu, uItem, fByPosition, lpmii)); RETURN( UserMenuItemInfo(Menu, uItem, fByPosition, (PROSMENUITEMINFO)lpmii, TRUE)); CLEANUP: TRACE("Leave NtUserThunkedMenuItemInfo, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } ////// ReactOS NtUserBad /* * @implemented */ DWORD APIENTRY NtUserBuildMenuItemList( HMENU hMenu, VOID* Buffer, ULONG nBufSize, DWORD Reserved) { DWORD res = -1; PMENU_OBJECT Menu; DECLARE_RETURN(DWORD); TRACE("Enter NtUserBuildMenuItemList\n"); UserEnterExclusive(); if(!(Menu = UserGetMenuObject(hMenu))) { RETURN( (DWORD)-1); } if(Buffer) { res = IntBuildMenuItemList(Menu, Buffer, nBufSize); } else { res = Menu->MenuInfo.MenuItemCount; } RETURN( res); CLEANUP: TRACE("Leave NtUserBuildMenuItemList, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } /* * @implemented */ UINT APIENTRY NtUserGetMenuDefaultItem( HMENU hMenu, UINT fByPos, UINT gmdiFlags) { PMENU_OBJECT Menu; DWORD gismc = 0; DECLARE_RETURN(UINT); TRACE("Enter NtUserGetMenuDefaultItem\n"); UserEnterExclusive(); if(!(Menu = UserGetMenuObject(hMenu))) { RETURN(-1); } RETURN( IntGetMenuDefaultItem(Menu, fByPos, gmdiFlags, &gismc)); CLEANUP: TRACE("Leave NtUserGetMenuDefaultItem, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } /* * @implemented */ BOOL APIENTRY NtUserMenuInfo( HMENU hMenu, PROSMENUINFO UnsafeMenuInfo, BOOL SetOrGet) { PMENU_OBJECT Menu; DECLARE_RETURN(BOOL); TRACE("Enter NtUserMenuInfo\n"); UserEnterShared(); if (!(Menu = UserGetMenuObject(hMenu))) { RETURN(FALSE); } RETURN(UserMenuInfo(Menu, UnsafeMenuInfo, SetOrGet)); CLEANUP: TRACE("Leave NtUserMenuInfo, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } /* * @implemented */ BOOL APIENTRY NtUserMenuItemInfo( HMENU hMenu, UINT Item, BOOL ByPosition, PROSMENUITEMINFO UnsafeItemInfo, BOOL SetOrGet) { PMENU_OBJECT Menu; DECLARE_RETURN(BOOL); TRACE("Enter NtUserMenuItemInfo\n"); UserEnterExclusive(); if (!(Menu = UserGetMenuObject(hMenu))) { RETURN(FALSE); } RETURN( UserMenuItemInfo(Menu, Item, ByPosition, UnsafeItemInfo, SetOrGet)); CLEANUP: TRACE("Leave NtUserMenuItemInfo, ret=%i\n",_ret_); UserLeave(); END_CLEANUP; } /* EOF */