WindowsToolbar.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / AccessibleTech / longhorn / Automation / Win32Providers / MS / Internal / AutomationProxies / WindowsToolbar.cs / 1 / WindowsToolbar.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: UIAutomation Toolbar Proxy 
//
// History: 
//  07/01/2003 : a-jeanp Created
//---------------------------------------------------------------------------

using System; 
using System.Collections;
using System.Runtime.InteropServices; 
using System.ComponentModel; 
using System.Globalization;
using System.Text; 
using System.Windows.Automation;
using System.Windows.Automation.Provider;
using System.Windows;
using MS.Win32; 

namespace MS.Internal.AutomationProxies 
{ 
    // Toolbar proxy
    class WindowsToolbar: ProxyHwnd 
    {
        // -----------------------------------------------------
        //
        // Constructors 
        //
        // ----------------------------------------------------- 
 
        #region Constructors
 
        protected WindowsToolbar (IntPtr hwnd, ProxyFragment parent, int item)
            : base( hwnd, parent, item )
        {
            // Set the control type string to return properly the properties. 
            _cControlType = ControlType.ToolBar;
            _fIsContent = false; 
 
            // support for events
            _createOnEvent = new WinEventTracker.ProxyRaiseEvents (RaiseEvents); 
        }

        #endregion
 
        #region Proxy Create
 
        // Static Create method called by UIAutomation to create this proxy. 
        // returns null if unsuccessful
        internal static IRawElementProviderSimple Create(IntPtr hwnd, int idChild, int idObject) 
        {
            return Create(hwnd, idChild);
        }
 
        internal static IRawElementProviderSimple Create(IntPtr hwnd, int idChild)
        { 
            WindowsToolbar wtv = null; 

            // By calling Accessible.CreateNativeFromEvent() instead of AccessibleObjectFromWindow() only controls with a native 
            // implementation of IAccessible will be found.  OleAcc will not create a IAccessible proxy, since
            // Accessible.CreateNativeFromEvent() by passes OleAcc by sending a WM_GETOBJECT directly to the control and creating
            // IAccessible from the return, if it can.
            Accessible acc = Accessible.CreateNativeFromEvent(hwnd, NativeMethods.OBJID_CLIENT, NativeMethods.CHILD_SELF); 
            if (acc != null)
            { 
                AccessibleRole role = acc.Role; 
                if (role == AccessibleRole.MenuBar || role == AccessibleRole.MenuPopup)
                { 
                    wtv = new WindowsToolbarAsMenu(hwnd, null, 0, acc);
                }
            }
 
            if( wtv == null)
            { 
                wtv = new WindowsToolbar(hwnd, null, 0); 
            }
 
            return idChild == 0 ? wtv : wtv.CreateToolbarItem (idChild - 1);
        }

        // Static Create method called by the event tracker system 
        internal static void RaiseEvents (IntPtr hwnd, int eventId, object idProp, int idObject, int idChild)
        { 
            if (idObject != NativeMethods.OBJID_VSCROLL && idObject != NativeMethods.OBJID_HSCROLL) 
            {
                ProxySimple proxySimple; 
                try
                {
                    proxySimple = (ProxySimple)Create(hwnd, idChild);
                } 
                catch(Win32Exception)
                { 
                    // With the toolbar on the classic Taskbar, we receive two EventObjectDestroy's.  The first 
                    // for the button/application that is going away and the second for an unknown button.
                    // The second unknown button fails the Create() with nonconsistant errors.  So just ignore 
                    // EventObjectDestroy's that causes Win32Exceptions in the Create().
                    if (eventId == NativeMethods.EventObjectDestroy && idProp == AutomationElement.StructureChangedEvent)
                    {
                        proxySimple = null; 
                    }
                    else 
                    { 
                        throw;
                    } 
                }
                // Ends up calling CreateToolbarItem which can return null
                if (proxySimple != null)
                { 
                    proxySimple.DispatchEvents(eventId, idProp, idObject, idChild);
                } 
            } 
        }
 
        #endregion Proxy Create

        //------------------------------------------------------
        // 
        //  Patterns Implementation
        // 
        //----------------------------------------------------- 

        #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)
        { 
            ProxySimple toolbarItem = null; 
            int count = Count;
 
            // Next for an item that does not exist in the list
            if (child._item >= count)
            {
                throw new ElementNotAvailableException (); 
            }
 
            // If the index of the next node would be out of range... 
            for (int item = child._item + 1; item >= 0 && item < count; item++)
            { 
                // This may fail if the toolbar item is hidden
                if ((toolbarItem = CreateToolbarItem (item)) != null)
                {
                    break; 
                }
            } 
 
            return toolbarItem;
        } 

        // 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)
        { 
            ProxySimple toolbarItem = null; 
            int count = Count;
 
            // Next for an item that does not exist in the list
            if (child._item >= count)
            {
                throw new ElementNotAvailableException (); 
            }
 
            // If the index of the prev node would be out of range... 
            for (int item = child._item - 1; item >= 0 && item < count; item--)
            { 
                // This may fail if the toolbar item is hidden
                if ((toolbarItem = CreateToolbarItem (item)) != null)
                {
                    break; 
                }
            } 
 
            return toolbarItem;
        } 

        // Returns the first child element in the raw hierarchy.
        internal override ProxySimple GetFirstChild ()
        { 
            ProxySimple toolbarItem = null;
 
            // If the index of the next node would be out of range... 
            for (int item = 0, count = Count; item < count; item++)
            { 
                // This may fail if the toolbar item is hidden
                if ((toolbarItem = CreateToolbarItem (item)) != null)
                {
                    break; 
                }
            } 
 
            return toolbarItem;
        } 

        // Returns the last child element in the raw hierarchy.
        internal override ProxySimple GetLastChild ()
        { 
            ProxySimple toolbarItem = null;
 
            // If the index of the prev node would be out of range... 
            for (int item = Count - 1; item >= 0; item--)
            { 
                // This may fail if the toolbar item is hidden
                if ((toolbarItem = CreateToolbarItem (item)) != null)
                {
                    break; 
                }
            } 
 
            return toolbarItem;
        } 

        // 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++)
            { 
                NativeMethods.Win32Rect rc = new NativeMethods.Win32Rect (ToolbarItem.GetBoundingRectangle (_hwnd, item)); 

                if (Misc.PtInRect(ref rc, x, y)) 
                {
                    return CreateToolbarItem (item);
                }
            } 

            return base.ElementProviderFromPoint (x, y); 
        } 

        #endregion 

        #region ProxySimple Interface

        // Returns an item corresponding to the focused element (if there is one), or null otherwise. 
        internal override ProxySimple GetFocus ()
        { 
            int focusIndex = Misc.ProxySendMessageInt(_hwnd, NativeMethods.TB_GETHOTITEM, IntPtr.Zero, IntPtr.Zero); 

            if (focusIndex >= 0) 
            {
                Accessible acc = Accessible.CreateNativeFromEvent(_hwnd, NativeMethods.OBJID_CLIENT, NativeMethods.CHILD_SELF);
                if (acc != null)
                { 
                    AccessibleRole role = acc.Role;
                    if (role == AccessibleRole.MenuBar || role == AccessibleRole.MenuPopup) 
                    { 
                        return new WindowsToolbarAsMenu(_hwnd, this, focusIndex, acc);
                    } 
                }

                return new WindowsToolbar(_hwnd, this, focusIndex);
            } 
            else
            { 
                return null; 
            }
        } 

        //Gets the localized name
        internal override string LocalizedName
        { 
            get
            { 
                // Outlook Express is now setting their toolbars with names, via SetWindowText(), so 
                // try to get the name from the windows text.
                string name = Misc.ProxyGetText(_hwnd); 
                if (string.IsNullOrEmpty(name))
                {
                    // if WM_GETTEXT failed try to get the name from the IAccessible object.
                    name = GetAccessibleName(NativeMethods.CHILD_SELF); 
                }
                // If still no name return null. 
                return string.IsNullOrEmpty(name) ? null : name; 
            }
        } 

        #endregion

        // ------------------------------------------------------ 
        //
        // Internal Methods 
        // 
        // ------------------------------------------------------
 
        #region Internal Methods

        // Create a WindowsToolbar instance.  Needs to be internal because
        // ApplicationWindow pattern needs to call this so needs to be internal 
        internal ProxySimple CreateToolbarItem (int item)
        { 
            NativeMethods.TBBUTTON tbb = new NativeMethods.TBBUTTON (); 

            // During the FocusChanged WinEvent (EVENT_OBJECT_FOCUS), 
            // some "ToolbarWindow32" children report an item ID (child id)
            // of 0x80000001, 0x80000002, etc. instead of 1, 2, etc.
            // However, when created as children of the parent toolbar,
            // these same items are assigned IDs of 1, 2, etc. 
            // Therefore, map negative item IDs of the form 0x80000001,
            // 0x80000002, etc. to 1, 2, etc. 
            item = (int)(~0x80000000 & (uint)item); 

            if (!XSendMessage.GetItem(_hwnd, item, ref tbb)) 
            {
                // If failed to get button infromation the button must not exist, so return null.
                return null;
            } 

            if (Misc.ProxySendMessageInt(_hwnd, NativeMethods.TB_ISBUTTONHIDDEN, new IntPtr(tbb.idCommand), IntPtr.Zero) == 0) 
            { 
                Accessible acc = Accessible.CreateNativeFromEvent(_hwnd, NativeMethods.OBJID_CLIENT, item + 1);
                if (acc != null) 
                {
                    if (acc.Role == AccessibleRole.MenuItem)
                    {
                        return new ToolbarItemAsMenuItem(_hwnd, this, item, tbb.idCommand, acc); 
                    }
                } 
 
                return new ToolbarItem(_hwnd, this, item, tbb.idCommand);
            } 
            return null;
        }

        #endregion 

        // ----------------------------------------------------- 
        // 
        // Private Methods
        // 
        // ------------------------------------------------------

        #region Private Methods
 
        private int Count
        { 
            get 
            {
                return Misc.ProxySendMessageInt(_hwnd, NativeMethods.TB_BUTTONCOUNT, IntPtr.Zero, IntPtr.Zero); 
            }
        }

        #endregion 

    } 
 
    // -----------------------------------------------------
    // 
    // ToolbarItem Classes
    //
    // -----------------------------------------------------
 
    #region ToolbarItem
 
    // Proxy for each button in a toolbar 
    class ToolbarItem : ProxySimple, IInvokeProvider, IToggleProvider
    { 
        // -----------------------------------------------------
        //
        // Constructors
        // 
        // ------------------------------------------------------
 
        #region Constructors 

        internal ToolbarItem(IntPtr hwnd, ProxyFragment parent, int item, int idCommand) 
            : base(hwnd, parent, item)
        {
            _idCommand = idCommand;
 
            NativeMethods.TBBUTTON tbb = new NativeMethods.TBBUTTON();
            int buttonStyle = 0; 
            if (XSendMessage.GetItem(_hwnd, _item, ref tbb)) 
            {
                buttonStyle = tbb.fsStyle; 
            }

            // Set the strings to return properly the properties.
            bool hasImageList = Misc.ProxySendMessageInt(_hwnd, NativeMethods.TB_GETIMAGELIST, IntPtr.Zero, IntPtr.Zero) != 0; 
            int exStyle = Misc.ProxySendMessageInt(_hwnd, NativeMethods.TB_GETEXTENDEDSTYLE, IntPtr.Zero, IntPtr.Zero);
 
            _isToggleButton = false; 
            _cControlType = ControlType.Button;
 
            // If a separator, say so
            if (Misc.IsBitSet(buttonStyle, NativeMethods.BTNS_SEP))
                _cControlType = ControlType.Separator;
            else if (Misc.IsBitSet(buttonStyle, NativeMethods.BTNS_CHECK)) 
            {
                // Special case for task list - they use the checked style, but only for visuals... 
                IntPtr hwndParent = Misc.GetParent(_hwnd); 
                if(Misc.GetClassName(hwndParent) != "MSTaskSwWClass")
                { 
                    _isToggleButton = true;
                }
            }
            else if (Misc.IsBitSet(buttonStyle, NativeMethods.BTNS_DROPDOWN) 
                  && Misc.IsBitSet(exStyle, NativeMethods.TBSTYLE_EX_DRAWDDARROWS))
            { 
                // if its a drop down and it has an arrow its a split button 
                _cControlType = ControlType.SplitButton;
            } 
            else if (!hasImageList || tbb.iBitmap == NativeMethods.I_IMAGENONE)
            {
                // Text-only, no bitmap, so it's effectively a menu item.
                // (eg. as used in MMC) 
                _cControlType = ControlType.MenuItem;
            } 
 
             _fIsContent = _cControlType != ControlType.Separator;
 
            // The Start Menu's "Shut Down" and "Log Off" buttons are toolbar items.  They need to have the
            // KeyboardFocusable property be set to true.
            _fIsKeyboardFocusable = (bool)parent.GetElementProperty(AutomationElement.IsKeyboardFocusableProperty);
 
            GetItemId(ref _sAutomationId);
        } 
 
        #endregion
 
        // -----------------------------------------------------
        //
        // Patterns Implementation
        // 
        // ------------------------------------------------------
 
        #region ProxySimple Interface 

        // Returns a pattern interface if supported. 
        internal override object GetPatternProvider(AutomationPattern iid)
        {
            // Check if button is a separator
            if (_cControlType == ControlType.Separator) 
            {
                return null; 
            } 

            // Check if button is hidden 
            if (Misc.ProxySendMessageInt(_hwnd, NativeMethods.TB_ISBUTTONHIDDEN, new IntPtr(_idCommand), IntPtr.Zero) != 0)
            {
                return null;
            } 

            if (iid == InvokePattern.Pattern && !_isToggleButton) 
            { 
                // button is enabled and not hidden and not a separator
                return this; 
            }
            else if (iid == TogglePattern.Pattern && _isToggleButton)
            {
                return this; 
            }
 
            return null; 
        }
 
        // Gets the bounding rectangle for this element
        internal override Rect BoundingRectangle
        {
            get 
            {
                return GetBoundingRectangle(_hwnd, _item); 
            } 
        }
 
        // Process all the Logical and Raw Element Properties
        internal override object GetElementProperty(AutomationProperty idProp)
        {
            if (idProp == AutomationElement.AccessKeyProperty) 
            {
                return Misc.AccessKey(Text); 
            } 
            else if (idProp == AutomationElement.IsControlElementProperty)
            { 
                return _cControlType != ControlType.Separator;
            }
            else if (idProp == AutomationElement.IsEnabledProperty)
            { 
                return Misc.ProxySendMessageInt(_hwnd, NativeMethods.TB_ISBUTTONENABLED, new IntPtr(_idCommand), IntPtr.Zero) != 0;
            } 
 
            return base.GetElementProperty(idProp);
        } 

        //Gets the controls help text
        internal override string HelpText
        { 
            get
            { 
                return GetItemToolTipText(); 
            }
        } 

        //Gets the localized name
        internal override string LocalizedName
        { 
            get
            { 
                // It does not look like Winforms support the AccessibleName for standard toolbar items. 
                // If ToolStrips are going to be supported by this proxy, will need to added code to check
                // if this is winforms toolbar button and use the AccessibleName if it is set. 

                return Misc.StripMnemonic(Text);
            }
        } 

        // This method will set the hot item since toolbar buttons can't have focus 
        internal override bool SetFocus() 
        {
            // Get current focus... 
            WindowsToolbar toolbar = (WindowsToolbar)_parent;
            ToolbarItem focused = toolbar.GetFocus() as ToolbarItem;

            // ... check for no current focus or currently focused item is not the one we want... 
            if (focused == null || _item != focused._item)
            { 
                //... set the focus 
                /*
                                    // should this go to parent window? 
                                    if ( NativeMethods.DefWindowProc( _hwnd, NativeMethods.WM_SETFOCUS, IntPtr.Zero, IntPtr.Zero ) != IntPtr.Zero )
                                    {
                                        return false;
                                    }; 
                */
                Misc.ProxySendMessage(_hwnd, NativeMethods.TB_SETHOTITEM, new IntPtr(_item), IntPtr.Zero); 
            } 

            return true; 
        }

        #endregion
 
        #region Invoke Pattern
 
        // Press a toolbar button 
        void IInvokeProvider.Invoke()
        { 
            Invoke();
        }

        #endregion 

        #region IToggleProvider 
 
        void IToggleProvider.Toggle()
        { 
            Invoke();
        }

        ToggleState IToggleProvider.ToggleState 
        {
            get 
            { 
                return ToggleState;
            } 
        }

        #endregion IToggleProvider
 
        //------------------------------------------------------
        // 
        //  Internal Methods 
        //
        //----------------------------------------------------- 

        #region Internal Methods

        // Returns the bounding rectangle of the control. 
        internal static Rect GetBoundingRectangle(IntPtr hwnd, int item)
        { 
            return XSendMessage.GetItemRect(hwnd, NativeMethods.TB_GETITEMRECT, item); 
        }
 
        #endregion

        //------------------------------------------------------
        // 
        //  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.ProxySendMessageInt(_hwnd, NativeMethods.TB_GETHOTITEM, IntPtr.Zero, IntPtr.Zero) == _item;
        } 
 
        protected bool IsSeparator()
        { 
            return _cControlType == ControlType.Separator;
        }

        #endregion 

        // ----------------------------------------------------- 
        // 
        // Private methods
        // 
        // -----------------------------------------------------

        #region Private Methods
 
        private string Text
        { 
            get 
            {
                int len = Misc.ProxySendMessageInt(_hwnd, NativeMethods.TB_GETBUTTONTEXT, new IntPtr(_idCommand), IntPtr.Zero); 
                if (len > 0)
                {
                    return XSendMessage.GetItemText(_hwnd, NativeMethods.TB_GETBUTTONTEXT, _idCommand, len);
                } 
                else
                { 
                    // If there is no button text then try getting accName from MSAA.  MSAA has 1 based ChildIDs 
                    // so add 1. As a last resort return the tooltip if there is one (may be long).
                    string name  = GetAccessibleName(_item + 1); 
                    if (!string.IsNullOrEmpty(name))
                    {
                        return name;
                    } 
                    else
                    { 
                        return GetItemToolTipText(); 
                    }
                } 
            }
        }

        private void GetItemId(ref string itemId) 
        {
            NativeMethods.TBBUTTON tbb = new NativeMethods.TBBUTTON(); 
 
            if (XSendMessage.GetItem(_hwnd, _item, ref tbb))
            { 
                if (tbb.idCommand > 0)
                {
                    itemId = "Item " + tbb.idCommand.ToString(CultureInfo.CurrentCulture);
                } 
            }
        } 
 
        private string GetItemToolTipText()
        { 
            IntPtr hwndToolTip = Misc.ProxySendMessage(_hwnd, NativeMethods.TB_GETTOOLTIPS, IntPtr.Zero, IntPtr.Zero);
            return Misc.GetItemToolTipText(_hwnd, hwndToolTip, _idCommand);
        }
 
        private void Invoke()
        { 
            // Make sure that the toolbar is enabled, and that the toolbar button is enabled. 
            if (!SafeNativeMethods.IsWindowEnabled(_hwnd)
                || Misc.ProxySendMessageInt(_hwnd, NativeMethods.TB_ISBUTTONENABLED, new IntPtr(_idCommand), IntPtr.Zero) == 0) 
            {
                throw new ElementNotEnabledException();
            }
 
            // Check that button can be clicked (button not hidden)
            // This state could change anytime so success is not guaranteed 
            if (Misc.ProxySendMessageInt(_hwnd, NativeMethods.TB_ISBUTTONHIDDEN, new IntPtr(_idCommand), IntPtr.Zero) != 0) 
            {
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); 
            }

            // Click the center of the button
            // TB_CHECKBUTTON and TB_PRESSBUTTON messages are not used as they will not trigger proper notifications 
            //
            Rect boundingRectangle = BoundingRectangle; 
 
            if (boundingRectangle.IsEmpty)
            { 
                throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed));
            }

            // make sure this item is active 
            SetFocus();
 
            Misc.MouseClick(((int)boundingRectangle.Left + (int)boundingRectangle.Right) / 2, ((int)boundingRectangle.Top + (int)boundingRectangle.Bottom) / 2); 
        }
 
        private ToggleState ToggleState
        {
            get
            { 
                ToggleState icsState = ToggleState.Indeterminate;
 
                if (Misc.ProxySendMessageInt(_hwnd, NativeMethods.TB_ISBUTTONCHECKED, new IntPtr(_idCommand), IntPtr.Zero) == 0) 
                {
                    icsState = ToggleState.Off; 
                }
                else
                {
                    icsState = ToggleState.On; 
                }
 
                return icsState; 
            }
        } 

        #endregion

        // ------------------------------------------------------ 
        //
        // Protected Fields 
        // 
        // -----------------------------------------------------
 
        #region Protected Fields

        // Command identifier for toolbar buttons
        protected int _idCommand; 
        private bool _isToggleButton;
 
        #endregion 

    } 

    #endregion
}
 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK