Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / UIAutomation / UIAutomationClient / System / Windows / Automation / AutomationElement.cs / 1 / AutomationElement.cs
//---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // // Description: Main class used by Automation clients, represents a UI element // // History: // 02/06/2003 : BrendanM Created // //--------------------------------------------------------------------------- using System.Windows.Automation; using System.Windows.Automation.Provider; using System; using System.Runtime.Serialization; using System.Security.Permissions; using System.Collections; using System.Collections.Specialized; using System.Diagnostics; using System.ComponentModel; using MS.Win32; using MS.Internal.Automation; using System.Runtime.InteropServices; #if EVENT_TRACING_PROPERTY using Microsoft.Win32.Diagnostics; #endif // PRESHARP: In order to avoid generating warnings about unkown message numbers and unknown pragmas. #pragma warning disable 1634, 1691 namespace System.Windows.Automation { ////// Represents an element in the UIAutomation tree. /// #if (INTERNAL_COMPILE) internal sealed class AutomationElement //: IDisposable #else public sealed class AutomationElement #endif { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors // Private ctor, used mostly by CacheHelper when reconstructing AutomationElements from // a CacheResponse. internal AutomationElement(SafeNodeHandle hnode, object[,] cachedValues, int cachedValuesIndex, UiaCoreApi.UiaCacheRequest request) { _hnode = hnode; // Can be IntPtr.Zero for a lightweight object _cachedValues = cachedValues; // Can be null if there are no cached properties for this node _cachedValuesIndex = cachedValuesIndex; _request = request; // Set RuntimeId (if available; 'as int[]' filters out AutomationElement.NotAvailable) _runtimeId = LookupCachedValue(AutomationElement.RuntimeIdProperty, false, true) as int[]; // // One scenario that allows for null runtimeID - doing UpdatedCache() on a node and asking only // for children - gives us back a placeholder node that only has valid .CachedChildren, // the node itself doesn't have any cached properties or a node. // Since null is a valid value for these, we need another value to // indicate that they were not requested - it's a bit obscure, but // 'this' works well here, since these can never have it as legal value. _cachedParent = this; _cachedFirstChild = this; _cachedNextSibling = this; } ////// Overrides Object.Finalize /// ~AutomationElement() { // } // Used by methods that return non-cached AutomationElements - examples currently include // AutomationElements returned as properties (SelecitonContainer, RowHeaders). internal static AutomationElement Wrap(SafeNodeHandle hnode) { if (hnode == null || hnode.IsInvalid) { return null; } return new AutomationElement(hnode, null, 0, null); } #endregion Constructors //------------------------------------------------------ // // Public Constants / Readonly Fields // //----------------------------------------------------- #region Public Constants and Readonly Fields ////// Indicates that a element does not support the requested value /// public static readonly object NotSupported = AutomationElementIdentifiers.NotSupported; ///Property ID: Indicates that this element should be included in the Control view of the tree public static readonly AutomationProperty IsControlElementProperty = AutomationElementIdentifiers.IsControlElementProperty; ///Property ID: The ControlType of this Element public static readonly AutomationProperty ControlTypeProperty = AutomationElementIdentifiers.ControlTypeProperty; ///Property ID: NativeWindowHandle - Window Handle, if the underlying control is a Window public static readonly AutomationProperty IsContentElementProperty = AutomationElementIdentifiers.IsContentElementProperty; ///Property ID: The AutomationElement that labels this element public static readonly AutomationProperty LabeledByProperty = AutomationElementIdentifiers.LabeledByProperty; ///Property ID: NativeWindowHandle - Window Handle, if the underlying control is a Window public static readonly AutomationProperty NativeWindowHandleProperty = AutomationElementIdentifiers.NativeWindowHandleProperty; ///Property ID: AutomationId - An identifier for an element that is unique within its containing element. public static readonly AutomationProperty AutomationIdProperty = AutomationElementIdentifiers.AutomationIdProperty; ///Property ID: ItemType - An application-level property used to indicate what the items in a list represent. public static readonly AutomationProperty ItemTypeProperty = AutomationElementIdentifiers.ItemTypeProperty; ///Property ID: True if the control is a password protected field. public static readonly AutomationProperty IsPasswordProperty = AutomationElementIdentifiers.IsPasswordProperty; ///Property ID: Localized control type description (eg. "Button") public static readonly AutomationProperty LocalizedControlTypeProperty = AutomationElementIdentifiers.LocalizedControlTypeProperty; ///Property ID: name of this instance of control public static readonly AutomationProperty NameProperty = AutomationElementIdentifiers.NameProperty; ///Property ID: Hot-key equivalent for this command item. (eg. Ctrl-P for Print) public static readonly AutomationProperty AcceleratorKeyProperty = AutomationElementIdentifiers.AcceleratorKeyProperty; ///Property ID: Keys used to move focus to this control public static readonly AutomationProperty AccessKeyProperty = AutomationElementIdentifiers.AccessKeyProperty; ///Property ID: HasKeyboardFocus public static readonly AutomationProperty HasKeyboardFocusProperty = AutomationElementIdentifiers.HasKeyboardFocusProperty; ///Property ID: IsKeyboardFocusable public static readonly AutomationProperty IsKeyboardFocusableProperty = AutomationElementIdentifiers.IsKeyboardFocusableProperty; ///Property ID: Enabled public static readonly AutomationProperty IsEnabledProperty = AutomationElementIdentifiers.IsEnabledProperty; ///Property ID: BoundingRectangle - bounding rectangle public static readonly AutomationProperty BoundingRectangleProperty = AutomationElementIdentifiers.BoundingRectangleProperty; ///Property ID: id of process that this element lives in public static readonly AutomationProperty ProcessIdProperty = AutomationElementIdentifiers.ProcessIdProperty; ///Property ID: RuntimeId - runtime unique ID public static readonly AutomationProperty RuntimeIdProperty = AutomationElementIdentifiers.RuntimeIdProperty; ///Property ID: ClassName - name of underlying class - implementation dependant, but useful for test public static readonly AutomationProperty ClassNameProperty = AutomationElementIdentifiers.ClassNameProperty; ///Property ID: HelpText - brief description of what this control does public static readonly AutomationProperty HelpTextProperty = AutomationElementIdentifiers.HelpTextProperty; ///Property ID: ClickablePoint - Set by provider, used internally for GetClickablePoint public static readonly AutomationProperty ClickablePointProperty = AutomationElementIdentifiers.ClickablePointProperty; ///Property ID: Culture - Returns the culture that provides information about the control's content. public static readonly AutomationProperty CultureProperty = AutomationElementIdentifiers.CultureProperty; ///Property ID: Offscreen - Determined to be not-visible to the sighted user public static readonly AutomationProperty IsOffscreenProperty = AutomationElementIdentifiers.IsOffscreenProperty; ///Property ID: Orientation - Identifies whether a control is positioned in a specfic direction public static readonly AutomationProperty OrientationProperty = AutomationElementIdentifiers.OrientationProperty; ///Property ID: FrameworkId - Identifies the underlying UI framework's name for the element being accessed public static readonly AutomationProperty FrameworkIdProperty = AutomationElementIdentifiers.FrameworkIdProperty; ///Property ID: IsRequiredForForm - Identifies weather an edit field is required to be filled out on a form public static readonly AutomationProperty IsRequiredForFormProperty = AutomationElementIdentifiers.IsRequiredForFormProperty; ///Property ID: ItemStatus - Identifies the status of the visual representation of a complex item public static readonly AutomationProperty ItemStatusProperty = AutomationElementIdentifiers.ItemStatusProperty; #region IsNnnnPatternAvailable properties ///Property that indicates whether the DockPattern is available for this AutomationElement public static readonly AutomationProperty IsDockPatternAvailableProperty = AutomationElementIdentifiers.IsDockPatternAvailableProperty; ///Property that indicates whether the ExpandCollapsePattern is available for this AutomationElement public static readonly AutomationProperty IsExpandCollapsePatternAvailableProperty = AutomationElementIdentifiers.IsExpandCollapsePatternAvailableProperty; ///Property that indicates whether the GridItemPattern is available for this AutomationElement public static readonly AutomationProperty IsGridItemPatternAvailableProperty = AutomationElementIdentifiers.IsGridItemPatternAvailableProperty; ///Property that indicates whether the GridPattern is available for this AutomationElement public static readonly AutomationProperty IsGridPatternAvailableProperty = AutomationElementIdentifiers.IsGridPatternAvailableProperty; ///Property that indicates whether the InvokePattern is available for this AutomationElement public static readonly AutomationProperty IsInvokePatternAvailableProperty = AutomationElementIdentifiers.IsInvokePatternAvailableProperty; ///Property that indicates whether the MultipleViewPattern is available for this AutomationElement public static readonly AutomationProperty IsMultipleViewPatternAvailableProperty = AutomationElementIdentifiers.IsMultipleViewPatternAvailableProperty; ///Property that indicates whether the RangeValuePattern is available for this AutomationElement public static readonly AutomationProperty IsRangeValuePatternAvailableProperty = AutomationElementIdentifiers.IsRangeValuePatternAvailableProperty; ///Property that indicates whether the SelectionItemPattern is available for this AutomationElement public static readonly AutomationProperty IsSelectionItemPatternAvailableProperty = AutomationElementIdentifiers.IsSelectionItemPatternAvailableProperty; ///Property that indicates whether the SelectionPattern is available for this AutomationElement public static readonly AutomationProperty IsSelectionPatternAvailableProperty = AutomationElementIdentifiers.IsSelectionPatternAvailableProperty; ///Property that indicates whether the ScrollPattern is available for this AutomationElement public static readonly AutomationProperty IsScrollPatternAvailableProperty = AutomationElementIdentifiers.IsScrollPatternAvailableProperty; ///Property that indicates whether the ScrollItemPattern is available for this AutomationElement public static readonly AutomationProperty IsScrollItemPatternAvailableProperty = AutomationElementIdentifiers.IsScrollItemPatternAvailableProperty; ///Property that indicates whether the TablePattern is available for this AutomationElement public static readonly AutomationProperty IsTablePatternAvailableProperty = AutomationElementIdentifiers.IsTablePatternAvailableProperty; ///Property that indicates whether the TableItemPattern is available for this AutomationElement public static readonly AutomationProperty IsTableItemPatternAvailableProperty = AutomationElementIdentifiers.IsTableItemPatternAvailableProperty; ///Property that indicates whether the TextPattern is available for this AutomationElement public static readonly AutomationProperty IsTextPatternAvailableProperty = AutomationElementIdentifiers.IsTextPatternAvailableProperty; ///Property that indicates whether the TogglePattern is available for this AutomationElement public static readonly AutomationProperty IsTogglePatternAvailableProperty = AutomationElementIdentifiers.IsTogglePatternAvailableProperty; ///Property that indicates whether the TransformPattern is available for this AutomationElement public static readonly AutomationProperty IsTransformPatternAvailableProperty = AutomationElementIdentifiers.IsTransformPatternAvailableProperty; ///Property that indicates whether the ValuePattern is available for this AutomationElement public static readonly AutomationProperty IsValuePatternAvailableProperty = AutomationElementIdentifiers.IsValuePatternAvailableProperty; ///Property that indicates whether the WindowPattern is available for this AutomationElement public static readonly AutomationProperty IsWindowPatternAvailableProperty = AutomationElementIdentifiers.IsWindowPatternAvailableProperty; #endregion IsNnnnPatternAvailable properties #region Events ///Event ID: ToolTipOpenedEvent - indicates a tooltip has appeared public static readonly AutomationEvent ToolTipOpenedEvent = AutomationElementIdentifiers.ToolTipOpenedEvent; ///Event ID: ToolTipClosedEvent - indicates a tooltip has closed. public static readonly AutomationEvent ToolTipClosedEvent = AutomationElementIdentifiers.ToolTipClosedEvent; ///Event ID: StructureChangedEvent - used mainly by servers to notify of structure changed events. Clients use AddStructureChangedHandler. public static readonly AutomationEvent StructureChangedEvent = AutomationElementIdentifiers.StructureChangedEvent; ///Event ID: MenuOpened - Indicates an a menu has opened. public static readonly AutomationEvent MenuOpenedEvent = AutomationElementIdentifiers.MenuOpenedEvent; ///Event ID: AutomationPropertyChangedEvent - used mainly by servers to notify of property changes. Clients use AddPropertyChangedListener. public static readonly AutomationEvent AutomationPropertyChangedEvent = AutomationElementIdentifiers.AutomationPropertyChangedEvent; ///Event ID: AutomationFocusChangedEvent - used mainly by servers to notify of focus changed events. Clients use AddAutomationFocusChangedListener. public static readonly AutomationEvent AutomationFocusChangedEvent = AutomationElementIdentifiers.AutomationFocusChangedEvent; ///Event ID: AsyncContentLoadedEvent - indicates an async content loaded event. public static readonly AutomationEvent AsyncContentLoadedEvent = AutomationElementIdentifiers.AsyncContentLoadedEvent; ///Event ID: MenuClosed - Indicates an a menu has closed. public static readonly AutomationEvent MenuClosedEvent = AutomationElementIdentifiers.MenuClosedEvent; ///Event ID: LayoutInvalidated - Indicates that many element locations/extents/offscreenedness have changed. public static readonly AutomationEvent LayoutInvalidatedEvent = AutomationElementIdentifiers.LayoutInvalidatedEvent; #endregion Events #endregion Public Constants and Readonly Fields //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods #region Equality ////// Overrides Object.Equals /// /// The Object to compare with the current object ///true if the AutomationElements refer to the same UI; otherwise, false ///Note that two AutomationElements that compare as equal may contain /// different cached information from different points in time; the equality check only /// tests that the AutomationElements refer to the same underlying UI. /// public override bool Equals(object obj) { AutomationElement el = obj as AutomationElement; if (obj == null || el == null) return false; return Misc.Compare(this, el); } ////// Overrides Object.GetHashCode /// ///An integer that represents the hashcode for this AutomationElement public override int GetHashCode() { int[] id = GetRuntimeId(); int hash = 0; if (id == null) { // Hash codes need to be unique if the runtime ids are null we will end up // handing out duplicates so throw an exception. throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } for (int i = 0; i < id.Length; i++) { hash = (hash * 2) ^ id[i]; } return hash; } ////// Tests whether two AutomationElement objects are equivalent /// /// The AutomationElement that is to the left of the equality operator /// The AutomationElement that is to the right of the equality operator ///This operator returns true if two AutomationElements refer to the same UI; otherwise false ///Note that two AutomationElements that compare as equal may contain /// different cached information from different points in time; the equality check only /// tests that the AutomationElements refer to the same underlying UI. /// public static bool operator ==(AutomationElement left, AutomationElement right) { if ((object)left == null) return (object)right == null; if ((object)right == null) return (object)left == null; return left.Equals(right); } ////// Tests whether two AutomationElement objects are not equivalent /// /// The AutomationElement that is to the left of the inequality operator /// The AutomationElement that is to the right of the inequality operator ///This operator returns true if two AutomationElements refer to different UI; otherwise false public static bool operator !=(AutomationElement left, AutomationElement right) { return !(left == right); } #endregion Equality ////// Returns an array of ints that uniquely identifies the UI element that this object represents. /// Caller should treat the array as an opaque value; do not attempt to analyze it or pick it apart, /// the format may change in future. /// /// These identifies are only guaranteed to be unique on a given desktop. /// Identifiers may be recycled over time. /// /// ////// This API does not work inside the secure execution environment. /// public int[] GetRuntimeId() { if (_runtimeId != null) return _runtimeId; //Not true - some AE's from properties and event args (eg. SelectionItem.SelectionContainer, //and FocuEventArgs's previousFocus) don't currently come through CacheReqest //Debug.Assert(false, "Should always have runtimeID from cache at ctor."); // false -> return null (instead of throwing) if not available; true->wrap int [] val = LookupCachedValue(AutomationElement.RuntimeIdProperty, false, true) as int[]; if (val != null) { _runtimeId = val; return _runtimeId; } // Possible that we got this element from a path that doesn't have prefetch // enabled - fall back to getting RuntimeId the slow cross-proc way for now // Also possible that this was called on an empty element - eg. where someone // use TreeScope.Children to get just the children, but not any info for this // element. CheckElement() will throw an exception in that case... CheckElement(); _runtimeId = UiaCoreApi.UiaGetRuntimeId(_hnode); return _runtimeId; } ////// /// Get element at specified point on current desktop /// /// point in screen coordinates ///element at specified point /// ////// This API does not work inside the secure execution environment. /// public static AutomationElement FromPoint(Point pt) { return DrillForPointOrFocus(true, pt, CacheRequest.CurrentUiaCacheRequest); } ////// /// Get element from specified HWND /// /// Handle of window to get element for ///element representing root node of specified window /// ////// This API does not work inside the secure execution environment. /// public static AutomationElement FromHandle(IntPtr hwnd) { Misc.ValidateArgument(hwnd != IntPtr.Zero, SRID.HwndMustBeNonNULL); SafeNodeHandle hnode = UiaCoreApi.UiaNodeFromHandle(hwnd); if (hnode.IsInvalid) { return null; } UiaCoreApi.UiaCacheRequest cacheRequest = CacheRequest.CurrentUiaCacheRequest; // Don't do any normalization when getting updated cache... UiaCoreApi.UiaCacheResponse response = UiaCoreApi.UiaGetUpdatedCache(hnode, cacheRequest, UiaCoreApi.NormalizeState.None, null); // return CacheHelper.BuildAutomationElementsFromResponse(cacheRequest, response); } ////// /// Converts a local IRawElementProvider implementation to an AutomationElement. /// /// Local object implementing IRawElementProvider ///A corresponding AutomationElement for the impl parameter ///This would be used by a client helper library that wanted /// to allow its callers to access its own native element type via PAW. /// For example, the Windows Client Platform uses its own Element type, but /// uses this iternally so that it can had back an AutomationElement to clients /// that want to get an AutomationElement directly from an Element. /// public static AutomationElement FromLocalProvider(IRawElementProviderSimple localImpl) { Misc.ValidateArgumentNonNull(localImpl, "localImpl"); return AutomationElement.Wrap(UiaCoreApi.UiaNodeFromProvider(localImpl)); } ////// Get current value of specified property from an element. /// /// AutomationProperty that identifies the property ///Returns value of specified property ////// If the specified property is not explicitly supported by the target UI, /// a default value will be returned. For example, if the target UI doesn't /// support the AutomationElement.NameProperty, calling GetCurrentPropertyValue /// for that property will return an empty string. /// /// This API gets the current value of the property at this point in time, /// without checking the cache. For some types of UI, this API will incur /// a cross-process performance hit. To access values in this AutomationElement's /// cache, use GetCachedPropertyValue instead. /// /// ////// This API does not work inside the secure execution environment. /// public object GetCurrentPropertyValue(AutomationProperty property) { return GetCurrentPropertyValue(property, false); } ////// /// Get the current value of specified property from an element. /// /// AutomationProperty that identifies the property /// Specifies whether a default value should be /// ignored if the specified property is supported by the target UI ///Returns value of specified property, or AutomationElement.NotSupported ////// This API gets the current value of the property at this point in time, /// without checking the cache. For some types of UI, this API will incur /// a cross-process performance hit. To access values in this AutomationElement's /// cache, use GetCachedPropertyValue instead. /// /// ////// This API does not work inside the secure execution environment. /// public object GetCurrentPropertyValue(AutomationProperty property, bool ignoreDefaultValue) { Misc.ValidateArgumentNonNull(property, "property"); CheckElement(); AutomationPropertyInfo pi; if (!Schema.GetPropertyInfo(property, out pi)) { return new ArgumentException(SR.Get(SRID.UnsupportedProperty)); } object value; // PRESHARP will flag this as warning 56506/6506:Parameter 'property' to this public method must be validated: A null-dereference can occur here. // False positive, property is checked, see above #pragma warning suppress 6506 UiaCoreApi.UiaGetPropertyValue(_hnode, property.Id, out value); if (value != AutomationElement.NotSupported) { // if (value != null && pi.ObjectConverter != null) { value = pi.ObjectConverter(value); } } else { if (ignoreDefaultValue) { value = AutomationElement.NotSupported; } else { value = Schema.GetDefaultValue(property); } } return value; } ////// /// Get a pattern class from this object /// /// AutomationPattern indicating the pattern to return ///Returns the pattern as an object, if currently supported ////// Throws InvalidOperationException if the pattern is not supported. /// /// This API gets the pattern based on availability at this point in time, /// without checking the cache. For some types of UI, this API will incur /// a cross-process performance hit. To access patterns in this AutomationElement's /// cache, use GetCachedPattern instead. /// /// ////// This API does not work inside the secure execution environment. /// public object GetCurrentPattern(AutomationPattern pattern) { object retObject; if (!TryGetCurrentPattern(pattern, out retObject)) { throw new InvalidOperationException(SR.Get(SRID.UnsupportedPattern)); } return retObject; } ////// /// Get a pattern class from this object /// /// an object repressenting the AutomationPattern indicating /// the pattern to return /// the returned pattern object will be an object /// implementing the control pattern interface if the pattern is supported else /// the object will be null. ///Returns true, if currently supported ////// This API gets the pattern based on availability at this point in time, /// without checking the cache. For some types of UI, this API will incur /// a cross-process performance hit. To access patterns in this AutomationElement's /// cache, use GetCachedPattern instead. /// /// ////// This API does not work inside the secure execution environment. /// public bool TryGetCurrentPattern(AutomationPattern pattern, out object patternObject) { patternObject = null; Misc.ValidateArgumentNonNull(pattern, "pattern"); CheckElement(); // Need to catch non-critical exceptions. The WinFormsSpinner will raise an // InvalidOperationException if it is a domain spinner and the SelectionPattern is asked for. SafePatternHandle hpatternobj = null; try { hpatternobj = UiaCoreApi.UiaGetPatternProvider(_hnode, pattern.Id); } catch (Exception e) { if (Misc.IsCriticalException(e)) { throw e; } return false; } if (hpatternobj.IsInvalid) { return false; } patternObject = Misc.WrapInterfaceOnClientSide(this, hpatternobj, pattern); return patternObject != null; } ////// /// Get cached value of specified property from an element. /// /// AutomationProperty that identifies the property ///Returns value of specified property ////// Throws InvalidOperationException if the requested property was not /// previously specified to be pre-fetched using a CacheRequest. /// /// If the specified property is not explicitly supported by the target UI, /// a default value will be returned. For example, if the target UI doesn't /// support the AutomationElement.NameProperty, calling GetCachedPropertyValue /// for that property will return an empty string. /// /// ////// This API does not work inside the secure execution environment. /// public object GetCachedPropertyValue(AutomationProperty property) { return GetCachedPropertyValue(property, false); } ////// /// Get the cached value of specified property from an element. /// /// AutomationProperty that identifies the property /// Specifies whether a default value should be /// ignored if the specified property is not supported by the target UI ///Returns value of specified property, or AutomationElement.NotSupported ////// Throws InvalidOperationException if the requested property was not /// previously specified to be pre-fetched using a CacheRequest. /// /// If ignoreDefaultValue is true, then when the specified property is not /// explicitly supported by the target UI, a default value will not be returned. /// For example, if the target UI doesn't /// support the AutomationElement.NameProperty, calling GetCachedPropertyValue /// for that property will return an empty string. /// When ignoreDefaultValue is true, the value AutomationElement.NotSupported will /// be returned instead. /// /// ////// This API does not work inside the secure execution environment. /// public object GetCachedPropertyValue(AutomationProperty property, bool ignoreDefaultValue) { Misc.ValidateArgumentNonNull(property, "property"); // true -> throw if not available, true -> wrap object val = LookupCachedValue(property, true, true); UiaCoreApi.IsErrorMarker(val, true/*throwException*/); if (val == AutomationElement.NotSupported && !ignoreDefaultValue) { val = Schema.GetDefaultValue(property); } return val; } ////// /// Get a pattern class from this object /// /// AutomationPattern indicating the pattern to return ///Returns the pattern as an object, if currently supported; otherwise returns null/ ////// Throws InvalidOperationException if the requested pattern was not /// previously specified to be pre-fetched using a CacheRequest. /// /// This API gets the pattern from the cache. /// /// ////// This API does not work inside the secure execution environment. /// public object GetCachedPattern(AutomationPattern pattern) { object patternObject; if (!TryGetCachedPattern(pattern, out patternObject)) { throw new InvalidOperationException(SR.Get(SRID.UnsupportedPattern)); } return patternObject; } ////// /// Get a pattern class from this object /// /// AutomationPattern indicating the pattern to return /// Is the pattern as an object, if currently in the cache; otherwise is null ///Returns true, if currently in the cache; otherwise returns false ////// This API gets the pattern from the cache. /// /// ////// This API does not work inside the secure execution environment. /// public bool TryGetCachedPattern(AutomationPattern pattern, out object patternObject) { patternObject = null; // Lookup a cached remote reference - but even if we get // back null, still go ahead an create a pattern wrapper // to provide access to cached properties Misc.ValidateArgumentNonNull(pattern, "pattern"); // false -> don't throw, false -> don't wrap object obj = LookupCachedValue(pattern, false, false); if (obj == null) { return false; } SafePatternHandle hPattern = (SafePatternHandle)obj; AutomationPatternInfo pi; if (!Schema.GetPatternInfo(pattern, out pi)) { throw new ArgumentException(SR.Get(SRID.UnsupportedPattern)); } patternObject = pi.ClientSideWrapper(this, hPattern, true); return patternObject != null; } ////// /// Get an AutomationElement with updated cached values /// /// CacheRequest object describing the properties and other information to fetch ///Returns a new AutomationElement, which refers to the same UI as this element, but which is /// populated with properties specified in the CacheRequest. ////// Unlike other methods, such as FromHandle, FromPoint, this method takes /// an explicit CacheRequest as a parameter, and ignores the currently /// active CacheRequest. /// public AutomationElement GetUpdatedCache(CacheRequest request) { Misc.ValidateArgumentNonNull(request, "request"); CheckElement(); UiaCoreApi.UiaCacheRequest cacheRequest = request.GetUiaCacheRequest(); // Don't normalize when getting updated cache... UiaCoreApi.UiaCacheResponse response = UiaCoreApi.UiaGetUpdatedCache(_hnode, cacheRequest, UiaCoreApi.NormalizeState.None, null); return CacheHelper.BuildAutomationElementsFromResponse(cacheRequest, response); } ////// Find first child or descendant element that matches specified condition /// /// Indicates whether to include this element, children /// or descendants in the search /// Condition to search for ///Returns first element that satisfies condition, /// or null if no match is found. public AutomationElement FindFirst(TreeScope scope, Condition condition) { Misc.ValidateArgumentNonNull(condition, "condition"); UiaCoreApi.UiaCacheResponse[] responses = Find(scope, condition, CacheRequest.CurrentUiaCacheRequest, true, null); if (responses.Length < 1) { return null; } Debug.Assert(responses.Length == 1); return CacheHelper.BuildAutomationElementsFromResponse(CacheRequest.CurrentUiaCacheRequest, responses[0]); } ////// Find all child or descendant elements that match specified condition /// /// Indicates whether to include this element, children /// or descendants in the search /// Condition to search for ///Returns collection of all AutomationElements that /// match specified condition. Collection will be empty if /// no matches found. public AutomationElementCollection FindAll(TreeScope scope, Condition condition) { Misc.ValidateArgumentNonNull(condition, "condition"); UiaCoreApi.UiaCacheRequest request = CacheRequest.CurrentUiaCacheRequest; UiaCoreApi.UiaCacheResponse[] responses = Find(scope, condition, request, false, null); AutomationElement[] els = new AutomationElement[responses.Length]; for( int i = 0 ; i < responses.Length ; i ++ ) { els[i] = CacheHelper.BuildAutomationElementsFromResponse(request, responses[i]); } return new AutomationElementCollection( els ); } ////// Get array of supported property identifiers /// ////// The returned array contains at least all the properties supported by this element; /// however it may also contain duplicate entries or properties that the element does not /// currently support or which have null or empty values. Use GetPropertyValue to determine /// whether a property is currently supported and to determine what its current value is. /// /// ////// This API does not work inside the secure execution environment. /// public AutomationProperty [ ] GetSupportedProperties() { CheckElement(); ArrayList propArrays = new ArrayList(4); propArrays.Add(Schema.GetBasicProperties()); AutomationPattern[] patterns = GetSupportedPatterns(); if (patterns != null && patterns.Length > 0) { foreach (AutomationPattern pattern in patterns) { AutomationPatternInfo pi; if (Schema.GetPatternInfo(pattern, out pi)) { if (pi.Properties != null) { propArrays.Add(pi.Properties); } } } } return (AutomationProperty[])Misc.RemoveDuplicates(Misc.CombineArrays(propArrays, typeof(AutomationProperty)), typeof(AutomationProperty)); } ////// /// Get the interfaces that this object supports /// ///An array of AutomationPatterns that represent the supported interfaces /// ////// This API does not work inside the secure execution environment. /// public AutomationPattern [ ] GetSupportedPatterns() { CheckElement(); ArrayList interfaces = new ArrayList(4); object patternObject; foreach (AutomationPatternInfo pi in Schema.GetPatternInfoTable()) { if (TryGetCurrentPattern(pi.ID, out patternObject)) { interfaces.Add(pi.ID); } } return (AutomationPattern[])interfaces.ToArray(typeof(AutomationPattern)); } ////// /// Request to set focus to this element /// /// ////// This API does not work inside the secure execution environment. /// public void SetFocus() { CheckElement(); object canReceiveFocus = GetCurrentPropertyValue(AutomationElement.IsKeyboardFocusableProperty); if (canReceiveFocus is bool && (bool)canReceiveFocus) { UiaCoreApi.UiaSetFocus(_hnode); } else { throw new InvalidOperationException(SR.Get(SRID.SetFocusFailed)); } } ////// /// Get a point that can be clicked on. If there is no ClickablePoint return false /// /// A point that can be used ba a client to click on this LogicalElement ///true if there is point that is clickable /// ////// This API does not work inside the secure execution environment. /// public bool TryGetClickablePoint( out Point pt ) { // initialize point here so if we return false its initialized pt = new Point (0, 0); // Request the provider for a clickable point. object ptClickable = GetCurrentPropertyValue(AutomationElement.ClickablePointProperty); if (ptClickable == NotSupported) { return false; } // if got one if (ptClickable is Point) { //If the ClickablePointProperty from the provider is NaN that means no point. if (double.IsNaN (((Point) ptClickable).X) || double.IsNaN (((Point) ptClickable).Y)) { return false; } // Allow the object if it is the element or a descentant... AutomationElement scan = AutomationElement.FromPoint((Point)ptClickable); while (scan != null) { if (scan == this) { pt = (Point)ptClickable; return true; } scan = TreeWalker.RawViewWalker.GetParent(scan, CacheRequest.DefaultCacheRequest); } } // the providers point is either no good or they did not have one so poke around // trying to find one. if (ClickablePoint.HitTestForClickablePoint( (AutomationElement)this, out pt) ) return true; return false; } ////// /// Get a point that can be clicked on. This throws the NoClickablePointException if there is no clickable point /// ///A point that can be used by a client to click on this LogicalElement ///If there is not clickable point for this element /// ////// This API does not work inside the secure execution environment. /// public Point GetClickablePoint() { Point pt; if ( !TryGetClickablePoint( out pt ) ) throw new NoClickablePointException(SR.Get(SRID.LogicalElementNoClickablePoint)); return pt; } #endregion Public Methods //----------------------------------------------------- // // Public Properties // //------------------------------------------------------ #region Public Properties ////// /// Get root element for current desktop /// ///root element for current desktop /// ////// This API does not work inside the secure execution environment. /// public static AutomationElement RootElement { get { SafeNodeHandle hnode = UiaCoreApi.UiaGetRootNode(); UiaCoreApi.UiaCacheRequest cacheRequest = CacheRequest.CurrentUiaCacheRequest; // Don't normalize... UiaCoreApi.UiaCacheResponse response = UiaCoreApi.UiaGetUpdatedCache(hnode, cacheRequest, UiaCoreApi.NormalizeState.None, null); // return CacheHelper.BuildAutomationElementsFromResponse(cacheRequest, response); } } ////// /// Return the currently focused element /// /// ////// This API does not work inside the secure execution environment. /// public static AutomationElement FocusedElement { get { //CASRemoval:AutomationPermission.Demand(AutomationPermissionFlag.Read); return DrillForPointOrFocus(false, new Point(0, 0), CacheRequest.CurrentUiaCacheRequest); } } ////// /// This member allows access to previously requested /// cached properties for this element. The returned object /// has accessors for AutomationElement properties. /// ////// Cached property values must have been previously requested /// using a CacheRequest. If you try to access a cached /// property that was not previously requested, an InvalidOperation /// Exception will be thrown. /// /// To get the value of a property at the current point in time, /// access the property via the Current accessor instead of /// Cached. /// public AutomationElementInformation Cached { get { return new AutomationElementInformation(this, true); } } ////// This member allows access to current property values /// for this element. The returned object has accessors for /// AutomationElement properties. /// ////// This AutomationElement must have a /// Full reference in order to get current values. If the /// AutomationElement was obtained using AutomationElementMode.None, /// then it contains only cached data, and attempting to get /// the current value of any property will throw an InvalidOperationException. /// /// To get the cached value of a property that was previously /// specified using a CacheRequest, access the property via the /// Cached accessor instead of Current. /// public AutomationElementInformation Current { get { return new AutomationElementInformation(this, false); } } ////// Returns the cached parent of this AutomationElement /// ////// Returns the parent of this element, with respect to the TreeFilter /// condition of the CacheRequest that was active when this AutomationElement /// was obtained. /// /// Throws InvalidOperationException if the parent was not previously requested /// in a CacheRequest. /// /// Can return null if the specified element has no parent - eg. is the root node. /// public AutomationElement CachedParent { get { // this is used as a marker to indicate 'not requested' // - used since null is a valid value for parent, but this can never be. // Use (object) case to ensure we just do a ref check here, not call .Equals if ((object)_cachedParent == (object)this) { // PRESHARP will flag this as a warning 56503/6503: Property get methods should not throw exceptions // We've spec'd as throwing an Exception, and that's what we do PreSharp shouldn't complain #pragma warning suppress 6503 throw new InvalidOperationException(SR.Get(SRID.CachedPropertyNotRequested)); } return _cachedParent; } } ////// Returns the cached children of this AutomationElement /// ////// Returns a collection of children of this element, with respect to the TreeFilter /// condition of the CacheRequest that was active when this AutomationElement /// was obtained. /// /// Throws InvalidOperationException if children or descendants were not previously requested /// in a CacheRequest. /// /// Can return an empty collection if this AutomationElement has no children. /// public AutomationElementCollection CachedChildren { get { // this is used as a marker to indicate 'not requested' // - used since null is a valid value for parent, but this can never be. // Use (object) case to ensure we just do a ref check here, not call .Equals if ((object)_cachedFirstChild == (object)this) { // PRESHARP will flag this as a warning 56503/6503: Property get methods should not throw exceptions // We've spec'd as throwing an Exception, and that's what we do PreSharp shouldn't complain #pragma warning suppress 6503 throw new InvalidOperationException(SR.Get(SRID.CachedPropertyNotRequested)); } // Build up an array to return - first count the children, // then build an array and populate it... int childCount = 0; AutomationElement scan = _cachedFirstChild; for (; scan != null; scan = scan._cachedNextSibling) { childCount++; } AutomationElement[] children = new AutomationElement[childCount]; scan = _cachedFirstChild; for (int i = 0; i < childCount; i++) { children[i] = scan; scan = scan._cachedNextSibling; } return new AutomationElementCollection(children); } } #endregion Public Properties //----------------------------------------------------- // // Internal Methods // //----------------------------------------------------- #region Internal Methods internal void CheckElement() { if (_hnode == null || _hnode.IsInvalid) { throw new InvalidOperationException(SR.Get(SRID.CacheRequestNeedElementReference)); } } // Called by the treewalker classes to navigate - we call through to the // provider wrapper, which gets the navigator code to do its stuff internal AutomationElement Navigate(NavigateDirection direction, Condition condition, CacheRequest request) { CheckElement(); UiaCoreApi.UiaCacheRequest cacheRequest; if (request == null) cacheRequest = CacheRequest.DefaultUiaCacheRequest; else cacheRequest = request.GetUiaCacheRequest(); UiaCoreApi.UiaCacheResponse response = UiaCoreApi.UiaNavigate(_hnode, direction, condition, cacheRequest); return CacheHelper.BuildAutomationElementsFromResponse(cacheRequest, response); } internal AutomationElement Normalize(Condition condition, CacheRequest request ) { CheckElement(); UiaCoreApi.UiaCacheRequest cacheRequest; if (request == null) cacheRequest = CacheRequest.DefaultUiaCacheRequest; else cacheRequest = request.GetUiaCacheRequest(); // Normalize against the treeview condition, not the one in the cache request... UiaCoreApi.UiaCacheResponse response = UiaCoreApi.UiaGetUpdatedCache(_hnode, cacheRequest, UiaCoreApi.NormalizeState.Custom, condition); return CacheHelper.BuildAutomationElementsFromResponse(cacheRequest, response); } // Used by the pattern wrappers to get property values internal object GetPatternPropertyValue(AutomationProperty property, bool useCache) { if (useCache) return GetCachedPropertyValue(property); else return GetCurrentPropertyValue(property); } // The following are used by CacheUtil when building up a cached AutomationElemen tree internal void SetCachedParent(AutomationElement cachedParent) { _cachedParent = cachedParent; // If we're setting the parent, it means this is one of potentially // many siblings - so set _cachedNextSibling to null, instead of // the 'not requested' marker value 'this' _cachedNextSibling = null; } internal void SetCachedFirstChild(AutomationElement cachedFirstChild) { _cachedFirstChild = cachedFirstChild; } internal void SetCachedNextSibling(AutomationElement cachedNextSibling) { _cachedNextSibling = cachedNextSibling; } #endregion Internal Methods //----------------------------------------------------- // // Internal Properties // //------------------------------------------------------ #region Internal Properties internal SafeNodeHandle RawNode { get { return _hnode; } } #endregion Internal Properties //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods // Lookup a cached AutomationPattern or AutomationProperty object LookupCachedValue(AutomationIdentifier id, bool throwIfNotRequested, bool wrap) { if (_cachedValues == null) { if (throwIfNotRequested) { throw new InvalidOperationException(SR.Get(SRID.CachedPropertyNotRequested)); } else { return null; } } AutomationProperty automationProperty = id as AutomationProperty; bool isProperty = automationProperty != null; AutomationIdentifier[] refTable = isProperty ? (AutomationIdentifier[])_request.Properties : (AutomationIdentifier[])_request.Patterns; bool found = false; object val = null; int dataOffset = isProperty ? 1 : 1 + _request.Properties.Length; for (int i = 0; i < refTable.Length; i++) { if (refTable[i] == id) { found = true; val = _cachedValues[_cachedValuesIndex, i + dataOffset]; break; } } if (!found) { if (throwIfNotRequested) { throw new InvalidOperationException(SR.Get(SRID.CachedPropertyNotRequested)); } else { return null; } } // Bail now if no wrapping required; also, even with wrapping, null remains null // for both properties and patterns.. if (!wrap || val == null) { return val; } AutomationPattern automationPattern = id as AutomationPattern; // Cached values are internally stored as unwrapped, direct-from-provider values, so // need to be wrapped as appropriate before handing back to client... if (automationPattern != null) { SafePatternHandle hpatternobj = (SafePatternHandle)val; val = Misc.WrapInterfaceOnClientSide(this, hpatternobj, automationPattern); } // No wrapping necessary here for properties - the objects in the array are fully wrapped/converted as soon as they are // received from the unmanaged API, so they're ready-to-use without any further processing. return val; } // drill for either focused raw element, or element at specified point private static AutomationElement DrillForPointOrFocus(bool atPoint, Point pt, UiaCoreApi.UiaCacheRequest cacheRequest) { UiaCoreApi.UiaCacheResponse response; if (atPoint) response = UiaCoreApi.UiaNodeFromPoint(pt.X, pt.Y, cacheRequest); else response = UiaCoreApi.UiaNodeFromFocus(cacheRequest); return CacheHelper.BuildAutomationElementsFromResponse(cacheRequest, response); } // called by FindFirst and FindAll private UiaCoreApi.UiaCacheResponse[] Find(TreeScope scope, Condition condition, UiaCoreApi.UiaCacheRequest request, bool findFirst, BackgroundWorker worker) { Misc.ValidateArgumentNonNull(condition, "condition"); if (scope == 0) { throw new ArgumentException(SR.Get(SRID.TreeScopeNeedAtLeastOne)); } if ((scope & ~(TreeScope.Element | TreeScope.Children | TreeScope.Descendants)) != 0) { throw new ArgumentException(SR.Get(SRID.TreeScopeElementChildrenDescendantsOnly)); } // Set up a find struct... UiaCoreApi.UiaFindParams findParams = new UiaCoreApi.UiaFindParams(); findParams.FindFirst = findFirst; if ((scope & TreeScope.Descendants) != 0) findParams.MaxDepth = -1; else if ((scope & TreeScope.Children) != 0) findParams.MaxDepth = 1; else findParams.MaxDepth = 0; if ((scope & TreeScope.Element) != 0) findParams.ExcludeRoot = false; else findParams.ExcludeRoot = true; UiaCoreApi.UiaCacheResponse[] retVal = UiaCoreApi.UiaFind(_hnode, findParams, condition, request); return retVal; } #endregion Private Methods //------------------------------------------------------ // // Private Fields // //----------------------------------------------------- #region Private Fields private SafeNodeHandle _hnode; private int[] _runtimeId; // Cached object values - use in conjunction with the Properties/Pattern arrays in // _request to figure out which properties/patterns they are. // Note that these use NotSupported, so need to substitute default values // when returning to user. private object[,] _cachedValues; private int _cachedValuesIndex; // index of row in cachedValues that corresponds to this element // Reference to the cache request information that was active when this // element was created private UiaCoreApi.UiaCacheRequest _request; // Cached structure links - these set to 'this' to indicate that they // were not requested - since null is a valid value. private AutomationElement _cachedParent; private AutomationElement _cachedFirstChild; private AutomationElement _cachedNextSibling; #endregion Private Fields //------------------------------------------------------ // // Nested Classes // //----------------------------------------------------- #region Nested Classes ////// This class provides access to either Cached or Current /// properties on an AutomationElement via the .Cached or /// .Current accessors. /// public struct AutomationElementInformation { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors internal AutomationElementInformation(AutomationElement el, bool useCache) { _el = el; _useCache = useCache; } #endregion Constructors //------------------------------------------------------ // // Public Properties // //----------------------------------------------------- #region Public Properties ///The ControlType of this Element public ControlType ControlType { get { return (ControlType) _el.GetPatternPropertyValue(ControlTypeProperty, _useCache); } } ///Localized control type description (eg. "Button") public string LocalizedControlType { get { return (string) _el.GetPatternPropertyValue(LocalizedControlTypeProperty, _useCache); } } ///Name of this instance of control public string Name { get { return (string) _el.GetPatternPropertyValue(NameProperty, _useCache); } } ///Hot-key equivalent for this command item. (eg. Ctrl-P for Print) public string AcceleratorKey { get { return (string) _el.GetPatternPropertyValue(AcceleratorKeyProperty, _useCache); } } ///Keys used to move focus to this control public string AccessKey { get { return (string) _el.GetPatternPropertyValue(AccessKeyProperty, _useCache); } } ///Indicates whether this control has keyboard focus public bool HasKeyboardFocus { get { return (bool) _el.GetPatternPropertyValue(HasKeyboardFocusProperty, _useCache); } } ///True if this control can take keyboard focus public bool IsKeyboardFocusable { get { return (bool) _el.GetPatternPropertyValue(IsKeyboardFocusableProperty, _useCache); } } ///True if this control is enabled public bool IsEnabled { get { return (bool) _el.GetPatternPropertyValue(IsEnabledProperty, _useCache); } } ///Bounding rectangle, in screen coordinates public Rect BoundingRectangle { get { return (Rect) _el.GetPatternPropertyValue(BoundingRectangleProperty, _useCache); } } ///HelpText - brief description of what this control does public string HelpText { get { return (string) _el.GetPatternPropertyValue(HelpTextProperty, _useCache); } } ///Indicates that this element should be included in the Control view of the tree public bool IsControlElement { get { return (bool) _el.GetPatternPropertyValue(IsControlElementProperty, _useCache); } } ///Indicates that this element should be included in the Content view of the tree public bool IsContentElement { get { return (bool) _el.GetPatternPropertyValue(IsContentElementProperty, _useCache); } } ///The AutomationElement that labels this element public AutomationElement LabeledBy { get { return (AutomationElement) _el.GetPatternPropertyValue(LabeledByProperty, _useCache); } } ///The identifier for an element that is unique within its containing element public string AutomationId { get { return (string) _el.GetPatternPropertyValue(AutomationIdProperty, _useCache); } } ///Localized string that indicates what the items in a list represent public string ItemType { get { return (string) _el.GetPatternPropertyValue(ItemTypeProperty, _useCache ); } } ///True if the control is a password protected field. public bool IsPassword { get { return (bool) _el.GetPatternPropertyValue(IsPasswordProperty, _useCache); } } ///Name of underlying class - implementation dependant, but useful for test public string ClassName { get { return (string) _el.GetPatternPropertyValue(ClassNameProperty, _useCache); } } ///Window Handle, if the underlying control is a Window public int NativeWindowHandle { get { return (int) _el.GetPatternPropertyValue(NativeWindowHandleProperty, _useCache); } } ///Id of process that this element lives in public int ProcessId { get { return (int) _el.GetPatternPropertyValue(ProcessIdProperty, _useCache); } } ///True if this control is not visible to the sighted user public bool IsOffscreen { get { return (bool) _el.GetPatternPropertyValue(IsOffscreenProperty, _useCache); } } ///The controls specfied direction public OrientationType Orientation { get { return (OrientationType) _el.GetPatternPropertyValue(OrientationProperty, _useCache); } } ///The controls specfied direction public string FrameworkId { get { return (string) _el.GetPatternPropertyValue(FrameworkIdProperty, _useCache); } } ///True if this element is required to be filled out on a form public bool IsRequiredForForm { get { return (bool) _el.GetPatternPropertyValue(IsRequiredForFormProperty, _useCache); } } ///The visual status of a complex item as a string public string ItemStatus { get { return (string) _el.GetPatternPropertyValue(ItemStatusProperty, _useCache); } } #endregion Public Properties //------------------------------------------------------ // // Private Fields // //------------------------------------------------------ #region Private Fields private AutomationElement _el; // AutomationElement that contains the cache or live reference private bool _useCache; // true to use cache, false to use live reference to get current values #endregion Private Fields } #endregion Nested Classes } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved. //---------------------------------------------------------------------------- // //// Copyright (C) Microsoft Corporation. All rights reserved. // // // // Description: Main class used by Automation clients, represents a UI element // // History: // 02/06/2003 : BrendanM Created // //--------------------------------------------------------------------------- using System.Windows.Automation; using System.Windows.Automation.Provider; using System; using System.Runtime.Serialization; using System.Security.Permissions; using System.Collections; using System.Collections.Specialized; using System.Diagnostics; using System.ComponentModel; using MS.Win32; using MS.Internal.Automation; using System.Runtime.InteropServices; #if EVENT_TRACING_PROPERTY using Microsoft.Win32.Diagnostics; #endif // PRESHARP: In order to avoid generating warnings about unkown message numbers and unknown pragmas. #pragma warning disable 1634, 1691 namespace System.Windows.Automation { ////// Represents an element in the UIAutomation tree. /// #if (INTERNAL_COMPILE) internal sealed class AutomationElement //: IDisposable #else public sealed class AutomationElement #endif { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors // Private ctor, used mostly by CacheHelper when reconstructing AutomationElements from // a CacheResponse. internal AutomationElement(SafeNodeHandle hnode, object[,] cachedValues, int cachedValuesIndex, UiaCoreApi.UiaCacheRequest request) { _hnode = hnode; // Can be IntPtr.Zero for a lightweight object _cachedValues = cachedValues; // Can be null if there are no cached properties for this node _cachedValuesIndex = cachedValuesIndex; _request = request; // Set RuntimeId (if available; 'as int[]' filters out AutomationElement.NotAvailable) _runtimeId = LookupCachedValue(AutomationElement.RuntimeIdProperty, false, true) as int[]; // // One scenario that allows for null runtimeID - doing UpdatedCache() on a node and asking only // for children - gives us back a placeholder node that only has valid .CachedChildren, // the node itself doesn't have any cached properties or a node. // Since null is a valid value for these, we need another value to // indicate that they were not requested - it's a bit obscure, but // 'this' works well here, since these can never have it as legal value. _cachedParent = this; _cachedFirstChild = this; _cachedNextSibling = this; } ////// Overrides Object.Finalize /// ~AutomationElement() { // } // Used by methods that return non-cached AutomationElements - examples currently include // AutomationElements returned as properties (SelecitonContainer, RowHeaders). internal static AutomationElement Wrap(SafeNodeHandle hnode) { if (hnode == null || hnode.IsInvalid) { return null; } return new AutomationElement(hnode, null, 0, null); } #endregion Constructors //------------------------------------------------------ // // Public Constants / Readonly Fields // //----------------------------------------------------- #region Public Constants and Readonly Fields ////// Indicates that a element does not support the requested value /// public static readonly object NotSupported = AutomationElementIdentifiers.NotSupported; ///Property ID: Indicates that this element should be included in the Control view of the tree public static readonly AutomationProperty IsControlElementProperty = AutomationElementIdentifiers.IsControlElementProperty; ///Property ID: The ControlType of this Element public static readonly AutomationProperty ControlTypeProperty = AutomationElementIdentifiers.ControlTypeProperty; ///Property ID: NativeWindowHandle - Window Handle, if the underlying control is a Window public static readonly AutomationProperty IsContentElementProperty = AutomationElementIdentifiers.IsContentElementProperty; ///Property ID: The AutomationElement that labels this element public static readonly AutomationProperty LabeledByProperty = AutomationElementIdentifiers.LabeledByProperty; ///Property ID: NativeWindowHandle - Window Handle, if the underlying control is a Window public static readonly AutomationProperty NativeWindowHandleProperty = AutomationElementIdentifiers.NativeWindowHandleProperty; ///Property ID: AutomationId - An identifier for an element that is unique within its containing element. public static readonly AutomationProperty AutomationIdProperty = AutomationElementIdentifiers.AutomationIdProperty; ///Property ID: ItemType - An application-level property used to indicate what the items in a list represent. public static readonly AutomationProperty ItemTypeProperty = AutomationElementIdentifiers.ItemTypeProperty; ///Property ID: True if the control is a password protected field. public static readonly AutomationProperty IsPasswordProperty = AutomationElementIdentifiers.IsPasswordProperty; ///Property ID: Localized control type description (eg. "Button") public static readonly AutomationProperty LocalizedControlTypeProperty = AutomationElementIdentifiers.LocalizedControlTypeProperty; ///Property ID: name of this instance of control public static readonly AutomationProperty NameProperty = AutomationElementIdentifiers.NameProperty; ///Property ID: Hot-key equivalent for this command item. (eg. Ctrl-P for Print) public static readonly AutomationProperty AcceleratorKeyProperty = AutomationElementIdentifiers.AcceleratorKeyProperty; ///Property ID: Keys used to move focus to this control public static readonly AutomationProperty AccessKeyProperty = AutomationElementIdentifiers.AccessKeyProperty; ///Property ID: HasKeyboardFocus public static readonly AutomationProperty HasKeyboardFocusProperty = AutomationElementIdentifiers.HasKeyboardFocusProperty; ///Property ID: IsKeyboardFocusable public static readonly AutomationProperty IsKeyboardFocusableProperty = AutomationElementIdentifiers.IsKeyboardFocusableProperty; ///Property ID: Enabled public static readonly AutomationProperty IsEnabledProperty = AutomationElementIdentifiers.IsEnabledProperty; ///Property ID: BoundingRectangle - bounding rectangle public static readonly AutomationProperty BoundingRectangleProperty = AutomationElementIdentifiers.BoundingRectangleProperty; ///Property ID: id of process that this element lives in public static readonly AutomationProperty ProcessIdProperty = AutomationElementIdentifiers.ProcessIdProperty; ///Property ID: RuntimeId - runtime unique ID public static readonly AutomationProperty RuntimeIdProperty = AutomationElementIdentifiers.RuntimeIdProperty; ///Property ID: ClassName - name of underlying class - implementation dependant, but useful for test public static readonly AutomationProperty ClassNameProperty = AutomationElementIdentifiers.ClassNameProperty; ///Property ID: HelpText - brief description of what this control does public static readonly AutomationProperty HelpTextProperty = AutomationElementIdentifiers.HelpTextProperty; ///Property ID: ClickablePoint - Set by provider, used internally for GetClickablePoint public static readonly AutomationProperty ClickablePointProperty = AutomationElementIdentifiers.ClickablePointProperty; ///Property ID: Culture - Returns the culture that provides information about the control's content. public static readonly AutomationProperty CultureProperty = AutomationElementIdentifiers.CultureProperty; ///Property ID: Offscreen - Determined to be not-visible to the sighted user public static readonly AutomationProperty IsOffscreenProperty = AutomationElementIdentifiers.IsOffscreenProperty; ///Property ID: Orientation - Identifies whether a control is positioned in a specfic direction public static readonly AutomationProperty OrientationProperty = AutomationElementIdentifiers.OrientationProperty; ///Property ID: FrameworkId - Identifies the underlying UI framework's name for the element being accessed public static readonly AutomationProperty FrameworkIdProperty = AutomationElementIdentifiers.FrameworkIdProperty; ///Property ID: IsRequiredForForm - Identifies weather an edit field is required to be filled out on a form public static readonly AutomationProperty IsRequiredForFormProperty = AutomationElementIdentifiers.IsRequiredForFormProperty; ///Property ID: ItemStatus - Identifies the status of the visual representation of a complex item public static readonly AutomationProperty ItemStatusProperty = AutomationElementIdentifiers.ItemStatusProperty; #region IsNnnnPatternAvailable properties ///Property that indicates whether the DockPattern is available for this AutomationElement public static readonly AutomationProperty IsDockPatternAvailableProperty = AutomationElementIdentifiers.IsDockPatternAvailableProperty; ///Property that indicates whether the ExpandCollapsePattern is available for this AutomationElement public static readonly AutomationProperty IsExpandCollapsePatternAvailableProperty = AutomationElementIdentifiers.IsExpandCollapsePatternAvailableProperty; ///Property that indicates whether the GridItemPattern is available for this AutomationElement public static readonly AutomationProperty IsGridItemPatternAvailableProperty = AutomationElementIdentifiers.IsGridItemPatternAvailableProperty; ///Property that indicates whether the GridPattern is available for this AutomationElement public static readonly AutomationProperty IsGridPatternAvailableProperty = AutomationElementIdentifiers.IsGridPatternAvailableProperty; ///Property that indicates whether the InvokePattern is available for this AutomationElement public static readonly AutomationProperty IsInvokePatternAvailableProperty = AutomationElementIdentifiers.IsInvokePatternAvailableProperty; ///Property that indicates whether the MultipleViewPattern is available for this AutomationElement public static readonly AutomationProperty IsMultipleViewPatternAvailableProperty = AutomationElementIdentifiers.IsMultipleViewPatternAvailableProperty; ///Property that indicates whether the RangeValuePattern is available for this AutomationElement public static readonly AutomationProperty IsRangeValuePatternAvailableProperty = AutomationElementIdentifiers.IsRangeValuePatternAvailableProperty; ///Property that indicates whether the SelectionItemPattern is available for this AutomationElement public static readonly AutomationProperty IsSelectionItemPatternAvailableProperty = AutomationElementIdentifiers.IsSelectionItemPatternAvailableProperty; ///Property that indicates whether the SelectionPattern is available for this AutomationElement public static readonly AutomationProperty IsSelectionPatternAvailableProperty = AutomationElementIdentifiers.IsSelectionPatternAvailableProperty; ///Property that indicates whether the ScrollPattern is available for this AutomationElement public static readonly AutomationProperty IsScrollPatternAvailableProperty = AutomationElementIdentifiers.IsScrollPatternAvailableProperty; ///Property that indicates whether the ScrollItemPattern is available for this AutomationElement public static readonly AutomationProperty IsScrollItemPatternAvailableProperty = AutomationElementIdentifiers.IsScrollItemPatternAvailableProperty; ///Property that indicates whether the TablePattern is available for this AutomationElement public static readonly AutomationProperty IsTablePatternAvailableProperty = AutomationElementIdentifiers.IsTablePatternAvailableProperty; ///Property that indicates whether the TableItemPattern is available for this AutomationElement public static readonly AutomationProperty IsTableItemPatternAvailableProperty = AutomationElementIdentifiers.IsTableItemPatternAvailableProperty; ///Property that indicates whether the TextPattern is available for this AutomationElement public static readonly AutomationProperty IsTextPatternAvailableProperty = AutomationElementIdentifiers.IsTextPatternAvailableProperty; ///Property that indicates whether the TogglePattern is available for this AutomationElement public static readonly AutomationProperty IsTogglePatternAvailableProperty = AutomationElementIdentifiers.IsTogglePatternAvailableProperty; ///Property that indicates whether the TransformPattern is available for this AutomationElement public static readonly AutomationProperty IsTransformPatternAvailableProperty = AutomationElementIdentifiers.IsTransformPatternAvailableProperty; ///Property that indicates whether the ValuePattern is available for this AutomationElement public static readonly AutomationProperty IsValuePatternAvailableProperty = AutomationElementIdentifiers.IsValuePatternAvailableProperty; ///Property that indicates whether the WindowPattern is available for this AutomationElement public static readonly AutomationProperty IsWindowPatternAvailableProperty = AutomationElementIdentifiers.IsWindowPatternAvailableProperty; #endregion IsNnnnPatternAvailable properties #region Events ///Event ID: ToolTipOpenedEvent - indicates a tooltip has appeared public static readonly AutomationEvent ToolTipOpenedEvent = AutomationElementIdentifiers.ToolTipOpenedEvent; ///Event ID: ToolTipClosedEvent - indicates a tooltip has closed. public static readonly AutomationEvent ToolTipClosedEvent = AutomationElementIdentifiers.ToolTipClosedEvent; ///Event ID: StructureChangedEvent - used mainly by servers to notify of structure changed events. Clients use AddStructureChangedHandler. public static readonly AutomationEvent StructureChangedEvent = AutomationElementIdentifiers.StructureChangedEvent; ///Event ID: MenuOpened - Indicates an a menu has opened. public static readonly AutomationEvent MenuOpenedEvent = AutomationElementIdentifiers.MenuOpenedEvent; ///Event ID: AutomationPropertyChangedEvent - used mainly by servers to notify of property changes. Clients use AddPropertyChangedListener. public static readonly AutomationEvent AutomationPropertyChangedEvent = AutomationElementIdentifiers.AutomationPropertyChangedEvent; ///Event ID: AutomationFocusChangedEvent - used mainly by servers to notify of focus changed events. Clients use AddAutomationFocusChangedListener. public static readonly AutomationEvent AutomationFocusChangedEvent = AutomationElementIdentifiers.AutomationFocusChangedEvent; ///Event ID: AsyncContentLoadedEvent - indicates an async content loaded event. public static readonly AutomationEvent AsyncContentLoadedEvent = AutomationElementIdentifiers.AsyncContentLoadedEvent; ///Event ID: MenuClosed - Indicates an a menu has closed. public static readonly AutomationEvent MenuClosedEvent = AutomationElementIdentifiers.MenuClosedEvent; ///Event ID: LayoutInvalidated - Indicates that many element locations/extents/offscreenedness have changed. public static readonly AutomationEvent LayoutInvalidatedEvent = AutomationElementIdentifiers.LayoutInvalidatedEvent; #endregion Events #endregion Public Constants and Readonly Fields //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods #region Equality ////// Overrides Object.Equals /// /// The Object to compare with the current object ///true if the AutomationElements refer to the same UI; otherwise, false ///Note that two AutomationElements that compare as equal may contain /// different cached information from different points in time; the equality check only /// tests that the AutomationElements refer to the same underlying UI. /// public override bool Equals(object obj) { AutomationElement el = obj as AutomationElement; if (obj == null || el == null) return false; return Misc.Compare(this, el); } ////// Overrides Object.GetHashCode /// ///An integer that represents the hashcode for this AutomationElement public override int GetHashCode() { int[] id = GetRuntimeId(); int hash = 0; if (id == null) { // Hash codes need to be unique if the runtime ids are null we will end up // handing out duplicates so throw an exception. throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } for (int i = 0; i < id.Length; i++) { hash = (hash * 2) ^ id[i]; } return hash; } ////// Tests whether two AutomationElement objects are equivalent /// /// The AutomationElement that is to the left of the equality operator /// The AutomationElement that is to the right of the equality operator ///This operator returns true if two AutomationElements refer to the same UI; otherwise false ///Note that two AutomationElements that compare as equal may contain /// different cached information from different points in time; the equality check only /// tests that the AutomationElements refer to the same underlying UI. /// public static bool operator ==(AutomationElement left, AutomationElement right) { if ((object)left == null) return (object)right == null; if ((object)right == null) return (object)left == null; return left.Equals(right); } ////// Tests whether two AutomationElement objects are not equivalent /// /// The AutomationElement that is to the left of the inequality operator /// The AutomationElement that is to the right of the inequality operator ///This operator returns true if two AutomationElements refer to different UI; otherwise false public static bool operator !=(AutomationElement left, AutomationElement right) { return !(left == right); } #endregion Equality ////// Returns an array of ints that uniquely identifies the UI element that this object represents. /// Caller should treat the array as an opaque value; do not attempt to analyze it or pick it apart, /// the format may change in future. /// /// These identifies are only guaranteed to be unique on a given desktop. /// Identifiers may be recycled over time. /// /// ////// This API does not work inside the secure execution environment. /// public int[] GetRuntimeId() { if (_runtimeId != null) return _runtimeId; //Not true - some AE's from properties and event args (eg. SelectionItem.SelectionContainer, //and FocuEventArgs's previousFocus) don't currently come through CacheReqest //Debug.Assert(false, "Should always have runtimeID from cache at ctor."); // false -> return null (instead of throwing) if not available; true->wrap int [] val = LookupCachedValue(AutomationElement.RuntimeIdProperty, false, true) as int[]; if (val != null) { _runtimeId = val; return _runtimeId; } // Possible that we got this element from a path that doesn't have prefetch // enabled - fall back to getting RuntimeId the slow cross-proc way for now // Also possible that this was called on an empty element - eg. where someone // use TreeScope.Children to get just the children, but not any info for this // element. CheckElement() will throw an exception in that case... CheckElement(); _runtimeId = UiaCoreApi.UiaGetRuntimeId(_hnode); return _runtimeId; } ////// /// Get element at specified point on current desktop /// /// point in screen coordinates ///element at specified point /// ////// This API does not work inside the secure execution environment. /// public static AutomationElement FromPoint(Point pt) { return DrillForPointOrFocus(true, pt, CacheRequest.CurrentUiaCacheRequest); } ////// /// Get element from specified HWND /// /// Handle of window to get element for ///element representing root node of specified window /// ////// This API does not work inside the secure execution environment. /// public static AutomationElement FromHandle(IntPtr hwnd) { Misc.ValidateArgument(hwnd != IntPtr.Zero, SRID.HwndMustBeNonNULL); SafeNodeHandle hnode = UiaCoreApi.UiaNodeFromHandle(hwnd); if (hnode.IsInvalid) { return null; } UiaCoreApi.UiaCacheRequest cacheRequest = CacheRequest.CurrentUiaCacheRequest; // Don't do any normalization when getting updated cache... UiaCoreApi.UiaCacheResponse response = UiaCoreApi.UiaGetUpdatedCache(hnode, cacheRequest, UiaCoreApi.NormalizeState.None, null); // return CacheHelper.BuildAutomationElementsFromResponse(cacheRequest, response); } ////// /// Converts a local IRawElementProvider implementation to an AutomationElement. /// /// Local object implementing IRawElementProvider ///A corresponding AutomationElement for the impl parameter ///This would be used by a client helper library that wanted /// to allow its callers to access its own native element type via PAW. /// For example, the Windows Client Platform uses its own Element type, but /// uses this iternally so that it can had back an AutomationElement to clients /// that want to get an AutomationElement directly from an Element. /// public static AutomationElement FromLocalProvider(IRawElementProviderSimple localImpl) { Misc.ValidateArgumentNonNull(localImpl, "localImpl"); return AutomationElement.Wrap(UiaCoreApi.UiaNodeFromProvider(localImpl)); } ////// Get current value of specified property from an element. /// /// AutomationProperty that identifies the property ///Returns value of specified property ////// If the specified property is not explicitly supported by the target UI, /// a default value will be returned. For example, if the target UI doesn't /// support the AutomationElement.NameProperty, calling GetCurrentPropertyValue /// for that property will return an empty string. /// /// This API gets the current value of the property at this point in time, /// without checking the cache. For some types of UI, this API will incur /// a cross-process performance hit. To access values in this AutomationElement's /// cache, use GetCachedPropertyValue instead. /// /// ////// This API does not work inside the secure execution environment. /// public object GetCurrentPropertyValue(AutomationProperty property) { return GetCurrentPropertyValue(property, false); } ////// /// Get the current value of specified property from an element. /// /// AutomationProperty that identifies the property /// Specifies whether a default value should be /// ignored if the specified property is supported by the target UI ///Returns value of specified property, or AutomationElement.NotSupported ////// This API gets the current value of the property at this point in time, /// without checking the cache. For some types of UI, this API will incur /// a cross-process performance hit. To access values in this AutomationElement's /// cache, use GetCachedPropertyValue instead. /// /// ////// This API does not work inside the secure execution environment. /// public object GetCurrentPropertyValue(AutomationProperty property, bool ignoreDefaultValue) { Misc.ValidateArgumentNonNull(property, "property"); CheckElement(); AutomationPropertyInfo pi; if (!Schema.GetPropertyInfo(property, out pi)) { return new ArgumentException(SR.Get(SRID.UnsupportedProperty)); } object value; // PRESHARP will flag this as warning 56506/6506:Parameter 'property' to this public method must be validated: A null-dereference can occur here. // False positive, property is checked, see above #pragma warning suppress 6506 UiaCoreApi.UiaGetPropertyValue(_hnode, property.Id, out value); if (value != AutomationElement.NotSupported) { // if (value != null && pi.ObjectConverter != null) { value = pi.ObjectConverter(value); } } else { if (ignoreDefaultValue) { value = AutomationElement.NotSupported; } else { value = Schema.GetDefaultValue(property); } } return value; } ////// /// Get a pattern class from this object /// /// AutomationPattern indicating the pattern to return ///Returns the pattern as an object, if currently supported ////// Throws InvalidOperationException if the pattern is not supported. /// /// This API gets the pattern based on availability at this point in time, /// without checking the cache. For some types of UI, this API will incur /// a cross-process performance hit. To access patterns in this AutomationElement's /// cache, use GetCachedPattern instead. /// /// ////// This API does not work inside the secure execution environment. /// public object GetCurrentPattern(AutomationPattern pattern) { object retObject; if (!TryGetCurrentPattern(pattern, out retObject)) { throw new InvalidOperationException(SR.Get(SRID.UnsupportedPattern)); } return retObject; } ////// /// Get a pattern class from this object /// /// an object repressenting the AutomationPattern indicating /// the pattern to return /// the returned pattern object will be an object /// implementing the control pattern interface if the pattern is supported else /// the object will be null. ///Returns true, if currently supported ////// This API gets the pattern based on availability at this point in time, /// without checking the cache. For some types of UI, this API will incur /// a cross-process performance hit. To access patterns in this AutomationElement's /// cache, use GetCachedPattern instead. /// /// ////// This API does not work inside the secure execution environment. /// public bool TryGetCurrentPattern(AutomationPattern pattern, out object patternObject) { patternObject = null; Misc.ValidateArgumentNonNull(pattern, "pattern"); CheckElement(); // Need to catch non-critical exceptions. The WinFormsSpinner will raise an // InvalidOperationException if it is a domain spinner and the SelectionPattern is asked for. SafePatternHandle hpatternobj = null; try { hpatternobj = UiaCoreApi.UiaGetPatternProvider(_hnode, pattern.Id); } catch (Exception e) { if (Misc.IsCriticalException(e)) { throw e; } return false; } if (hpatternobj.IsInvalid) { return false; } patternObject = Misc.WrapInterfaceOnClientSide(this, hpatternobj, pattern); return patternObject != null; } ////// /// Get cached value of specified property from an element. /// /// AutomationProperty that identifies the property ///Returns value of specified property ////// Throws InvalidOperationException if the requested property was not /// previously specified to be pre-fetched using a CacheRequest. /// /// If the specified property is not explicitly supported by the target UI, /// a default value will be returned. For example, if the target UI doesn't /// support the AutomationElement.NameProperty, calling GetCachedPropertyValue /// for that property will return an empty string. /// /// ////// This API does not work inside the secure execution environment. /// public object GetCachedPropertyValue(AutomationProperty property) { return GetCachedPropertyValue(property, false); } ////// /// Get the cached value of specified property from an element. /// /// AutomationProperty that identifies the property /// Specifies whether a default value should be /// ignored if the specified property is not supported by the target UI ///Returns value of specified property, or AutomationElement.NotSupported ////// Throws InvalidOperationException if the requested property was not /// previously specified to be pre-fetched using a CacheRequest. /// /// If ignoreDefaultValue is true, then when the specified property is not /// explicitly supported by the target UI, a default value will not be returned. /// For example, if the target UI doesn't /// support the AutomationElement.NameProperty, calling GetCachedPropertyValue /// for that property will return an empty string. /// When ignoreDefaultValue is true, the value AutomationElement.NotSupported will /// be returned instead. /// /// ////// This API does not work inside the secure execution environment. /// public object GetCachedPropertyValue(AutomationProperty property, bool ignoreDefaultValue) { Misc.ValidateArgumentNonNull(property, "property"); // true -> throw if not available, true -> wrap object val = LookupCachedValue(property, true, true); UiaCoreApi.IsErrorMarker(val, true/*throwException*/); if (val == AutomationElement.NotSupported && !ignoreDefaultValue) { val = Schema.GetDefaultValue(property); } return val; } ////// /// Get a pattern class from this object /// /// AutomationPattern indicating the pattern to return ///Returns the pattern as an object, if currently supported; otherwise returns null/ ////// Throws InvalidOperationException if the requested pattern was not /// previously specified to be pre-fetched using a CacheRequest. /// /// This API gets the pattern from the cache. /// /// ////// This API does not work inside the secure execution environment. /// public object GetCachedPattern(AutomationPattern pattern) { object patternObject; if (!TryGetCachedPattern(pattern, out patternObject)) { throw new InvalidOperationException(SR.Get(SRID.UnsupportedPattern)); } return patternObject; } ////// /// Get a pattern class from this object /// /// AutomationPattern indicating the pattern to return /// Is the pattern as an object, if currently in the cache; otherwise is null ///Returns true, if currently in the cache; otherwise returns false ////// This API gets the pattern from the cache. /// /// ////// This API does not work inside the secure execution environment. /// public bool TryGetCachedPattern(AutomationPattern pattern, out object patternObject) { patternObject = null; // Lookup a cached remote reference - but even if we get // back null, still go ahead an create a pattern wrapper // to provide access to cached properties Misc.ValidateArgumentNonNull(pattern, "pattern"); // false -> don't throw, false -> don't wrap object obj = LookupCachedValue(pattern, false, false); if (obj == null) { return false; } SafePatternHandle hPattern = (SafePatternHandle)obj; AutomationPatternInfo pi; if (!Schema.GetPatternInfo(pattern, out pi)) { throw new ArgumentException(SR.Get(SRID.UnsupportedPattern)); } patternObject = pi.ClientSideWrapper(this, hPattern, true); return patternObject != null; } ////// /// Get an AutomationElement with updated cached values /// /// CacheRequest object describing the properties and other information to fetch ///Returns a new AutomationElement, which refers to the same UI as this element, but which is /// populated with properties specified in the CacheRequest. ////// Unlike other methods, such as FromHandle, FromPoint, this method takes /// an explicit CacheRequest as a parameter, and ignores the currently /// active CacheRequest. /// public AutomationElement GetUpdatedCache(CacheRequest request) { Misc.ValidateArgumentNonNull(request, "request"); CheckElement(); UiaCoreApi.UiaCacheRequest cacheRequest = request.GetUiaCacheRequest(); // Don't normalize when getting updated cache... UiaCoreApi.UiaCacheResponse response = UiaCoreApi.UiaGetUpdatedCache(_hnode, cacheRequest, UiaCoreApi.NormalizeState.None, null); return CacheHelper.BuildAutomationElementsFromResponse(cacheRequest, response); } ////// Find first child or descendant element that matches specified condition /// /// Indicates whether to include this element, children /// or descendants in the search /// Condition to search for ///Returns first element that satisfies condition, /// or null if no match is found. public AutomationElement FindFirst(TreeScope scope, Condition condition) { Misc.ValidateArgumentNonNull(condition, "condition"); UiaCoreApi.UiaCacheResponse[] responses = Find(scope, condition, CacheRequest.CurrentUiaCacheRequest, true, null); if (responses.Length < 1) { return null; } Debug.Assert(responses.Length == 1); return CacheHelper.BuildAutomationElementsFromResponse(CacheRequest.CurrentUiaCacheRequest, responses[0]); } ////// Find all child or descendant elements that match specified condition /// /// Indicates whether to include this element, children /// or descendants in the search /// Condition to search for ///Returns collection of all AutomationElements that /// match specified condition. Collection will be empty if /// no matches found. public AutomationElementCollection FindAll(TreeScope scope, Condition condition) { Misc.ValidateArgumentNonNull(condition, "condition"); UiaCoreApi.UiaCacheRequest request = CacheRequest.CurrentUiaCacheRequest; UiaCoreApi.UiaCacheResponse[] responses = Find(scope, condition, request, false, null); AutomationElement[] els = new AutomationElement[responses.Length]; for( int i = 0 ; i < responses.Length ; i ++ ) { els[i] = CacheHelper.BuildAutomationElementsFromResponse(request, responses[i]); } return new AutomationElementCollection( els ); } ////// Get array of supported property identifiers /// ////// The returned array contains at least all the properties supported by this element; /// however it may also contain duplicate entries or properties that the element does not /// currently support or which have null or empty values. Use GetPropertyValue to determine /// whether a property is currently supported and to determine what its current value is. /// /// ////// This API does not work inside the secure execution environment. /// public AutomationProperty [ ] GetSupportedProperties() { CheckElement(); ArrayList propArrays = new ArrayList(4); propArrays.Add(Schema.GetBasicProperties()); AutomationPattern[] patterns = GetSupportedPatterns(); if (patterns != null && patterns.Length > 0) { foreach (AutomationPattern pattern in patterns) { AutomationPatternInfo pi; if (Schema.GetPatternInfo(pattern, out pi)) { if (pi.Properties != null) { propArrays.Add(pi.Properties); } } } } return (AutomationProperty[])Misc.RemoveDuplicates(Misc.CombineArrays(propArrays, typeof(AutomationProperty)), typeof(AutomationProperty)); } ////// /// Get the interfaces that this object supports /// ///An array of AutomationPatterns that represent the supported interfaces /// ////// This API does not work inside the secure execution environment. /// public AutomationPattern [ ] GetSupportedPatterns() { CheckElement(); ArrayList interfaces = new ArrayList(4); object patternObject; foreach (AutomationPatternInfo pi in Schema.GetPatternInfoTable()) { if (TryGetCurrentPattern(pi.ID, out patternObject)) { interfaces.Add(pi.ID); } } return (AutomationPattern[])interfaces.ToArray(typeof(AutomationPattern)); } ////// /// Request to set focus to this element /// /// ////// This API does not work inside the secure execution environment. /// public void SetFocus() { CheckElement(); object canReceiveFocus = GetCurrentPropertyValue(AutomationElement.IsKeyboardFocusableProperty); if (canReceiveFocus is bool && (bool)canReceiveFocus) { UiaCoreApi.UiaSetFocus(_hnode); } else { throw new InvalidOperationException(SR.Get(SRID.SetFocusFailed)); } } ////// /// Get a point that can be clicked on. If there is no ClickablePoint return false /// /// A point that can be used ba a client to click on this LogicalElement ///true if there is point that is clickable /// ////// This API does not work inside the secure execution environment. /// public bool TryGetClickablePoint( out Point pt ) { // initialize point here so if we return false its initialized pt = new Point (0, 0); // Request the provider for a clickable point. object ptClickable = GetCurrentPropertyValue(AutomationElement.ClickablePointProperty); if (ptClickable == NotSupported) { return false; } // if got one if (ptClickable is Point) { //If the ClickablePointProperty from the provider is NaN that means no point. if (double.IsNaN (((Point) ptClickable).X) || double.IsNaN (((Point) ptClickable).Y)) { return false; } // Allow the object if it is the element or a descentant... AutomationElement scan = AutomationElement.FromPoint((Point)ptClickable); while (scan != null) { if (scan == this) { pt = (Point)ptClickable; return true; } scan = TreeWalker.RawViewWalker.GetParent(scan, CacheRequest.DefaultCacheRequest); } } // the providers point is either no good or they did not have one so poke around // trying to find one. if (ClickablePoint.HitTestForClickablePoint( (AutomationElement)this, out pt) ) return true; return false; } ////// /// Get a point that can be clicked on. This throws the NoClickablePointException if there is no clickable point /// ///A point that can be used by a client to click on this LogicalElement ///If there is not clickable point for this element /// ////// This API does not work inside the secure execution environment. /// public Point GetClickablePoint() { Point pt; if ( !TryGetClickablePoint( out pt ) ) throw new NoClickablePointException(SR.Get(SRID.LogicalElementNoClickablePoint)); return pt; } #endregion Public Methods //----------------------------------------------------- // // Public Properties // //------------------------------------------------------ #region Public Properties ////// /// Get root element for current desktop /// ///root element for current desktop /// ////// This API does not work inside the secure execution environment. /// public static AutomationElement RootElement { get { SafeNodeHandle hnode = UiaCoreApi.UiaGetRootNode(); UiaCoreApi.UiaCacheRequest cacheRequest = CacheRequest.CurrentUiaCacheRequest; // Don't normalize... UiaCoreApi.UiaCacheResponse response = UiaCoreApi.UiaGetUpdatedCache(hnode, cacheRequest, UiaCoreApi.NormalizeState.None, null); // return CacheHelper.BuildAutomationElementsFromResponse(cacheRequest, response); } } ////// /// Return the currently focused element /// /// ////// This API does not work inside the secure execution environment. /// public static AutomationElement FocusedElement { get { //CASRemoval:AutomationPermission.Demand(AutomationPermissionFlag.Read); return DrillForPointOrFocus(false, new Point(0, 0), CacheRequest.CurrentUiaCacheRequest); } } ////// /// This member allows access to previously requested /// cached properties for this element. The returned object /// has accessors for AutomationElement properties. /// ////// Cached property values must have been previously requested /// using a CacheRequest. If you try to access a cached /// property that was not previously requested, an InvalidOperation /// Exception will be thrown. /// /// To get the value of a property at the current point in time, /// access the property via the Current accessor instead of /// Cached. /// public AutomationElementInformation Cached { get { return new AutomationElementInformation(this, true); } } ////// This member allows access to current property values /// for this element. The returned object has accessors for /// AutomationElement properties. /// ////// This AutomationElement must have a /// Full reference in order to get current values. If the /// AutomationElement was obtained using AutomationElementMode.None, /// then it contains only cached data, and attempting to get /// the current value of any property will throw an InvalidOperationException. /// /// To get the cached value of a property that was previously /// specified using a CacheRequest, access the property via the /// Cached accessor instead of Current. /// public AutomationElementInformation Current { get { return new AutomationElementInformation(this, false); } } ////// Returns the cached parent of this AutomationElement /// ////// Returns the parent of this element, with respect to the TreeFilter /// condition of the CacheRequest that was active when this AutomationElement /// was obtained. /// /// Throws InvalidOperationException if the parent was not previously requested /// in a CacheRequest. /// /// Can return null if the specified element has no parent - eg. is the root node. /// public AutomationElement CachedParent { get { // this is used as a marker to indicate 'not requested' // - used since null is a valid value for parent, but this can never be. // Use (object) case to ensure we just do a ref check here, not call .Equals if ((object)_cachedParent == (object)this) { // PRESHARP will flag this as a warning 56503/6503: Property get methods should not throw exceptions // We've spec'd as throwing an Exception, and that's what we do PreSharp shouldn't complain #pragma warning suppress 6503 throw new InvalidOperationException(SR.Get(SRID.CachedPropertyNotRequested)); } return _cachedParent; } } ////// Returns the cached children of this AutomationElement /// ////// Returns a collection of children of this element, with respect to the TreeFilter /// condition of the CacheRequest that was active when this AutomationElement /// was obtained. /// /// Throws InvalidOperationException if children or descendants were not previously requested /// in a CacheRequest. /// /// Can return an empty collection if this AutomationElement has no children. /// public AutomationElementCollection CachedChildren { get { // this is used as a marker to indicate 'not requested' // - used since null is a valid value for parent, but this can never be. // Use (object) case to ensure we just do a ref check here, not call .Equals if ((object)_cachedFirstChild == (object)this) { // PRESHARP will flag this as a warning 56503/6503: Property get methods should not throw exceptions // We've spec'd as throwing an Exception, and that's what we do PreSharp shouldn't complain #pragma warning suppress 6503 throw new InvalidOperationException(SR.Get(SRID.CachedPropertyNotRequested)); } // Build up an array to return - first count the children, // then build an array and populate it... int childCount = 0; AutomationElement scan = _cachedFirstChild; for (; scan != null; scan = scan._cachedNextSibling) { childCount++; } AutomationElement[] children = new AutomationElement[childCount]; scan = _cachedFirstChild; for (int i = 0; i < childCount; i++) { children[i] = scan; scan = scan._cachedNextSibling; } return new AutomationElementCollection(children); } } #endregion Public Properties //----------------------------------------------------- // // Internal Methods // //----------------------------------------------------- #region Internal Methods internal void CheckElement() { if (_hnode == null || _hnode.IsInvalid) { throw new InvalidOperationException(SR.Get(SRID.CacheRequestNeedElementReference)); } } // Called by the treewalker classes to navigate - we call through to the // provider wrapper, which gets the navigator code to do its stuff internal AutomationElement Navigate(NavigateDirection direction, Condition condition, CacheRequest request) { CheckElement(); UiaCoreApi.UiaCacheRequest cacheRequest; if (request == null) cacheRequest = CacheRequest.DefaultUiaCacheRequest; else cacheRequest = request.GetUiaCacheRequest(); UiaCoreApi.UiaCacheResponse response = UiaCoreApi.UiaNavigate(_hnode, direction, condition, cacheRequest); return CacheHelper.BuildAutomationElementsFromResponse(cacheRequest, response); } internal AutomationElement Normalize(Condition condition, CacheRequest request ) { CheckElement(); UiaCoreApi.UiaCacheRequest cacheRequest; if (request == null) cacheRequest = CacheRequest.DefaultUiaCacheRequest; else cacheRequest = request.GetUiaCacheRequest(); // Normalize against the treeview condition, not the one in the cache request... UiaCoreApi.UiaCacheResponse response = UiaCoreApi.UiaGetUpdatedCache(_hnode, cacheRequest, UiaCoreApi.NormalizeState.Custom, condition); return CacheHelper.BuildAutomationElementsFromResponse(cacheRequest, response); } // Used by the pattern wrappers to get property values internal object GetPatternPropertyValue(AutomationProperty property, bool useCache) { if (useCache) return GetCachedPropertyValue(property); else return GetCurrentPropertyValue(property); } // The following are used by CacheUtil when building up a cached AutomationElemen tree internal void SetCachedParent(AutomationElement cachedParent) { _cachedParent = cachedParent; // If we're setting the parent, it means this is one of potentially // many siblings - so set _cachedNextSibling to null, instead of // the 'not requested' marker value 'this' _cachedNextSibling = null; } internal void SetCachedFirstChild(AutomationElement cachedFirstChild) { _cachedFirstChild = cachedFirstChild; } internal void SetCachedNextSibling(AutomationElement cachedNextSibling) { _cachedNextSibling = cachedNextSibling; } #endregion Internal Methods //----------------------------------------------------- // // Internal Properties // //------------------------------------------------------ #region Internal Properties internal SafeNodeHandle RawNode { get { return _hnode; } } #endregion Internal Properties //----------------------------------------------------- // // Private Methods // //------------------------------------------------------ #region Private Methods // Lookup a cached AutomationPattern or AutomationProperty object LookupCachedValue(AutomationIdentifier id, bool throwIfNotRequested, bool wrap) { if (_cachedValues == null) { if (throwIfNotRequested) { throw new InvalidOperationException(SR.Get(SRID.CachedPropertyNotRequested)); } else { return null; } } AutomationProperty automationProperty = id as AutomationProperty; bool isProperty = automationProperty != null; AutomationIdentifier[] refTable = isProperty ? (AutomationIdentifier[])_request.Properties : (AutomationIdentifier[])_request.Patterns; bool found = false; object val = null; int dataOffset = isProperty ? 1 : 1 + _request.Properties.Length; for (int i = 0; i < refTable.Length; i++) { if (refTable[i] == id) { found = true; val = _cachedValues[_cachedValuesIndex, i + dataOffset]; break; } } if (!found) { if (throwIfNotRequested) { throw new InvalidOperationException(SR.Get(SRID.CachedPropertyNotRequested)); } else { return null; } } // Bail now if no wrapping required; also, even with wrapping, null remains null // for both properties and patterns.. if (!wrap || val == null) { return val; } AutomationPattern automationPattern = id as AutomationPattern; // Cached values are internally stored as unwrapped, direct-from-provider values, so // need to be wrapped as appropriate before handing back to client... if (automationPattern != null) { SafePatternHandle hpatternobj = (SafePatternHandle)val; val = Misc.WrapInterfaceOnClientSide(this, hpatternobj, automationPattern); } // No wrapping necessary here for properties - the objects in the array are fully wrapped/converted as soon as they are // received from the unmanaged API, so they're ready-to-use without any further processing. return val; } // drill for either focused raw element, or element at specified point private static AutomationElement DrillForPointOrFocus(bool atPoint, Point pt, UiaCoreApi.UiaCacheRequest cacheRequest) { UiaCoreApi.UiaCacheResponse response; if (atPoint) response = UiaCoreApi.UiaNodeFromPoint(pt.X, pt.Y, cacheRequest); else response = UiaCoreApi.UiaNodeFromFocus(cacheRequest); return CacheHelper.BuildAutomationElementsFromResponse(cacheRequest, response); } // called by FindFirst and FindAll private UiaCoreApi.UiaCacheResponse[] Find(TreeScope scope, Condition condition, UiaCoreApi.UiaCacheRequest request, bool findFirst, BackgroundWorker worker) { Misc.ValidateArgumentNonNull(condition, "condition"); if (scope == 0) { throw new ArgumentException(SR.Get(SRID.TreeScopeNeedAtLeastOne)); } if ((scope & ~(TreeScope.Element | TreeScope.Children | TreeScope.Descendants)) != 0) { throw new ArgumentException(SR.Get(SRID.TreeScopeElementChildrenDescendantsOnly)); } // Set up a find struct... UiaCoreApi.UiaFindParams findParams = new UiaCoreApi.UiaFindParams(); findParams.FindFirst = findFirst; if ((scope & TreeScope.Descendants) != 0) findParams.MaxDepth = -1; else if ((scope & TreeScope.Children) != 0) findParams.MaxDepth = 1; else findParams.MaxDepth = 0; if ((scope & TreeScope.Element) != 0) findParams.ExcludeRoot = false; else findParams.ExcludeRoot = true; UiaCoreApi.UiaCacheResponse[] retVal = UiaCoreApi.UiaFind(_hnode, findParams, condition, request); return retVal; } #endregion Private Methods //------------------------------------------------------ // // Private Fields // //----------------------------------------------------- #region Private Fields private SafeNodeHandle _hnode; private int[] _runtimeId; // Cached object values - use in conjunction with the Properties/Pattern arrays in // _request to figure out which properties/patterns they are. // Note that these use NotSupported, so need to substitute default values // when returning to user. private object[,] _cachedValues; private int _cachedValuesIndex; // index of row in cachedValues that corresponds to this element // Reference to the cache request information that was active when this // element was created private UiaCoreApi.UiaCacheRequest _request; // Cached structure links - these set to 'this' to indicate that they // were not requested - since null is a valid value. private AutomationElement _cachedParent; private AutomationElement _cachedFirstChild; private AutomationElement _cachedNextSibling; #endregion Private Fields //------------------------------------------------------ // // Nested Classes // //----------------------------------------------------- #region Nested Classes ////// This class provides access to either Cached or Current /// properties on an AutomationElement via the .Cached or /// .Current accessors. /// public struct AutomationElementInformation { //----------------------------------------------------- // // Constructors // //----------------------------------------------------- #region Constructors internal AutomationElementInformation(AutomationElement el, bool useCache) { _el = el; _useCache = useCache; } #endregion Constructors //------------------------------------------------------ // // Public Properties // //----------------------------------------------------- #region Public Properties ///The ControlType of this Element public ControlType ControlType { get { return (ControlType) _el.GetPatternPropertyValue(ControlTypeProperty, _useCache); } } ///Localized control type description (eg. "Button") public string LocalizedControlType { get { return (string) _el.GetPatternPropertyValue(LocalizedControlTypeProperty, _useCache); } } ///Name of this instance of control public string Name { get { return (string) _el.GetPatternPropertyValue(NameProperty, _useCache); } } ///Hot-key equivalent for this command item. (eg. Ctrl-P for Print) public string AcceleratorKey { get { return (string) _el.GetPatternPropertyValue(AcceleratorKeyProperty, _useCache); } } ///Keys used to move focus to this control public string AccessKey { get { return (string) _el.GetPatternPropertyValue(AccessKeyProperty, _useCache); } } ///Indicates whether this control has keyboard focus public bool HasKeyboardFocus { get { return (bool) _el.GetPatternPropertyValue(HasKeyboardFocusProperty, _useCache); } } ///True if this control can take keyboard focus public bool IsKeyboardFocusable { get { return (bool) _el.GetPatternPropertyValue(IsKeyboardFocusableProperty, _useCache); } } ///True if this control is enabled public bool IsEnabled { get { return (bool) _el.GetPatternPropertyValue(IsEnabledProperty, _useCache); } } ///Bounding rectangle, in screen coordinates public Rect BoundingRectangle { get { return (Rect) _el.GetPatternPropertyValue(BoundingRectangleProperty, _useCache); } } ///HelpText - brief description of what this control does public string HelpText { get { return (string) _el.GetPatternPropertyValue(HelpTextProperty, _useCache); } } ///Indicates that this element should be included in the Control view of the tree public bool IsControlElement { get { return (bool) _el.GetPatternPropertyValue(IsControlElementProperty, _useCache); } } ///Indicates that this element should be included in the Content view of the tree public bool IsContentElement { get { return (bool) _el.GetPatternPropertyValue(IsContentElementProperty, _useCache); } } ///The AutomationElement that labels this element public AutomationElement LabeledBy { get { return (AutomationElement) _el.GetPatternPropertyValue(LabeledByProperty, _useCache); } } ///The identifier for an element that is unique within its containing element public string AutomationId { get { return (string) _el.GetPatternPropertyValue(AutomationIdProperty, _useCache); } } ///Localized string that indicates what the items in a list represent public string ItemType { get { return (string) _el.GetPatternPropertyValue(ItemTypeProperty, _useCache ); } } ///True if the control is a password protected field. public bool IsPassword { get { return (bool) _el.GetPatternPropertyValue(IsPasswordProperty, _useCache); } } ///Name of underlying class - implementation dependant, but useful for test public string ClassName { get { return (string) _el.GetPatternPropertyValue(ClassNameProperty, _useCache); } } ///Window Handle, if the underlying control is a Window public int NativeWindowHandle { get { return (int) _el.GetPatternPropertyValue(NativeWindowHandleProperty, _useCache); } } ///Id of process that this element lives in public int ProcessId { get { return (int) _el.GetPatternPropertyValue(ProcessIdProperty, _useCache); } } ///True if this control is not visible to the sighted user public bool IsOffscreen { get { return (bool) _el.GetPatternPropertyValue(IsOffscreenProperty, _useCache); } } ///The controls specfied direction public OrientationType Orientation { get { return (OrientationType) _el.GetPatternPropertyValue(OrientationProperty, _useCache); } } ///The controls specfied direction public string FrameworkId { get { return (string) _el.GetPatternPropertyValue(FrameworkIdProperty, _useCache); } } ///True if this element is required to be filled out on a form public bool IsRequiredForForm { get { return (bool) _el.GetPatternPropertyValue(IsRequiredForFormProperty, _useCache); } } ///The visual status of a complex item as a string public string ItemStatus { get { return (string) _el.GetPatternPropertyValue(ItemStatusProperty, _useCache); } } #endregion Public Properties //------------------------------------------------------ // // Private Fields // //------------------------------------------------------ #region Private Fields private AutomationElement _el; // AutomationElement that contains the cache or live reference private bool _useCache; // true to use cache, false to use live reference to get current values #endregion Private Fields } #endregion Nested Classes } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- SplitContainer.cs
- ConfigurationSectionHelper.cs
- LinqDataSourceHelper.cs
- FrameDimension.cs
- EventArgs.cs
- XDRSchema.cs
- CodeSpit.cs
- Padding.cs
- SoapObjectWriter.cs
- BindingWorker.cs
- RenderTargetBitmap.cs
- SurrogateSelector.cs
- DiscoveryProxy.cs
- Function.cs
- WbemProvider.cs
- DbConnectionPoolOptions.cs
- Color.cs
- MatrixTransform3D.cs
- XhtmlBasicListAdapter.cs
- Size.cs
- ReferenceAssemblyAttribute.cs
- HtmlFormAdapter.cs
- XmlSchemaObjectCollection.cs
- HexParser.cs
- __FastResourceComparer.cs
- LogEntryDeserializer.cs
- unitconverter.cs
- ProcessThread.cs
- RemotingHelper.cs
- UrlMappingsSection.cs
- ApplicationServiceManager.cs
- CodeCompiler.cs
- GAC.cs
- Config.cs
- ToolStripArrowRenderEventArgs.cs
- ReaderWriterLock.cs
- xsdvalidator.cs
- WebResourceAttribute.cs
- PaintValueEventArgs.cs
- EnumerableValidator.cs
- DeclarativeExpressionConditionDeclaration.cs
- StrokeNodeEnumerator.cs
- CompoundFileReference.cs
- Int16.cs
- BinHexEncoder.cs
- DeclarativeExpressionConditionDeclaration.cs
- MultiBindingExpression.cs
- BaseValidator.cs
- EdmRelationshipRoleAttribute.cs
- Selector.cs
- AnnotationDocumentPaginator.cs
- RoleManagerModule.cs
- DataFormats.cs
- GeneralTransform3DTo2DTo3D.cs
- FontNamesConverter.cs
- SignerInfo.cs
- Accessible.cs
- LOSFormatter.cs
- ProviderConnectionPointCollection.cs
- DataGridViewImageCell.cs
- MailMessage.cs
- Msmq.cs
- ColorConvertedBitmap.cs
- BCryptNative.cs
- CombinedGeometry.cs
- PropertyChangeTracker.cs
- PtsCache.cs
- WebServiceTypeData.cs
- RemoteCryptoDecryptRequest.cs
- ISCIIEncoding.cs
- EasingKeyFrames.cs
- XmlIlVisitor.cs
- NullableLongSumAggregationOperator.cs
- SynchronizingStream.cs
- altserialization.cs
- AlphabeticalEnumConverter.cs
- ResolveDuplexAsyncResult.cs
- MarginCollapsingState.cs
- DataGridViewLinkColumn.cs
- WebPartsPersonalization.cs
- TextBounds.cs
- Token.cs
- ActiveXContainer.cs
- basenumberconverter.cs
- Setter.cs
- ResolveInfo.cs
- BitmapEffect.cs
- RuleDefinitions.cs
- CodeThrowExceptionStatement.cs
- ImpersonateTokenRef.cs
- SmiRecordBuffer.cs
- GlyphCollection.cs
- WebScriptMetadataInstanceContextProvider.cs
- RubberbandSelector.cs
- PhonemeConverter.cs
- MaxValueConverter.cs
- IMembershipProvider.cs
- XPathSelfQuery.cs
- ZipIOExtraField.cs
- OleDbCommand.cs