Accessible.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / UIAutomation / Win32Providers / MS / Internal / AutomationProxies / Accessible.cs / 1 / Accessible.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: Wraps some of IAccessible to support getting basic properties 
//              and default action
// 
// History:
//  06/02/2003 : BrendanM Ported to WCP
//  03/15/2004 : Micw enhanced to support a native MSAA fallback proxy
// 
//---------------------------------------------------------------------------
 
// PRESHARP: In order to avoid generating warnings about unkown message numbers and unknown pragmas. 
#pragma warning disable 1634, 1691
 
using System;
using System.Diagnostics;
using System.Collections;
using System.Globalization; 
using System.Threading;
using System.Windows.Automation; 
using System.Windows; 
using Accessibility;
using System.Text; 
using System.Runtime.InteropServices;
using MS.Win32;

namespace MS.Internal.AutomationProxies 
{
    // values return from IAccessible.get_accRole. 
    internal enum AccessibleRole: int 
    {
        TitleBar = 0x1, 
        MenuBar = 0x2,
        ScrollBar = 0x3,
        Grip = 0x4,
        Sound = 0x5, 
        Cursor = 0x6,
        Caret = 0x7, 
        Alert = 0x8, 
        Window = 0x9,
        Client = 0xa, 
        MenuPopup = 0xb,
        MenuItem = 0xc,
        Tooltip = 0xd,
        Application = 0xe, 
        Document = 0xf,
        Pane = 0x10, 
        Chart = 0x11, 
        Dialog = 0x12,
        Border = 0x13, 
        Grouping = 0x14,
        Separator = 0x15,
        ToolBar = 0x16,
        StatusBar = 0x17, 
        Table = 0x18,
        ColumnHeader = 0x19, 
        RowHeader = 0x1a, 
        Column = 0x1b,
        Row = 0x1c, 
        Cell = 0x1d,
        Link = 0x1e,
        HelpBalloon = 0x1f,
        Character = 0x20, 
        List = 0x21,
        ListItem = 0x22, 
        Outline = 0x23, 
        OutlineItem = 0x24,
        PageTab = 0x25, 
        PropertyPage = 0x26,
        Indicator = 0x27,
        Graphic = 0x28,
        StaticText = 0x29, 
        Text = 0x2a,
        PushButton = 0x2b, 
        CheckButton = 0x2c, 
        RadioButton = 0x2d,
        Combobox = 0x2e, 
        DropList = 0x2f,
        ProgressBar = 0x30,
        Dial = 0x31,
        HotKeyField = 0x32, 
        Slider = 0x33,
        SpinButton = 0x34, 
        Diagram = 0x35, 
        Animation = 0x36,
        Equation = 0x37, 
        ButtonDropDown = 0x38,
        ButtonMenu = 0x39,
        ButtonDropDownGrid = 0x3a,
        Whitespace = 0x3b, 
        PageTabList = 0x3c,
        Clock = 0x3d, 
        SplitButton = 0x3e, 
        IpAddress = 0x3f,
        OutlineButton = 0x40, 
    }

    // values returned from IAccessible.get_accState.
    [Flags] 
    internal enum AccessibleState: int
    { 
        Normal =            0x00000000, 
        Unavailable =       0x00000001,
        Selected =          0x00000002, 
        Focused =           0x00000004,
        Pressed =           0x00000008,
        Checked =           0x00000010,
        Mixed =             0x00000020, 
        ReadOnly =          0x00000040,
        HotTracked =        0x00000080, 
        Default =           0x00000100, 
        Expanded =          0x00000200,
        Collapsed =         0x00000400, 
        Busy =              0x00000800,
        Floating =          0x00001000,
        Marqueed =          0x00002000,
        Animated =          0x00004000, 
        Invisible =         0x00008000,
        Offscreen =         0x00010000, 
        Sizeable =          0x00020000, 
        Moveable =          0x00040000,
        SelfVoicing =       0x00080000, 
        Focusable =         0x00100000,
        Selectable =        0x00200000,
        Linked =            0x00400000,
        Traversed =         0x00800000, 
        Multiselectable =   0x01000000,
        ExtSelectable =     0x02000000, 
        AlertLow =          0x04000000, 
        AlertMedium =       0x08000000,
        AlertHigh =         0x10000000, 
        Protected =         0x20000000,
    }

    internal class Accessible 
    {
        //----------------------------------------------------- 
        // 
        //  Constructors
        // 
        //-----------------------------------------------------

        #region Constructors
 
        //
 
 

 
        // called by Wrap to create a node Accessible that manages its children
        private Accessible(IAccessible acc, int idChild)
        {
            Debug.Assert(acc != null, "null IAccessible"); 
            _acc = acc;
            _idChild = idChild; 
            _accessibleChildrenIndex = -1; 
        }
 
        // Here we are re-implementing AccessibleObjectFromEvent with a critical difference.
        // AccessibleObjectFromEvent, via AccessibleObjectFromWindow, will default to a standard implementation
        // of IAccessible if the window doesn't have a native implementation.
        // However we only want to succeed constructing the object if the window has a native implementation. 
        internal static Accessible CreateNativeFromEvent(IntPtr hwnd, int idObject, int idChild)
        { 
            // On Vista, pass PID as wParam - allows credUI scenario to work (OLEACC needs to know our PID to 
            // DuplicateHandle back to this process.)
            IntPtr wParam = IntPtr.Zero; 
            if(Environment.OSVersion.Version.Major >= 6)
                wParam = new IntPtr(UnsafeNativeMethods.GetCurrentProcessId());

            // send the window a WM_GETOBJECT message requesting the specific object id. 
            IntPtr lResult = Misc.ProxySendMessage(hwnd, NativeMethods.WM_GETOBJECT, wParam, new IntPtr(idObject));
            if (lResult == IntPtr.Zero) 
            { 
                return null;
            } 

            // unwrap the pointer that was returned
            IAccessible acc = null;
            int hr = NativeMethods.S_FALSE; 

            try 
            { 
                hr = UnsafeNativeMethods.ObjectFromLresult(lResult, ref UnsafeNativeMethods.IID_IAccessible, wParam, ref acc);
            } 
            catch (InvalidCastException)
            {
                // CLR remoting appears to be interfering in cases where the remote IAccessible is a Winforms control -
                // the object we get back is a __Transparent proxy, and casting that to IAccessible fails with an exception 
                // (which is caught and ignored here). See bug #1110719 for details.
                // One way around this is to use AccessibleObjectFromWindow - that returns IAccessible instead of IUnknown - 
                // in effect it does the case in unmanaged code, and seems to avoid this issue. Other winforms code in the 
                // proxies uses this approach. AccessibleObjectFromWindow will return an OLEACC proxy if one is available,
                // however, so we can't use it here, as this code only wants to deal with native IAccessibles. 
                return null;
            }

            // ObjectFromLresult returns an IAccessible from the remote process. If that impl is managed, however, then 
            // the local CLR will set up a CLR-Remoting-based connection instead and bypass COM - this causes problems
            // because CLR Remoting typically isn't initalized, so calls fail with a RemotingException: "This remoting 
            // proxy has no channel sink which means either the server has no registered server channels that are listening, 
            // or this application has no suitable client channel to talk to the server." - see bug #1519030. The local CLR
            // detects that the remote object is a managed impl by QI'ing for a specifc interface (IManagedObject?). 
            // We can prevent this from happening by dropping the IAccessible we've gotten back from ObjectFromLresult,
            // and instead use AccessibleObjectFromWindow: AOFW wraps the real IAccessible in a DynamicAnnotation wrapper
            // that passes through all IAccessible (and related interface) calls - but it doesn't pass through the
            // IManagedObject interface, so the CLR treats it as a COM object, and continues to use plain COM to access it, 
            // avoiding the CLR Remoting issues.
            // 
            // In effect, we're sending WM_GETOBJECT to the HWND to see if there's a native impl there, using ObjectFromLresult 
            // just to free that object, and then using AccessibleObjectFromWindow on the window to get the IAccessible
            // that we actually use. (Can't just use AccessibleObjectFromWindow from the start, since that would return 
            // an oleacc proxy for hwnds that don't support IAccessible natively, and we only care about actual IAccessible
            // impls here.)
            //
            // We used to do use AOFW below only if the acc we got back above was a managed object (checked using 
            // !Marshal.IsComObject()) - that only protects us from managed IAccessibles we get back directly; we could
            // still hit the above issue if we get back a remote unmanaged impl that then returns a maanged impl via 
            // navigation (Media Center does this). So we now use AOFW all the time. 
            if(hr == NativeMethods.S_OK && acc != null)
            { 
                object obj = null;
                hr = UnsafeNativeMethods.AccessibleObjectFromWindow(hwnd, idObject, ref UnsafeNativeMethods.IID_IUnknown, ref obj);
                acc = obj as IAccessible;
            } 

            if (hr != NativeMethods.S_OK || acc == null) 
            { 
                return null;
            } 

            // This takes care of calling get_accChild, if necessary...
            return AccessibleFromObject(idChild, acc);
        } 

#if DEBUG 
        /* 
        // strictly for debugging purposes:
        public override string ToString() 
        {
            try
            {
                return string.Format( "{0} \"{1}\" {2} {3}", RoleText, Name, _idChild, Window ); 
            }
            catch (Exception e) 
            { 
                return e.Message;
            } 
        }

        [DllImport( "oleacc.dll" )]
        internal static extern int GetRoleText( int dwRole, StringBuilder lpszRole, int cchRoleMax ); 

        private string RoleText 
        { 
            get
            { 
                const int cch = 64;
                StringBuilder sb = new StringBuilder( cch );
                int len = GetRoleText( (int)Role, sb, cch );
                return sb.ToString().Substring( 0, len ); 
            }
        } 
        */ 
#endif
 
        #endregion Constructors


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

        // returns a new Accessible for the IAccessible, or null if IAccessible is null
        internal static Accessible Wrap(IAccessible acc) 
        {
            return Wrap(acc, NativeMethods.CHILD_SELF); 
        } 

        // returns a new Accessible for the IAccessible + child id, or null if IAccessible is null 
        internal static Accessible Wrap(IAccessible acc, int idChild)
        {
            return acc != null ? new Accessible(acc, idChild) : null;
        } 

        internal IAccessible IAccessible   { get { return _acc; } } 
        internal int    ChildCount         { get { return GetChildCount(_acc); } } 
        internal int    ChildId            { get { return _idChild; } }
        internal string Description        { get { return GetDescription(_acc, _idChild); } } 
        internal string KeyboardShortcut   { get { return GetKeyboardShortcut(_acc, _idChild); } }
        internal string Name               { get { return GetName(_acc, _idChild); } }
        internal string DefaultAction      { get { return GetDefaultAction(_acc, _idChild); } }
        internal AccessibleRole Role { get { return GetRole(_acc, _idChild); } } 
        internal bool   IsPassword         { get { return HasState(AccessibleState.Protected); } }
        internal bool   IsSelected         { get { return HasState(AccessibleState.Selected); } } 
        internal bool   IsMultiSelectable  { get { return HasState(AccessibleState.Multiselectable); } } 
        internal bool   IsIndeterminate    { get { return HasState(AccessibleState.Mixed); } }
        internal bool   IsChecked          { get { return HasState(AccessibleState.Checked); } } 
        internal bool   IsReadOnly         { get { return HasState(AccessibleState.ReadOnly); } }
        internal bool   IsEnabled          { get { return ! HasState(AccessibleState.Unavailable); } }
        internal bool   IsFocused          { get { return HasState(AccessibleState.Focused); } }
        internal bool   IsOffScreen        { get { return HasState(AccessibleState.Offscreen); } } 

        internal Accessible FirstChild 
        { 
            get
            { 
                return _idChild == NativeMethods.CHILD_SELF ? GetChildAt(_acc, null, 0) : null;
            }
        }
 
        internal Accessible LastChild
        { 
            get 
            {
                return _idChild == NativeMethods.CHILD_SELF ? GetChildAt(_acc, null, Accessible.GetChildCount(_acc) - 1) : null; 
            }
        }

        internal Accessible NextSibling(Accessible parent) 
        {
            Debug.Assert(parent != null); 
 
            // if this object doesn't yet have an index into parent's children find it
            object[] children = null; // if we need to get children to find an index; re-use them 
            if (_accessibleChildrenIndex == -1)
            {
                children = SetAccessibleChildrenIndexAndGetChildren(parent._acc);
 
                // if unable to find this child (broken IAccessible impl?) bail (
                if (_accessibleChildrenIndex == -1) 
                { 
                    Debug.Assert(false);
                    return null; 
                }
            }

            Accessible rval = null; 
            if (_accessibleChildrenIndex + 1 < Accessible.GetChildCount(parent._acc))
            { 
                rval = GetChildAt(parent._acc, children, _accessibleChildrenIndex + 1); 
            }
 
            return rval;
        }

        internal Accessible PreviousSibling(Accessible parent) 
        {
            Debug.Assert(parent != null); 
 
            // if this object doesn't yet have an index into parent's children find it
            object[] children = null; // if we need to get children to find an index; re-use them 
            if (_accessibleChildrenIndex == -1)
            {
                children = SetAccessibleChildrenIndexAndGetChildren(parent._acc);
 
                // if unable to find this child (broken IAccessible impl?) bail (
                if (_accessibleChildrenIndex == -1) 
                { 
                    Debug.Assert(false);
                    return null; 
                }
            }

            Accessible rval = null; 
            if (_accessibleChildrenIndex - 1 >= 0)
            { 
                rval = GetChildAt(parent._acc, children, _accessibleChildrenIndex - 1); 
            }
 
            return rval;
        }

        internal Accessible Parent 
        {
            get 
            { 
                //
 


                // review: I think it might be better to throw an exception here than return a bogus value.
 
                IAccessible rval;
                if (_idChild != NativeMethods.CHILD_SELF) 
                { 
                    rval = _acc; // parent is managing this child
                } 
                else
                {
                    try
                    { 
                        rval = (IAccessible)_acc.accParent;
                    } 
                    catch (Exception e) 
                    {
                        if (HandleIAccessibleException(e)) 
                        {
                            // PerSharp/PreFast will flag this as a warning, 6503/56503: Property get methods should not throw exceptions.
                            // We are communicate with the underlying control to get the information.
                            // The control may not be able to give us the information we need. 
                            // Throw the correct exception to communicate the failure.
#pragma warning suppress 6503 
                            throw; 
                        }
                        return null; 
                    }
                }
                return Wrap(rval);
            } 
        }
 
        internal int AccessibleChildrenIndex(Accessible parent) 
        {
            // if this is the first time we are called then compute the value and cache it. 
            if (_accessibleChildrenIndex < 0)
            {
                SetAccessibleChildrenIndexAndGetChildren(parent._acc);
            } 
            return _accessibleChildrenIndex;
        } 
 
        internal bool IsAvailableToUser
        { 
            get
            {
                AccessibleState state = State;
 
                // From MSDN:
                // STATE_SYSTEM_INVISIBLE means the object is programmatically hidden. For example, menu items 
                // are programmatically hidden until a user activates the menu. Because objects with this 
                // state are not available to users, client applications should not communicate information
                // about the object to users. However, if client applications find an object with this state, 
                // they should check to see if STATE_SYSTEM_OFFSCREEN is also set. If this second state is
                // defined, then clients can communicate the information about the object to users.
                //
                // We're not dealing with menus [in this version of NativeMsaaProxy] so won't worry about them 
                // here.  To "clean up" the tree we'll skip over IAccessibles that have the above states.
                // May revisit per user feedback. 
                if (Accessible.HasState(state, AccessibleState.Invisible) && !Accessible.HasState(state, AccessibleState.Offscreen)) 
                    return false;
 
                return true;
            }
        }
 
        internal bool InSameHwnd(IntPtr hwnd)
        { 
            bool inSameHwnd = Window != IntPtr.Zero && Window == hwnd; 
            return inSameHwnd;
        } 

        // returns true if accessible object should be exposed to UIA clients.
        // accessible objects are exposed UIA if they are visible, not offscreen, and do not correspond to a child window.
        internal bool IsExposedToUIA 
        {
            get 
            { 
                bool rval = false;
                // if the accessible object is "available"... 
                if (IsAvailableToUser)
                {
                    // ... and is not a child window...
                    // 

 
 

 
                    AccessibleRole role = Role;
                    if (role != AccessibleRole.Window)
                    {
                        // ... and is not a child window that is trident ... 
                        // (special case since trident doesn't have a ROLE_SYSTEM_WINDOW object for its "Internet Explorer_Server" window.
                        if (role != AccessibleRole.Client || Description != "MSAAHTML Registered Handler") 
                        { 
                            // then it is visible
                            rval = true; 
                        }
                    }
                }
                return rval; 
            }
        } 
 
        internal AccessibleState State
        { 
            get
            {
                try
                { 
                    return (AccessibleState)_acc.get_accState(_idChild);
                } 
                catch (Exception e) 
                {
                    if (HandleIAccessibleException(e)) 
                    {
                        // PerSharp/PreFast will flag this as a warning, 6503/56503: Property get methods should not throw exceptions.
                        // We are communicate with the underlying control to get the information.
                        // The control may not be able to give us the information we need. 
                        // Throw the correct exception to communicate the failure.
#pragma warning suppress 6503 
                        throw; 
                    }
                    return AccessibleState.Unavailable; 
                }
            }
        }
 
        internal string Value
        { 
            get 
            {
                try 
                {
                    string value = FixBstr(_acc.get_accValue(_idChild));
                    // PerSharp/PreFast will flag this as warning 6507/56507: Prefer 'string.IsNullOrEmpty(value)' over checks for null and/or emptiness.
                    // Need to convert nulls into an empty string, so need to just test for a null. 
                    // Therefore we can not use IsNullOrEmpty() here, suppress the warning.
#pragma warning suppress 6507 
                    return value != null ? value : ""; 
                }
                catch (Exception e) 
                {
                    if (HandleIAccessibleException(e))
                    {
                        // PerSharp/PreFast will flag this as a warning, 6503/56503: Property get methods should not throw exceptions. 
                        // We are communicate with the underlying control to get the information.
                        // The control may not be able to give us the information we need. 
                        // Throw the correct exception to communicate the failure. 
#pragma warning suppress 6503
                        throw; 
                    }
                    return "";
                }
            } 
            set
            { 
                try 
                {
                    _acc.set_accValue(_idChild, value); 
                }
                catch (Exception e)
                {
                    if (HandleIAccessibleException(e)) 
                    {
                        throw; 
                    } 

                    // 
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed), e);
                }
            }
        } 

        // Return the Rect that bounds this element in screen coordinates 
        internal Rect Location 
        {
            get 
            {
                NativeMethods.Win32Rect rcW32 = GetLocation(_acc, _idChild);
                return rcW32.ToRect(false);
            } 
        }
 
        internal static Accessible GetFullAccessibleChildByIndex(Accessible accParent, int index) 
        {
            int childCount = 0; 
            object[] accChildren = Accessible.GetAccessibleChildren(accParent.IAccessible, out childCount);

            if (accChildren != null && 0 <= index && index < accChildren.Length)
            { 
                object child = accChildren[index];
                IAccessible accChild = child as IAccessible; 
                if (accChild != null) 
                {
                    return Accessible.Wrap(accChild); 
                }
                else if (child is int)
                {
                    int idChild = (int)child; 
                    return Accessible.Wrap(accParent.IAccessible, idChild);
                } 
            } 

            return null; 
        }

        internal static AccessibleRole GetRole(IAccessible acc, int idChild)
        { 
            AccessibleRole rval;
            try 
            { 
                object role = acc.get_accRole(idChild);
 
                // get_accRole can return a non-int! for example, Outlook 2003 SUPERGRID entries
                // can return the string "Table View". so we return an int if we got one otherwise
                // we convert it to the generic "client" role.
                rval = (role is int) ? (AccessibleRole)(int)role : AccessibleRole.Client; 
            }
            catch (Exception e) 
            { 
                if (HandleIAccessibleException(e))
                { 
                    throw;
                }
                rval = AccessibleRole.Client;
            } 
            return rval;
        } 
 
        // Get the selected children in a container
        internal Accessible [] GetSelection() 
        {
            //
            object obj = null;
            try 
            {
                obj = _acc.accSelection; 
            } 
            catch (Exception e)
            { 
                if (HandleIAccessibleException(e))
                {
                    throw;
                } 
                obj = null;
            } 
 
            if (obj == null)
            { 
                return null;
            }

            Accessible [] children = null; 
            if (obj is int)
            { 
                children = new Accessible[1]; 
                children[0] = AccessibleFromObject(obj, _acc);
            } 
            else if (obj is object)
            {
                children = new Accessible[1];
                children[0] = AccessibleFromObject(obj, _acc); 
            }
            else if (obj is object []) 
            { 
                object [] objs = (object [])obj;
                children = new Accessible[objs.Length]; 
                for (int i=0;i 0) 
                { 
                    aChildren = new object[childCount];
 
                    // Get the raw children because accNavigate doesn't work
                    if (UnsafeNativeMethods.AccessibleChildren(accessibleObject, 0, childCount, aChildren, out childrenReturned) == NativeMethods.E_INVALIDARG)
                    {
                        System.Diagnostics.Debug.Assert(false, "Call to AccessibleChildren() returned E_INVALIDARG."); 
                        throw new ElementNotAvailableException();
                    } 
                } 

                return aChildren; 
            }
            catch (Exception e)
            {
                if (HandleIAccessibleException(e)) 
                {
                    throw; 
                } 
                throw new ElementNotAvailableException();
            } 
        }

        #endregion
 
        #endregion Internal Methods
 
 
        //------------------------------------------------------
        // 
        //  Private Methods
        //
        //------------------------------------------------------
 
        #region Private Methods
 
        // Returns a child by index 
        private static Accessible GetChildAt(IAccessible parent, object [] children, int index)
        { 
            // note: calling AccessibleChildren on Trident and asking for a single child can
            // result in a Fatal Execution Engine Error (79697ADA)(80121506).
            // Perhaps the implementation ignores the cChildren param?
            // To avoid the problem we always ask for all of the children and just 
            // use the specific one we are interested in.
 
            if (children == null) 
            {
                children = GetChildren(parent); 
            }
            if (children == null)
            {
                return null; 
            }
 
            // Paranoia that between calls accChildCount returns different counts 
            if (index >= children.Length)
                index = children.Length - 1; 

            Accessible nav = AccessibleFromObject(children[index], parent);
            if (nav != null)
            { 
                nav._accessibleChildrenIndex = index;
            } 
 
            return nav;
        } 

        // Find _acc's index among its siblings with optimization to return children collection
        // if that would be needed later by the caller
        private object [] SetAccessibleChildrenIndexAndGetChildren(IAccessible parent) 
        {
            // this is only called if the index hasn't been set yet. 
            Debug.Assert(_accessibleChildrenIndex < 0); 

            object [] children = GetChildren(parent); 
            if (children == null)
            {
                return null;   // unlikely to happen but...
            } 

            // Try to figure out which child in this array '_acc' is 
 
            for (int i=0;i
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: Wraps some of IAccessible to support getting basic properties 
//              and default action
// 
// History:
//  06/02/2003 : BrendanM Ported to WCP
//  03/15/2004 : Micw enhanced to support a native MSAA fallback proxy
// 
//---------------------------------------------------------------------------
 
// PRESHARP: In order to avoid generating warnings about unkown message numbers and unknown pragmas. 
#pragma warning disable 1634, 1691
 
using System;
using System.Diagnostics;
using System.Collections;
using System.Globalization; 
using System.Threading;
using System.Windows.Automation; 
using System.Windows; 
using Accessibility;
using System.Text; 
using System.Runtime.InteropServices;
using MS.Win32;

namespace MS.Internal.AutomationProxies 
{
    // values return from IAccessible.get_accRole. 
    internal enum AccessibleRole: int 
    {
        TitleBar = 0x1, 
        MenuBar = 0x2,
        ScrollBar = 0x3,
        Grip = 0x4,
        Sound = 0x5, 
        Cursor = 0x6,
        Caret = 0x7, 
        Alert = 0x8, 
        Window = 0x9,
        Client = 0xa, 
        MenuPopup = 0xb,
        MenuItem = 0xc,
        Tooltip = 0xd,
        Application = 0xe, 
        Document = 0xf,
        Pane = 0x10, 
        Chart = 0x11, 
        Dialog = 0x12,
        Border = 0x13, 
        Grouping = 0x14,
        Separator = 0x15,
        ToolBar = 0x16,
        StatusBar = 0x17, 
        Table = 0x18,
        ColumnHeader = 0x19, 
        RowHeader = 0x1a, 
        Column = 0x1b,
        Row = 0x1c, 
        Cell = 0x1d,
        Link = 0x1e,
        HelpBalloon = 0x1f,
        Character = 0x20, 
        List = 0x21,
        ListItem = 0x22, 
        Outline = 0x23, 
        OutlineItem = 0x24,
        PageTab = 0x25, 
        PropertyPage = 0x26,
        Indicator = 0x27,
        Graphic = 0x28,
        StaticText = 0x29, 
        Text = 0x2a,
        PushButton = 0x2b, 
        CheckButton = 0x2c, 
        RadioButton = 0x2d,
        Combobox = 0x2e, 
        DropList = 0x2f,
        ProgressBar = 0x30,
        Dial = 0x31,
        HotKeyField = 0x32, 
        Slider = 0x33,
        SpinButton = 0x34, 
        Diagram = 0x35, 
        Animation = 0x36,
        Equation = 0x37, 
        ButtonDropDown = 0x38,
        ButtonMenu = 0x39,
        ButtonDropDownGrid = 0x3a,
        Whitespace = 0x3b, 
        PageTabList = 0x3c,
        Clock = 0x3d, 
        SplitButton = 0x3e, 
        IpAddress = 0x3f,
        OutlineButton = 0x40, 
    }

    // values returned from IAccessible.get_accState.
    [Flags] 
    internal enum AccessibleState: int
    { 
        Normal =            0x00000000, 
        Unavailable =       0x00000001,
        Selected =          0x00000002, 
        Focused =           0x00000004,
        Pressed =           0x00000008,
        Checked =           0x00000010,
        Mixed =             0x00000020, 
        ReadOnly =          0x00000040,
        HotTracked =        0x00000080, 
        Default =           0x00000100, 
        Expanded =          0x00000200,
        Collapsed =         0x00000400, 
        Busy =              0x00000800,
        Floating =          0x00001000,
        Marqueed =          0x00002000,
        Animated =          0x00004000, 
        Invisible =         0x00008000,
        Offscreen =         0x00010000, 
        Sizeable =          0x00020000, 
        Moveable =          0x00040000,
        SelfVoicing =       0x00080000, 
        Focusable =         0x00100000,
        Selectable =        0x00200000,
        Linked =            0x00400000,
        Traversed =         0x00800000, 
        Multiselectable =   0x01000000,
        ExtSelectable =     0x02000000, 
        AlertLow =          0x04000000, 
        AlertMedium =       0x08000000,
        AlertHigh =         0x10000000, 
        Protected =         0x20000000,
    }

    internal class Accessible 
    {
        //----------------------------------------------------- 
        // 
        //  Constructors
        // 
        //-----------------------------------------------------

        #region Constructors
 
        //
 
 

 
        // called by Wrap to create a node Accessible that manages its children
        private Accessible(IAccessible acc, int idChild)
        {
            Debug.Assert(acc != null, "null IAccessible"); 
            _acc = acc;
            _idChild = idChild; 
            _accessibleChildrenIndex = -1; 
        }
 
        // Here we are re-implementing AccessibleObjectFromEvent with a critical difference.
        // AccessibleObjectFromEvent, via AccessibleObjectFromWindow, will default to a standard implementation
        // of IAccessible if the window doesn't have a native implementation.
        // However we only want to succeed constructing the object if the window has a native implementation. 
        internal static Accessible CreateNativeFromEvent(IntPtr hwnd, int idObject, int idChild)
        { 
            // On Vista, pass PID as wParam - allows credUI scenario to work (OLEACC needs to know our PID to 
            // DuplicateHandle back to this process.)
            IntPtr wParam = IntPtr.Zero; 
            if(Environment.OSVersion.Version.Major >= 6)
                wParam = new IntPtr(UnsafeNativeMethods.GetCurrentProcessId());

            // send the window a WM_GETOBJECT message requesting the specific object id. 
            IntPtr lResult = Misc.ProxySendMessage(hwnd, NativeMethods.WM_GETOBJECT, wParam, new IntPtr(idObject));
            if (lResult == IntPtr.Zero) 
            { 
                return null;
            } 

            // unwrap the pointer that was returned
            IAccessible acc = null;
            int hr = NativeMethods.S_FALSE; 

            try 
            { 
                hr = UnsafeNativeMethods.ObjectFromLresult(lResult, ref UnsafeNativeMethods.IID_IAccessible, wParam, ref acc);
            } 
            catch (InvalidCastException)
            {
                // CLR remoting appears to be interfering in cases where the remote IAccessible is a Winforms control -
                // the object we get back is a __Transparent proxy, and casting that to IAccessible fails with an exception 
                // (which is caught and ignored here). See bug #1110719 for details.
                // One way around this is to use AccessibleObjectFromWindow - that returns IAccessible instead of IUnknown - 
                // in effect it does the case in unmanaged code, and seems to avoid this issue. Other winforms code in the 
                // proxies uses this approach. AccessibleObjectFromWindow will return an OLEACC proxy if one is available,
                // however, so we can't use it here, as this code only wants to deal with native IAccessibles. 
                return null;
            }

            // ObjectFromLresult returns an IAccessible from the remote process. If that impl is managed, however, then 
            // the local CLR will set up a CLR-Remoting-based connection instead and bypass COM - this causes problems
            // because CLR Remoting typically isn't initalized, so calls fail with a RemotingException: "This remoting 
            // proxy has no channel sink which means either the server has no registered server channels that are listening, 
            // or this application has no suitable client channel to talk to the server." - see bug #1519030. The local CLR
            // detects that the remote object is a managed impl by QI'ing for a specifc interface (IManagedObject?). 
            // We can prevent this from happening by dropping the IAccessible we've gotten back from ObjectFromLresult,
            // and instead use AccessibleObjectFromWindow: AOFW wraps the real IAccessible in a DynamicAnnotation wrapper
            // that passes through all IAccessible (and related interface) calls - but it doesn't pass through the
            // IManagedObject interface, so the CLR treats it as a COM object, and continues to use plain COM to access it, 
            // avoiding the CLR Remoting issues.
            // 
            // In effect, we're sending WM_GETOBJECT to the HWND to see if there's a native impl there, using ObjectFromLresult 
            // just to free that object, and then using AccessibleObjectFromWindow on the window to get the IAccessible
            // that we actually use. (Can't just use AccessibleObjectFromWindow from the start, since that would return 
            // an oleacc proxy for hwnds that don't support IAccessible natively, and we only care about actual IAccessible
            // impls here.)
            //
            // We used to do use AOFW below only if the acc we got back above was a managed object (checked using 
            // !Marshal.IsComObject()) - that only protects us from managed IAccessibles we get back directly; we could
            // still hit the above issue if we get back a remote unmanaged impl that then returns a maanged impl via 
            // navigation (Media Center does this). So we now use AOFW all the time. 
            if(hr == NativeMethods.S_OK && acc != null)
            { 
                object obj = null;
                hr = UnsafeNativeMethods.AccessibleObjectFromWindow(hwnd, idObject, ref UnsafeNativeMethods.IID_IUnknown, ref obj);
                acc = obj as IAccessible;
            } 

            if (hr != NativeMethods.S_OK || acc == null) 
            { 
                return null;
            } 

            // This takes care of calling get_accChild, if necessary...
            return AccessibleFromObject(idChild, acc);
        } 

#if DEBUG 
        /* 
        // strictly for debugging purposes:
        public override string ToString() 
        {
            try
            {
                return string.Format( "{0} \"{1}\" {2} {3}", RoleText, Name, _idChild, Window ); 
            }
            catch (Exception e) 
            { 
                return e.Message;
            } 
        }

        [DllImport( "oleacc.dll" )]
        internal static extern int GetRoleText( int dwRole, StringBuilder lpszRole, int cchRoleMax ); 

        private string RoleText 
        { 
            get
            { 
                const int cch = 64;
                StringBuilder sb = new StringBuilder( cch );
                int len = GetRoleText( (int)Role, sb, cch );
                return sb.ToString().Substring( 0, len ); 
            }
        } 
        */ 
#endif
 
        #endregion Constructors


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

        // returns a new Accessible for the IAccessible, or null if IAccessible is null
        internal static Accessible Wrap(IAccessible acc) 
        {
            return Wrap(acc, NativeMethods.CHILD_SELF); 
        } 

        // returns a new Accessible for the IAccessible + child id, or null if IAccessible is null 
        internal static Accessible Wrap(IAccessible acc, int idChild)
        {
            return acc != null ? new Accessible(acc, idChild) : null;
        } 

        internal IAccessible IAccessible   { get { return _acc; } } 
        internal int    ChildCount         { get { return GetChildCount(_acc); } } 
        internal int    ChildId            { get { return _idChild; } }
        internal string Description        { get { return GetDescription(_acc, _idChild); } } 
        internal string KeyboardShortcut   { get { return GetKeyboardShortcut(_acc, _idChild); } }
        internal string Name               { get { return GetName(_acc, _idChild); } }
        internal string DefaultAction      { get { return GetDefaultAction(_acc, _idChild); } }
        internal AccessibleRole Role { get { return GetRole(_acc, _idChild); } } 
        internal bool   IsPassword         { get { return HasState(AccessibleState.Protected); } }
        internal bool   IsSelected         { get { return HasState(AccessibleState.Selected); } } 
        internal bool   IsMultiSelectable  { get { return HasState(AccessibleState.Multiselectable); } } 
        internal bool   IsIndeterminate    { get { return HasState(AccessibleState.Mixed); } }
        internal bool   IsChecked          { get { return HasState(AccessibleState.Checked); } } 
        internal bool   IsReadOnly         { get { return HasState(AccessibleState.ReadOnly); } }
        internal bool   IsEnabled          { get { return ! HasState(AccessibleState.Unavailable); } }
        internal bool   IsFocused          { get { return HasState(AccessibleState.Focused); } }
        internal bool   IsOffScreen        { get { return HasState(AccessibleState.Offscreen); } } 

        internal Accessible FirstChild 
        { 
            get
            { 
                return _idChild == NativeMethods.CHILD_SELF ? GetChildAt(_acc, null, 0) : null;
            }
        }
 
        internal Accessible LastChild
        { 
            get 
            {
                return _idChild == NativeMethods.CHILD_SELF ? GetChildAt(_acc, null, Accessible.GetChildCount(_acc) - 1) : null; 
            }
        }

        internal Accessible NextSibling(Accessible parent) 
        {
            Debug.Assert(parent != null); 
 
            // if this object doesn't yet have an index into parent's children find it
            object[] children = null; // if we need to get children to find an index; re-use them 
            if (_accessibleChildrenIndex == -1)
            {
                children = SetAccessibleChildrenIndexAndGetChildren(parent._acc);
 
                // if unable to find this child (broken IAccessible impl?) bail (
                if (_accessibleChildrenIndex == -1) 
                { 
                    Debug.Assert(false);
                    return null; 
                }
            }

            Accessible rval = null; 
            if (_accessibleChildrenIndex + 1 < Accessible.GetChildCount(parent._acc))
            { 
                rval = GetChildAt(parent._acc, children, _accessibleChildrenIndex + 1); 
            }
 
            return rval;
        }

        internal Accessible PreviousSibling(Accessible parent) 
        {
            Debug.Assert(parent != null); 
 
            // if this object doesn't yet have an index into parent's children find it
            object[] children = null; // if we need to get children to find an index; re-use them 
            if (_accessibleChildrenIndex == -1)
            {
                children = SetAccessibleChildrenIndexAndGetChildren(parent._acc);
 
                // if unable to find this child (broken IAccessible impl?) bail (
                if (_accessibleChildrenIndex == -1) 
                { 
                    Debug.Assert(false);
                    return null; 
                }
            }

            Accessible rval = null; 
            if (_accessibleChildrenIndex - 1 >= 0)
            { 
                rval = GetChildAt(parent._acc, children, _accessibleChildrenIndex - 1); 
            }
 
            return rval;
        }

        internal Accessible Parent 
        {
            get 
            { 
                //
 


                // review: I think it might be better to throw an exception here than return a bogus value.
 
                IAccessible rval;
                if (_idChild != NativeMethods.CHILD_SELF) 
                { 
                    rval = _acc; // parent is managing this child
                } 
                else
                {
                    try
                    { 
                        rval = (IAccessible)_acc.accParent;
                    } 
                    catch (Exception e) 
                    {
                        if (HandleIAccessibleException(e)) 
                        {
                            // PerSharp/PreFast will flag this as a warning, 6503/56503: Property get methods should not throw exceptions.
                            // We are communicate with the underlying control to get the information.
                            // The control may not be able to give us the information we need. 
                            // Throw the correct exception to communicate the failure.
#pragma warning suppress 6503 
                            throw; 
                        }
                        return null; 
                    }
                }
                return Wrap(rval);
            } 
        }
 
        internal int AccessibleChildrenIndex(Accessible parent) 
        {
            // if this is the first time we are called then compute the value and cache it. 
            if (_accessibleChildrenIndex < 0)
            {
                SetAccessibleChildrenIndexAndGetChildren(parent._acc);
            } 
            return _accessibleChildrenIndex;
        } 
 
        internal bool IsAvailableToUser
        { 
            get
            {
                AccessibleState state = State;
 
                // From MSDN:
                // STATE_SYSTEM_INVISIBLE means the object is programmatically hidden. For example, menu items 
                // are programmatically hidden until a user activates the menu. Because objects with this 
                // state are not available to users, client applications should not communicate information
                // about the object to users. However, if client applications find an object with this state, 
                // they should check to see if STATE_SYSTEM_OFFSCREEN is also set. If this second state is
                // defined, then clients can communicate the information about the object to users.
                //
                // We're not dealing with menus [in this version of NativeMsaaProxy] so won't worry about them 
                // here.  To "clean up" the tree we'll skip over IAccessibles that have the above states.
                // May revisit per user feedback. 
                if (Accessible.HasState(state, AccessibleState.Invisible) && !Accessible.HasState(state, AccessibleState.Offscreen)) 
                    return false;
 
                return true;
            }
        }
 
        internal bool InSameHwnd(IntPtr hwnd)
        { 
            bool inSameHwnd = Window != IntPtr.Zero && Window == hwnd; 
            return inSameHwnd;
        } 

        // returns true if accessible object should be exposed to UIA clients.
        // accessible objects are exposed UIA if they are visible, not offscreen, and do not correspond to a child window.
        internal bool IsExposedToUIA 
        {
            get 
            { 
                bool rval = false;
                // if the accessible object is "available"... 
                if (IsAvailableToUser)
                {
                    // ... and is not a child window...
                    // 

 
 

 
                    AccessibleRole role = Role;
                    if (role != AccessibleRole.Window)
                    {
                        // ... and is not a child window that is trident ... 
                        // (special case since trident doesn't have a ROLE_SYSTEM_WINDOW object for its "Internet Explorer_Server" window.
                        if (role != AccessibleRole.Client || Description != "MSAAHTML Registered Handler") 
                        { 
                            // then it is visible
                            rval = true; 
                        }
                    }
                }
                return rval; 
            }
        } 
 
        internal AccessibleState State
        { 
            get
            {
                try
                { 
                    return (AccessibleState)_acc.get_accState(_idChild);
                } 
                catch (Exception e) 
                {
                    if (HandleIAccessibleException(e)) 
                    {
                        // PerSharp/PreFast will flag this as a warning, 6503/56503: Property get methods should not throw exceptions.
                        // We are communicate with the underlying control to get the information.
                        // The control may not be able to give us the information we need. 
                        // Throw the correct exception to communicate the failure.
#pragma warning suppress 6503 
                        throw; 
                    }
                    return AccessibleState.Unavailable; 
                }
            }
        }
 
        internal string Value
        { 
            get 
            {
                try 
                {
                    string value = FixBstr(_acc.get_accValue(_idChild));
                    // PerSharp/PreFast will flag this as warning 6507/56507: Prefer 'string.IsNullOrEmpty(value)' over checks for null and/or emptiness.
                    // Need to convert nulls into an empty string, so need to just test for a null. 
                    // Therefore we can not use IsNullOrEmpty() here, suppress the warning.
#pragma warning suppress 6507 
                    return value != null ? value : ""; 
                }
                catch (Exception e) 
                {
                    if (HandleIAccessibleException(e))
                    {
                        // PerSharp/PreFast will flag this as a warning, 6503/56503: Property get methods should not throw exceptions. 
                        // We are communicate with the underlying control to get the information.
                        // The control may not be able to give us the information we need. 
                        // Throw the correct exception to communicate the failure. 
#pragma warning suppress 6503
                        throw; 
                    }
                    return "";
                }
            } 
            set
            { 
                try 
                {
                    _acc.set_accValue(_idChild, value); 
                }
                catch (Exception e)
                {
                    if (HandleIAccessibleException(e)) 
                    {
                        throw; 
                    } 

                    // 
                    throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed), e);
                }
            }
        } 

        // Return the Rect that bounds this element in screen coordinates 
        internal Rect Location 
        {
            get 
            {
                NativeMethods.Win32Rect rcW32 = GetLocation(_acc, _idChild);
                return rcW32.ToRect(false);
            } 
        }
 
        internal static Accessible GetFullAccessibleChildByIndex(Accessible accParent, int index) 
        {
            int childCount = 0; 
            object[] accChildren = Accessible.GetAccessibleChildren(accParent.IAccessible, out childCount);

            if (accChildren != null && 0 <= index && index < accChildren.Length)
            { 
                object child = accChildren[index];
                IAccessible accChild = child as IAccessible; 
                if (accChild != null) 
                {
                    return Accessible.Wrap(accChild); 
                }
                else if (child is int)
                {
                    int idChild = (int)child; 
                    return Accessible.Wrap(accParent.IAccessible, idChild);
                } 
            } 

            return null; 
        }

        internal static AccessibleRole GetRole(IAccessible acc, int idChild)
        { 
            AccessibleRole rval;
            try 
            { 
                object role = acc.get_accRole(idChild);
 
                // get_accRole can return a non-int! for example, Outlook 2003 SUPERGRID entries
                // can return the string "Table View". so we return an int if we got one otherwise
                // we convert it to the generic "client" role.
                rval = (role is int) ? (AccessibleRole)(int)role : AccessibleRole.Client; 
            }
            catch (Exception e) 
            { 
                if (HandleIAccessibleException(e))
                { 
                    throw;
                }
                rval = AccessibleRole.Client;
            } 
            return rval;
        } 
 
        // Get the selected children in a container
        internal Accessible [] GetSelection() 
        {
            //
            object obj = null;
            try 
            {
                obj = _acc.accSelection; 
            } 
            catch (Exception e)
            { 
                if (HandleIAccessibleException(e))
                {
                    throw;
                } 
                obj = null;
            } 
 
            if (obj == null)
            { 
                return null;
            }

            Accessible [] children = null; 
            if (obj is int)
            { 
                children = new Accessible[1]; 
                children[0] = AccessibleFromObject(obj, _acc);
            } 
            else if (obj is object)
            {
                children = new Accessible[1];
                children[0] = AccessibleFromObject(obj, _acc); 
            }
            else if (obj is object []) 
            { 
                object [] objs = (object [])obj;
                children = new Accessible[objs.Length]; 
                for (int i=0;i 0) 
                { 
                    aChildren = new object[childCount];
 
                    // Get the raw children because accNavigate doesn't work
                    if (UnsafeNativeMethods.AccessibleChildren(accessibleObject, 0, childCount, aChildren, out childrenReturned) == NativeMethods.E_INVALIDARG)
                    {
                        System.Diagnostics.Debug.Assert(false, "Call to AccessibleChildren() returned E_INVALIDARG."); 
                        throw new ElementNotAvailableException();
                    } 
                } 

                return aChildren; 
            }
            catch (Exception e)
            {
                if (HandleIAccessibleException(e)) 
                {
                    throw; 
                } 
                throw new ElementNotAvailableException();
            } 
        }

        #endregion
 
        #endregion Internal Methods
 
 
        //------------------------------------------------------
        // 
        //  Private Methods
        //
        //------------------------------------------------------
 
        #region Private Methods
 
        // Returns a child by index 
        private static Accessible GetChildAt(IAccessible parent, object [] children, int index)
        { 
            // note: calling AccessibleChildren on Trident and asking for a single child can
            // result in a Fatal Execution Engine Error (79697ADA)(80121506).
            // Perhaps the implementation ignores the cChildren param?
            // To avoid the problem we always ask for all of the children and just 
            // use the specific one we are interested in.
 
            if (children == null) 
            {
                children = GetChildren(parent); 
            }
            if (children == null)
            {
                return null; 
            }
 
            // Paranoia that between calls accChildCount returns different counts 
            if (index >= children.Length)
                index = children.Length - 1; 

            Accessible nav = AccessibleFromObject(children[index], parent);
            if (nav != null)
            { 
                nav._accessibleChildrenIndex = index;
            } 
 
            return nav;
        } 

        // Find _acc's index among its siblings with optimization to return children collection
        // if that would be needed later by the caller
        private object [] SetAccessibleChildrenIndexAndGetChildren(IAccessible parent) 
        {
            // this is only called if the index hasn't been set yet. 
            Debug.Assert(_accessibleChildrenIndex < 0); 

            object [] children = GetChildren(parent); 
            if (children == null)
            {
                return null;   // unlikely to happen but...
            } 

            // Try to figure out which child in this array '_acc' is 
 
            for (int i=0;i

                        

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