AutomationElement.cs source code in C# .NET

Source code for the .NET framework in C#

                        

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

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