Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / WinForms / Managed / System / WinForms / AccessibleObject.cs / 1305376 / 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; ////// /// [ComVisible(true)] public class AccessibleObject : StandardOleMarshalObject, IReflect, IAccessible, UnsafeNativeMethods.IEnumVariant, UnsafeNativeMethods.IOleWindow { // Member variables ///Provides an implementation for an object that can be inspected by an /// accessibility application. ////// /// private IAccessible systemIAccessible = null; ///Specifies the ///interface 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 ///Specifies the /// ///used by this . public AccessibleObject() { } // This constructor is used ONLY for wrapping system IAccessible objects // private AccessibleObject(IAccessible iAcc) { this.systemIAccessible = iAcc; this.systemWrapper = true; } // Properties /// /// /// 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 the bounds of the accessible object, in screen coordinates. ////// /// 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 default action for an object. ////// /// 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 the object's visual appearance to the user. ////// /// 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 a description of what the object does or how the object is used. ////// /// 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 the object shortcut key or access key /// for an accessible object. ////// /// 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; } } } } } ///Gets /// or sets the object name. ////// /// public virtual AccessibleObject Parent { [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] get { if (systemIAccessible != null) { return WrapIAccessible(systemIAccessible.accParent); } else { return null; } } } ///When overridden in a derived class, gets or sets the parent of an accessible object. ////// /// public virtual AccessibleRole Role { get { if (systemIAccessible != null) { return (AccessibleRole) systemIAccessible.get_accRole(NativeMethods.CHILDID_SELF); } else { return AccessibleRole.None; } } } ///Gets the role 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 /// the state of this 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 ///Gets or sets the value of an accessible object. ////// /// public virtual AccessibleObject GetChild(int index) { return null; } ///When overridden in a derived class, gets the accessible child corresponding to the specified /// index. ////// /// public virtual int GetChildCount() { return -1; } ///When overridden in a derived class, gets the number of children /// belonging to an accessible object. ////// /// 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; } ////// /// 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; } ///When overridden in a derived class, /// gets the object that has the keyboard focus. ////// /// 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; } ////// Gets an identifier for a Help topic and the path to the Help file associated /// with this accessible object. ////// /// 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; } ///When overridden in /// a derived class, gets the currently selected child. ////// /// 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; } ///Return the child object at the given screen coordinates. ////// /// /// 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 the default action /// ////// /// /// 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; } ////// Perform a hit test /// ////// /// /// 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; } } ////// The location of the 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; } ////// Navigate to another 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; } } ////// Select an accessible object. /// ////// /// 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; } } ////// /// /// 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; } ////// Returns a child Accessible object /// ////// /// /// 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; } } ////// /// /// 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 default action /// ////// /// /// 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; } ////// Return the object or child description /// ////// /// 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; } } ////// /// /// 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 help for this accessible object. /// ////// /// /// 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 help topic /// ////// /// /// 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 keyboard shortcut /// ////// /// /// string IAccessible.get_accName(object childID) { return get_accNameInternal(childID); } ////// Return the object or child name /// ////// 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); } } ////// /// /// 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; } ////// The role property describes an object's purpose in terms of its /// relationship with sibling or child objects. /// ////// /// /// 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; } } ////// /// /// 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 state /// ////// /// /// 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; } ////// Return the object or child value /// ////// /// /// 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 name /// ////// /// /// 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; } } ////// Set the object or child value /// ////// /// [[....] - 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 } /// /// /// void UnsafeNativeMethods.IEnumVariant.Clone(UnsafeNativeMethods.IEnumVariant[] v) { EnumVariant.Clone(v); } ////// Clone this accessible object. /// ////// /// int UnsafeNativeMethods.IEnumVariant.Next(int n, IntPtr rgvar, int[] ns) { return EnumVariant.Next(n, rgvar, ns); } ////// Obtain the next n children of this accessible object. /// ////// /// Resets the child accessible object enumerator. /// void UnsafeNativeMethods.IEnumVariant.Reset() { EnumVariant.Reset(); } ////// /// void UnsafeNativeMethods.IEnumVariant.Skip(int n) { EnumVariant.Skip(n); } ////// Skip the next n child accessible objects /// ////// /// [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; } ///When overridden in a derived class, /// navigates to another 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; } ////// Selects this accessible object. /// ////// /// 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. // //----------------------------------------------------------------------------- /* */ 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; ////// /// [ComVisible(true)] public class AccessibleObject : StandardOleMarshalObject, IReflect, IAccessible, UnsafeNativeMethods.IEnumVariant, UnsafeNativeMethods.IOleWindow { // Member variables ///Provides an implementation for an object that can be inspected by an /// accessibility application. ////// /// private IAccessible systemIAccessible = null; ///Specifies the ///interface 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 ///Specifies the /// ///used by this . public AccessibleObject() { } // This constructor is used ONLY for wrapping system IAccessible objects // private AccessibleObject(IAccessible iAcc) { this.systemIAccessible = iAcc; this.systemWrapper = true; } // Properties /// /// /// 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 the bounds of the accessible object, in screen coordinates. ////// /// 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 default action for an object. ////// /// 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 the object's visual appearance to the user. ////// /// 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 a description of what the object does or how the object is used. ////// /// 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 the object shortcut key or access key /// for an accessible object. ////// /// 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; } } } } } ///Gets /// or sets the object name. ////// /// public virtual AccessibleObject Parent { [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] get { if (systemIAccessible != null) { return WrapIAccessible(systemIAccessible.accParent); } else { return null; } } } ///When overridden in a derived class, gets or sets the parent of an accessible object. ////// /// public virtual AccessibleRole Role { get { if (systemIAccessible != null) { return (AccessibleRole) systemIAccessible.get_accRole(NativeMethods.CHILDID_SELF); } else { return AccessibleRole.None; } } } ///Gets the role 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 /// the state of this 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 ///Gets or sets the value of an accessible object. ////// /// public virtual AccessibleObject GetChild(int index) { return null; } ///When overridden in a derived class, gets the accessible child corresponding to the specified /// index. ////// /// public virtual int GetChildCount() { return -1; } ///When overridden in a derived class, gets the number of children /// belonging to an accessible object. ////// /// 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; } ////// /// 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; } ///When overridden in a derived class, /// gets the object that has the keyboard focus. ////// /// 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; } ////// Gets an identifier for a Help topic and the path to the Help file associated /// with this accessible object. ////// /// 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; } ///When overridden in /// a derived class, gets the currently selected child. ////// /// 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; } ///Return the child object at the given screen coordinates. ////// /// /// 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 the default action /// ////// /// /// 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; } ////// Perform a hit test /// ////// /// /// 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; } } ////// The location of the 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; } ////// Navigate to another 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; } } ////// Select an accessible object. /// ////// /// 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; } } ////// /// /// 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; } ////// Returns a child Accessible object /// ////// /// /// 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; } } ////// /// /// 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 default action /// ////// /// /// 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; } ////// Return the object or child description /// ////// /// 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; } } ////// /// /// 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 help for this accessible object. /// ////// /// /// 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 help topic /// ////// /// /// 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 keyboard shortcut /// ////// /// /// string IAccessible.get_accName(object childID) { return get_accNameInternal(childID); } ////// Return the object or child name /// ////// 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); } } ////// /// /// 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; } ////// The role property describes an object's purpose in terms of its /// relationship with sibling or child objects. /// ////// /// /// 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; } } ////// /// /// 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 state /// ////// /// /// 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; } ////// Return the object or child value /// ////// /// /// 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 name /// ////// /// /// 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; } } ////// Set the object or child value /// ////// /// [[....] - 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 } /// /// /// void UnsafeNativeMethods.IEnumVariant.Clone(UnsafeNativeMethods.IEnumVariant[] v) { EnumVariant.Clone(v); } ////// Clone this accessible object. /// ////// /// int UnsafeNativeMethods.IEnumVariant.Next(int n, IntPtr rgvar, int[] ns) { return EnumVariant.Next(n, rgvar, ns); } ////// Obtain the next n children of this accessible object. /// ////// /// Resets the child accessible object enumerator. /// void UnsafeNativeMethods.IEnumVariant.Reset() { EnumVariant.Reset(); } ////// /// void UnsafeNativeMethods.IEnumVariant.Skip(int n) { EnumVariant.Skip(n); } ////// Skip the next n child accessible objects /// ////// /// [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; } ///When overridden in a derived class, /// navigates to another 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; } ////// Selects this accessible object. /// ////// /// 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.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ZipIOEndOfCentralDirectoryBlock.cs
- QueuePathDialog.cs
- StrokeCollectionDefaultValueFactory.cs
- NamespaceEmitter.cs
- DocumentPageHost.cs
- ExpressionParser.cs
- TablePattern.cs
- ToolBarDesigner.cs
- FreeIndexList.cs
- FrameworkElementAutomationPeer.cs
- GeneratedView.cs
- HWStack.cs
- SplineKeyFrames.cs
- ProvideValueServiceProvider.cs
- WebConfigurationHostFileChange.cs
- TypeDependencyAttribute.cs
- AppModelKnownContentFactory.cs
- NameValuePair.cs
- XmlEncodedRawTextWriter.cs
- XmlValidatingReaderImpl.cs
- HandleCollector.cs
- TextEditorCharacters.cs
- HtmlButton.cs
- Int32.cs
- CompilerScope.cs
- WinInet.cs
- BaseTemplateBuildProvider.cs
- Configuration.cs
- AsyncPostBackTrigger.cs
- DnsPermission.cs
- ComplexPropertyEntry.cs
- OdbcError.cs
- WindowsPrincipal.cs
- ListBase.cs
- XmlBinaryReader.cs
- TemplatedEditableDesignerRegion.cs
- WebPartVerbsEventArgs.cs
- UniformGrid.cs
- UserControl.cs
- UserInitiatedNavigationPermission.cs
- TcpChannelHelper.cs
- Delegate.cs
- FormViewUpdateEventArgs.cs
- SchemaSetCompiler.cs
- Registry.cs
- ToolboxComponentsCreatingEventArgs.cs
- EntityPropertyMappingAttribute.cs
- DataTableClearEvent.cs
- TimestampInformation.cs
- VideoDrawing.cs
- VScrollBar.cs
- XmlSchemaObjectTable.cs
- DetailsViewUpdatedEventArgs.cs
- AndCondition.cs
- FragmentNavigationEventArgs.cs
- ipaddressinformationcollection.cs
- ElapsedEventArgs.cs
- PersonalizableAttribute.cs
- SelectionRangeConverter.cs
- CaseInsensitiveOrdinalStringComparer.cs
- CornerRadiusConverter.cs
- PiiTraceSource.cs
- ShapingEngine.cs
- RequiredFieldValidator.cs
- InitializerFacet.cs
- QilFunction.cs
- FormViewDeleteEventArgs.cs
- WebPartEditorCancelVerb.cs
- SafeNativeMethods.cs
- IisTraceWebEventProvider.cs
- ListComponentEditorPage.cs
- SerializationSectionGroup.cs
- connectionpool.cs
- LayoutTable.cs
- MetadataItemCollectionFactory.cs
- QueryActivatableWorkflowsCommand.cs
- AstTree.cs
- Convert.cs
- TimeSpanValidator.cs
- ManagementScope.cs
- NavigationPropertyEmitter.cs
- DayRenderEvent.cs
- PopOutPanel.cs
- URLBuilder.cs
- ObjectQuery.cs
- URI.cs
- FormViewRow.cs
- DnsEndPoint.cs
- SerialErrors.cs
- MutexSecurity.cs
- DynamicPropertyReader.cs
- WebServicesInteroperability.cs
- AQNBuilder.cs
- SubclassTypeValidator.cs
- Rule.cs
- ActivityIdHeader.cs
- VirtualizingPanel.cs
- XmlLanguage.cs
- RetriableClipboard.cs
- PathNode.cs