File: MS\Internal\AutomationProxies\WindowsMenu.cs
Web Access
Project: src\src\Microsoft.DotNet.Wpf\src\UIAutomation\UIAutomationClientSideProviders\UIAutomationClientSideProviders.csproj (UIAutomationClientSideProviders)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
// Description: HWND-based Menu Proxy
 
// PRESHARP: In order to avoid generating warnings about unkown message numbers and unknown pragmas.
#pragma warning disable 1634, 1691
 
using System;
using System.Collections;
using System.Globalization;
using System.Text;
using System.ComponentModel;
using Accessibility;
using System.Windows.Automation.Provider;
using System.Windows.Automation;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using MS.Win32;
 
// Is it worth it to make WindowsMenu a protected base class
// and have a specific menu classes (e.g. MenuBar) that derives from it?
// The whole menu code is a bit complicated and hard to understand.
 
namespace MS.Internal.AutomationProxies
{
    // Win32 menu proxy
    class WindowsMenu: ProxyHwnd
    {
        // ------------------------------------------------------
        //
        // Constructors
        //
        // ------------------------------------------------------
 
        #region Constructors
 
        internal WindowsMenu(IntPtr hwnd, ProxyFragment parent, IntPtr hmenu, MenuType type, int item)
            : base (hwnd, parent, item)
        {
            _type = type;
            _fNonClientAreaElement = true;
            _fIsContent = false;
 
            FixMDIMenuType();
 
            // (Vista Explorer FolerBandModuleInner menu items don't raise InvokedEvent).  During events, this ctor is
            // called with parent = null and type = MenuType.Menu.  I think it should be parent != null and type = MenuType.Toplevel
            // since it is acting like a top-level menu.  Need to work through this with the other core team members, though.  Start
            // here to investigate.
            //Console.WriteLine("WindowsMenu {0} is {1} parent is {2}", hwnd.ToInt32(), (int)_type, (parent != null)?parent._hwnd.ToInt32() : 0);
 
            // According to spec:
            switch (_type)
            {
                case MenuType.Toplevel :
                    {
                        _cControlType = ControlType.MenuBar;
                        _sAutomationId = "MenuBar"; // This string is a non-localizable string
                    }
                    break;
 
                case MenuType.System :
                    {
                        _cControlType = ControlType.MenuBar;
                        _sAutomationId = "SystemMenuBar"; // This string is a non-localizable string
 
                        // Cache this menu, so change use during the Collapse Property Change Event.
                        if (!_expandedMenus.Contains(IntPtr.Zero))
                        {
                            _expandedMenus[IntPtr.Zero] = new MenuParentInfo(hwnd, item, type);
                        }
                    }
                    break;
 
 
                case MenuType.SystemPopup :
                    {
                        // Re-parent properly a system popup to the system menu
                        _parent = GetSystemPopupParent();
                        _cControlType = ControlType.Menu;
                        _sAutomationId = "MenuPopup"; // This string is a non-localizable string
 
                        // Cache the parent menu, so change use during the Collapse Property Change Event.
                        if (!_expandedMenus.Contains(hwnd))
                        {
                            _expandedMenus[hwnd] = new MenuParentInfo(_parent._hwnd, _parent._item, ((MenuItem)_parent)._menuType);
                        }
                    }
                    break;
 
                case MenuType.Submenu :
                    {
                        // Re-parent properly a popup menu to the proper parent
                        _parent = GetHierarchyParent(hwnd);
                        _cControlType = ControlType.Menu;
 
                        // Cache the parent menu, so change use during the Collapse Property Change Event.
                        if (!_expandedMenus.Contains(hwnd))
                        {
                            _expandedMenus[hwnd] = new MenuParentInfo(_parent._hwnd, _parent._item, ((MenuItem)_parent)._menuType);
                        }
                    }
                    break;
 
                default :
                    {
                        _cControlType = ControlType.Menu;
                    }
                    break;
            }
 
            _hmenu = hmenu;
        }
 
        internal static ProxySimple CreateMenuItemFromEvent(IntPtr hwndMenu, int eventId, int idChild, int idObject)
        {
            // This assert is valid because idObject is a non-volatile enumeration or constant
            System.Diagnostics.Debug.Assert(idObject == NativeMethods.OBJID_MENU || idObject == NativeMethods.OBJID_SYSMENU, "Unexpected idObject");
 
            if (eventId == NativeMethods.EventObjectInvoke)
            {
                // When a menu item is invoked the containing hwnd is destroyed and calling methods on hwndMenu result in an exception
                // (Target element corresponds to UI that is no longer available. For example, the parent window has closed.) so
                // at this point the only thing we can know about this menu item is whether it was an item on the system menu or
                // a menu bar and an identifier for the menu item.
                MenuParentInfo parentInfo = (MenuParentInfo)_expandedMenus[hwndMenu];
                if (parentInfo != null)
                {
                    return new DestroyedMenuItem(hwndMenu, idChild, parentInfo._hwndParent);
                }
            }
 
            return null;
        }
 
        // Handle the case of an MDI child frame system menu,
        // which would otherwise be treated as a normal submenu.
        private void FixMDIMenuType()
        {
            if (_type == MenuType.Submenu && GetHierarchyParent(_hwnd) == null && GetSystemPopupParent() != null)
            {
                _type = MenuType.SystemPopup;
            }
        }
 
        #endregion
 
        #region Proxy Create
 
        // Static Create method called by UIAutomation to create this proxy.
        // null if unsuccessful
        internal static IRawElementProviderSimple Create(IntPtr hwnd, int idChild, int idObject)
        {
            return Create(hwnd, idChild);
        }
 
        private static IRawElementProviderSimple Create(IntPtr hwnd, int idChild)
        {
            MenuType type = MenuType.Toplevel;
            IntPtr hmenu;
 
            try
            {
                hmenu = UnsafeNativeMethods.GetMenu(hwnd);
 
                if (hmenu == IntPtr.Zero)
                {
                    hmenu = HmenuFromHwnd(hwnd);
                    if (hmenu == IntPtr.Zero)
                    {
                        // bail
                        return null;
                    }
                }
                // get type of the submenu
                type = GetSubMenuType(hwnd, hmenu);
            }
            catch (ElementNotAvailableException)
            {
                return null;
            }
 
            WindowsMenu windowsMenu = new WindowsMenu(hwnd, null, hmenu, type, 0);
            if (idChild == 0)
            {
                return windowsMenu;
            }
            else
            {
                return windowsMenu.CreateMenuItem(idChild - 1);
            }
        }
 
        // Special method responsible for creating a System MenuBar
        // The type will be automatically set to the System
        internal static WindowsMenu CreateSystemMenu (IntPtr hwnd, ProxyFragment parent)
        {
            IntPtr hSysMenu = GetSystemMenuHandle(hwnd);
            if (hSysMenu != IntPtr.Zero)
            {
                return new WindowsMenu(hwnd, parent, hSysMenu, MenuType.System, 1);
            }
 
            return null;
        }
 
        // Called by UIA when we're in menu mode
        // Note that we have to drill all the way down to an item here, UIA expects us
        // to return the lowest focused item.
        internal static IRawElementProviderSimple CreateFocusedMenuItem(IntPtr hwnd, int idChild, int idObject)
        {
            NativeMethods.GUITHREADINFO gui;
            if (!Misc.ProxyGetGUIThreadInfo(0, out gui))
            {
                return null;
            }
 
            // The following code assumes that regardless of the type of menu mode
            // we're in, there's only one chain of cascaded menus present - you never
            // have two unrelated sets of menus present at a time.
            // So, we can look for *any* visible popup menu window (which could get us
            // half-way into a cascade chain, or at the start or end),
            // then follow the chain (by looking for selected items) to the lowest
            // item.
            // If no visible menu popup present, then need to special case
            // based on menu mode (eg. sys vs menubar vs popup).
 
            // first, check that we're really in menu mode (all menu mode flags
            // also include this...
            if (!Misc.IsBitSet(gui.dwFlags, NativeMethods.GUI_INMENUMODE))
                return null;
 
            IntPtr hwndPopup = IntPtr.Zero;
            for (; ; )
            {
                hwndPopup = Misc.FindWindowEx(IntPtr.Zero, hwndPopup, WindowsMenu.MenuClassName, null);
                if (hwndPopup == IntPtr.Zero)
                    break;
                if (!SafeNativeMethods.IsWindowVisible(hwndPopup))
                    continue;
 
                // No other tests needed - it's menu-class and visible, use it...
                break;
            }
 
            if (hwndPopup != IntPtr.Zero)
            {
                // Now drill down to lowest item...
                for (; ; )
                {
                    // Get hmenu of popup...
                    IntPtr hmenu = HmenuFromHwnd(hwndPopup);
                    if (hmenu == IntPtr.Zero)
                        return null;
 
                    // Check for item focused in the popup...
                    int i = GetHighlightedMenuItem(hmenu);
                    if (i == -1)
                    {
                        // No selected item - could be the menu itself (eg. context menus
                        // sometimes appear with no item having focus)
                        return Create(hwndPopup, 0);
                    }
 
                    // Got an item - it could be a sub-menu or a leaf node item...
                    IntPtr hSubMenu = UnsafeNativeMethods.GetSubMenu(hmenu, i);
                    if (hSubMenu == IntPtr.Zero)
                    {
                        // actual menu item...
                        return Create(hwndPopup, i + 1);
                    }
 
                    // Check to see if there's a popup open for that sub hmenu...
                    IntPtr hwndSubMenuPopup = GetPopupHwndForHMenu(hSubMenu);
                    if (hwndSubMenuPopup == IntPtr.Zero)
                    {
                        // No popup present - so just means that a popup item is selected,
                        // but not popped out...
                        return Create(hwndPopup, i + 1);
                    }
 
                    // Popup is present - so reassign the loop variable, and drill into it...
                    hwndPopup = hwndSubMenuPopup;
                }
            }
 
            // No popup present, so must be a special case...
            //
            // For any of these, the item could be a menu itself or an item in a menu -
            // most reliable approach is to pick an appropriate starting point (eg. sysmenu or menubar),
            // and follow the trail of focused items.
            if (Misc.IsBitSet(gui.dwFlags, NativeMethods.GUI_SYSTEMMENUMODE))
            {
                // Sys menu mode but no popup, means it must be the sys menu button (on the non-client area)
 
                // Can't create a sys menu area directly - have to create nonclientarea then titlebar first...
                NonClientArea nonClient = (NonClientArea)NonClientArea.Create(gui.hwndActive, 0);
                WindowsTitleBar titlebar = new WindowsTitleBar(gui.hwndActive, nonClient, 0);
                return CreateSystemMenu(gui.hwndActive, titlebar);
            }
            else if (Misc.IsBitSet(gui.dwFlags, NativeMethods.GUI_POPUPMENUMODE))
            {
                // Popup/context menu mode but no popup - shouldn't happen, unless it's just
                // disappeared.
                return null;
            }
            else if (Misc.IsBitSet(gui.dwFlags, NativeMethods.GUI_INMENUMODE))
            {
                // Menu/menubar mode, but no menu present - so could be item on menu bar
                // or menu bar itself...
                IntPtr hmenu = UnsafeNativeMethods.GetMenu(gui.hwndActive);
                int i = GetHighlightedMenuItem(hmenu);
                if (i == -1)
                {
                    // No selected item - so its the menubar itself...
                    // Need to create this via NonClient proxy...
                    return NonClientArea.CreateMenuBarItem(gui.hwndActive, 0, 0/*ignored by CreateMenuBarItem*/);
                }
                else
                {
                    // selected item on menubar...
                    return NonClientArea.CreateMenuBarItem(gui.hwndActive, i + 1, 0/*ignored by CreateMenuBarItem*/);
                }
            }
            return null;
        }
 
        #endregion
 
        //------------------------------------------------------
        //
        //  Patterns Implementation
        //
        //------------------------------------------------------
 
        #region ProxySimple Interface
 
        //Gets the runtime id
        internal override int[] GetRuntimeId()
        {
            return new int[] { 1, unchecked((int)(long)_hwnd), unchecked((int)(long)_hmenu) };
        }
 
        // Returns a pattern interface if supported.
        internal override object GetPatternProvider (AutomationPattern iid)
        {
            return null;
        }
 
        // Process all the Element Properties
        internal override object GetElementProperty(AutomationProperty idProp)
        {
            if (idProp == AutomationElement.NameProperty)
            {
                // NOTE: It does not look like Winforms support the AccessibleName for standard menus.
                // If MenuStrips are going to be supported by this proxy this code will need to be removed.
                return LocalizedName;
            }
 
            return base.GetElementProperty(idProp);
        }
 
        // Gets the bounding rectangle for this element
        internal override Rect BoundingRectangle
        {
            get
            {
                return GetBoundingRectangle();
            }
        }
 
        //Gets the localized name
        internal override string LocalizedName
        {
            get
            {
                if (_parent != null && _type == MenuType.Submenu)
                {
                    return _parent.LocalizedName;
                }
                else
                {
                    return SR.GetResourceString(GetLocalizedNameFromType());
                }
            }
        }
        #endregion
 
        #region ProxyFragment Interface
 
        // Returns the next sibling element in the raw hierarchy.
        // Peripheral controls have always negative values.
        // Returns null if no next child
        internal override ProxySimple GetNextSibling (ProxySimple child)
        {
            int item = child._item;
 
            return item + 1 < Count ? CreateMenuItem (item + 1) : null;
        }
 
        // Returns the previous sibling element in the raw hierarchy.
        // Peripheral controls have always negative values.
        // Returns null is no previous
        internal override ProxySimple GetPreviousSibling (ProxySimple child)
        {
            int item = child._item;
 
            return item > 0 && (item - 1) < Count ? CreateMenuItem (item - 1) : null;
        }
 
        // Returns the first child element in the raw hierarchy.
        internal override ProxySimple GetFirstChild ()
        {
            return Count > 0 ? CreateMenuItem (0) : null;
        }
 
        // Returns the last child element in the raw hierarchy.
        internal override ProxySimple GetLastChild ()
        {
            int count = Count;
 
            return count > 0 ? CreateMenuItem (count - 1) : null;
        }
 
        // Returns a Proxy element corresponding to the specified screen coordinates.
        internal override ProxySimple ElementProviderFromPoint (int x, int y)
        {
            for (int item = 0, count = Count; item < count; item++)
            {
                // The point might be in this menu item or in one of the popup Menu Item
                ProxySimple menuItem = CreateMenuItem(item).ElementProviderFromPoint(x, y);
                if (menuItem != null)
                {
                    return menuItem;
                }
            }
 
            return null;
        }
 
        // Returns an item corresponding to the focused element (if there is one), or null otherwise.
        internal override ProxySimple GetFocus()
        {
            int i = GetHighlightedMenuItem(_hmenu);
            if (i == -1)
                return null;
            else
                return CreateMenuItem(i);
        }
 
        #endregion ProxyFragment Interface
 
        #region ProxyHwnd Interface
 
        internal override void AdviseEventAdded (AutomationEvent eventId, AutomationProperty [] aidProps)
        {
            // NOTE: Menu supports SYSTEM wide events (SYS_MENUPOPUPSTART and SYS_MENUPOPUPEND)
            // Each proxy will register for the system-wide event only once (this is ensured by the event-framework (see BuildEventsList in WinEventTracker.cs)
            if (MenuRelatedEvent(eventId, aidProps))
            {
                // Sytem wide event register with hwnd == IntPtr.Zero
                WinEventTracker.AddToNotificationList(IntPtr.Zero, new WinEventTracker.ProxyRaiseEvents(MenuEvents), _menuEvents, _menuEvents.Length);
 
                // Keep counter of how many requests came so we will know when to remove ourselves from the notification list
                // We need a counter since system wide events are not based on the hwnd.
                _eventListeners++;
            }
        }
 
        internal override void AdviseEventRemoved (AutomationEvent eventId, AutomationProperty [] aidProps)
        {
            // NOTE: Menu supports SYSTEM wide events (SYS_MENUPOPUPSTART and SYS_MENUPOPUPEND)
            // Each proxy will register for the system-wide event only once (this is ensured by the event-framework (see BuildEventsList in WinEventTracker.cs)
            // We'll keep an internal counter on how many times user asked us to sign up for event
            // and when counter will get to zero we will remove ourselve from notification list
            // In the case when counter is not 0 we will do nothing but UIAutomation will ensure that LE that asked to be removed from being notified
            // of the event will not be getting anymore notification
            if (_eventListeners > 0)
            {
                --_eventListeners;
                if (_eventListeners == 0 && MenuRelatedEvent (eventId, aidProps))
                {
                    WinEventTracker.RemoveToNotificationList (IntPtr.Zero, _menuEvents, new WinEventTracker.ProxyRaiseEvents (MenuEvents), _menuEvents.Length);
                }
            }
        }
 
        #endregion ProxyHwnd Interface
 
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------
 
        #region Internal Methods
 
        internal MenuItem CreateMenuItem (int index)
        {
            return new MenuItem(_hwnd, this, index, _hmenu, _type);
        }
 
        // wrapper for GetMenuBarInfo
        internal static bool GetMenuBarInfo(IntPtr hwnd, int idObject, uint idItem, out NativeMethods.MENUBARINFO mbi)
        {
            mbi = new NativeMethods.MENUBARINFO();
            mbi.cbSize = Marshal.SizeOf(mbi.GetType());
            bool result = Misc.GetMenuBarInfo(hwnd, idObject, idItem, ref mbi);
 
#if _NEED_DEBUG_OUTPUT
            StringBuilder sb = new StringBuilder(1024);
            sb.Append("MENUBARINFO\n\r");
            sb.Append("{\n\r");
            sb.AppendFormat("\tcbSize = {0},\n\r", mbi.cbSize);
            sb.AppendFormat("\trcBar = ({0}, {1}, {2}, {3}),\n\r", mbi.rcBar.left, mbi.rcBar.top, mbi.rcBar.right, mbi.rcBar.bottom);
            sb.AppendFormat("\thMenu = 0x{0:x8},\n\r", (mbi.hMenu).ToInt32());
            sb.AppendFormat("\thwndMenu = 0x{0:x8},\n\r", (mbi.hwndMenu).ToInt32());
            sb.AppendFormat("\tfocusFlags = 0x{0:x8},\n\r", mbi.focusFlags);
            sb.Append("}\n\r");
            System.Diagnostics.Debug.WriteLine(sb.ToString());
#endif
 
            return result;
        }
 
        // Return menuItem object which is a hierarchical parent of the given menu (specified via hwnd)
        // return NULL in the case when menu does not have a parent (e.g. Context menu)
        // NOTE: this method should not be called for the menuItem that lives on the System or Menubar
        internal static MenuItem GetHierarchyParent(IntPtr hwnd)
        {
            int ownerMenuItemPos = -1;
            IntPtr menuParent = IntPtr.Zero;
            IntPtr hwndParent = IntPtr.Zero;
 
            IntPtr menu = HmenuFromHwnd(hwnd);
            if (menu == IntPtr.Zero)
            {
                throw new ElementNotAvailableException();
            }
            MenuType currentType = GetSubMenuType(hwnd, menu);
            MenuType parentType = MenuType.Toplevel;
 
            if (currentType == MenuType.Submenu)
            {
                if (!GetSubMenuParent(hwnd, out menuParent, out hwndParent, out ownerMenuItemPos, out parentType))
                {
                    return null;
                }
 
                ProxyFragment parent = null;
                if (parentType == MenuType.Toplevel)
                {
                    // Top Level Menu.
                    // We need to have the parenthood defined in the same way as if it was done
                    // from the non client area code.
 
                    NonClientArea nonClientArea = new NonClientArea(hwndParent);
                    parent = nonClientArea.CreateNonClientChild(NonClientArea.NonClientItem.Menu);
                }
                else
                {
                    parent = new WindowsMenu(hwndParent, null, menuParent, parentType, ownerMenuItemPos);
                }
 
                return new MenuItem(hwndParent, parent, ownerMenuItemPos, menuParent, parentType);
            }
 
            return null;
        }
 
        // Return menuItem object which is a hierarchical parent of the given menu (specified via hwnd)
        // return NULL in the case when menu does not have a parent (e.g. Context menu)
        // NOTE: this method should not be called for the menuItem that lives on the System or Menubar
        private static bool GetSubMenuParent (IntPtr hwndMenu, out IntPtr menuParent, out IntPtr hwndParent, out int ownerMenuItemPos, out MenuType parentType)
        {
            ownerMenuItemPos = -1;
            hwndParent = IntPtr.Zero;
            menuParent = IntPtr.Zero;
 
            parentType = MenuType.Toplevel;
            IntPtr hMenu = HmenuFromHwnd (hwndMenu);
            if (hMenu == IntPtr.Zero)
            {
                return false;
            }
 
            // this covers rest of cases
            // Parent lives on menuBar or parent lives on another submenu
            // or parent lives on the context or parent lives on system popup menu ...
            // Start from menuBar
            NativeMethods.GUITHREADINFO gui;
 
            if (!Misc.ProxyGetGUIThreadInfo(0, out gui))
            {
                return false;
            }
 
            IntPtr hMenuPossibleParent = UnsafeNativeMethods.GetMenu (gui.hwndActive);
 
            if (hMenuPossibleParent != IntPtr.Zero)
            {
                int menuItem = GetMenuItemParent (hMenuPossibleParent, hMenu);
 
                if (menuItem != -1)
                {
                    ownerMenuItemPos = menuItem;
                    menuParent = hMenuPossibleParent;
                    hwndParent = gui.hwndActive;
                    parentType = MenuType.Toplevel;
                    return true;
                }
            }
 
            // got here: menuItem does not live on the menubar
            // Menu on which menuItem lives located after us in the hwnd-hierarchy
            for (IntPtr hwndPossibleParent = Misc.FindWindowEx(IntPtr.Zero, hwndMenu, WindowsMenu.MenuClassName, null);
                 hwndPossibleParent != IntPtr.Zero;
                 hwndPossibleParent = Misc.FindWindowEx(IntPtr.Zero, hwndPossibleParent, WindowsMenu.MenuClassName, null))
            {
                if (SafeNativeMethods.IsWindowVisible (hwndPossibleParent))
                {
                    hMenuPossibleParent = HmenuFromHwnd (hwndPossibleParent);
                    if (hMenuPossibleParent != IntPtr.Zero)
                    {
                        int menuItem = GetMenuItemParent (hMenuPossibleParent, hMenu);
 
                        if (menuItem != -1)
                        {
                            ownerMenuItemPos = menuItem;
                            menuParent = hMenuPossibleParent;
                            hwndParent = hwndPossibleParent;
                            parentType = GetSubMenuType (hwndParent, menuParent);
                            return true;
                        }
                    }
                }
            }
            return false;
        }
 
        // Find visible hwnd that contains the submenu
        internal static IntPtr WindowFromSubmenu (IntPtr submenu)
        {
            for (IntPtr hwndSubMenu = Misc.FindWindowEx(IntPtr.Zero, IntPtr.Zero, MenuClassName, null);
                 hwndSubMenu != IntPtr.Zero;
                 hwndSubMenu = Misc.FindWindowEx(IntPtr.Zero, hwndSubMenu, MenuClassName, null))
            {
                if (SafeNativeMethods.IsWindowVisible (hwndSubMenu))
                {
                    IntPtr submenuCandidate = HmenuFromHwnd (hwndSubMenu);
 
                    if (submenuCandidate == submenu)
                    {
                        return hwndSubMenu;
                    }
                }
            }
 
            return IntPtr.Zero;
        }
 
        // Get type of the submenu
        // DO NOT call this method for System and MenuBar
        internal static MenuType GetSubMenuType (IntPtr hwnd, IntPtr hMenu)
        {
            if (IsSystemPopupMenu(hMenu))
            {
                return MenuType.SystemPopup;
            }
 
            if (IntPtr.Zero != Misc.GetWindow(hwnd, NativeMethods.GW_OWNER))
            {
                return MenuType.Submenu;
            }
 
            return MenuType.Context;
        }
 
        // This method returns the index of menuItem that lives on hmenuPossibleParent
        // and that is possible responsible for showing hmenuChild
        // If such menuItem is not found return -1
        private static int GetMenuItemParent (IntPtr hmenuPossibleParent, IntPtr hmenuChild)
        {
            int count = Misc.GetMenuItemCount(hmenuPossibleParent);
 
            for (int i = 0; i < count; i++)
            {
                // for speed reasons do not try to filter out menuItem that are not of type SubMenu
                if (UnsafeNativeMethods.GetSubMenu (hmenuPossibleParent, i) == hmenuChild)
                {
                    return i;
                }
            }
 
            return -1;
        }
 
        internal int Count
        {
            get
            {
                // The GetMenuItemCount API return always 1 for the system popup event
                // when it is not there. Work around to deal with it.
                if (_type == MenuType.System)
                {
                    return 1;
                }
 
                return Misc.GetMenuItemCount(_hmenu);
            }
        }
 
        // Retrieve hMenu represented by passed in hwnd
        // NOTE: do not call for menubar or system menubar
        internal static IntPtr HmenuFromHwnd (IntPtr hwnd)
        {
            if (SafeNativeMethods.IsWindowVisible (hwnd))
            {
                return Misc.ProxySendMessage(hwnd, NativeMethods.MN_GETHMENU, IntPtr.Zero, IntPtr.Zero);
            }
 
            return IntPtr.Zero;
        }
 
        // check if passed in menu handle represents windows system menu
        internal static bool IsInSystemMenuMode()
        {
            try
            {
                NativeMethods.GUITHREADINFO gui;
 
                if (Misc.ProxyGetGUIThreadInfo(0, out gui))
                {
                    return Misc.IsBitSet(gui.dwFlags, NativeMethods.GUI_SYSTEMMENUMODE);
                }
 
                return false;
            }
            catch (ElementNotAvailableException)
            {
                return false;
            }
        }
 
        internal static IntPtr GetSystemMenuHandle(IntPtr hwnd)
        {
            NativeMethods.MENUBARINFO mbi;
 
            if (GetMenuBarInfo(hwnd, NativeMethods.OBJID_SYSMENU, 0, out mbi) && mbi.hMenu != IntPtr.Zero)
            {
                return mbi.hMenu;
            }
 
            return IntPtr.Zero;
        }
 
        #endregion
 
        //------------------------------------------------------
        //
        //  Internal Fields
        //
        //------------------------------------------------------
 
        #region Internal Fields
 
        // Defines the menu item types
        internal enum MenuType : int
        {
            Submenu = 0, //  submenu
            System, //  menubar for the system (This mb has one control only)
            Toplevel, // top-level menu (a.k.a - menubar)
            Context, // context menu (a.k.a shortcut) - brough by right-click on client area or specific object
            SystemPopup, // pop-up that gets displayed when user "invokes" system menu bar's control
        }
 
        // Win32 Menu class name
        internal const string MenuClassName = "#32768";
 
        // Time out for showing and disappearance of menus
        internal const int TimeOut = 100;
 
        #endregion
 
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------
 
        #region Private Methods
 
        private Rect GetBoundingRectangle()
        {
            switch (_type)
            {
                case MenuType.System:
                    {
                        // This is to take in count for a bug in GetMenuBarInfo().  It does not calculate the
                        // rcBar correctly when the WS_EX_LAYOUTRTL extended style is set. GetMenuBarInfo()
                        // assumes SYSMENU is always on the left of the title bar.
                        NativeMethods.MENUBARINFO mbi;
                        if (!GetMenuBarInfo(_hwnd, NativeMethods.OBJID_SYSMENU, 0, out mbi))
                        {
                            throw new ElementNotAvailableException();
                        }
 
                        int leftEdge = mbi.rcBar.left;
                        int buttonWidth = mbi.rcBar.right - mbi.rcBar.left;
                        int buttonHeight = mbi.rcBar.bottom - mbi.rcBar.top;
 
                        //
                        // Builds prior to Vista 5359 failed to correctly account for RTL menu layouts.
                        //
                        if ((Environment.OSVersion.Version.Major < 6) && (Misc.IsLayoutRTL(_hwnd)))
                        {
                            // Get the bounding rectangle of the whole title bar to be able to calculate
                            // the true left boundary in this extend style.
                            UnsafeNativeMethods.TITLEBARINFO ti;
                            if (!Misc.ProxyGetTitleBarInfo(_hwnd, out ti))
                            {
                                throw new ElementNotAvailableException();
                            }
 
                            leftEdge = ti.rcTitleBar.right - buttonWidth;
                        }
                        return new Rect(leftEdge, mbi.rcBar.top, buttonWidth, buttonHeight);
                    }
 
                case MenuType.Toplevel:
                    {
                        NativeMethods.MENUBARINFO mbi;
                        if (GetMenuBarInfo(_hwnd, NativeMethods.OBJID_MENU, 0, out mbi))
                        {
                            return mbi.rcBar.ToRect(false);
                        }
 
                        throw new ElementNotAvailableException();
                    }
 
                default:
                    return base.BoundingRectangle;
            }
        }
 
        //Returns the key of the resource name string
        private string GetLocalizedNameFromType()
        {
            switch (_type)
            {
                case MenuType.Toplevel:
                    return nameof(SR.LocalizedNameWindowsMenuBar);
 
                case MenuType.System:
                    return nameof(SR.LocalizedNameWindowsSystemMenuBar);
 
                case MenuType.SystemPopup:
                    return nameof(SR.LocalizedNameWindowsMenu);
 
                case MenuType.Submenu:
                    return nameof(SR.LocalizedNameWindowsMenu);
 
                default:
                    return nameof(SR.LocalizedNameWindowsMenu);
            }
        }
 
        // get a handle to the system menu
        // note - passed in hwnd should be apps hwnd
        //  Returns the system HMENU for the given HWND.
        //
        //  Can't use the Win32 API GetSystemMenu, since that modifies the system
        //  HMENU for the window.
        private static IntPtr GetSystemPopupMenu (IntPtr hwnd)
        {
            NativeMethods.MENUBARINFO mbi;
 
            // Only the 2 bits are valid in the focusFlags field. Strip the other ones as sometimes
            // they are set to none zero value.
            if (GetMenuBarInfo(hwnd, NativeMethods.OBJID_SYSMENU, 0, out mbi) &&
                mbi.hMenu != IntPtr.Zero &&
                Misc.IsBitSet(mbi.focusFlags, 3))
            {
                return UnsafeNativeMethods.GetSubMenu(mbi.hMenu, 0);
            }
 
            return IntPtr.Zero;
        }
 
        // check if passed in menu handle represents windows system menu
        private static bool IsSystemPopupMenu (IntPtr hmenu)
        {
            if (hmenu == IntPtr.Zero)
            {
                return false;
            }
 
            NativeMethods.GUITHREADINFO gui;
 
            if (Misc.ProxyGetGUIThreadInfo(0, out gui))
            {
                if (hmenu == GetSystemPopupMenu(gui.hwndActive))
                {
                    return true;
                }
            }
 
            return false;
        }
 
        // detect if hwnd corresponds to the submenu
        private static bool IsWindowSubMenu (IntPtr hwnd)
        {
            return (String.Compare(Misc.ProxyGetClassName(hwnd), WindowsMenu.MenuClassName, StringComparison.OrdinalIgnoreCase) == 0);
        }
 
 
        private static int GetHighlightedMenuItem(IntPtr hmenu)
        {
            int count = Misc.GetMenuItemCount(hmenu);
            for (int i = 0; i < count; i++)
            {
                int state = UnsafeNativeMethods.GetMenuState(hmenu, i, NativeMethods.MF_BYPOSITION);
                if (Misc.IsBitSet(state, NativeMethods.MF_HILITE))
                {
                    return i;
                }
            }
            return -1;
        }
 
        private static IntPtr GetPopupHwndForHMenu(IntPtr hmenu)
        {
            IntPtr hwndPopup = IntPtr.Zero;
            for (; ; )
            {
                hwndPopup = Misc.FindWindowEx(IntPtr.Zero, hwndPopup, WindowsMenu.MenuClassName, null);
                if (hwndPopup == IntPtr.Zero)
                    break;
                if (!SafeNativeMethods.IsWindowVisible(hwndPopup))
                    continue;
 
                // Get the hMenu, and see if it matches...
                IntPtr hmenuTest = HmenuFromHwnd(hwndPopup);
                if (hmenuTest == hmenu)
                    return hwndPopup;
            }
            return IntPtr.Zero;
        }
 
        // Handle menu specific events
        private static void MenuEvents (IntPtr hwnd, int eventId, object idProp, int idObject, int idChild)
        {
            MenuItem parent = null;
 
            if (eventId == NativeMethods.EventSystemMenuPopupEnd)
            {
                // EVENT_SYSTEM_MENUPOPUPEND comes with the hwnd for the menu that got closed and hwnd is not valid anymore,
                // hence we cannot use it to obtain any information
                // Solution: MENUPOPUPEND cannot happen without MENUPOPUPSTART, and we will be notified about MENUPOPUPSTART.
                // During the processing of MENUPOPUPSTART we will cache the parent(a.k.a menuItem) of the MENU that got "started"
                // When processing MENUPOPUPEND we will refer to the cached info in order to retrieve the valid-cached parent
                // of the menu that got ended
                // Update 3/9/2005:
                // Cacheing the parent durning the processing of MENUPOPUPSTART is not a option sometimes.  If the menu is already
                // expanded before registring for the ExpandCollapsePropertyChange event is one example.  To solve this cache the
                // parent during the ctor if it has not already been cached.
                MenuParentInfo parentInfo = null;
 
                while (_expandedMenus.Contains(hwnd) && parent == null)
                {
                    // get the parent info
                    parentInfo = (MenuParentInfo) _expandedMenus [hwnd];
 
                    // remove object from the hashtable (since menu was collapsed)
                    _expandedMenus.Remove (hwnd);
                    if (SafeNativeMethods.IsWindowVisible (parentInfo._hwndParent))
                    {
                        WindowsMenu menu = null;
 
                        if (parentInfo._type == MenuType.System)
                        {
                            menu = CreateSystemMenu (parentInfo._hwndParent, null);
                        }
                        else
                        {
                            menu = (WindowsMenu) WindowsMenu.Create (parentInfo._hwndParent, 0);
                        }
 
                        if (menu != null)
                        {
                            parent = (MenuItem) menu.CreateMenuItem (parentInfo._menuItem);
                        }
                    }
                    else
                    {
                        // NOTE: EVENT_SYSTEM_MENUPOPUPSTART comes one after another
                        // at the same time we can have many EVENT_SYSTEM_MENUPOPUPEND happen at the same time
                        // (e.g. Hierachy of submenus got removed after app lost focus), we will unroll the
                        // hierarchical chain (which would be in the hastable) and raise the AutomationPropertyChangedEvent
                        // only for the first visible parent. It is perfectly possible that there would be no
                        // visible parent (e.g. Hierarchy was rooted at the menuItem that lived on the Context menu)
                        // in this case there would be no event raised.
                        hwnd = parentInfo._hwndParent;
                    }
                }
 
                // If could not find cached parent information, check to see if the system menu has been
                // cached.  If so use the system menu as the parent.
                if (parent == null && _expandedMenus.Contains(IntPtr.Zero))
                {
                    // get the parent info
                    parentInfo = (MenuParentInfo)_expandedMenus[IntPtr.Zero];
 
                    WindowsMenu menu = null;
                    if (parentInfo._type == MenuType.System)
                    {
                        menu = CreateSystemMenu(parentInfo._hwndParent, null);
                    }
                    if (menu != null)
                    {
                        parent = (MenuItem)menu.CreateMenuItem(0);
                    }
                }
            }
            else
            {
                if (!IsWindowSubMenu(hwnd))
                {
                    // Event does not belong to win32 menu
                    return;
                }
 
                if (IsInSystemMenuMode())
                {
                    parent = (MenuItem)GetSystemPopupParent();
                }
                else
                {
                    parent = GetHierarchyParent(hwnd);
                }
            }
 
            // Raise an event
            if (parent != null)
            {
                object propertyValue = ((IExpandCollapseProvider)parent).ExpandCollapseState;
 
                if (propertyValue != null && propertyValue != AutomationElement.NotSupported)
                {
                    AutomationInteropProvider.RaiseAutomationPropertyChangedEvent(parent, new AutomationPropertyChangedEventArgs((AutomationProperty)idProp, null, propertyValue));
                }
            }
        }
 
        // Detect if requested event corresponds to the events supported by menu
        private static bool MenuRelatedEvent (AutomationEvent eventId, AutomationProperty [] aidProps)
        {
            // MenuItem supports ExpandCollapseState property change event only
            if (eventId != AutomationElement.AutomationPropertyChangedEvent)
            {
                return false;
            }
 
            int count = aidProps.Length;
 
            for (int i = 0; i < count; i++)
            {
                if (aidProps[i] == ExpandCollapsePattern.ExpandCollapseStateProperty)
                {
                    return true;
                }
            }
 
            return false;
        }
 
        // Return menuItem object which is a hierarchical parent of the given menu (specified via hwnd)
        // return NULL in the case when menu does not have a parent (e.g. Context menu)
        // NOTE: this method should not be called for the menuItem that lives on the System or Menubar
        private static ProxyFragment GetSystemPopupParent ()
        {
            // Parent lives on menuBar or parent lives on another submenu
            // or parent lives on the context or parent lives on system popup menu ...
            // Start from menuBar
            NativeMethods.GUITHREADINFO gui;
 
            if (!Misc.ProxyGetGUIThreadInfo(0, out gui))
            {
                return null;
            }
 
            NonClientArea nonClientArea = new NonClientArea (gui.hwndActive);
            WindowsTitleBar titleBar = (WindowsTitleBar) nonClientArea.CreateNonClientChild (NonClientArea.NonClientItem.TitleBar);
            ProxyFragment systemMenu = (ProxyFragment) titleBar.CreateTitleBarChild (WindowsTitleBar._systemMenu);
 
            return (ProxyFragment) systemMenu.GetFirstChild ();
        }
 
        #endregion
 
        //------------------------------------------------------
        //
        //  Private Fields
        //
        //------------------------------------------------------
 
        #region Private Fields
 
        private IntPtr _hmenu;
 
        private MenuType _type;
 
        // Menu-specific events
        private readonly static WinEventTracker.EvtIdProperty [] _menuEvents = new WinEventTracker.EvtIdProperty [] {
                new WinEventTracker.EvtIdProperty(NativeMethods.EventSystemMenuPopupStart, ExpandCollapsePattern.ExpandCollapseStateProperty),
                new WinEventTracker.EvtIdProperty(NativeMethods.EventSystemMenuPopupEnd, ExpandCollapsePattern.ExpandCollapseStateProperty),
                new WinEventTracker.EvtIdProperty(NativeMethods.EventObjectInvoke, InvokePattern.InvokedEvent)
            };
 
        private static Hashtable _expandedMenus = new Hashtable(5);
 
        // counter of elements interested in menu-related events
        private static int _eventListeners = 0;
 
        #endregion
 
        // ------------------------------------------------------
        //
        //  MenuParentInfo Private Class
        //
        //------------------------------------------------------
 
        #region MenuParentInfo
 
        private class MenuParentInfo
        {
            internal IntPtr _hwndParent; // menu's hwnd on which menuItem lives
            internal int _menuItem; // menuItem index
            internal MenuType _type; // type of the menu on which menuItem lives
 
            internal MenuParentInfo (IntPtr hwndParent, int menuItem, MenuType type)
            {
                _hwndParent = hwndParent;
                _menuItem = menuItem;
                _type = type;
            }
        }
 
        #endregion
 
        // ------------------------------------------------------
        //
        //  MenuItem Internal Class
        //
        //------------------------------------------------------
 
        #region MenuItem
 
        // Class implementation for the WindowsMenuItemProxy.
        internal class MenuItem : ProxyFragment, IInvokeProvider, IExpandCollapseProvider, ISelectionItemProvider, IToggleProvider
        {
            // ------------------------------------------------------
            //
            // Constructors
            //
            // ------------------------------------------------------
 
            #region Constructors
 
            internal MenuItem (IntPtr hwnd, ProxyFragment parent, int item, IntPtr hmenu, WindowsMenu.MenuType type)
            : base(hwnd, parent, item)
            {
                _fNonClientAreaElement = true;
                _menuType = type;
                _hmenu = hmenu;
                _type = GetMenuItemType ();
 
                if (_type == MenuItemType.Spacer)
                {
                    _cControlType = ControlType.Separator;
                    _sAutomationId = "Separator " + (_item + 1).ToString(CultureInfo.InvariantCulture); // This string is a non-localizable string
                    _fIsContent = false;
                }
                else
                {
                    _cControlType = ControlType.MenuItem;
                    GetItemId(ref _sAutomationId);
                }
            }
 
            #endregion
 
            //------------------------------------------------------
            //
            //  Patterns Implementation
            //
            //------------------------------------------------------
 
            #region ProxySimple Interface
 
            internal override ProviderOptions ProviderOptions
            {
                get
                {
                    // Use ProviderOwnsSetFocus to take complete control of set focus,
                    // don't use UIA's default behavior, which would call SetFocus on,
                    // the HWND and cause it to collapse.
                    return base.ProviderOptions | ProviderOptions.ProviderOwnsSetFocus;
                }
            }
 
            // Returns a pattern interface if supported.
            internal override object GetPatternProvider (AutomationPattern iid)
            {
                // if item is !visible or item is Spacer than none of the patterns are supported
                if (!SafeNativeMethods.IsWindowVisible (_hwnd) || _type == MenuItemType.Spacer)
                {
                    return null;
                }
 
                if (iid == ExpandCollapsePattern.Pattern && _type == MenuItemType.SubMenu)
                {
                    return this;
                }
                else if (iid == InvokePattern.Pattern && _type == MenuItemType.Command)
                {
                    return this;
                }
                else if (iid == SelectionItemPattern.Pattern && _type == MenuItemType.Command && IsRadioCheck())
                {
                    return this;
                }
                else if (iid == TogglePattern.Pattern && _type == MenuItemType.Command && IsChecked() && !IsRadioCheck())
                {
                    return this;
                }
 
                return null;
            }
 
            // Gets the bounding rectangle for this element
            internal override Rect BoundingRectangle
            {
                get
                {
                    if (_menuType == WindowsMenu.MenuType.System)
                    {
                        NativeMethods.MENUBARINFO mbi;
 
                        if (GetMenuBarInfo(_hwnd, NativeMethods.OBJID_SYSMENU, 0, out mbi))
                        {
                            int leftEdge = mbi.rcBar.left;
                            int buttonWidth = mbi.rcBar.right - mbi.rcBar.left;
                            int buttonHeight = mbi.rcBar.bottom - mbi.rcBar.top;
 
                            //
                            // Builds prior to Vista 5359 failed to correctly account for RTL menu layouts.
                            //
                            if ((Environment.OSVersion.Version.Major < 6) && (Misc.IsLayoutRTL(_hwnd)))
                            {
                                // Get the bounding rectangle of the whole title bar to be able to calculate
                                // the true left boundary in this extend style.
                                UnsafeNativeMethods.TITLEBARINFO ti;
                                if (!Misc.ProxyGetTitleBarInfo(_hwnd, out ti))
                                {
// Suppress Property get methods should not throw exceptions for internal getter
#pragma warning suppress 6503
                                    throw new ElementNotAvailableException();
                                }
 
                                leftEdge = ti.rcTitleBar.right - buttonWidth;
                            }
                            return new Rect(leftEdge, mbi.rcBar.top, buttonWidth, buttonHeight);
                        }
                    }
                    else
                    {
                        NativeMethods.Win32Rect rc;
                        if (Misc.GetMenuItemRect(_hwnd, _hmenu, _item, out rc))
                        {
                            return rc.ToRect(false);
                        }
                    }
 
                    return Rect.Empty;
                }
            }
 
            //Gets the localized name
            internal override string LocalizedName
            {
                get
                {
                    // It does not look like Winforms support the AccessibleName for standard menus or there items.
                    // If MenuStrips are going to be supported by this proxy, will need to added code to check
                    // if this is winforms menu item and use the AccessibleName if it is set.
 
                    if (_menuType == WindowsMenu.MenuType.System)
                    {
                        return SR.LocalizedNameWindowsSystemMenuItem;
                    }
 
                    string menuRawText = Text;
 
                    if (string.IsNullOrEmpty(menuRawText))
                    {
                        return null;
                    }
 
                    // Get the full string with the & removed
                    menuRawText = Misc.StripMnemonic(menuRawText);
 
                    // A tab, '\t', is usually used to separate the menu string from the accelerator.  If a
                    // tab is found assume that the menu string is before the tab.
                    int pos = menuRawText.IndexOf('\t');
                    if (pos > 0)
                    {
                        return menuRawText.Substring(0, pos);
                    }
 
                    // Try to remove the Ctrl or Alt, etc at the end of the string if there
                    // Be caution modifying this code, it must miror the code for AcceleratorKeyProperty
 
                    // Try to look for a combination Ctrl or Alt + something
                    string keyCtrl = SR.KeyCtrl;
                    string keyControl = SR.KeyControl;
                    string keyAlt = SR.KeyAlt;
                    string keyShift = SR.KeyShift;
                    string keyWin = SR.KeyWinKey;
 
                    string menuText = menuRawText.ToLower(CultureInfo.InvariantCulture);
                    string accelerator;
 
                    if ((accelerator = AccelatorKeyCtrl(keyCtrl.ToLower(CultureInfo.InvariantCulture), keyCtrl + " + ", menuText, menuRawText, out pos)) != null ||
                        (accelerator = AccelatorKeyCtrl(keyControl.ToLower(CultureInfo.InvariantCulture), keyCtrl + " + ", menuText, menuRawText, out pos)) != null ||
                        (accelerator = AccelatorKeyCtrl(keyAlt.ToLower(CultureInfo.InvariantCulture), keyAlt + " + ", menuText, menuRawText, out pos)) != null ||
                        (accelerator = AccelatorKeyCtrl(keyShift.ToLower(CultureInfo.InvariantCulture), keyShift + " + ", menuText, menuRawText, out pos)) != null ||
                        (accelerator = AccelatorKeyCtrl(keyWin.ToLower(CultureInfo.InvariantCulture), keyWin + " + ", menuText, menuRawText, out pos)) != null)
                    {
                        return menuRawText.Substring(0, SkipMenuSpaceChar(menuText, pos));
                    }
 
                    // Try to look for a Fxx
                    accelerator = AccelatorFxx(menuText);
                    if (!string.IsNullOrEmpty(accelerator))
                    {
                        pos = menuText.LastIndexOf(accelerator, StringComparison.OrdinalIgnoreCase);
                        if (pos >= 0)
                        {
                            return menuRawText.Substring(0, SkipMenuSpaceChar(menuText, pos));
                        }
                        else
                        {
                            // Wrong logic, we should be able to find the Fxx combination we just built
                            System.Diagnostics.Debug.Assert(false, "Cannot find back the accelerator in the menu!");
                            return menuRawText;
                        }
                    }
 
                    // Look for a bunch of Predefined keyword
                    string[] keywordsAccelerators = GetKeywordsAccelerators();
 
                    for (int i = 0; i < keywordsAccelerators.Length; i++)
                    {
                        pos = menuText.LastIndexOf(keywordsAccelerators[i], StringComparison.OrdinalIgnoreCase);
                        if (pos > 0 && pos + keywordsAccelerators[i].Length == menuText.Length && (menuText[pos - 1] == '\a' || menuText[pos - 1] == '\t'))
                        {
                            return menuRawText.Substring(0, SkipMenuSpaceChar(menuText, pos));
                        }
                    }
 
                    return menuRawText;
                }
            }
 
            // Process all the Element Properties
            internal override object GetElementProperty (AutomationProperty idProp)
            {
                if (idProp == AutomationElement.AcceleratorKeyProperty)
                {
                    string acceleratorKey = AcceleratorKey;
                    if (!string.IsNullOrEmpty(acceleratorKey))
                        return AcceleratorKey;
                }
                else if (idProp == AutomationElement.IsEnabledProperty)
                {
                    // If an element in the parent chain is disabled there is not point in checking the menu
                    if (!Misc.IsEnabled(_hwnd))
                        return false;
 
                    return IsEnabledMenu;
                }
                else if (idProp == AutomationElement.AccessKeyProperty)
                {
                    return GetAccessKey();
                }
                else if (idProp == AutomationElement.IsKeyboardFocusableProperty)
                {
                    return _type != MenuItemType.Spacer;
                }
                else if (idProp == AutomationElement.HasKeyboardFocusProperty)
                {
                    // The check for the focused window fails!!!
                    return IsFocused ();
                }
                else if (idProp == AutomationElement.IsOffscreenProperty)
                {
                    // Even if the menu item that is the parent to a popup menu is off the screen
                    // the popup menu will be displayed on the screen, so must override the
                    // default action of checking the parent.
                    Rect itemRect = BoundingRectangle;
 
                    if (itemRect.IsEmpty)
                    {
                        return true;
                    }
 
                    // if this element is not on any monitor than it is off the screen.
                    NativeMethods.Win32Rect itemWin32Rect = new NativeMethods.Win32Rect(itemRect);
                    return UnsafeNativeMethods.MonitorFromRect(ref itemWin32Rect, UnsafeNativeMethods.MONITOR_DEFAULTTONULL) == IntPtr.Zero;
                }
 
                return base.GetElementProperty (idProp);
            }
 
            // Sets the focus to this item.
            // Note: parent should be focused at the time of call
            internal override bool SetFocus()
            {
                if (!SafeNativeMethods.IsWindowVisible(_hwnd) || _type == MenuItemType.Spacer)
                {
                    return false;
                }
 
                // Occasionally this fails due to timing issues.
                // To massively lower the probability of this occurring we try it several times.
                for (int i = 0; i < 4; i++)
                {
                    // Put ourselves in the menu mode (if already in the menu mode
                    // cancel out from it and get back to it)
                    if ((_menuType == MenuType.Toplevel || _menuType == MenuType.System))
                    {
                        if (Misc.InMenuMode())
                        {
                            IntPtr hwndFocus = Misc.GetFocusedWindow();
 
                            // Detects if the Menu is expanded (popup)
                            // If this is the case, get entirely out of the Menu mode to get rid of the popup
                            if (hwndFocus != IntPtr.Zero && hwndFocus != _hwnd)
                            {
                                SendAltKey();
                                WaitForPopupMenu(false);
                                System.Threading.Thread.Sleep(1);
                            }
                        }
 
                        // Set the focus and the menu bar if it is not already the case
                        if (!Misc.InMenuMode() && !MenuMode(true))
                        {
                            return false;
                        }
                    }
                    else
                    {
                        if (!Misc.InMenuMode())
                            return false;
                    }
                        // It is possible to use easily the hot key because they do
                        // both selection and expand. For now, limit ourself
                        // to use moves keyboard in the menus
#if future

                // If menuItem has a hotkey, use it
                char hotKey;
 
                // This scheme does not work for the MFC. It terminates the application
                // Further more an accelerator might be defined twice and this is not handled
                // Comment this code out and let the default behavior go through testing.
                if (_menuType != MenuType.Toplevel && '\0' != (hotKey = HotKeyCheckNoDups))
                {
                    short convert = UnsafeNativeMethods.VkKeyScan (hotKey);
 
                    if (-1 != convert)
                    {
                        byte vk = (byte) (convert & 0xff);
 
                        // NOTE: Do not worry if we are already in the menu mode
                        // sending Alt will take care of everything in this case
                        Input.SendKeyboardInputVK (UnsafeNativeMethods.VK_MENU, true);
                        Input.SendKeyboardInputVK (vk, true);
                        Input.SendKeyboardInputVK (vk, false);
                        Input.SendKeyboardInputVK (UnsafeNativeMethods.VK_MENU, false);
                    }
                }
                else
#endif
                    {
                        // No Accelerator - use the keyboard to move to a given element
                        if (!KeyBoardNavigate())
                        {
                            System.Threading.Thread.Sleep(100);
                            continue;
                        }
                    }
 
                    // Make sure that the our hwnd has the focus
                    // Wait for a few millisecond for this operation to be completed
                    UInt32 dwTicks = SafeNativeMethods.GetTickCount();
                    UInt32 dwDelta = 0;
 
                    // Wait until the action has been completed
                    while (!Misc.IsBitSet(UnsafeNativeMethods.GetMenuState(_hmenu, _item, NativeMethods.MF_BYPOSITION), NativeMethods.MF_HILITE) &&
                           (dwDelta = SubtractTicks(SafeNativeMethods.GetTickCount(), dwTicks)) <= WindowsMenu.TimeOut)
                    {
                        System.Threading.Thread.Sleep(1);
                    }
 
                    if (dwDelta <= WindowsMenu.TimeOut)
                        return true;
 
                    System.Threading.Thread.Sleep(100);
                }
 
                return false;
            }
 
            internal override string GetAccessKey()
            {
                MenuType type = ((WindowsMenu)_parent)._type;
 
                switch (type)
                {
                    case MenuType.System:
                        {
                            return SR.KeyAlt + " + " + SR.KeySpace;
                        }
                    case MenuType.Submenu:
                    case MenuType.SystemPopup:
                        {
                            string text = Text;
                            return string.IsNullOrEmpty(text) ? null : SubMenuAccessKey(text);
                        }
                    default:
                        return Misc.AccessKey(Text);
                }
            }
 
            internal static string SubMenuAccessKey(string s)
            {
                // Get the index of the shortcut
                int iPosShortCut = s.IndexOf('&');
 
                // Did we found an & or is it at the end of the string
                if (iPosShortCut < 0 || iPosShortCut + 1 >= s.Length)
                {
                    return null;
                }
 
                // Build the result string
                return s[iPosShortCut + 1].ToString();
            }
 
            #endregion
 
            #region ProxyFragment Interface
 
            // Returns the next sibling element in the raw hierarchy.
            // Peripheral controls have always negative values.
            // Returns null if no next child
            internal override ProxySimple GetNextSibling (ProxySimple child)
            {
                // If the parent is a MenuItem then there is one child
                // a popup Menu. A Popup Menu cannot have siblings
                if (child is WindowsMenu)
                {
                    return null;
                }
 
                // A child is a Menu Item
                return ((MenuItem) child).PreviousMenuItem;
            }
 
            // Returns the previous sibling element in the raw hierarchy.
            // Peripheral controls have always negative values.
            // Returns null is no previous
            internal override ProxySimple GetPreviousSibling (ProxySimple child)
            {
                // If the parent is a MenuItem then there is one child
                // a popup Menu. A Popup Menu cannot have siblings
                if (child is WindowsMenu)
                {
                    return null;
                }
 
                // A child is a Menu Item
                return ((MenuItem) child).NextMenuItem;
            }
 
            // Returns the first child element in the raw hierarchy.
            internal override ProxySimple GetFirstChild ()
            {
                IntPtr submenu = _menuType == MenuType.System ? _hmenu : UnsafeNativeMethods.GetSubMenu (_hmenu, _item);
                if (submenu == IntPtr.Zero)
                {
                    return null;
                }
 
                IntPtr hwndSubmenu = WindowsMenu.WindowFromSubmenu (submenu);
 
                if (hwndSubmenu != IntPtr.Zero)
                {
                    WindowsMenu.MenuType type = WindowsMenu.GetSubMenuType (hwndSubmenu, submenu);
                    return new WindowsMenu (hwndSubmenu, null, submenu, type, 0);
                }
                return null;
            }
 
            // Returns the last child element in the raw hierarchy.
            internal override ProxySimple GetLastChild ()
            {
                IntPtr submenu = _menuType == MenuType.System ? _hmenu : UnsafeNativeMethods.GetSubMenu (_hmenu, _item);
                if (submenu == IntPtr.Zero)
                {
                    return null;
                }
 
                IntPtr hwndSubmenu = WindowsMenu.WindowFromSubmenu(submenu);
 
                if (hwndSubmenu != IntPtr.Zero)
                {
                    WindowsMenu.MenuType type = WindowsMenu.GetSubMenuType (hwndSubmenu, submenu);
                    return new WindowsMenu (hwndSubmenu, null, submenu, type, 0);
                }
                return null;
            }
 
            // Returns a Proxy element corresponding to the specified screen coordinates.
            internal override ProxySimple ElementProviderFromPoint (int x, int y)
            {
                // Hit test on all the descendent
                for (MenuItem menuCur = FirstOrLastChild (true); menuCur != null; menuCur = menuCur.NextMenuItem)
                {
                    ProxySimple menuItem = menuCur.ElementProviderFromPoint(x, y);
 
                    if (menuItem != null)
                    {
                        return menuItem;
                    }
                }
 
                Rect rc = BoundingRectangle;
                if (Misc.PtInRect(ref rc, x, y))
                {
                    return this;
                }
 
                return null;
            }
 
            #endregion ProxyFragment Interface
 
            #region Invoke Pattern
 
            // Select the desired menuItem.  This will expand a menu item as well as
            // invoke a menu item.  The enter key is used here to make sure in the
            // case where we are not expanding that the menu get dissmissed properly.
            void IInvokeProvider.Invoke ()
            {
                // Make sure that the control is enabled
                if (!IsEnabledMenu)
                {
                    throw new ElementNotEnabledException();
                }
 
                SetFocus();
 
                // sending enter key to the currently selected item
                ExpandViaEnter();
                WaitForMenuMode(false);
            }
 
            #endregion
 
            #region ExpandCollapse Pattern
 
            // Show all Children
            void IExpandCollapseProvider.Expand ()
            {
                if (!IsEnabledMenu)
                {
                    throw new ElementNotEnabledException();
                }
 
                if (!IsSubmenuCollapsed ())
                {
                    return;
                }
 
                // For some menus we need to have a right to input
                if (ReadyForInput ())
                {
                    // sytem menu item has its own way to expand
                    // this should preceed all other expand calls
                    if (IsSystemMenuItem())
                    {
                        if (ExpandCollapseSystem(true))
                            return;
 
                        throw new InvalidOperationException(SR.OperationCannotBePerformed);
                    }
 
                    // top level
                    if (_menuType == WindowsMenu.MenuType.Toplevel)
                    {
                        if (ExpandTopLevelMenu())
                            return;
 
                        throw new InvalidOperationException(SR.OperationCannotBePerformed);
                    }
 
                    // submenu
                    if( ExpandSubmenu ())
                        return;
                }
 
                throw new InvalidOperationException(SR.OperationCannotBePerformed);
            }
 
            // Hide all Children
            void IExpandCollapseProvider.Collapse()
            {
                if (!IsEnabledMenu)
                {
                    throw new ElementNotEnabledException();
                }
 
                if (IsSubmenuCollapsed ())
                {
                    return;
                }
 
                // For some menus we need to have a right to input
                if (ReadyForInput ())
                {
                    // sytem menu item has its own way to expand
                    // this should be preceed all other collapse calls
                    if (IsSystemMenuItem ())
                    {
                        if (ExpandCollapseSystem(false))
                            return;
 
                        throw new InvalidOperationException(SR.OperationCannotBePerformed);
                    }
 
                    // top-level
                    if (_menuType == WindowsMenu.MenuType.Toplevel)
                    {
                        if (CollapseTopLevelMenu())
                            return;
 
                        throw new InvalidOperationException(SR.OperationCannotBePerformed);
                    }
 
                    // submenu
                    if (CollapseSubmenu())
                        return;
                }
 
                // probably should throw
                throw new InvalidOperationException(SR.OperationCannotBePerformed);
            }
 
            // Indicates an elements current Collapsed or Expanded state
            ExpandCollapseState IExpandCollapseProvider.ExpandCollapseState
            {
                get
                {
                    return (IsSubmenuCollapsed()) ? ExpandCollapseState.Collapsed : ExpandCollapseState.Expanded;
                }
            }
 
            #endregion ExpandCollapse Pattern
 
            #region SelectionItem Pattern
 
            // Selects this element
            void ISelectionItemProvider.Select()
            {
                // Make sure that the control is enabled
                if (!IsEnabledMenu)
                {
                    throw new ElementNotEnabledException();
                }
 
                SetFocus();
 
                // sending enter key to the currently selected item
                ExpandViaEnter();
            }
 
            // Adds this element to the selection
            void ISelectionItemProvider.AddToSelection()
            {
                throw new InvalidOperationException(SR.DoesNotSupportMultipleSelection);
            }
 
            // Removes this element from the selection
            void ISelectionItemProvider.RemoveFromSelection()
            {
                throw new InvalidOperationException(SR.DoesNotSupportMultipleSelection);
            }
 
            // True if this element is part of the the selection
            bool ISelectionItemProvider.IsSelected
            {
                get
                {
                    return IsChecked() ? true : false;
                }
            }
 
            // Returns the container for this element
            IRawElementProviderSimple ISelectionItemProvider.SelectionContainer
            {
                get
                {
                    return GetParent();
                }
            }
 
            #endregion SelectionItem Pattern
 
            #region IToggleProvider
 
            void IToggleProvider.Toggle()
            {
                // Make sure that the control is enabled
                if (!IsEnabledMenu)
                {
                    throw new ElementNotEnabledException();
                }
 
                SetFocus();
 
                // sending enter key to the currently selected item
                ExpandViaEnter();
            }
 
            ToggleState IToggleProvider.ToggleState
            {
                get
                {
                    return IsChecked() ? ToggleState.On : ToggleState.Off;
                }
            }
 
            #endregion IToggleProvider
 
            //------------------------------------------------------
            //
            //  Protected Methods
            //
            //------------------------------------------------------
 
            #region Protected Methods
 
            // This routine is only called on elements belonging to an hwnd that has the focus.
            protected override bool IsFocused()
            {
                return Misc.IsBitSet(UnsafeNativeMethods.GetMenuState(_hmenu, _item, NativeMethods.MF_BYPOSITION), NativeMethods.MF_HILITE);
            }
 
            #endregion
 
            // ------------------------------------------------------
            //
            // Private Methods
            //
            // ------------------------------------------------------
 
            #region Private Methods
 
            private bool IsChecked()
            {
                return Misc.IsBitSet(UnsafeNativeMethods.GetMenuState(_hmenu, _item, NativeMethods.MF_BYPOSITION), NativeMethods.MF_CHECKED);
            }
 
            private bool IsRadioCheck()
            {
                NativeMethods.MENUITEMINFO menuItemInfo = new NativeMethods.MENUITEMINFO();
                menuItemInfo.cbSize = Marshal.SizeOf(menuItemInfo.GetType());
                menuItemInfo.fMask = NativeMethods.MIIM_FTYPE | NativeMethods.MIIM_SUBMENU | NativeMethods.MIIM_STATE;
 
                if (!Misc.GetMenuItemInfo(_hmenu, _item, true, ref menuItemInfo))
                {
                    return false;
                }
 
                return (Misc.IsBitSet(menuItemInfo.fType, NativeMethods.MFT_RADIOCHECK) && menuItemInfo.hbmpChecked == IntPtr.Zero);
            }
 
            // Also needed for SetFocus Keyboard navigation
            private static bool IsSeparator (IntPtr hmenu, int position)
            {
                NativeMethods.MENUITEMINFO menuItemInfo = new NativeMethods.MENUITEMINFO ();
                menuItemInfo.cbSize = Marshal.SizeOf (menuItemInfo.GetType ());
                menuItemInfo.fMask = NativeMethods.MIIM_FTYPE | NativeMethods.MIIM_SUBMENU | NativeMethods.MIIM_STATE;
 
                if (!Misc.GetMenuItemInfo(hmenu, position, true, ref menuItemInfo))
                {
                    return false;
                }
 
                return (Misc.IsBitSet(menuItemInfo.fType, NativeMethods.MF_SEPARATOR) ||
                        Misc.IsBitSet(menuItemInfo.fType, NativeMethods.MF_MENUBARBREAK) ||
                        Misc.IsBitSet(menuItemInfo.fType, NativeMethods.MF_MENUBREAK));
            }
 
            //Gets the localized keywords accelerators
            private string[] GetKeywordsAccelerators()
            {
                return new string[] {
                    SR.KeyHome,
                    SR.KeyEnd,
                    SR.KeyDel,
                    SR.KeyDelete,
                    SR.KeyIns,
                    SR.KeyInsert,
                    SR.KeyPageUp,
                    SR.KeyPageDown,
                    SR.KeyEsc,
                    SR.KeyScrLk,
                    SR.KeyPause,
                    SR.KeySysRq,
                    SR.KeyPrtScn,
                    SR.KeyTab,
                    SR.KeyHelp,
                };
            }
 
            // Retrieve type of menu item
            private MenuItemType GetMenuItemType ()
            {
                if (_menuType == WindowsMenu.MenuType.System)
                {
                    return MenuItemType.SubMenu;
                }
 
                NativeMethods.MENUITEMINFO menuItemInfo = new NativeMethods.MENUITEMINFO();
                menuItemInfo.cbSize = Marshal.SizeOf(menuItemInfo.GetType());
                menuItemInfo.fMask = NativeMethods.MIIM_FTYPE | NativeMethods.MIIM_SUBMENU | NativeMethods.MIIM_STATE;
 
                if (Misc.GetMenuItemInfo(_hmenu, _item, true, ref menuItemInfo))
                {
                    if (menuItemInfo.hSubMenu != IntPtr.Zero)
                    {
                        return MenuItemType.SubMenu;
                    }
 
                    if (Misc.IsBitSet(menuItemInfo.fType, NativeMethods.MF_SEPARATOR) ||
                        Misc.IsBitSet(menuItemInfo.fType, NativeMethods.MF_MENUBARBREAK) ||
                        Misc.IsBitSet(menuItemInfo.fType, NativeMethods.MF_MENUBREAK))
                    {
                        return MenuItemType.Spacer;
                    }
                }
 
                return MenuItemType.Command; // Everything else
            }
 
            // Detect if a submenu is collapsed (not expanded).
            private bool IsSubmenuCollapsed()
            {
                // Not a submenu
                if (_type != MenuItemType.SubMenu)
                {
                    return false;
                }
 
                if (IsInSystemMenuMode())
                {
                    IntPtr hwndSubMenu = Misc.FindWindowEx(IntPtr.Zero, IntPtr.Zero, MenuClassName, null);
                    return (hwndSubMenu == IntPtr.Zero || !SafeNativeMethods.IsWindowVisible(hwndSubMenu));
                }
                else
                {
                    IntPtr submenu = UnsafeNativeMethods.GetSubMenu(_hmenu, _item);
                    return (IntPtr.Zero == WindowsMenu.WindowFromSubmenu(submenu));
                }
            }
 
            // Expand menu that is a child of the top-level menuItem
            private bool ExpandTopLevelMenu ()
            {
                // Put us in menu mode and expand the Menu via the Enter key
                if (SetFocus())
                {
                    ExpandViaEnter();
                    return WaitForPopupMenu(true);
                }
 
                return false;
            }
 
            // Expand menu that is a child of the top-level menuItem
            private bool CollapseTopLevelMenu ()
            {
                SendAltKey ();
                if (WaitForPopupMenu(false))
                {
                    // Wait for the Highlighted menu to be gone
                    // this avoids odd timing issue
                    return WaitForNoFocus();
                }
 
                return false;
            }
 
            // Expand the submenu
            private bool ExpandSubmenu ()
            {
                // Since IsSubmenuCollapsed returns true for null or invisible menus, this code
                // should return false if the window is already invisible.
                 if (!SafeNativeMethods.IsWindowVisible (_hwnd))
                 {
                     return false;
                 }
 
                // In order to expand the submenu we will send a hotkey to the menuItem that shows it
                // But before we can do this we need to make sure that there are no other submenus
                // open that can interfere with us.
                // If there any other submenu open we need to collapse them before sending a hotkey
                // collaps all the submenus (if any) that go after us
                if (CollapseSubmenusAfter ())
                {
                    char hotKey = HotKeyCheckNoDups;
 
                    if ('\0' != hotKey)
                    {
                        short convert = UnsafeNativeMethods.VkKeyScan (hotKey);
 
                        if (-1 != convert)
                        {
                            short vk = convert;
 
                            Input.SendKeyboardInputVK(vk, true);
                            Input.SendKeyboardInputVK(vk, false);
                            return WaitForPopupMenu (true);
                        }
                    }
 
                    // Bad dev did not put any hot-keys
                    // Navigate to the menu item and send enter key
                    if (KeyBoardNavigate ())
                    {
                        ExpandViaEnter ();
                        return WaitForPopupMenu (true);
                    }
                }
 
                return false;
            }
 
            // Collapse the submenu
            private bool CollapseSubmenu ()
            {
                // Since IsSubmenuCollapsed returns true for invisible menus, this code
                // can return true if the window is already invisible.
                if (!SafeNativeMethods.IsWindowVisible(_hwnd))
                {
                    return false;
                }
 
                // In order to collapse the submenu we will send an ESC
                // But before we can do this we need to make sure that there are no other submenus
                // open that can interfere with us.
                // If there any other submenu open we need to collapse them before sending our ESC
                if (CollapseSubmenusAfter ())
                {
                    return WaitForPopupMenu (false);
                }
 
                return false;
            }
 
            // Collapses all the submenus that follow _hMenu in the hierarchy
            private bool CollapseSubmenusAfter ()
            {
                // Submenus that were brough after us, are located before us in top-level windows hierarchy
                int afterUsCounter = 0;
 
                for (IntPtr hwndSubMenu = Misc.FindWindowEx(IntPtr.Zero, IntPtr.Zero, WindowsMenu.MenuClassName, null);
                     hwndSubMenu != _hwnd;
                     hwndSubMenu = Misc.FindWindowEx(IntPtr.Zero, hwndSubMenu, WindowsMenu.MenuClassName, null))
                {
                    // At this point all that left is to bail out
                    if (hwndSubMenu == IntPtr.Zero)
                    {
                        return false;
                    }
 
                    if (SafeNativeMethods.IsWindowVisible (hwndSubMenu))
                    {
                        afterUsCounter++;
                    }
                }
 
                // now collapse menus that follow after us
                while (afterUsCounter > 0)
                {
                    SingleCollapse ();
                    afterUsCounter--;
                }
 
                return true;
            }
 
            // expands or collapses the systemmenupop
            private bool ExpandCollapseSystem(bool fExpand)
            {
                if (fExpand)
                {
                    Misc.PostMessage(_hwnd, NativeMethods.WM_SYSCOMMAND, (IntPtr)NativeMethods.SC_KEYMENU, (IntPtr)Convert.ToInt32(' '));
                }
                else
                {
                    SendAltKey();
                }
 
                // Wait for a few millisecond for this operation to be completed
                return WaitForMenuMode(fExpand);
            }
 
            private MenuItem FirstOrLastChild (bool returnFirstChild)
            {
                // Return first or last menuItem on the menu that this menuItem will drop
                if (_type == MenuItemType.SubMenu && IsEnabledMenu)
                {
                    IntPtr hSubmenu = UnsafeNativeMethods.GetSubMenu(_hmenu, _item);
                    if (hSubmenu == IntPtr.Zero)
                    {
                        return null;
                    }
                    IntPtr hwndSubmenu = WindowsMenu.WindowFromSubmenu(hSubmenu);
 
                    if (hwndSubmenu != IntPtr.Zero)
                    {
                        WindowsMenu.MenuType type = WindowsMenu.GetSubMenuType(hwndSubmenu, hSubmenu);
                        WindowsMenu parent = new WindowsMenu(hwndSubmenu, null, hSubmenu, type, 0);
                        int childIndex = (returnFirstChild) ? 0 : Misc.GetMenuItemCount(hSubmenu) - 1;
 
                        return new MenuItem(hwndSubmenu, parent, childIndex, hSubmenu, type);
                    }
                    return null;
                }
 
                return null;
            }
 
            // Put us in menu mode and expand the Menu via the Enter key
            // Wait for a few milliseconds for the menu to be expanded before
            // exiting
            private bool WaitForPopupMenu (bool fShow)
            {
                UInt32 dwTicks = SafeNativeMethods.GetTickCount (), dwDelta = 0;
 
                // Get out through a timer
                while (true)
                {
                    // Wait for a few milliseconds for this operation to be completed
                    System.Threading.Thread.Sleep(10);
 
                    // Wait until at least one child is there
                    MenuItem firstMenu = FirstOrLastChild (true);
 
                    // Wait until the action has been completed
                    // If fShow == true, also make sure last child is present.
                    // (This makes it more certain that the menu is done with initialization.)
                    if ((fShow && firstMenu != null && FirstOrLastChild(false) != null
                            || !fShow && firstMenu == null)
                        || (dwDelta = SubtractTicks (SafeNativeMethods.GetTickCount (), dwTicks)) >= WindowsMenu.TimeOut)
                    {
                        return dwDelta < WindowsMenu.TimeOut;
                    }
                }
            }
 
            // Wait for the focus to be gone or a time out before proceeding
            internal bool WaitForNoFocus()
            {
                // Wait for a few millisecond for this operation to be completed
                UInt32 dwTicks = SafeNativeMethods.GetTickCount();
 
                // Wait until the action has been completed
                do
                {
                    int item = 0;
                    int cItems = Misc.GetMenuItemCount(_hmenu);
 
                    // Loops on all the MenuItems
                    for (item = 0; item < cItems && !Misc.IsBitSet(UnsafeNativeMethods.GetMenuState(_hmenu, item, NativeMethods.MF_BYPOSITION), NativeMethods.MF_HILITE); item++)
                    {
                    }
 
                    if (item == cItems)
                    {
                        return true;
                    }
                    // Check if we run out of time
                } while (SubtractTicks(SafeNativeMethods.GetTickCount(), dwTicks) <= WindowsMenu.TimeOut);
 
                return false;
            }
 
            // Last can wrap around, make it a ulong if this happens
            private static UInt32 SubtractTicks (UInt32 last, UInt32 first)
            {
                if (last < first)
                {
                    return (UInt32) ((ulong) last + (ulong) UInt32.MaxValue + 1 - first);
                }
 
                return last - first;
            }
 
            // Make sure that our window is an active one
            // If not try to make it active
            // Assumtpion: window is shown
            private bool ReadyForInput ()
            {
                if (!SafeNativeMethods.IsWindowVisible (_hwnd))
                {
                    throw new ElementNotAvailableException ();
                }
 
                if (_menuType == WindowsMenu.MenuType.Submenu || _menuType == WindowsMenu.MenuType.Context || _menuType == WindowsMenu.MenuType.SystemPopup)
                {
                    // if menu's type one of the above we do have the right of input
                    // otheriwce window would not be visible
                    return true;
                }
 
                NativeMethods.GUITHREADINFO gui;
 
                if (Misc.ProxyGetGUIThreadInfo(0, out gui) && _hwnd == gui.hwndActive)
                {
                    // Remark: ProxyGetClassName() does not return the actual classname.  Instead
                    // it returns the underlying classname and hence the compare is done with "ListBox" and
                    // not "ComboLBox".
                    if (gui.hwndCapture != IntPtr.Zero && Misc.ProxyGetClassName(gui.hwndCapture) == "ListBox")
                    {
                        // If a combobox's listbox already has the capture, release it to make menu ready for input.
                        // To release the combobox send an escape key sequence.
                        SingleCollapse();
                    }
 
                    return true;
                }
 
                // try to set focus
                return Misc.SetFocus(_hwnd);
            }
 
            private static bool WaitForMenuMode (bool fInMenuMode)
            {
                // Wait for a few millisecond for this operation to be completed
                UInt32 dwTicks = SafeNativeMethods.GetTickCount();
                UInt32 dwDelta = 0;
 
                // Wait until the action has been completed
                while (Misc.InMenuMode() != fInMenuMode && (dwDelta = SubtractTicks(SafeNativeMethods.GetTickCount(), dwTicks)) < WindowsMenu.TimeOut)
                {
                    // Sleep the shortest amount of time possible while still guaranteeing that some sleep occurs
                    System.Threading.Thread.Sleep(1);
                }
 
                return dwDelta < WindowsMenu.TimeOut;
            }
 
            // Set or Remove the application in Menu mode
            private static bool MenuMode(bool fSet)
            {
                if (Misc.InMenuMode() == fSet)
                    return true;
 
                SendAltKey();
 
                // Wait until the action has been completed
                return WaitForMenuMode(fSet);
            }
 
            // This method navigates to our menuItem
            // using down key
            // Note: This algorithm is simplier and less prone to the bugs
            // than the one where we would get the currently higlighted item
            // than calculate the delta (taking Spacer into account) and the direction
            // and only than move. The fact that down key will go from the last item to the
            // first item allows us to do this. We could of also use the up key only
            private bool KeyBoardNavigate ()
            {
                int cMoves;
 
                if (CalculateKeyboardMoves (out cMoves))
                {
                    Key key;
 
                    // For Menu Bar, simulates keyboard right arrow move to get to the item
                    if (this._menuType == MenuType.Toplevel)
                    {
                        key = cMoves > 0 ? Key.Right : Key.Left;
                    }
                    else
                    {
                        key = cMoves > 0 ? Key.Down : Key.Up;
                    }
 
                    // This math is used a few times throughout the proxy code
                    // Very simple primitives are used. It might be worth reimplementing
                    // them in the proxy dll.
                    cMoves = Math.Abs (cMoves);
                    for (int i = 0; i < cMoves; i++)
                    {
                        Input.SendKeyboardInput (key, true);
                        Input.SendKeyboardInput (key, false);
 
                        // Sleep for a millisecond to let the target process the Keypresses
                        System.Threading.Thread.Sleep(1);
                    }
 
                    // Make sure that the our hwnd has the focus
                    // Wait for a few millisecond for this operation to be completed
                    UInt32 dwTicks = SafeNativeMethods.GetTickCount ();
                    UInt32 dwDelta = 0;
 
                    // Wait until the action has been completed
                    while (!Misc.IsBitSet(UnsafeNativeMethods.GetMenuState(_hmenu, _item, NativeMethods.MF_BYPOSITION), NativeMethods.MF_HILITE) &&
                           (dwDelta = SubtractTicks (SafeNativeMethods.GetTickCount (), dwTicks)) <= WindowsMenu.TimeOut)
                    {
                        // Sleep the shortest amount of time possible while still guaranteeing that some sleep occurs
                        System.Threading.Thread.Sleep(1);
                    }
 
                    return dwDelta <= WindowsMenu.TimeOut;
                }
 
                return false;
            }
 
            // This method calculates the number of right keys
            // that we need to send in order to move to the
            // needed menu item
            // NOTE: call this method only for the top-level menu
            private bool CalculateKeyboardMoves (out int cMoves)
            {
                // Figure out how far away we are from the hilited item
                int c = Misc.GetMenuItemCount(_hmenu);
                int rMoves = 0;
                bool pd = false;
 
                cMoves = 0;
 
                for (int i = 0; i < c; i++)
                {
                    if (!IsSeparator(_hmenu, i))
                        rMoves++;
 
                    if (Misc.IsBitSet(UnsafeNativeMethods.GetMenuState(_hmenu, i, NativeMethods.MF_BYPOSITION), NativeMethods.MF_HILITE))
                    {
                        cMoves = -rMoves;
                        if( pd )
                            break;
                        rMoves = 0;
                        pd = true;
                    }
 
                    if( i == _item )
                    {
                        cMoves = rMoves;
                        if( pd )
                            break;
                        rMoves = 0;
                        pd = true;
                    }
                }
 
                return true;
            }
 
            // detect if given menuItem is a system menuItem
            // Either _menuType is System
            // or in case of maximized MDI - 1st item (on TopLevel) has a submenu and a bitmap associated with it
            private bool IsSystemMenuItem ()
            {
                if (_menuType == WindowsMenu.MenuType.System)
                {
                    return true;
                }
 
                // MDI case. The system menu is the first item.
                if (_item == 0 && _menuType == WindowsMenu.MenuType.Toplevel &&
                    (IntPtr.Zero != UnsafeNativeMethods.GetSubMenu (_hmenu, 0)) &&
                    Misc.IsBitSet(UnsafeNativeMethods.GetMenuState(_hmenu, 0, NativeMethods.MF_BYPOSITION), NativeMethods.MF_BITMAP))
                {
                    return true;
                }
 
                return false;
            }
 
            // Collapses the last open submenu is the hierarchy
            private static void SingleCollapse ()
            {
                Input.SendKeyboardInput (Key.Escape, true);
                Input.SendKeyboardInput (Key.Escape, false);
            }
 
            // Expands the menu by the means of sending an enter key
            // NOTE: the needed menuItem should be highlighted
            private static void ExpandViaEnter ()
            {
                Input.SendKeyboardInput (Key.Return, true);
                Input.SendKeyboardInput (Key.Return, false);
            }
 
            // This method has multiple purposes depending on situation at which it is called
            // It can be used to do a full menu collapse
            // It can be used to take us off the menu mode
            // It can be used to put us back into the menu mode
            private static void SendAltKey ()
            {
                Input.SendKeyboardInput (Key.LeftAlt, true);
                Input.SendKeyboardInput (Key.LeftAlt, false);
            }
 
            // Search in a menu if the menu item string finishes with an accelerator
            // of the form Ctrl+Am Control+Shift+K.
            private static string AccelatorKeyCtrl(string sKeyword, string sCanonicalsKeyword, string menuText, string menuRawText, out int pos)
            {
                int cMenuChars = menuText.Length;
                char ch;
 
                // Try to find the keyword
               // Eg: Ctrl or Control; 4 == "ctrl".Length; 2 '+' or ' ' + one char
                int cKeyChars = sKeyword.Length;
                if ((pos = menuText.LastIndexOf(sKeyword, StringComparison.Ordinal)) >= 0 && pos + cKeyChars + 2 <= cMenuChars)
                {
                    ch = menuText [pos + cKeyChars];
                    if (ch == '+' || ch == ' ')
                    {
                        // Found a combination "Ctrl+letter"
                        if (pos + cKeyChars + 2 == cMenuChars)
                        {
                            // UperCase the letter, case Ctr+A
                            return string.Format(CultureInfo.CurrentCulture, "{0}{1}{2}", sCanonicalsKeyword, menuText.Substring(pos + cKeyChars + 1, cMenuChars - (pos + cKeyChars + 2)), Char.ToUpper(menuText[cMenuChars - 1], CultureInfo.InvariantCulture));
                        }
                        else
                        {
                            // Take the remaining string from the Keyword
                            // Case Alt+Enter
                            return sCanonicalsKeyword + menuRawText.Substring(pos + cKeyChars + 1, cMenuChars - (pos + cKeyChars + 1));
                        }
                    }
                }
                return null;
            }
 
            // Search in a menu if the menu item string finishes with an accelerator
            // of the form Fxx (F5, F12, etc)
            private static string AccelatorFxx (string menuText)
            {
                int cChars = menuText.Length;
                int pos;
 
                // Get the function key number
                for (pos = cChars - 1; pos > 0 && cChars - pos <= 2 && Char.IsDigit (menuText [pos]); pos--)
                {
                }
 
                // Check that it is the form Fxx
                if (pos < cChars - 1 && pos > 0 && menuText [pos] == 'f')
                {
                    int iKey = int.Parse(menuText.Substring(pos + 1, cChars - (pos + 1)), CultureInfo.InvariantCulture);
                    if (iKey > 0 && iKey <= 12)
                    {
                        return "F" + iKey.ToString(CultureInfo.CurrentCulture);
                    }
                }
                return null;
            }
 
            // Backward walk to skip over char that are space in menu
            private static int SkipMenuSpaceChar(string s, int iStart)
            {
                char ch;
 
                // Spaces for Menus are ' ', '\t', '\a'
                while (iStart - 1 >= 0 && ((ch = s[iStart - 1]) == ' ' || ch == '\t' || ch == '\a'))
                {
                    iStart--;
                }
 
                return iStart;
            }
 
            private void GetItemId(ref string itemId)
            {
                int result = UnsafeNativeMethods.GetMenuItemID(_hmenu, _item);
 
                if (result > 0)
                {
                    itemId = "Item " + result.ToString(CultureInfo.CurrentCulture);
                }
                else if (result == -1)
                {
                    // since the "Application-defined 16-bit value that identifies the menu item", i.e.
                    // the MENUITEMINFO.wID, changes from instance to instance, I am using the position as
                    // the ID of the menu items.
                    itemId = "Item " + (_item + 1).ToString(CultureInfo.CurrentCulture);
                }
            }
 
            #endregion
 
            // ------------------------------------------------------
            //
            // Private Properties
            //
            // ------------------------------------------------------
 
            #region Private Properties
 
            // This method gets the menu item string of an menu.  First gets the length of the string then
            // allocates resources to accomodate the length of the string.
            private string Text
            {
                get
                {
                    // Get the length. passing the length of zero returns the length
                    int length = UnsafeNativeMethods.GetMenuString(_hmenu, _item, IntPtr.Zero, 0, NativeMethods.MF_BYPOSITION);
 
                    // if the item has zero length, exit gracefully
                    if (length > 0)
                    {
                        // allocate resources for the string
                        StringBuilder strbldr = new StringBuilder(length + 1);
 
                        // Send the message...
                        if (UnsafeNativeMethods.GetMenuString(_hmenu, _item, strbldr, length + 1, NativeMethods.MF_BYPOSITION) == length)
                        {
                            // assign output parameters
                            return strbldr.ToString();
                        }
                    }
                    else
                    {
                        NativeMethods.MENUITEMINFO menuItemInfo = new NativeMethods.MENUITEMINFO();
                        menuItemInfo.cbSize = Marshal.SizeOf(menuItemInfo.GetType());
                        menuItemInfo.fMask = NativeMethods.MIIM_TYPE | NativeMethods.MIIM_STATE | NativeMethods.MIIM_DATA | NativeMethods.MIIM_ID;
                        menuItemInfo.cch = 0;
 
                        if (Misc.GetMenuItemInfo(_hmenu, _item, true, ref menuItemInfo))
                        {
                            if (Misc.IsBitSet(menuItemInfo.fType, NativeMethods.MF_SEPARATOR) ||
                                Misc.IsBitSet(menuItemInfo.fType, NativeMethods.MF_MENUBARBREAK) ||
                                Misc.IsBitSet(menuItemInfo.fType, NativeMethods.MF_MENUBREAK))
                            {
                                return SR.LocalizedNameWindowsMenuSeparator;
                            }
                            else if (Misc.IsBitSet(menuItemInfo.fType, NativeMethods.MF_OWNERDRAW))
                            {
                                // If it's owner-draw, check if it supports the 'dwData is ptr to MSAA data' workaround.
                                return TryMSAAMenuWorkAround(menuItemInfo.dwItemData);
                            }
                        }
                    }
 
                    return "";
                }
            }
 
            private unsafe string TryMSAAMenuWorkAround(IntPtr dwItemData)
            {
                if (_hwnd == IntPtr.Zero)
                {
                    return "";
                }
 
                // Open that process so we can read its memory...
                using (SafeProcessHandle hProcess = new SafeProcessHandle(_hwnd))
                {
                    if (hProcess.IsInvalid)
                    {
                        return "";
                    }
 
                    // Treat dwItemData as an address, and try to read a MSAAMENUINFO struct from there...
                    MSAAMENUINFO msaaMenuInfo = new MSAAMENUINFO();
                    int readSize = Marshal.SizeOf(msaaMenuInfo.GetType());
                    IntPtr count;
 
                    if (!Misc.ReadProcessMemory(hProcess, dwItemData, new IntPtr(&msaaMenuInfo), new IntPtr(readSize), out count))
                    {
                        return "";
                    }
                    // Check signature...
                    if (msaaMenuInfo.dwMSAASignature != MSAA_MENU_SIG)
                    {
                        return "";
                    }
                    // Very large values of cchWText can lead to overflows in the length calculation below, and/or
                    // large allocations; to avoid this, bail if cchWText reports a length greater than 4k - which
                    // should be more than sufficient for any menu item.
                    if (msaaMenuInfo.cchWText > 4096)
                    {
                        return "";
                    }
 
                    // Work out len of UNICODE string to copy (+1 for terminating NUL)
                    readSize = (msaaMenuInfo.cchWText + 1) * sizeof(char);
 
                    char* text = stackalloc char[readSize];
 
                    // Do the copy...
                    if (Misc.ReadProcessMemory(hProcess, msaaMenuInfo.pszWText, new IntPtr(text), new IntPtr(readSize), out count))
                    {
                        string menuText = new string(text);
 
                        int nullTermination = menuText.IndexOf('\0');
 
                        if (-1 != nullTermination)
                        {
                            // We need to strip null terminated char and everything behind it from the str
                            menuText = menuText.Remove(nullTermination, readSize - nullTermination);
                        }
                        return menuText;
                    }
                }
 
                return "";
            }
 
            private bool IsEnabledMenu
            {
                get
                {
                    if (_menuType == WindowsMenu.MenuType.System)
                    {
                        return SafeNativeMethods.IsWindowEnabled(_hwnd);
                    }
 
                    // get the menu states
                    int state = UnsafeNativeMethods.GetMenuState(_hmenu, _item, NativeMethods.MF_BYPOSITION);
 
                    // check if the menu state contains `the disabled or grayed state
                    return !(Misc.IsBitSet(state, NativeMethods.MF_DISABLED) | Misc.IsBitSet(state, NativeMethods.MF_GRAYED));
                }
            }
 
            private MenuItem PreviousMenuItem
            {
                get
                {
                    // return our prev hierarchical sibling of type WindowsMenuItem
                    if (_item > 0)
                    {
                        return new MenuItem(_hwnd, _parent, _item - 1, _hmenu, _menuType);
                    }
                    return null;
                }
            }
 
            private MenuItem NextMenuItem
            {
                get
                {
                    // return our next hierarchical sibling of type WindowsMenuItem
                    int nextItem = _item + 1;
 
                    if (nextItem < Misc.GetMenuItemCount(_hmenu))
                    {
                        return new MenuItem(_hwnd, _parent, nextItem, _hmenu, _menuType);
                    }
                    return null;
                }
            }
 
            // retrieve a hotkey char if any
            private char HotKey
            {
                get
                {
                    string name = Text;
                    int hotKeyStart = name.IndexOf ('&');
 
                    if (hotKeyStart == -1)
                    {
                        return '\0';
                    }
 
                    System.Diagnostics.Debug.Assert (name.Length > hotKeyStart + 1, "Unexpected end of string");
                    return name[hotKeyStart + 1];
                }
            }
 
            // retrieve a hotkey char if any.
            // Checks if there is an another menu prior to this menu item with the same accelerator
            private char HotKeyCheckNoDups
            {
                get
                {
                    char chHotKey = HotKey;
 
                    if (chHotKey != '\0')
                    {
                        for (int i = 0; i < _item; i++)
                        {
                            if (new MenuItem (_hwnd, this._parent, i, _hmenu, _menuType).HotKey == chHotKey)
                                return '\0';
                        }
                    }
                    return chHotKey;
                }
            }
 
            private string AcceleratorKey
            {
                get
                {
                    string menuRawText = Text;
 
                    if (string.IsNullOrEmpty(menuRawText))
                    {
                        return null;
                    }
 
                    menuRawText = Misc.StripMnemonic(Text);
 
                    // A tab, '\t', is usually used to separate the menu string from the accelerator.  If a
                    // tab is found assume that the acceleraor is after the tab.
                    int pos = menuRawText.IndexOf('\t');
                    if (pos > 0)
                    {
                        return menuRawText.Remove(0, pos + 1);
                    }
 
                    // !!! Be caution modifying this code, it must miror the code for the Name Property
 
                    // Try to look for a combination Ctrl or Alt + something
                    string keyCtrl = SR.KeyCtrl;
                    string keyControl = SR.KeyControl;
                    string keyAlt = SR.KeyAlt;
                    string keyShift = SR.KeyShift;
                    string keyWin = SR.KeyWinKey;
 
                    string menuText = menuRawText.ToLower(CultureInfo.InvariantCulture);
                    string accelerator;
 
                    if ((accelerator = AccelatorKeyCtrl(keyCtrl.ToLower(CultureInfo.InvariantCulture), keyCtrl + " + ", menuText, menuRawText, out pos)) != null ||
                        (accelerator = AccelatorKeyCtrl(keyControl.ToLower(CultureInfo.InvariantCulture), keyCtrl + " + ", menuText, menuRawText, out pos)) != null ||
                        (accelerator = AccelatorKeyCtrl(keyAlt.ToLower(CultureInfo.InvariantCulture), keyAlt + " + ", menuText, menuRawText, out pos)) != null ||
                        (accelerator = AccelatorKeyCtrl(keyShift.ToLower(CultureInfo.InvariantCulture), keyShift + " + ", menuText, menuRawText, out pos)) != null ||
                        (accelerator = AccelatorKeyCtrl(keyWin.ToLower(CultureInfo.InvariantCulture), keyWin + " + ", menuText, menuRawText, out pos)) != null)
                    {
                        return accelerator;
                    }
 
                    // Try to look for a Fxx
                    accelerator = AccelatorFxx(menuText);
                    if (!string.IsNullOrEmpty(accelerator))
                    {
                        return accelerator;
                    }
 
                    // Look for a bunch of Predefined keyword
                    string[] keywordsAccelerators = GetKeywordsAccelerators();
 
                    for (int i = 0; i < keywordsAccelerators.Length; i++)
                    {
                        pos = menuText.LastIndexOf(keywordsAccelerators[i], StringComparison.OrdinalIgnoreCase);
                        if (pos > 0 && pos + keywordsAccelerators[i].Length == menuText.Length && (menuText[pos - 1] == '\a' || menuText[pos - 1] == '\t'))
                        {
                            return keywordsAccelerators[i];
                        }
                    }
 
                    return null;
                }
            }
 
 
            #endregion
 
            // ------------------------------------------------------
            //
            // Private Fields and Types Declaration
            //
            // ------------------------------------------------------
 
            #region Private Fields
 
            private enum MenuItemType
            {
                Spacer,
                Command,
                SubMenu
            }
 
 
            // The following structure is used for accessibility.  Accessibility tools
            // use it to get a descriptive string out of an owner-draw menu.  This
            // stuff will probably be put in a system header someday.
            private const int MSAA_MENU_SIG = unchecked((int)0xAA0DF00D);
 
            // Menu's dwItemData should point to one of these structs:
            // (or can point to an app-defined struct containing this as the first
            // member)
            [StructLayout(LayoutKind.Sequential)]
            private struct MSAAMENUINFO
            {
                internal int dwMSAASignature; // Must be MSAA_MENU_SIG
                internal int cchWText;        // Length of text in chars
                internal IntPtr pszWText;        // NUL-terminated text, in Unicode
            }
 
            private MenuItemType _type;
            private IntPtr _hmenu;
            internal WindowsMenu.MenuType _menuType;
 
            #endregion
        }
 
        #endregion
 
        // ------------------------------------------------------
        //
        //  DestroyedMenuItem Internal Class
        //
        //------------------------------------------------------
 
        #region DestroyedMenuItem
 
        // Represents a menu item whose container hwnd has been destroyed as is the case with InvokedEvent
        internal class DestroyedMenuItem : ProxyFragment, IInvokeProvider
        {
            // ------------------------------------------------------
            //
            // Constructors
            //
            // ------------------------------------------------------
 
            #region Constructors
 
            // Constructor used only for the Invoke event.  At this point in the Invoked event, hwnd is destroyed and there
            // is no reliable way to get the parent.  Most properties and methods for this object will throw InvalidOperation.
            internal DestroyedMenuItem(IntPtr hwnd, int item, IntPtr hwndParent)
                : base(hwnd, null, item)
            {
                _fNonClientAreaElement = true;
                _cControlType = ControlType.MenuItem;
                _item = item;
 
                _sAutomationId = "Item " + (item).ToString(CultureInfo.CurrentCulture);
 
                // This is used only to return a HostRawElementProvider for this menu item
                _hwndParent = hwndParent;
            }
 
            #endregion
 
 
            #region ProxySimple Interface
 
            internal override IRawElementProviderSimple HostRawElementProvider
            {
                get
                {
                    // Although we have the hwnd that contains this menu item that hwnd has been destroyed
                    // but go ahead and use it for the fragment root so events can be scoped to it.
                    return AutomationInteropProvider.HostProviderFromHandle(_hwndParent);
                }
            }
 
            // This might be a good idea for RuntimeId for menu items (base, hwnd menubar, item) in general.
            // Commenting out for now because UIA core doesn't give this provider a chance to provide RuntimeId.
            //internal override int [] GetRuntimeId()
            //{
            //    return new int[] { 1, unchecked((int)(long)_hwnd), _item };
            //}
 
            // Returns a pattern interface if supported.
            internal override object GetPatternProvider(AutomationPattern iid)
            {
                // even though this element is dead, return 'this' so events are raised properly
                if (iid == InvokePattern.Pattern)
                {
                    return this;
                }
 
                return null;
            }
 
            // Gets the bounding rectangle for this element
            internal override Rect BoundingRectangle
            {
                get
                {
                    return Rect.Empty;
                }
            }
 
            internal override bool SetFocus()
            {
                throw new ElementNotAvailableException();
            }
 
            internal override object GetElementProperty (AutomationProperty idProp)
            {
                // Expose enough properties to identify this as a particular menu item
                if (idProp == AutomationElement.ControlTypeProperty)
                {
                    return ControlType.MenuItem.Id;
                }
 
                if (idProp == AutomationElement.AutomationIdProperty)
                {
                    return _sAutomationId.Length > 0 ? _sAutomationId : null;
                }
 
                // This property is used by UIAutomationCore when raising events
                if (idProp == AutomationElement.NativeWindowHandleProperty)
                {
                    return _hwnd;
                }
 
                return AutomationElement.NotSupported;
            }
 
            #endregion
 
            #region Invoke Pattern
 
            void IInvokeProvider.Invoke()
            {
                throw new ElementNotAvailableException();
            }
 
            #endregion
 
 
            #region ProxyFragment Interface
            //
            // Throw ElementNotAvailable for any ProxyFragment implementation
            // since this element is quite dead.
            //
            internal override ProxySimple GetNextSibling (ProxySimple child)
            {
                throw new ElementNotAvailableException();
            }
 
            internal override ProxySimple GetPreviousSibling (ProxySimple child)
            {
                throw new ElementNotAvailableException();
            }
 
            internal override ProxySimple GetFirstChild ()
            {
                throw new ElementNotAvailableException();
            }
 
            internal override ProxySimple GetLastChild ()
            {
                throw new ElementNotAvailableException();
            }
 
            internal override ProxySimple ElementProviderFromPoint (int x, int y)
            {
                throw new ElementNotAvailableException();
            }
 
            #endregion ProxyFragment Interface
 
            // ------------------------------------------------------
            //
            // Private Fields
            //
            // ------------------------------------------------------
 
            #region Private Fields
 
            IntPtr _hwndParent;
 
            #endregion
        }
 
        #endregion
    }
}