AutomationElement.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / UIAutomation / UIAutomationClient / System / Windows / Automation / AutomationElement.cs / 1305600 / 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 SynchronizedInputPattern is available for this AutomationElement
        public static readonly AutomationProperty IsSynchronizedInputPatternAvailableProperty = AutomationElementIdentifiers.IsSynchronizedInputPatternAvailableProperty;
        /// Property that indicates whether the ScrollItemPattern is available for this AutomationElement 
        public static readonly AutomationProperty IsScrollItemPatternAvailableProperty = AutomationElementIdentifiers.IsScrollItemPatternAvailableProperty;
        /// Property that indicates whether the VirtualizedItemPattern is available for this AutomationElement 
        public static readonly AutomationProperty IsVirtualizedItemPatternAvailableProperty = AutomationElementIdentifiers.IsVirtualizedItemPatternAvailableProperty; 
        /// Property that indicates whether the ItemContainerPattern is available for this AutomationElement
        public static readonly AutomationProperty IsItemContainerPatternAvailableProperty = AutomationElementIdentifiers.IsItemContainerPatternAvailableProperty; 
        /// 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 (pi.ID != null && 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 SynchronizedInputPattern is available for this AutomationElement
        public static readonly AutomationProperty IsSynchronizedInputPatternAvailableProperty = AutomationElementIdentifiers.IsSynchronizedInputPatternAvailableProperty;
        /// Property that indicates whether the ScrollItemPattern is available for this AutomationElement 
        public static readonly AutomationProperty IsScrollItemPatternAvailableProperty = AutomationElementIdentifiers.IsScrollItemPatternAvailableProperty;
        /// Property that indicates whether the VirtualizedItemPattern is available for this AutomationElement 
        public static readonly AutomationProperty IsVirtualizedItemPatternAvailableProperty = AutomationElementIdentifiers.IsVirtualizedItemPatternAvailableProperty; 
        /// Property that indicates whether the ItemContainerPattern is available for this AutomationElement
        public static readonly AutomationProperty IsItemContainerPatternAvailableProperty = AutomationElementIdentifiers.IsItemContainerPatternAvailableProperty; 
        /// 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 (pi.ID != null && 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