AccessibleObject.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / WinForms / Managed / System / WinForms / AccessibleObject.cs / 1 / AccessibleObject.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

/* 
 */ 

namespace System.Windows.Forms { 
    using Accessibility;
    using System.Runtime.InteropServices;
    using System.Diagnostics;
    using System; 
    using System.Collections;
    using System.Drawing; 
    using System.Windows.Forms; 
    using Microsoft.Win32;
    using System.ComponentModel; 
    using System.Reflection;
    using System.Globalization;
    using System.Security;
    using System.Security.Permissions; 

    ///  
    ///  
    ///    Provides an implementation for an object that can be inspected by an
    ///       accessibility application. 
    /// 
    [ComVisible(true)]
    public class AccessibleObject : StandardOleMarshalObject,
                                    IReflect, 
                                    IAccessible,
                                    UnsafeNativeMethods.IEnumVariant, 
                                    UnsafeNativeMethods.IOleWindow { 

        // Member variables 

        /// 
        /// 
        /// Specifies the interface used by this . 
        /// 
        private IAccessible systemIAccessible = null; 
 
        /// 
        ///  
        ///    Specifies the
        ///    used by this  .
        /// 
        private UnsafeNativeMethods.IEnumVariant systemIEnumVariant = null; 
        private UnsafeNativeMethods.IEnumVariant enumVariant = null;
 
        // IOleWindow interface of the 'inner' system IAccessible object that we are wrapping 
        private UnsafeNativeMethods.IOleWindow systemIOleWindow = null;
 
        private bool systemWrapper = false;     // Indicates this object is being used ONLY to wrap a system IAccessible

        private int accObjId = NativeMethods.OBJID_CLIENT;    // Indicates what kind of 'inner' system accessible object we are using
 
        /// 
        public AccessibleObject() { 
        } 

        // This constructor is used ONLY for wrapping system IAccessible objects 
        //
        private AccessibleObject(IAccessible iAcc) {
            this.systemIAccessible = iAcc;
            this.systemWrapper = true; 
        }
 
        // Properties 

        ///  
        /// 
        ///     Gets the bounds of the accessible object, in screen coordinates.
        /// 
        public virtual Rectangle Bounds { 
            get {
                // Use the system provided bounds 
                if (systemIAccessible != null) { 
                    int left = 0;
                    int top = 0; 
                    int width = 0;
                    int height = 0;
                    try {
                        systemIAccessible.accLocation(out left, out top, out width, out height, NativeMethods.CHILDID_SELF); 
                        return new Rectangle(left, top, width, height);
                    } 
                    catch (COMException e) { 
                        if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                            throw e; 
                        }
                    }
                }
                return Rectangle.Empty; 
            }
        } 
 
        /// 
        ///  
        ///    Gets a description of the default action for an object.
        /// 
        public virtual string DefaultAction {
            get { 
                if (systemIAccessible != null) {
                    try { 
                        return systemIAccessible.get_accDefaultAction(NativeMethods.CHILDID_SELF); 
                    }
                    catch (COMException e) { 
                        // Not all objects provide a default action
                        //
                        if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                            throw e; 
                        }
                    } 
                } 
                return null;
            } 
        }

        /// 
        ///  
        ///    Gets a description
        ///       of the object's visual appearance to the user. 
        ///  
        public virtual string Description {
            get { 
                if (systemIAccessible != null) {
                    try {
                        return systemIAccessible.get_accDescription(NativeMethods.CHILDID_SELF);
                    } 
                    catch (COMException e) {
                        if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) { 
                            throw e; 
                        }
                    } 
                }
                return null;
            }
        } 

        private UnsafeNativeMethods.IEnumVariant EnumVariant { 
            get { 
                if (enumVariant == null) {
                    enumVariant = new EnumVariantObject(this); 
                }
                return enumVariant;
            }
        } 

        ///  
        ///  
        ///    Gets a description of what the object does or how the object is used.
        ///  
        public virtual string Help {
            get {
                if (systemIAccessible != null) {
                    try { 
                        return systemIAccessible.get_accHelp(NativeMethods.CHILDID_SELF);
                    } 
                    catch (COMException e) { 
                        if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                            throw e; 
                        }
                    }
                }
                return null; 
            }
        } 
 
        /// 
        ///  
        ///    Gets the object shortcut key or access key
        ///       for an accessible object.
        /// 
        public virtual string KeyboardShortcut { 
            get {
                if (systemIAccessible != null) { 
                    try { 
                        return systemIAccessible.get_accKeyboardShortcut(NativeMethods.CHILDID_SELF);
                    } 
                    catch (COMException e) {
                        if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                            throw e;
                        } 
                    }
                } 
                return null; 
            }
        } 

        /// 
        /// 
        ///    Gets 
        ///       or sets the object name.
        ///  
        public virtual string Name { 
            // Does nothing by default
            get { 
                if (systemIAccessible != null) {
                    try {
                        return systemIAccessible.get_accName(NativeMethods.CHILDID_SELF);
                    } 
                    catch (COMException e) {
                        if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) { 
                            throw e; 
                        }
                    } 
                }
                return null;
            }
 
            set {
                if (systemIAccessible != null) { 
                    try { 
                        systemIAccessible.set_accName(NativeMethods.CHILDID_SELF, value);
                    } 
                    catch (COMException e) {
                        if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                            throw e;
                        } 
                    }
                } 
 
            }
        } 

        /// 
        /// 
        ///    When overridden in a derived class, gets or sets the parent of an accessible object. 
        /// 
        public virtual AccessibleObject Parent { 
            [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
            get {
                if (systemIAccessible != null) { 
                    return WrapIAccessible(systemIAccessible.accParent);
                }
                else {
                    return null; 
                }
            } 
        } 

        ///  
        /// 
        ///    Gets the role of this accessible object.
        /// 
        public virtual AccessibleRole Role { 
            get {
                if (systemIAccessible != null) { 
                    return (AccessibleRole) systemIAccessible.get_accRole(NativeMethods.CHILDID_SELF); 
                }
                else { 
                    return AccessibleRole.None;
                }
            }
        } 

        ///  
        ///  
        ///    Gets
        ///       the state of this accessible object. 
        /// 
        public virtual AccessibleStates State {
            get {
                if (systemIAccessible != null) { 
                    return (AccessibleStates) systemIAccessible.get_accState(NativeMethods.CHILDID_SELF);
                } 
                else { 
                    return AccessibleStates.None;
                } 
            }
        }

        ///  
        /// 
        ///    Gets or sets the value of an accessible object. 
        ///  
        public virtual string Value {
            // Does nothing by default 
            [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
            get {
                if (systemIAccessible != null) {
                    try { 
                        return systemIAccessible.get_accValue(NativeMethods.CHILDID_SELF);
                    } 
                    catch (COMException e) { 
                        if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                            throw e; 
                        }
                    }
                }
                return ""; 
            }
 
            [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
            set {
                if (systemIAccessible != null) { 
                    try {
                        systemIAccessible.set_accValue(NativeMethods.CHILDID_SELF, value);
                    }
                    catch (COMException e) { 
                        if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                            throw e; 
                        } 
                    }
                } 
            }
        }

        // Methods 

        ///  
        ///  
        ///    When overridden in a derived class, gets the accessible child corresponding to the specified
        ///       index. 
        /// 
        public virtual AccessibleObject GetChild(int index) {
            return null;
        } 

        ///  
        ///  
        ///     When overridden in a derived class, gets the number of children
        ///       belonging to an accessible object. 
        /// 
        public virtual int GetChildCount() {
            return -1;
        } 

        ///  
        ///  
        ///     Mechanism for overriding default IEnumVariant behavior of the 'inner' system accessible object
        ///     (IEnumVariant is how a system accessible object exposes its ordered list of child objects). 
        ///
        ///     USAGE: Overridden method in derived class should return array of integers representing new order
        ///     to be imposed on the child accessible object collection returned by the system (which
        ///     we assume will be a set of accessible objects that represent the child windows, in 
        ///     z-order). Each array element contains the original z-order based rank of the child window
        ///     that is to appear at that position in the new ordering. Note: This array could also be 
        ///     used to filter out unwanted child windows too, if necessary (not recommended). 
        /// 
        internal virtual int[] GetSysChildOrder() { 
            return null;
        }

        ///  
        /// 
        ///     Mechanism for overriding default IAccessible.accNavigate behavior of the 'inner' system accessible 
        ///     object (accNavigate is how you move between parent, child and sibling accessible objects). 
        ///
        ///     USAGE: 'navdir' indicates navigation operation to perform, relative to this accessible object. 
        ///     If operation is unsupported, return false to allow fall-back to default system behavior. Otherwise
        ///     return destination object in the out parameter, or null to indicate 'off end of list'.
        /// 
        internal virtual bool GetSysChild(AccessibleNavigation navdir, out AccessibleObject accessibleObject) { 
            accessibleObject = null;
            return false; 
        } 

        ///  
        /// 
        ///     When overridden in a derived class,
        ///       gets the object that has the keyboard focus.
        ///  
        public virtual AccessibleObject GetFocused() {
 
            // Default behavior for objects with AccessibleObject children 
            //
            if (GetChildCount() >= 0) { 
                int count = GetChildCount();
                for(int index=0; index < count; ++index) {
                    AccessibleObject child = GetChild(index);
                    Debug.Assert(child != null, "GetChild(" + index.ToString(CultureInfo.InvariantCulture) + ") returned null!"); 
                    if (child != null && ((child.State & AccessibleStates.Focused) != 0)) {
                        return child; 
                    } 
                }
                if ((this.State & AccessibleStates.Focused) != 0) { 
                    return this;
                }
                return null;
            } 

            if (systemIAccessible != null) { 
                try { 
                    return WrapIAccessible(systemIAccessible.accFocus);
                } 
                catch (COMException e) {
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                        throw e;
                    } 
                }
            } 
 
            return null;
        } 

        /// 
        /// 
        ///     
        ///       Gets an identifier for a Help topic and the path to the Help file associated
        ///       with this accessible object. 
        ///  
        public virtual int GetHelpTopic(out string fileName) {
            if (systemIAccessible != null) { 
                try {
                    int retVal = systemIAccessible.get_accHelpTopic(out fileName, NativeMethods.CHILDID_SELF);
                    if (fileName != null && fileName.Length > 0) {
                        IntSecurity.DemandFileIO(FileIOPermissionAccess.PathDiscovery, fileName); 
                    }
                    return retVal; 
                } 
                catch (COMException e) {
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) { 
                        throw e;
                    }
                }
            } 
            fileName = null;
            return -1; 
        } 

        ///  
        /// 
        ///     When overridden in
        ///       a derived class, gets the currently selected child.
        ///  
        public virtual AccessibleObject GetSelected() {
            // Default behavior for objects with AccessibleObject children 
            // 
            if (GetChildCount() >= 0) {
                int count = GetChildCount(); 
                for(int index=0; index < count; ++index) {
                    AccessibleObject child = GetChild(index);
                    Debug.Assert(child != null, "GetChild(" + index.ToString(CultureInfo.InvariantCulture) + ") returned null!");
                    if (child != null && ((child.State & AccessibleStates.Selected) != 0)) { 
                        return child;
                    } 
                } 
                if ((this.State & AccessibleStates.Selected) != 0) {
                    return this; 
                }
                return null;
            }
 
            if (systemIAccessible != null) {
                try { 
                    return WrapIAccessible(systemIAccessible.accSelection); 
                }
                catch (COMException e) { 
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                        throw e;
                    }
                } 
            }
 
            return null; 
        }
 
        /// 
        /// 
        ///    Return the child object at the given screen coordinates.
        ///  
        public virtual AccessibleObject HitTest(int x, int y) {
 
            // Default behavior for objects with AccessibleObject children 
            //
            if (GetChildCount() >= 0) { 
                int count = GetChildCount();
                for(int index=0; index < count; ++index) {
                    AccessibleObject child = GetChild(index);
                    Debug.Assert(child != null, "GetChild(" + index.ToString(CultureInfo.InvariantCulture) + ") returned null!"); 
                    if (child != null && child.Bounds.Contains(x, y)) {
                        return child; 
                    } 
                }
                return this; 
            }

            if (systemIAccessible != null) {
                try { 
                    return WrapIAccessible(systemIAccessible.accHitTest(x, y));
                } 
                catch (COMException e) { 
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                        throw e; 
                    }
                }
            }
 
            if (this.Bounds.Contains(x, y)) {
                return this; 
            } 

            return null; 
        }

        /// 
        ///  
        /// 
        ///  
        /// Perform the default action 
        /// 
        ///  
        void IAccessible.accDoDefaultAction(Object childID) {

            IntSecurity.UnmanagedCode.Demand();
 
            if (IsClientObject) {
                ValidateChildID(ref childID); 
 
                Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.AccDoDefaultAction: this = " +
                    this.ToString() + ", childID = " + childID.ToString()); 

                // If the default action is to be performed on self, do it.
                if (childID.Equals(NativeMethods.CHILDID_SELF)) {
                    DoDefaultAction(); 
                    return;
                } 
 
                // If we have an accessible object collection, get the appropriate child
                AccessibleObject child = GetAccessibleChild(childID); 
                if (child != null) {
                    child.DoDefaultAction();
                    return;
                } 
            }
 
            if (systemIAccessible != null) { 
                try {
                    systemIAccessible.accDoDefaultAction(childID); 
                }
                catch (COMException e) {
                    // Not all objects provide a default action
                    // 
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                        throw e; 
                    } 
                }
            } 
        }

        /// 
        ///  
        /// 
        ///  
        /// Perform a hit test 
        /// 
        ///  
        Object IAccessible.accHitTest(
                                 int xLeft,
                                 int yTop) {
 
            if (IsClientObject) {
                Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.AccHitTest: this = " + 
                    this.ToString()); 

                AccessibleObject obj = HitTest(xLeft, yTop); 
                if (obj != null) {
                    return AsVariant(obj);
                }
            } 

            if (systemIAccessible != null) { 
                try { 
                    return systemIAccessible.accHitTest(xLeft, yTop);
                } 
                catch (COMException e) {
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                        throw e;
                    } 
                }
            } 
 
            return null;
        } 

        /// 
        /// 
        ///  
        /// 
        /// The location of the Accessible object 
        ///  
        /// 
        void IAccessible.accLocation( 
                               out int pxLeft,
                               out int pyTop,
                               out int pcxWidth,
                               out int pcyHeight, 
                               Object childID) {
 
            pxLeft = 0; 
            pyTop = 0;
            pcxWidth = 0; 
            pcyHeight = 0;

            if (IsClientObject) {
                ValidateChildID(ref childID); 

                Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.AccLocation: this = " + 
                    this.ToString() + ", childID = " + childID.ToString()); 

                // Use the Location function's return value if available 
                //
                if (childID.Equals(NativeMethods.CHILDID_SELF)) {
                    Rectangle bounds = this.Bounds;
                    pxLeft = bounds.X; 
                    pyTop = bounds.Y;
                    pcxWidth = bounds.Width; 
                    pcyHeight = bounds.Height; 

                    Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.AccLocation: Returning " + 
                        bounds.ToString());

                    return;
                } 

                // If we have an accessible object collection, get the appropriate child 
                // 
                AccessibleObject child = GetAccessibleChild(childID);
                if (child != null) { 
                    Rectangle bounds = child.Bounds;
                    pxLeft = bounds.X;
                    pyTop = bounds.Y;
                    pcxWidth = bounds.Width; 
                    pcyHeight = bounds.Height;
 
                    Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.AccLocation: Returning " + 
                        bounds.ToString());
 
                    return;
                }
            }
 
            if (systemIAccessible != null) {
                try { 
                    systemIAccessible.accLocation(out pxLeft, out pyTop, out pcxWidth, out pcyHeight, childID); 

                    Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.AccLocation: Setting " + 
                        pxLeft.ToString(CultureInfo.InvariantCulture) + ", " +
                        pyTop.ToString(CultureInfo.InvariantCulture) + ", " +
                        pcxWidth.ToString(CultureInfo.InvariantCulture) + ", " +
                        pcyHeight.ToString(CultureInfo.InvariantCulture)); 
                }
                catch (COMException e) { 
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) { 
                        throw e;
                    } 
                }

                return;
            } 
        }
 
        ///  
        /// 
        ///  
        /// 
        /// Navigate to another accessible object.
        /// 
        ///  
        Object IAccessible.accNavigate(
                                  int navDir, 
                                  Object childID) { 

            IntSecurity.UnmanagedCode.Demand(); 

            if (IsClientObject) {
                ValidateChildID(ref childID);
 
                Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.AccNavigate: this = " +
                    this.ToString() + ", navdir = " + navDir.ToString(CultureInfo.InvariantCulture) + ", childID = " + childID.ToString()); 
 
                // Use the Navigate function's return value if available
                // 
                if (childID.Equals(NativeMethods.CHILDID_SELF)) {
                    AccessibleObject newObject = Navigate((AccessibleNavigation)navDir);
                    if (newObject != null) {
                        return AsVariant(newObject); 
                    }
                } 
 
                // If we have an accessible object collection, get the appropriate child
                AccessibleObject child = GetAccessibleChild(childID); 
                if (child != null) {
                    return AsVariant(child.Navigate((AccessibleNavigation)navDir));
                }
            } 

            if (systemIAccessible != null) { 
                try { 
                    Object retObject;
                    if (!SysNavigate(navDir, childID, out retObject)) 
                        retObject = systemIAccessible.accNavigate(navDir, childID);
                    return retObject;
                }
                catch (COMException e) { 
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                        throw e; 
                    } 
                }
            } 

            return null;
        }
 
        /// 
        ///  
        ///  
        /// 
        /// Select an accessible object. 
        /// 
        /// 
        void IAccessible.accSelect(int flagsSelect, Object childID) {
 
            IntSecurity.UnmanagedCode.Demand();
 
            if (IsClientObject) { 
                ValidateChildID(ref childID);
 
                Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.AccSelect: this = " +
                    this.ToString() + ", flagsSelect = " + flagsSelect.ToString(CultureInfo.InvariantCulture) + ", childID = " + childID.ToString());

                // If the selection is self, do it. 
                if (childID.Equals(NativeMethods.CHILDID_SELF)) {
                    Select((AccessibleSelection)flagsSelect);    // Uses an Enum which matches SELFLAG 
                    return; 
                }
 
                // If we have an accessible object collection, get the appropriate child
                AccessibleObject child = GetAccessibleChild(childID);
                if (child != null) {
                    child.Select((AccessibleSelection)flagsSelect); 
                    return;
                } 
            } 

            if (systemIAccessible != null) { 
                try {
                    systemIAccessible.accSelect(flagsSelect, childID);
                }
                catch (COMException e) { 
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                        throw e; 
                    } 
                }
                return; 
            }

        }
 
        /// 
        ///  
        ///      Performs the default action associated with this accessible object. 
        /// 
        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
        public virtual void DoDefaultAction() {
            // By default, just does the system default action if available
            //
            if (systemIAccessible != null) { 
                try {
                    systemIAccessible.accDoDefaultAction(0); 
                } 
                catch (COMException e) {
                    // Not all objects provide a default action 
                    //
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                        throw e;
                    } 
                }
                return; 
            } 
        }
 
        /// 
        /// 
        /// 
        ///  
        /// Returns a child Accessible object
        ///  
        ///  
        object IAccessible.get_accChild(object childID) {
 
            if (IsClientObject) {
                ValidateChildID(ref childID);

                Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.GetAccChild: this = " + 
                    this.ToString() + ", childID = " + childID.ToString());
 
                // Return self for CHILDID_SELF 
                if (childID.Equals(NativeMethods.CHILDID_SELF)) {
                    return AsIAccessible(this); 
                }

                // If we have an accessible object collection, get the appropriate child
                AccessibleObject child = GetAccessibleChild(childID); 
                if (child != null) {
                    // Make sure we're not returning ourselves as our own child 
                    // 
                    Debug.Assert(child != this, "An accessible object is returning itself as its own child. This can cause Accessibility client applications to hang.");
                    if (child == this) { 
                        return null;
                    }

                    return AsIAccessible(child); 
                }
            } 
 
            // Otherwise, return the default system child for this control (if any)
            if (systemIAccessible != null) { 
                return systemIAccessible.get_accChild(childID);
            }

            return null; 
        }
 
        ///  
        /// 
        ///  
        /// Return the number of children
        /// 
        int IAccessible.accChildCount {
            get { 
                int childCount = -1;
 
                if (IsClientObject) { 
                    childCount = GetChildCount();
                } 

                if (childCount == -1) {
                    if (systemIAccessible != null) {
                        childCount = systemIAccessible.accChildCount; 
                    }
                    else { 
                        childCount = 0; 
                    }
                } 

                Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.accHildCount: this = " + this.ToString() + ", returning " + childCount.ToString(CultureInfo.InvariantCulture));

                return childCount; 
            }
        } 
 
        /// 
        ///  
        /// 
        /// 
        /// Return the default action
        ///  
        /// 
        string IAccessible.get_accDefaultAction(Object childID) { 
 
            if (IsClientObject) {
                ValidateChildID(ref childID); 

                // Return the default action property if available
                if (childID.Equals(NativeMethods.CHILDID_SELF)) {
                    return DefaultAction; 
                }
 
                // If we have an accessible object collection, get the appropriate child 
                AccessibleObject child = GetAccessibleChild(childID);
                if (child != null) { 
                    return child.DefaultAction;
                }
            }
 
            if (systemIAccessible != null) {
                try { 
                    return systemIAccessible.get_accDefaultAction(childID); 
                }
                catch (COMException e) { 
                    // Not all objects provide a default action
                    //
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                        throw e; 
                    }
                } 
            } 

            return null; 
        }

        /// 
        ///  
        /// 
        ///  
        /// Return the object or child description 
        /// 
        ///  
        string IAccessible.get_accDescription(Object childID) {

            if (IsClientObject) {
                ValidateChildID(ref childID); 

                // Return the description property if available 
                if (childID.Equals(NativeMethods.CHILDID_SELF)) { 
                    return Description;
                } 

                // If we have an accessible object collection, get the appropriate child
                AccessibleObject child = GetAccessibleChild(childID);
                if (child != null) { 
                    return child.Description;
                } 
            } 

            if (systemIAccessible != null) { 
                try {
                    return systemIAccessible.get_accDescription(childID);
                }
                catch (COMException e) { 
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                        throw e; 
                    } 
                }
            } 

            return null;
        }
 
        /// 
        ///  
        ///      Returns the appropriate child from the Accessible Child Collection, if available 
        /// 
        private AccessibleObject GetAccessibleChild(object childID) { 
            if (!childID.Equals(NativeMethods.CHILDID_SELF)) {
                int index = (int)childID - 1;   // The first child is childID == 1 (index == 0)
                if (index >= 0 && index < GetChildCount()) {
                    return GetChild(index); 
                }
            } 
            return null; 
        }
 
        /// 
        /// 
        /// 
        /// Return the object or child focus 
        /// 
        object IAccessible.accFocus { 
            get { 

                if (IsClientObject) { 
                    Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.GetAccFocus: this = " +
                        this.ToString());

                    AccessibleObject obj = GetFocused(); 
                    if (obj != null) {
                        return AsVariant(obj); 
                    } 
                }
 
                if (systemIAccessible != null) {
                    try {
                        return systemIAccessible.accFocus;
                    } 
                    catch (COMException e) {
                        if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) { 
                            throw e; 
                        }
                    } 
                }

                return null;
            } 
        }
 
        ///  
        /// 
        ///  
        /// 
        /// Return help for this accessible object.
        /// 
        ///  
        string IAccessible.get_accHelp(Object childID) {
 
            if (IsClientObject) { 
                ValidateChildID(ref childID);
 
                if (childID.Equals(NativeMethods.CHILDID_SELF)) {
                    return Help;
                }
 
                // If we have an accessible object collection, get the appropriate child
                AccessibleObject child = GetAccessibleChild(childID); 
                if (child != null) { 
                    return child.Help;
                } 
            }

            if (systemIAccessible != null) {
                try { 
                    return systemIAccessible.get_accHelp(childID);
                } 
                catch (COMException e) { 
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                        throw e; 
                    }
                }
            }
 
            return null;
        } 
 
        /// 
        ///  
        /// 
        /// 
        /// Return the object or child help topic
        ///  
        /// 
        int IAccessible.get_accHelpTopic(out string pszHelpFile, Object childID) { 
 
            if (IsClientObject) {
                ValidateChildID(ref childID); 

                if (childID.Equals(NativeMethods.CHILDID_SELF)) {
                    return GetHelpTopic(out pszHelpFile);
                } 

                // If we have an accessible object collection, get the appropriate child 
                AccessibleObject child = GetAccessibleChild(childID); 
                if (child != null) {
                    return child.GetHelpTopic(out pszHelpFile); 
                }
            }

            if (systemIAccessible != null) { 
                try {
                    return systemIAccessible.get_accHelpTopic(out pszHelpFile, childID); 
                } 
                catch (COMException e) {
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) { 
                        throw e;
                    }
                }
            } 

            pszHelpFile = null; 
            return -1; 
        }
 
        /// 
        /// 
        /// 
        ///  
        /// Return the object or child keyboard shortcut
        ///  
        ///  
        string IAccessible.get_accKeyboardShortcut(Object childID) {
            return get_accKeyboardShortcutInternal(childID); 
        }

        internal virtual string get_accKeyboardShortcutInternal(Object childID) {
 
            if (IsClientObject) {
                ValidateChildID(ref childID); 
 
                if (childID.Equals(NativeMethods.CHILDID_SELF)) {
                    return KeyboardShortcut; 
                }

                // If we have an accessible object collection, get the appropriate child
                AccessibleObject child = GetAccessibleChild(childID); 
                if (child != null) {
                    return child.KeyboardShortcut; 
                } 
            }
 
            if (systemIAccessible != null) {
                try {
                    return systemIAccessible.get_accKeyboardShortcut(childID);
                } 
                catch (COMException e) {
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) { 
                        throw e; 
                    }
                } 
            }

            return null;
        } 

        ///  
        ///  
        /// 
        ///  
        /// Return the object or child name
        /// 
        /// 
        string IAccessible.get_accName(object childID) { 
            return get_accNameInternal(childID);
        } 
 
        /// 
        ///  
        internal virtual string get_accNameInternal(object childID) {
            if (IsClientObject) {
                ValidateChildID(ref childID);
 
                Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.get_accName: this = " + this.ToString() +
                    ", childID = " + childID.ToString()); 
 
                // Return the name property if available
                if (childID.Equals(NativeMethods.CHILDID_SELF)) { 
                    return Name;
                }

                // If we have an accessible object collection, get the appropriate child 
                AccessibleObject child = GetAccessibleChild(childID);
                if (child != null) { 
                    return child.Name; 
                }
            } 

            // Otherwise, use the system provided name
            if (systemIAccessible != null) {
                string retval = systemIAccessible.get_accName(childID); 

                if (IsClientObject) { 
                    if (retval == null || retval.Length == 0) { 
                        retval = Name;  // Name the child after its parent
                    } 
                }

                return retval;
            } 

            return null; 
        } 

        ///  
        /// 
        /// 
        /// Return the parent object
        ///  
        object IAccessible.accParent {
            get { 
                IntSecurity.UnmanagedCode.Demand(); 

                Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.accParent: this = " + this.ToString()); 
                AccessibleObject parent = Parent;
                if (parent != null) {
                    // Some debugging related tests
                    // 
                    Debug.Assert(parent != this, "An accessible object is returning itself as its own parent. This can cause accessibility clients to hang.");
                    if (parent == this) { 
                        parent = null;  // This should prevent accessibility clients from hanging 
                    }
                } 

                return AsIAccessible(parent);
            }
        } 

        ///  
        ///  
        /// 
        ///  
        /// The role property describes an object's purpose in terms of its
        /// relationship with sibling or child objects.
        /// 
        ///  
        object IAccessible.get_accRole(object childID) {
 
            if (IsClientObject) { 
                ValidateChildID(ref childID);
 
                // Return the role property if available
                if (childID.Equals(NativeMethods.CHILDID_SELF)) {
                    return (int)Role;
                } 

                // If we have an accessible object collection, get the appropriate child 
                AccessibleObject child = GetAccessibleChild(childID); 
                if (child != null) {
                    return (int)child.Role; 
                }
            }

            if (systemIAccessible != null) { 
                return systemIAccessible.get_accRole(childID);
            } 
 
            return null;
        } 

        /// 
        /// 
        ///  
        /// Return the object or child selection
        ///  
        object IAccessible.accSelection { 
            get {
 
                if (IsClientObject) {
                    Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.GetAccSelection: this = " +
                        this.ToString());
 
                    AccessibleObject obj = GetSelected();
                    if (obj != null) { 
                        return AsVariant(obj); 
                    }
                } 

                if (systemIAccessible != null) {
                    try {
                        return systemIAccessible.accSelection; 
                    }
                    catch (COMException e) { 
                        if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) { 
                            throw e;
                        } 
                    }
                }

                return null; 
            }
        } 
 
        /// 
        ///  
        /// 
        /// 
        /// Return the object or child state
        ///  
        /// 
        object IAccessible.get_accState(object childID) { 
 
            if (IsClientObject) {
                ValidateChildID(ref childID); 

                Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.GetAccState: this = " +
                    this.ToString() + ", childID = " + childID.ToString());
 
                // Return the state property if available
                if (childID.Equals(NativeMethods.CHILDID_SELF)) { 
                    return (int)State; 
                }
 
                // If we have an accessible object collection, get the appropriate child
                AccessibleObject child = GetAccessibleChild(childID);
                if (child != null) {
                    return (int)child.State; 
                }
            } 
 
            if (systemIAccessible != null) {
                return systemIAccessible.get_accState(childID); 
            }

            return null;
        } 

        ///  
        ///  
        /// 
        ///  
        /// Return the object or child value
        /// 
        /// 
        string IAccessible.get_accValue(object childID) { 

            IntSecurity.UnmanagedCode.Demand(); 
 
            if (IsClientObject) {
                ValidateChildID(ref childID); 

                // Return the value property if available
                if (childID.Equals(NativeMethods.CHILDID_SELF)) {
                    return Value; 
                }
 
                // If we have an accessible object collection, get the appropriate child 
                AccessibleObject child = GetAccessibleChild(childID);
                if (child != null) { 
                    return child.Value;
                }
            }
 
            if (systemIAccessible != null) {
                try { 
                    return systemIAccessible.get_accValue(childID); 
                }
                catch (COMException e) { 
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                        throw e;
                    }
                } 
            }
 
            return null; 
        }
 
        /// 
        /// 
        /// 
        ///  
        /// Set the object or child name
        ///  
        ///  
        void IAccessible.set_accName(
                              Object childID, 
                              string newName) {

            if (IsClientObject) {
                ValidateChildID(ref childID); 

                // Set the name property if available 
                if (childID.Equals(NativeMethods.CHILDID_SELF)) { 
                    // Attempt to set the name property
                    Name = newName; 
                    return;
                }

                // If we have an accessible object collection, get the appropriate child 
                AccessibleObject child = GetAccessibleChild(childID);
                if (child != null) { 
                    child.Name = newName; 
                    return;
                } 
            }

            if (systemIAccessible != null) {
                systemIAccessible.set_accName(childID, newName); 
                return;
            } 
        } 

        ///  
        /// 
        /// 
        /// 
        /// Set the object or child value 
        /// 
        ///  
        void IAccessible.set_accValue( 
                               Object childID,
                               string newValue) { 

            IntSecurity.UnmanagedCode.Demand();

            if (IsClientObject) { 
                ValidateChildID(ref childID);
 
                // Set the value property if available 
                if (childID.Equals(NativeMethods.CHILDID_SELF)) {
                    // Attempt to set the value property 
                    Value = newValue;
                    return;
                }
 
                // If we have an accessible object collection, get the appropriate child
                AccessibleObject child = GetAccessibleChild(childID); 
                if (child != null) { 
                    child.Value = newValue;
                    return; 
                }
            }

            if (systemIAccessible != null) { 
                try {
                    systemIAccessible.set_accValue(childID, newValue); 
                } 
                catch (COMException e) {
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) { 
                        throw e;
                    }
                }
                return; 
            }
        } 
 
        /// 
        ///  
        ///     [[....] - Apr04]
        ///
        ///     Now that AccessibleObject is used to wrap all system-provided (OLEACC.DLL) accessible
        ///     objects, it needs to implement IOleWindow and pass this down to the inner object. This is 
        ///     necessary because the OS function WindowFromAccessibleObject() walks up the parent chain
        ///     looking for the first object that implements IOleWindow, and uses that to get the hwnd. 
        /// 
        ///     But this creates a new problem for AccessibleObjects that do NOT have windows, ie. which
        ///     represent simple elements. To the OS, these simple elements will now appear to implement 
        ///     IOleWindow, so it will try to get hwnds from them - which they simply cannot provide.
        ///
        ///     To work around this problem, the AccessibleObject for a simple element will delegate all
        ///     IOleWindow calls up the parent chain itself. This will stop at the first window-based 
        ///     accessible object, which will be able to return an hwnd back to the OS. So we are
        ///     effectively 'preempting' what WindowFromAccessibleObject() would do. 
        ///  
        /// 
        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
        int UnsafeNativeMethods.IOleWindow.GetWindow(out IntPtr hwnd) {
            // See if we have an inner object that can provide the window handle
            if (systemIOleWindow != null) {
                return systemIOleWindow.GetWindow(out hwnd); 
            }
 
            // Otherwise delegate to the parent object 
            AccessibleObject parent = this.Parent;
            if (parent is UnsafeNativeMethods.IOleWindow) { 
                return (parent as UnsafeNativeMethods.IOleWindow).GetWindow(out hwnd);
            }

            // Or fail if there is no parent 
            hwnd = IntPtr.Zero;
            return NativeMethods.E_FAIL; 
        } 

        ///  
        /// 
        ///     See GetWindow() above for details.
        /// 
        ///  
        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        void UnsafeNativeMethods.IOleWindow.ContextSensitiveHelp(int fEnterMode) { 
            // See if we have an inner object that can provide help 
            if (systemIOleWindow != null) {
                systemIOleWindow.ContextSensitiveHelp(fEnterMode); 
                return;
            }

            // Otherwise delegate to the parent object 
            AccessibleObject parent = this.Parent;
            if (parent is UnsafeNativeMethods.IOleWindow) { 
                (parent as UnsafeNativeMethods.IOleWindow).ContextSensitiveHelp(fEnterMode); 
                return;
            } 

            // Or do nothing if there is no parent
        }
 
        /// 
        ///  
        ///     
        ///       Clone this accessible object.
        ///     
        /// 
        void UnsafeNativeMethods.IEnumVariant.Clone(UnsafeNativeMethods.IEnumVariant[] v) {
            EnumVariant.Clone(v);
        } 

        ///  
        ///  
        ///    
        ///       Obtain the next n children of this accessible object. 
        ///    
        /// 
        int UnsafeNativeMethods.IEnumVariant.Next(int n, IntPtr rgvar, int[] ns) {
            return EnumVariant.Next(n, rgvar, ns); 
        }
 
        ///  
        /// 
        ///      Resets the child accessible object enumerator. 
        /// 
        void UnsafeNativeMethods.IEnumVariant.Reset() {
            EnumVariant.Reset();
        } 

        ///  
        ///  
        ///    
        ///       Skip the next n child accessible objects 
        ///    
        /// 
        void UnsafeNativeMethods.IEnumVariant.Skip(int n) {
            EnumVariant.Skip(n); 
        }
 
        ///  
        /// 
        ///    When overridden in a derived class, 
        ///       navigates to another object.
        /// 
        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public virtual AccessibleObject Navigate(AccessibleNavigation navdir) { 

            // Some default behavior for objects with AccessibleObject children 
            // 
            if (GetChildCount() >= 0) {
                switch(navdir) { 
                    case AccessibleNavigation.FirstChild:
                        return GetChild(0);
                    case AccessibleNavigation.LastChild:
                        return GetChild(GetChildCount() - 1); 
                    case AccessibleNavigation.Previous:
                    case AccessibleNavigation.Up: 
                    case AccessibleNavigation.Left: 
                        if (Parent.GetChildCount() > 0) {
                            return null; 
                        }
                        break;
                    case AccessibleNavigation.Next:
                    case AccessibleNavigation.Down: 
                    case AccessibleNavigation.Right:
                        if (Parent.GetChildCount() > 0) { 
                            return null; 
                        }
                        break; 
                }
            }

            if (systemIAccessible != null) { 
                try {
                    object retObject = null; 
                    if (!SysNavigate((int)navdir, NativeMethods.CHILDID_SELF, out retObject)) 
                        retObject = systemIAccessible.accNavigate((int)navdir, NativeMethods.CHILDID_SELF);
                    return WrapIAccessible(retObject); 
                }
                catch (COMException e) {
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                        throw e; 
                    }
                } 
            } 
            return null;
        } 

        /// 
        /// 
        ///     
        ///       Selects this accessible object.
        ///     
        ///  
        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public virtual void Select(AccessibleSelection flags) { 

            // By default, do the system behavior
            //
            if (systemIAccessible != null) { 
                try {
                    systemIAccessible.accSelect((int)flags, 0); 
                } 
                catch (COMException e) {
                    // Not all objects provide the select function 
                    //
                    if (e.ErrorCode != NativeMethods.DISP_E_MEMBERNOTFOUND) {
                        throw e;
                    } 
                }
                return; 
            } 
        }
 
        private object AsVariant(AccessibleObject obj) {
            if (obj == this) {
                return NativeMethods.CHILDID_SELF;
            } 
            return AsIAccessible(obj);
        } 
 
        private IAccessible AsIAccessible(AccessibleObject obj) {
            if (obj != null && obj.systemWrapper) { 
                return obj.systemIAccessible;
            }
            return obj;
        } 

        ///  
        ///  
        ///     Indicates what kind of 'inner' system accessible object we are using as our fall-back
        ///     implementation of IAccessible (when the systemIAccessible member is not null). The inner 
        ///     object is provided by OLEACC.DLL. Note that although the term 'id' is used, this value
        ///     really represents a category or type of accessible object. Ids are only unique among
        ///     accessible objects associated with the same window handle. Currently supported ids are...
        /// 
        ///     OBJID_CLIENT - represents the window's client area (including any child windows)
        ///     OBJID_WINDOW - represents the window's non-client area (including caption, frame controls and scrollbars) 
        /// 
        ///     NOTE: When the id is OBJID_WINDOW, we short-circuit most of the virtual override behavior of
        ///     AccessibleObject, and turn the object into a simple wrapper around the inner system object. So 
        ///     for a *user-defined* accessible object, that has NO inner object, its important that the id is
        ///     left as OBJID_CLIENT, otherwise the object will be short-circuited into a total NOP!
        /// 
        ///  
        internal int AccessibleObjectId {
            get { 
                return accObjId; 
            }
            set { 
                accObjId = value;
            }
        }
 
        /// 
        ///  
        ///    Indicates whether this accessible object represents the client area of the window. 
        /// 
        ///  
        internal bool IsClientObject {
            get {
                return AccessibleObjectId == NativeMethods.OBJID_CLIENT;
            } 
        }
 
        ///  
        /// 
        ///    Indicates whether this accessible object represents the non-client area of the window. 
        /// 
        /// 
        internal bool IsNonClientObject {
            get { 
                return AccessibleObjectId == NativeMethods.OBJID_WINDOW;
            } 
        } 

        ///  
        /// 
        /// 
        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        internal IAccessible GetSystemIAccessibleInternal() { 
            return this.systemIAccessible;
        } 
 
        /// 
        ///  
        ///    [To be supplied.]
        /// 
        /// 
        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] 
        protected void UseStdAccessibleObjects(IntPtr handle) {
            UseStdAccessibleObjects(handle, AccessibleObjectId); 
        } 

        ///  
        /// 
        [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected void UseStdAccessibleObjects(IntPtr handle, int objid) {
            // Get a standard accessible Object 
            Guid IID_IAccessible = new Guid(NativeMethods.uuid_IAccessible);
            object acc = null; 
            int result = UnsafeNativeMethods.CreateStdAccessibleObject( 
                                                          new HandleRef(this, handle),
                                                          objid, 
                                                          ref IID_IAccessible,
                                                          ref acc);

            // Get the IEnumVariant interface 
            Guid IID_IEnumVariant = new Guid(NativeMethods.uuid_IEnumVariant);
            object en = null; 
            result = UnsafeNativeMethods.CreateStdAccessibleObject( 
                                                      new HandleRef(this, handle),
                                                      objid, 
                                                      ref IID_IEnumVariant,
                                                      ref en);

            Debug.Assert(acc != null, "SystemIAccessible is null"); 
            Debug.Assert(en != null, "SystemIEnumVariant is null");
 
            if (acc != null || en != null) { 
                systemIAccessible = (IAccessible)acc;
                systemIEnumVariant = (UnsafeNativeMethods.IEnumVariant)en; 
                systemIOleWindow = acc as UnsafeNativeMethods.IOleWindow;
            }
        }
 
        /// 
        ///     Performs custom navigation between parent/child/sibling accessible objects. This is basically 
        ///     just a wrapper for GetSysChild(), that does some of the dirty work, such as wrapping the 
        ///     returned object in a VARIANT. Usage is similar to GetSysChild(). Called prior to calling
        ///     IAccessible.accNavigate on the 'inner' system accessible object. 
        /// 
        /// 
        private bool SysNavigate(int navDir, Object childID, out Object retObject) {
            retObject = null; 

            // Only override system navigation relative to ourselves (since we can't interpret OLEACC child ids) 
            if (!childID.Equals(NativeMethods.CHILDID_SELF)) 
                return false;
 
            // Perform any supported navigation operation (fall back on system for unsupported navigation ops)
            AccessibleObject newObject;
            if (!GetSysChild((AccessibleNavigation) navDir, out newObject))
                return false; 

            // If object found, wrap in a VARIANT. Otherwise return null for 'end of list' (OLEACC expects this) 
            retObject = (newObject == null) ? null : AsVariant(newObject); 

            // Tell caller not to fall back on system behavior now 
            return true;
        }

        ///  
        /// 
        ///      Make sure that the childID is valid. 
        ///  
        internal void ValidateChildID(ref object childID) {
            // An empty childID is considered to be the same as CHILDID_SELF. 
            // Some accessibility programs pass null into our functions, so we
            // need to convert them here.
            if (childID == null) {
                childID = NativeMethods.CHILDID_SELF; 
            }
            else if (childID.Equals(NativeMethods.DISP_E_PARAMNOTFOUND)) { 
                childID = 0; 
            }
            else if (!(childID is Int32)) { 
                // AccExplorer seems to occasionally pass in objects instead of an int ChildID.
                //
                childID = 0;
            } 
        }
 
        private AccessibleObject WrapIAccessible(object iacc) { 
            IAccessible accessible = iacc as IAccessible;
            if (accessible == null) { 
                return null;
            }

            // Check to see if this object already wraps iacc 
            //
            if (this.systemIAccessible == iacc) { 
                return this; 
            }
 
            return new AccessibleObject(accessible);
        }

        ///  
        /// 
        ///  
        /// Return the requested method if it is implemented by the Reflection object.  The 
        /// match is based upon the name and DescriptorInfo which describes the signature
        /// of the method. 
        /// 
        MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers) {
            return typeof(IAccessible).GetMethod(name, bindingAttr, binder, types, modifiers);
        } 

        ///  
        ///  
        /// 
        /// Return the requested method if it is implemented by the Reflection object.  The 
        /// match is based upon the name of the method.  If the object implementes multiple methods
        /// with the same name an AmbiguousMatchException is thrown.
        /// 
        MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr) { 
            return typeof(IAccessible).GetMethod(name, bindingAttr);
        } 
 
        /// 
        ///  
        MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr) {
            return typeof(IAccessible).GetMethods(bindingAttr);
        }
 
        /// 
        ///  
        ///  
        /// Return the requestion field if it is implemented by the Reflection object.  The
        /// match is based upon a name.  There cannot be more than a single field with 
        /// a name.
        /// 
        FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr) {
            return typeof(IAccessible).GetField(name, bindingAttr); 
        }
 
        ///  
        /// 
        FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr) { 
            return typeof(IAccessible).GetFields(bindingAttr);
        }

        ///  
        /// 
        ///  
        /// Return the property based upon name.  If more than one property has the given 
        /// name an AmbiguousMatchException will be thrown.  Returns null if no property
        /// is found. 
        /// 
        PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr) {
            return typeof(IAccessible).GetProperty(name, bindingAttr);
        } 

        ///  
        ///  
        /// 
        /// Return the property based upon the name and Descriptor info describing the property 
        /// indexing.  Return null if no property is found.
        /// 
        PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) {
            return typeof(IAccessible).GetProperty(name, bindingAttr, binder, returnType, types, modifiers); 
        }
 
        ///  
        /// 
        ///  
        /// Returns an array of PropertyInfos for all the properties defined on
        /// the Reflection object.
        /// 
        PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr) { 
            return typeof(IAccessible).GetProperties(bindingAttr);
        } 
 
        /// 
        ///  
        /// 
        /// Return an array of members which match the passed in name.
        /// 
        MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr) { 
            return typeof(IAccessible).GetMember(name, bindingAttr);
        } 
 
        /// 
        ///  
        /// 
        /// Return an array of all of the members defined for this object.
        /// 
        MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr) { 
            return typeof(IAccessible).GetMembers(bindingAttr);
        } 
 
        /// 
        ///  
        /// 
        /// Description of the Binding Process.
        /// We must invoke a method that is accessable and for which the provided
        /// parameters have the most specific match.  A method may be called if 
        /// 1. The number of parameters in the method declaration equals the number of
        /// arguments provided to the invocation 
        /// 2. The type of each argument can be converted by the binder to the 
        /// type of the type of the parameter.
        /// 
        /// The binder will find all of the matching methods.  These method are found based
        /// upon the type of binding requested (MethodInvoke, Get/Set Properties).  The set
        /// of methods is filtered by the name, number of arguments and a set of search modifiers
        /// defined in the Binder. 
        ///
        /// After the method is selected, it will be invoked.  Accessability is checked 
        /// at that point.  The search may be control which set of methods are searched based 
        /// upon the accessibility attribute associated with the method.
        /// 
        /// The BindToMethod method is responsible for selecting the method to be invoked.
        /// For the default binder, the most specific method will be selected.
        ///
        /// This will invoke a specific member... 
        /// @exception If invokeAttr is CreateInstance then all other
        /// Access types must be undefined.  If not we throw an ArgumentException. 
        /// @exception If the invokeAttr is not CreateInstance then an 
        /// ArgumentException when name is null.
        /// @exception ArgumentException when invokeAttr does not specify the type 
        /// @exception ArgumentException when invokeAttr specifies both get and set of
        /// a property or field.
        /// @exception ArgumentException when invokeAttr specifies property set and
        /// invoke method. 
        /// 
        object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) { 
 
            if (args.Length == 0) {
                MemberInfo[] member = typeof(IAccessible).GetMember(name); 
                if (member != null && member.Length > 0 && member[0] is PropertyInfo) {
                    MethodInfo getMethod = ((PropertyInfo)member[0]).GetGetMethod();
                    if (getMethod != null && getMethod.GetParameters().Length > 0) {
                        args = new object[getMethod.GetParameters().Length]; 
                        for (int i = 0; i < args.Length; i++) {
                            args[i] = NativeMethods.CHILDID_SELF; 
                        } 
                    }
                } 
            }
            return typeof(IAccessible).InvokeMember(name, invokeAttr, binder, target, args, modifiers, culture, namedParameters);
        }
 
        /// 
        ///  
        ///  
        /// Return the underlying Type that represents the IReflect Object.  For expando object,
        /// this is the (Object) IReflectInstance.GetType().  For Type object it is this. 
        /// 
        Type IReflect.UnderlyingSystemType {
            get {
                return typeof(IAccessible); 
            }
        } 
 
        private class EnumVariantObject : UnsafeNativeMethods.IEnumVariant {
 
            private int currentChild = 0;
            private AccessibleObject owner;

            public EnumVariantObject(AccessibleObject owner) { 
                Debug.Assert(owner != null, "Cannot create EnumVariantObject with a null owner");
                this.owner = owner; 
            } 

            public EnumVariantObject(AccessibleObject owner, int currentChild) { 
                Debug.Assert(owner != null, "Cannot create EnumVariantObject with a null owner");
                this.owner = owner;
                this.currentChild = currentChild;
            } 

            void UnsafeNativeMethods.IEnumVariant.Clone(UnsafeNativeMethods.IEnumVariant[] v) { 
                v[0] = new EnumVariantObject(owner, currentChild); 
            }
 
            /// 
            /// 
            ///     Resets the child accessible object enumerator.
            ///  
            void UnsafeNativeMethods.IEnumVariant.Reset() {
                currentChild = 0; 
 
                // SECREVIEW: This assert is safe, and is needed to fix VSWhidbey#126319
                // (allow access to children of an AccessibleObject in partial trust). 
                //
                IntSecurity.UnmanagedCode.Assert();
                try {
                    if (owner.systemIEnumVariant != null) 
                        owner.systemIEnumVariant.Reset();
                } 
                finally { 
                    CodeAccessPermission.RevertAssert();
                } 
            }

            /// 
            ///  
            ///     Skips the next n child accessible objects.
            ///  
            void UnsafeNativeMethods.IEnumVariant.Skip(int n) { 
                currentChild += n;
 
                // SECREVIEW: This assert is safe, and is needed to fix VSWhidbey#126319
                // (allow access to children of an AccessibleObject in partial trust).
                //
                IntSecurity.UnmanagedCode.Assert(); 
                try {
                    if (owner.systemIEnumVariant != null) 
                        owner.systemIEnumVariant.Skip(n); 
                }
                finally { 
                    CodeAccessPermission.RevertAssert();
                }
            }
 
            /// 
            ///  
            ///     Gets the next n child accessible objects. 
            /// 
            int UnsafeNativeMethods.IEnumVariant.Next(int n, IntPtr rgvar, int[] ns) { 
                // NOTE: rgvar is a pointer to an array of variants

                if (owner.IsClientObject) {
                    Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "EnumVariantObject: owner = " + owner.ToString() + ", n = " + n); 

                    Debug.Indent(); 
 
                    int childCount;
                    int[] newOrder; 

                    if ((childCount = owner.GetChildCount()) >= 0)
                        NextFromChildCollection(n, rgvar, ns, childCount);
                    else if (owner.systemIEnumVariant == null) 
                        NextEmpty(n, rgvar, ns);
                    else if ((newOrder = owner.GetSysChildOrder()) != null) 
                        NextFromSystemReordered(n, rgvar, ns, newOrder); 
                    else
                        NextFromSystem(n, rgvar, ns); 

                    Debug.Unindent();
                }
                else { 
                    NextFromSystem(n, rgvar, ns);
                } 
 
                // Tell caller whether requested number of items was returned. Once list of items has
                // been exhausted, we return S_FALSE so that caller knows to stop calling this method. 
                return (ns[0] == n) ? NativeMethods.S_OK : NativeMethods.S_FALSE;
            }

            ///  
            ///     When we have the IEnumVariant of an accessible proxy provided by the system (ie.
            ///     OLEACC.DLL), we can fall back on that to return the children. Generally, the system 
            ///     proxy will enumerate the child windows, create a suitable kind of child accessible 
            ///     proxy for each one, and return a set of IDispatch interfaces to these proxy objects.
            ///  
            private void NextFromSystem(int n, IntPtr rgvar, int[] ns) {

                // SECREVIEW: This assert is safe, and is needed to fix VSWhidbey#126319
                // (allow access to children of an AccessibleObject in partial trust). 
                //
                IntSecurity.UnmanagedCode.Assert(); 
                try { 
                    owner.systemIEnumVariant.Next(n, rgvar, ns);
                } 
                finally {
                    CodeAccessPermission.RevertAssert();
                }
 
                currentChild += ns[0];
                Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.IEV.Next: Delegating to systemIEnumVariant"); 
            } 

            ///  
            ///     Sometimes we want to rely on the system-provided behavior to create and return child
            ///     accessible objects, but we want to impose a new order on those objects (or even filter
            ///     some objects out).
            /// 
            ///     This method takes an array of ints that dictates the new order. It queries the system
            ///     for each child individually, and inserts the result into the correct *new* position. 
            /// 
            ///     Note: This code has to make certain *assumptions* about OLEACC.DLL proxy object behavior.
            ///     However, this behavior is well documented. We *assume* the proxy will return a set of 
            ///     child accessible objects that correspond 1:1 with the owning control's child windows,
            ///     and that the default order it returns these objects in is z-order (which also happens
            ///     to be the order that children appear in the Control.Controls[] collection).
            ///  
            private void NextFromSystemReordered(int n, IntPtr rgvar, int[] ns, int[] newOrder) {
                int i; 
 
                for (i = 0; i < n && currentChild < newOrder.Length; ++i) {
                    if (!GotoItem(owner.systemIEnumVariant, newOrder[currentChild], GetAddressOfVariantAtIndex(rgvar, i))) 
                        break;
                    ++currentChild;
                    Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.IEV.Next: adding sys child " + currentChild + " of " + newOrder.Length);
                } 

                ns[0] = i; 
            } 

            ///  
            ///     If we have our own custom accessible child collection, return a set of 1-based integer
            ///     child ids, that the caller will eventually pass back to us via IAccessible.get_accChild().
            /// 
            private void NextFromChildCollection(int n, IntPtr rgvar, int[] ns, int childCount) { 
                int i;
 
                for (i = 0; i < n && currentChild < childCount; ++i) { 
                    ++currentChild;
                    Marshal.GetNativeVariantForObject(((object) currentChild), GetAddressOfVariantAtIndex(rgvar, i)); 
                    Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.IEV.Next: adding own child " + currentChild + " of " + childCount);
                }

                ns[0] = i; 
            }
 
            ///  
            ///     Default behavior if there is no custom child collection or system-provided
            ///     proxy to fall back on. In this case, we return an empty child collection. 
            /// 
            private void NextEmpty(int n, IntPtr rgvar, int[] ns) {
                ns[0] = 0;
                Debug.WriteLineIf(CompModSwitches.MSAA.TraceInfo, "AccessibleObject.IEV.Next: no children to add"); 
            }
 
            ///  
            ///     Given an IEnumVariant interface, this method jumps to a specific
            ///     item in the collection and extracts the result for that one item. 
            /// 
            private static bool GotoItem(UnsafeNativeMethods.IEnumVariant iev, int index, IntPtr variantPtr) {
                int[] ns = new int[1];
 
                // SECREVIEW: This assert is safe, and is needed to fix VSWhidbey#126319
                // (allow access to children of an AccessibleObject in partial trust). 
                // 
                IntSecurity.UnmanagedCode.Assert();
                try { 
                    iev.Reset();
                    iev.Skip(index);
                    iev.Next(1, variantPtr, ns);
                } 
                finally {
                    CodeAccessPermission.RevertAssert(); 
                } 

                return (ns[0] == 1); 
            }

            /// 
            ///     Given an array of pointers to variants, calculate address of a given array element. 
            /// 
            private static IntPtr GetAddressOfVariantAtIndex(IntPtr variantArrayPtr, int index) { 
                int variantSize = 8 + (IntPtr.Size * 2); 
                return (IntPtr) ((ulong) variantArrayPtr + ((ulong) index) * ((ulong) variantSize));
            } 

        }

    } // end class AccessibleObject 

    ///  
    ///    Internal object passed out to OLEACC clients via WM_GETOBJECT. 
    ///    NOTE: THIS CLASS IS INTERNAL FOR SECURITY REASONS AND SHOULD REMAIN SO!
    ///  
    internal sealed class InternalAccessibleObject : StandardOleMarshalObject,
                                    UnsafeNativeMethods.IAccessibleInternal,
                                    System.Reflection.IReflect,
                                    UnsafeNativeMethods.IEnumVariant, 
                                    UnsafeNativeMethods.IOleWindow {
 
        private IAccessible publicIAccessible;                       // AccessibleObject as IAccessible 
        private UnsafeNativeMethods.IEnumVariant publicIEnumVariant; // AccessibleObject as IEnumVariant
        private UnsafeNativeMethods.IOleWindow publicIOleWindow;     // AccessibleObject as IOleWindow 
        private IReflect publicIReflect;                             // AccessibleObject as IReflect

        /// 
        ///     Create a new wrapper. Protect this with UnmanagedCode Permission 
        /// 
        [ 
        SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode) 
        ]
        internal InternalAccessibleObject(AccessibleObject accessibleImplemention) { 
            // Get all the casts done here to catch any issues early
            publicIAccessible = (IAccessible) accessibleImplemention;
            publicIEnumVariant = (UnsafeNativeMethods.IEnumVariant) accessibleImplemention;
            publicIOleWindow = (UnsafeNativeMethods.IOleWindow) accessibleImplemention; 
            publicIReflect = (IReflect) accessibleImplemention;
            // Note: Deliberately not holding onto AccessibleObject to enforce all access through the interfaces 
        } 

        ///  
        ///     If the given object is an AccessibleObject return it as a InternalAccessibleObject
        ///     This ensures we wrap all AccessibleObjects before handing them out to OLEACC
        /// 
        private object AsNativeAccessible(object accObject) { 
            if (accObject is AccessibleObject) {
                return new InternalAccessibleObject(accObject as AccessibleObject); 
            } 
            else {
                return accObject; 
            }
        }

        // 
        // IAccessibleInternal implementation...
        // 
 
        void UnsafeNativeMethods.IAccessibleInternal.accDoDefaultAction(object childID) {
            IntSecurity.UnmanagedCode.Assert(); 
            publicIAccessible.accDoDefaultAction(childID);
        }

        object UnsafeNativeMethods.IAccessibleInternal.accHitTest(int xLeft, int yTop) { 
            IntSecurity.UnmanagedCode.Assert();
            return AsNativeAccessible(publicIAccessible.accHitTest(xLeft, yTop)); 
        } 

        void UnsafeNativeMethods.IAccessibleInternal.accLocation(out int l, out int t, out int w, out int h, Object childID) { 
            IntSecurity.UnmanagedCode.Assert();
            publicIAccessible.accLocation(out l, out t, out w, out h, childID);
        }
 
        object UnsafeNativeMethods.IAccessibleInternal.accNavigate(int navDir, object childID) {
            IntSecurity.UnmanagedCode.Assert(); 
            return AsNativeAccessible(publicIAccessible.accNavigate(navDir, childID)); 
        }
 
        void UnsafeNativeMethods.IAccessibleInternal.accSelect(int flagsSelect, Object childID) {
            IntSecurity.UnmanagedCode.Assert();
            publicIAccessible.accSelect(flagsSelect, childID);
        } 

        object UnsafeNativeMethods.IAccessibleInternal.get_accChild(object childID) { 
            IntSecurity.UnmanagedCode.Assert(); 
            return AsNativeAccessible(publicIAccessible.get_accChild(childID));
        } 

        int UnsafeNativeMethods.IAccessibleInternal.get_accChildCount() {
            IntSecurity.UnmanagedCode.Assert();
            return publicIAccessible.accChildCount; 
        }
 
        string UnsafeNativeMethods.IAccessibleInternal.get_accDefaultAction(Object childID) { 
            IntSecurity.UnmanagedCode.Assert();
            return publicIAccessible.get_accDefaultAction(childID); 
        }

        string UnsafeNativeMethods.IAccessibleInternal.get_accDescription(Object childID) {
            IntSecurity.UnmanagedCode.Assert(); 
            return publicIAccessible.get_accDescription(childID);
        } 
 
        object UnsafeNativeMethods.IAccessibleInternal.get_accFocus() {
            IntSecurity.UnmanagedCode.Assert(); 
            return AsNativeAccessible(publicIAccessible.accFocus);
        }

        string UnsafeNativeMethods.IAccessibleInternal.get_accHelp(Object childID) { 
            IntSecurity.UnmanagedCode.Assert();
            return publicIAccessible.get_accHelp(childID); 
        } 

        int UnsafeNativeMethods.IAccessibleInternal.get_accHelpTopic(out string pszHelpFile, Object childID) { 
            IntSecurity.UnmanagedCode.Assert();
            return publicIAccessible.get_accHelpTopic(out pszHelpFile, childID);
        }
 
        string UnsafeNativeMethods.IAccessibleInternal.get_accKeyboardShortcut(Object childID) {
            IntSecurity.UnmanagedCode.Assert(); 
            return publicIAccessible.get_accKeyboardShortcut(childID); 
        }
 
        string UnsafeNativeMethods.IAccessibleInternal.get_accName(Object childID) {
            IntSecurity.UnmanagedCode.Assert();
            return publicIAccessible.get_accName(childID);
        } 

        object UnsafeNativeMethods.IAccessibleInternal.get_accParent() { 
            IntSecurity.UnmanagedCode.Assert(); 
            return AsNativeAccessible(publicIAccessible.accParent);
        } 

        object UnsafeNativeMethods.IAccessibleInternal.get_accRole(object childID) {
 		    IntSecurity.UnmanagedCode.Assert();
		    return publicIAccessible.get_accRole(childID); 
	    }
 
        object UnsafeNativeMethods.IAccessibleInternal.get_accSelection() { 
            IntSecurity.UnmanagedCode.Assert();
            return AsNativeAccessible(publicIAccessible.accSelection); 
        }

        object UnsafeNativeMethods.IAccessibleInternal.get_accState(object childID) {
            IntSecurity.UnmanagedCode.Assert(); 
            return publicIAccessible.get_accState(childID);
        } 
 
        string UnsafeNativeMethods.IAccessibleInternal.get_accValue(object childID) {
            IntSecurity.UnmanagedCode.Assert(); 
            return publicIAccessible.get_accValue(childID);
        }

        void UnsafeNativeMethods.IAccessibleInternal.set_accName(Object childID, string newName) { 
            IntSecurity.UnmanagedCode.Assert();
            publicIAccessible.set_accName(childID, newName); 
        } 

        void UnsafeNativeMethods.IAccessibleInternal.set_accValue(Object childID, string newValue) { 
            IntSecurity.UnmanagedCode.Assert();
            publicIAccessible.set_accValue(childID, newValue);
        }
 
        //
        // IEnumVariant implementation... 
        // 

        void UnsafeNativeMethods.IEnumVariant.Clone(UnsafeNativeMethods.IEnumVariant[] v) { 
            IntSecurity.UnmanagedCode.Assert();
            publicIEnumVariant.Clone(v);
        }
 
        int UnsafeNativeMethods.IEnumVariant.Next(int n, IntPtr rgvar, int[] ns) {
            IntSecurity.UnmanagedCode.Assert(); 
            return publicIEnumVariant.Next(n, rgvar, ns); 
        }
 
        void UnsafeNativeMethods.IEnumVariant.Reset() {
            IntSecurity.UnmanagedCode.Assert();
            publicIEnumVariant.Reset();
        } 

        void UnsafeNativeMethods.IEnumVariant.Skip(int n) { 
            IntSecurity.UnmanagedCode.Assert(); 
            publicIEnumVariant.Skip(n);
        } 

        //
        // IOleWindow implementation...
        // 

        int UnsafeNativeMethods.IOleWindow.GetWindow(out IntPtr hwnd) { 
            IntSecurity.UnmanagedCode.Assert(); 
            return publicIOleWindow.GetWindow(out hwnd);
        } 

        void UnsafeNativeMethods.IOleWindow.ContextSensitiveHelp(int fEnterMode) {
            IntSecurity.UnmanagedCode.Assert();
            publicIOleWindow.ContextSensitiveHelp(fEnterMode); 
        }
 
        // 
        // IReflect implementation...
        // 

        MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers) {
            return publicIReflect.GetMethod(name, bindingAttr, binder, types, modifiers);
        } 

        MethodInfo IReflect.GetMethod(string name, BindingFlags bindingAttr) { 
            return publicIReflect.GetMethod(name, bindingAttr); 
        }
 
        MethodInfo[] IReflect.GetMethods(BindingFlags bindingAttr) {
            return publicIReflect.GetMethods(bindingAttr);
        }
 
        FieldInfo IReflect.GetField(string name, BindingFlags bindingAttr) {
            return publicIReflect.GetField(name, bindingAttr); 
        } 

        FieldInfo[] IReflect.GetFields(BindingFlags bindingAttr) { 
            return publicIReflect.GetFields(bindingAttr);
        }

        PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr) { 
            return publicIReflect.GetProperty(name, bindingAttr);
        } 
 
        PropertyInfo IReflect.GetProperty(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) {
            return publicIReflect.GetProperty(name, bindingAttr, binder, returnType, types, modifiers); 
        }

        PropertyInfo[] IReflect.GetProperties(BindingFlags bindingAttr) {
            return publicIReflect.GetProperties(bindingAttr); 
        }
 
        MemberInfo[] IReflect.GetMember(string name, BindingFlags bindingAttr) { 
            return publicIReflect.GetMember(name, bindingAttr);
        } 

        MemberInfo[] IReflect.GetMembers(BindingFlags bindingAttr) {
            return publicIReflect.GetMembers(bindingAttr);
        } 

        object IReflect.InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) { 
            IntSecurity.UnmanagedCode.Demand(); 
            return publicIReflect.InvokeMember(name, invokeAttr, binder, publicIAccessible, args, modifiers, culture, namedParameters);
        } 

        Type IReflect.UnderlyingSystemType {
            get {
                IReflect r = publicIReflect; 
                return publicIReflect.UnderlyingSystemType;
            } 
        } 

    } // end class InternalAccessibleObject 

}

// 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