AutomationPeer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Core / CSharp / System / Windows / Automation / Peers / AutomationPeer.cs / 1 / AutomationPeer.cs

                            using System; 
using System.Collections;
using System.Security;
using System.Security.Permissions;
using System.Windows; 
using System.Windows.Interop;
using System.Windows.Media; 
using System.Windows.Threading; 
using System.Collections.Generic;
using System.Windows.Automation.Provider; 

using MS.Internal;
using MS.Internal.Automation;
using MS.Internal.Media; 
using MS.Internal.PresentationCore;
using MS.Win32; 
 
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID; 

namespace System.Windows.Automation.Peers
{
    /// 
    public enum PatternInterface
    { 
        /// 
        Invoke,
        /// 
        Selection,
        ///
        Value,
        /// 
        RangeValue,
        /// 
        Scroll, 
        ///
        ScrollItem, 
        ///
        ExpandCollapse,
        ///
        Grid, 
        ///
        GridItem, 
        /// 
        MultipleView,
        /// 
        Window,
        ///
        SelectionItem,
        /// 
        Dock,
        /// 
        Table, 
        ///
        TableItem, 
        ///
        Toggle,
        ///
        Transform, 
        ///
        Text, 
    } 

    /// 
    public enum AutomationOrientation
    {
        ///
        None = 0, 
        ///
        Horizontal, 
        /// 
        Vertical,
    } 

    ///
    public enum AutomationControlType
    { 
        ///
        Button, 
        /// 
        Calendar,
        /// 
        CheckBox,
        ///
        ComboBox,
        /// 
        Edit,
        /// 
        Hyperlink, 
        ///
        Image, 
        ///
        ListItem,
        ///
        List, 
        ///
        Menu, 
        /// 
        MenuBar,
        /// 
        MenuItem,
        ///
        ProgressBar,
        /// 
        RadioButton,
        /// 
        ScrollBar, 
        ///
        Slider, 
        ///
        Spinner,
        ///
        StatusBar, 
        ///
        Tab, 
        /// 
        TabItem,
        /// 
        Text,
        ///
        ToolBar,
        /// 
        ToolTip,
        /// 
        Tree, 
        ///
        TreeItem, 
        ///
        Custom,
        ///
        Group, 
        ///
        Thumb, 
        /// 
        DataGrid,
        /// 
        DataItem,
        ///
        Document,
        /// 
        SplitButton,
        /// 
        Window, 
        ///
        Pane, 
        ///
        Header,
        ///
        HeaderItem, 
        ///
        Table, 
        /// 
        TitleBar,
        /// 
        Separator,
    }

    /// 
    public enum AutomationEvents
    { 
        /// 
        ToolTipOpened,
        /// 
        ToolTipClosed,
        ///
        MenuOpened,
        /// 
        MenuClosed,
        /// 
        AutomationFocusChanged, 
        ///
        InvokePatternOnInvoked, 
        ///
        SelectionItemPatternOnElementAddedToSelection,
        ///
        SelectionItemPatternOnElementRemovedFromSelection, 
        ///
        SelectionItemPatternOnElementSelected, 
        /// 
        SelectionPatternOnInvalidated,
        /// 
        TextPatternOnTextSelectionChanged,
        ///
        TextPatternOnTextChanged,
        /// 
        AsyncContentLoaded,
        /// 
        PropertyChanged, 
        ///
        StructureChanged, 
    }


    /// This is a helper class to facilate the storage of Security critical data ( aka "Plutonium") 
    /// It's primary purpose is to do put a [SecurityCritical] on all access to the data.
    /// What is "critical data" ? This is any data created that required an Assert for it's creation. 
    /// As an example - the passage of hosted Hwnd between some AutomationPeer and UIA infrastructure. 
    public sealed class HostedWindowWrapper
    { 
        /// 
        /// This is the only public constructor on this class.
        /// It requires "Full Trust" level of security permissions to be executed, since this
        /// class is wrappign an HWND direct access to which is a critical asset. 
        /// 
        ///  
        /// Critical - as this accesses _hwnd which is Critical. 
        /// Safe - as the caller already got the critical value.
        /// In addition, we prevent creating this class by external callers who does not have UnmanagedCode permission. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        public HostedWindowWrapper(IntPtr hwnd)
        { 
            (new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)).Demand();
            _hwnd = hwnd; 
        } 

        //  
        //    Critical "by definition" - this class is intended to store critical data.
        // 
        [SecurityCritical]
        private HostedWindowWrapper() 
        {
            _hwnd = IntPtr.Zero; 
        } 

        //  
        //    Critical "by definition" - this class is intended to store critical data.
        // 
        [SecurityCritical]
        internal static HostedWindowWrapper CreateInternal(IntPtr hwnd) 
        {
            HostedWindowWrapper wrapper = new HostedWindowWrapper(); 
            wrapper._hwnd = hwnd; 
            return wrapper;
        } 

        // 
        //    Critical "by definition" - this class is intended to store critical data.
        //  
        internal IntPtr Handle
        { 
            [SecurityCritical] 
            get
            { 
                return _hwnd;
            }
        }
 
        /// 
        /// Critical - by definition as this is a wrapper for Critical data. 
        ///  
        [SecurityCritical]
        private IntPtr _hwnd; 
    }


    /// 
    public abstract class AutomationPeer: DispatcherObject
    { 
        /// 
        protected AutomationPeer()
        { 
            if (!s_initialized)
            {
                Initialize();
            } 
        }
 
        // 
        // VIRTUAL CALLBACKS
        // 

        ///
        abstract protected List GetChildrenCore();
 
        ///
        abstract public object GetPattern(PatternInterface patternInterface); 
 

        // 
        // PUBLIC METHODS
        //

        /// 
        public void InvalidatePeer()
        { 
            if(_invalidated) return; 

            Dispatcher.BeginInvoke(DispatcherPriority.Background, _updatePeer, this); 
            _invalidated = true;
        }

        /// 
        /// Used to check if Automation is indeed listening for the event.
        /// Typical usage is to check this before even creating the peer that will fire the event. 
        /// Basically, this is a performance measure since if the Automation does not listen for the event, 
        /// it does not make sense to create a peer to fire one.
        /// NOTE: the method is static and only answers if there is some listener in Automation, 
        /// not specifically for some element. The Automation can hook up "broadcast listeners" so the
        /// per-element info is basically unavailable.
        ///
        static public bool ListenerExists(AutomationEvents eventId) 
        {
            return (EventMap.HasRegisteredEvent(eventId)); 
        } 

        /// 
        /// Used by peer implementation to raise an event for Automation
        ///
        // Never inline, as we don't want to unnecessarily link the automation DLL.
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] 
        public void RaiseAutomationEvent(AutomationEvents eventId)
        { 
            AutomationEvent eventObject = EventMap.GetRegisteredEvent(eventId); 

            if (eventObject == null) 
            {
                // nobody is listening to this event
                return;
            } 

            IRawElementProviderSimple provider = ProviderFromPeer(this); 
            if (provider != null) 
            {
                AutomationInteropProvider.RaiseAutomationEvent( 
                    eventObject,
                    provider,
                    new AutomationEventArgs(eventObject));
            } 
        }
 
        ///  
        /// This method is called by implementation of the peer to raise the automation propertychange notifications
        /// Typically, the peers that implement automation patterns liek IScrollProvider need to raise events specified by 
        /// the particular pattern in case specific properties are changing.
        /// 
        // Never inline, as we don't want to unnecessarily link the automation DLL via the ScrollPattern reference.
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] 
        public void RaisePropertyChangedEvent(AutomationProperty property, object oldValue, object newValue)
        { 
            // Only send the event if there are listeners for this property change 
            if (AutomationInteropProvider.ClientsAreListening)
            { 
                RaisePropertyChangedInternal(ProviderFromPeer(this), property,oldValue,newValue);
            }
        }
 
        /// 
        /// This method is called by implementation of the peer to raise the automation "async content loaded" notifications 
        ///  
        // Never inline, as we don't want to unnecessarily link the automation DLL.
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] 
        public void RaiseAsyncContentLoadedEvent(AsyncContentLoadedEventArgs args)
        {
            if(args == null)
                throw new ArgumentNullException("args"); 

            if (EventMap.HasRegisteredEvent(AutomationEvents.AsyncContentLoaded)) 
            { 
                IRawElementProviderSimple provider = ProviderFromPeer(this);
                if(provider != null) 
                {
                    AutomationInteropProvider.RaiseAutomationEvent(
                        AutomationElementIdentifiers.AsyncContentLoadedEvent,
                        provider, 
                        args);
                } 
            } 
        }
 
        internal static void RaiseFocusChangedEventHelper(IInputElement newFocus)
        {
            // Callers have only checked if automation clients are present so filter for any interest in this particular event.
            if (EventMap.HasRegisteredEvent(AutomationEvents.AutomationFocusChanged)) 
            {
                AutomationPeer peer = AutomationPeerFromInputElement(newFocus); 
 
                if (peer != null)
                { 
                    peer.RaiseAutomationEvent(AutomationEvents.AutomationFocusChanged);
                }
                else //non-automated element got focus, same as focus lost
                { 
                    //No focused peer. Just don't report anything.
                } 
            } 
        }
 
        //  helper method. Makes attempt to find an automation peer corresponding to the given IInputElement...
        internal static AutomationPeer AutomationPeerFromInputElement(IInputElement focusedElement)
        {
            AutomationPeer peer = null; 

            UIElement uie = focusedElement as UIElement; 
            if (uie != null) 
            {
                peer = UIElementAutomationPeer.CreatePeerForElement(uie); 
            }
            else
            {
                ContentElement ce = focusedElement as ContentElement; 
                if (ce != null)
                { 
                    peer = ContentElementAutomationPeer.CreatePeerForElement(ce); 
                }
                else 
                {
                    UIElement3D uie3D = focusedElement as UIElement3D;
                    if (uie3D != null)
                    { 
                        peer = UIElement3DAutomationPeer.CreatePeerForElement(uie3D);
                    } 
                } 
            }
 
            if (peer != null)
            {
                //  ValidateConnected ensures that EventsSource is initialized
                peer.ValidateConnected(peer); 

                //  always use event source when available 
                if (peer.EventsSource != null) 
                {
                    peer = peer.EventsSource; 
                }
            }

            return peer; 
        }
 
        // We can only return peers to UIA that are properly connected to the UIA tree already 
        // This means they should have _hwnd and _parent already set and _parent should point to the
        // peer which would have this peer returned from its GetChildrenCore. This method checks if the 
        // peer is already connected, and if not then it walks the tree of peers from the top down, calling
        // GetChildren and trying to find itself in someone's children. Once this succeeds, the peer is connected
        // (because GetChildren will connect it). In this case this method will return "this".
        // However if the search does not find the peer, that means the peer 
        // would never be exposed by specific context even though it is createable on the element (the decision to expose
        // children is on parent peers and parent peer may decide not to expose subpart of itself). In this case, 
        // this method returns null. 
        // ConnectedPeer parameter is some peer which is known to be connected (typically root, but if not, this method will
        // walk up from the given connectedPeer up to find a root) 
        ///
        ///     Critical - Accessing _hwnd
        ///     TreatAsSafe - _hwnd is used internally and not exposed.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal AutomationPeer ValidateConnected(AutomationPeer connectedPeer) 
        { 
            if(connectedPeer == null)
                throw new ArgumentNullException("connectedPeer"); 

            if(_parent != null && _hwnd != IntPtr.Zero) return this;

            if((connectedPeer._hwnd) != IntPtr.Zero) 
            {
                while(connectedPeer._parent != null) connectedPeer = connectedPeer._parent; 
 
                //now connectedPeer is the root
                if ((connectedPeer == this) || isDescendantOf(connectedPeer)) 
                    return this;
            }

            //last effort - find across all roots 
            //only start fault in the tree from the root if we are not in the recursive [....] update
            //Otherwise it will go through the peers that are currently on the stack 
            ContextLayoutManager lm = ContextLayoutManager.From(this.Dispatcher); 
            if(lm != null && lm.AutomationSyncUpdateCounter == 0)
            { 
                AutomationPeer[] roots = lm.GetAutomationRoots();
                for(int i = 0; i < roots.Length; i++)
                {
                    AutomationPeer root = roots[i]; 

                    if (root != null) 
                    { 
                        if((root == this) || isDescendantOf(root))
                        return this; 
                    }
                }
            }
 
            return null;
        } 
 
        private bool isDescendantOf(AutomationPeer parent)
        { 
            if(parent == null)
                throw new ArgumentNullException("parent");

            List children  = parent.GetChildren(); 

            if(children == null) 
                return false; 

            int cnt = children.Count; 
            for(int i = 0; i < cnt; ++i)
            {
                AutomationPeer child = children[i];
 
                //depth first
                if(child == this || this.isDescendantOf(child)) 
                    return true; 
            }
 
            return false;
        }

        /// 
        /// Outside of hosting scenarios AutomationPeers shoudl not override this method.
        /// It is needed for peers that implement their own host HWNDs 
        /// for these HWNDs to appear in a proper place in the UIA tree. 
        /// Without this interface being omplemented, the HWND is parented by UIA as a child
        /// of the HwndSource that hosts whole Avalon app. Instead, it is usually desirable 
        /// to override this defautl behavior and tell UIA to parent hosted HWND as a child
        /// somewhere in Avlaon tree where it is actually hosted.
        /// 
        /// Automation infrastructure provides necessary hookup, the AutomationPeer of the element that 
        /// immediately hosts the HWND should implement this interface to be properly wired in.
        /// In addition to that, it should return this peer as IRawElementProviderSimple as a response to 
        /// WM_GETOBJECT coming to the hosted HWND. 
        /// 
        /// To obtain the IRawElementProviderSimple interface, the peer should use 
        /// System.Windows.Automation.AutomationInteropProvider.HostProviderFromHandle(hwnd).
        ///
        /// 
        ///     Critical    - Calls critical AutomationPeer.Hwnd. 
        ///     TreatAsSafe - Critical data is used internally and not explosed
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        virtual protected HostedWindowWrapper GetHostRawElementProviderCore()
        { 
            HostedWindowWrapper host = null;

            //in normal Avalon subtrees, only root peers should return wrapped HWND
            if(GetParent() == null) 
            {
                // this way of creating HostedWindowWrapper does not require FullTrust 
                host = HostedWindowWrapper.CreateInternal(Hwnd); 
            }
 
            return host;
        }

        internal HostedWindowWrapper GetHostRawElementProvider() 
        {
            return GetHostRawElementProviderCore(); 
        } 

        /// 
        /// Returns 'true' only if this is a peer that hosts HWND in Avalon (WindowsFormsHost or Popup for example).
        /// Such peers also have to override GetHostRawElementProviderCore method.
        ///
        virtual protected internal bool IsHwndHost { get { return false; }} 

        // 
        // P R O P E R T I E S 
        //
 
        ///
        abstract protected Rect GetBoundingRectangleCore();

        /// 
        abstract protected bool IsOffscreenCore();
 
        /// 
        abstract protected AutomationOrientation GetOrientationCore();
 
        ///
        abstract protected string GetItemTypeCore();

        /// 
        abstract protected string GetClassNameCore();
 
        /// 
        abstract protected string GetItemStatusCore();
 
        ///
        abstract protected bool IsRequiredForFormCore();

        /// 
        abstract protected bool IsKeyboardFocusableCore();
 
        /// 
        abstract protected bool HasKeyboardFocusCore();
 
        ///
        abstract protected bool IsEnabledCore();

        /// 
        abstract protected bool IsPasswordCore();
 
        /// 
        abstract protected string GetAutomationIdCore();
 
        ///
        abstract protected string GetNameCore();

        /// 
        abstract protected AutomationControlType GetAutomationControlTypeCore();
 
        /// 
        virtual protected string GetLocalizedControlTypeCore()
        { 
            ControlType controlType = GetControlType();
            return controlType.LocalizedControlType;
        }
 
        ///
        abstract protected bool IsContentElementCore(); 
 
        ///
        abstract protected bool IsControlElementCore(); 

        ///
        abstract protected AutomationPeer GetLabeledByCore();
 
        ///
        abstract protected string GetHelpTextCore(); 
 
        ///
        abstract protected string GetAcceleratorKeyCore(); 

        ///
        abstract protected string GetAccessKeyCore();
 
        ///
        abstract protected Point GetClickablePointCore(); 
 
        ///
        abstract protected void SetFocusCore(); 

        //
        // INTERNAL STUFF - NOT OVERRIDABLE
        // 

 
        /// 
        public Rect GetBoundingRectangle()
        { 
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));

            try 
            {
                _publicCallInProgress = true; 
                _boundingRectangle = GetBoundingRectangleCore(); 
            }
            finally 
            {
                _publicCallInProgress = false;
            }
            return _boundingRectangle; 
        }
 
        /// 
        public bool IsOffscreen()
        { 
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));

            try 
            {
                _publicCallInProgress = true; 
                _isOffscreen = IsOffscreenCore(); 
            }
            finally 
            {
                _publicCallInProgress = false;
            }
            return _isOffscreen; 
        }
 
        /// 
        public AutomationOrientation GetOrientation()
        { 
            AutomationOrientation result;

            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 

            try 
            { 
                _publicCallInProgress = true;
                result = GetOrientationCore(); 
            }
            finally
            {
                _publicCallInProgress = false; 
            }
            return result; 
        } 

        /// 
        public string GetItemType()
        {
            string result;
 
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 
 
            try
            { 
                _publicCallInProgress = true;
                result = GetItemTypeCore();
            }
            finally 
            {
                _publicCallInProgress = false; 
            } 
            return result;
        } 

        ///
        public string GetClassName()
        { 
            string result;
 
            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try
            {
                _publicCallInProgress = true;
                result = GetClassNameCore(); 
            }
            finally 
            { 
                _publicCallInProgress = false;
            } 
            return result;
        }

        /// 
        public string GetItemStatus()
        { 
            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try
            {
                _publicCallInProgress = true;
                _itemStatus = GetItemStatusCore(); 
            }
            finally 
            { 
                _publicCallInProgress = false;
            } 
            return _itemStatus;
        }

        /// 
        public bool IsRequiredForForm()
        { 
            bool result; 

            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));

            try
            { 
                _publicCallInProgress = true;
                result = IsRequiredForFormCore(); 
            } 
            finally
            { 
                _publicCallInProgress = false;
            }
            return result;
        } 

        /// 
        public bool IsKeyboardFocusable() 
        {
            bool result; 

            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try
            { 
                _publicCallInProgress = true; 
                result = IsKeyboardFocusableCore();
            } 
            finally
            {
                _publicCallInProgress = false;
            } 
            return result;
        } 
 
        ///
        public bool HasKeyboardFocus() 
        {
            bool result;
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 

            try 
            { 
                _publicCallInProgress = true;
                result = HasKeyboardFocusCore(); 
            }
            finally
            {
                _publicCallInProgress = false; 
            }
            return result; 
        } 

        /// 
        public bool IsEnabled()
        {
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 

            try 
            { 
                _publicCallInProgress = true;
                _isEnabled = IsEnabledCore(); 
            }
            finally
            {
                _publicCallInProgress = false; 
            }
            return _isEnabled; 
        } 

        /// 
        public bool IsPassword()
        {
            bool result;
 
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 
 
            try
            { 
                _publicCallInProgress = true;
                result = IsPasswordCore();
            }
            finally 
            {
                _publicCallInProgress = false; 
            } 
            return result;
        } 

        ///
        public string GetAutomationId()
        { 
            string result;
 
            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try
            {
                _publicCallInProgress = true;
                result = GetAutomationIdCore(); 
            }
            finally 
            { 
                _publicCallInProgress = false;
            } 
            return result;
        }

        /// 
        public string GetName()
        { 
            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try
            {
                _publicCallInProgress = true;
                _name = GetNameCore(); 
            }
            finally 
            { 
                _publicCallInProgress = false;
            } 
            return _name;
        }

        /// 
        public AutomationControlType GetAutomationControlType()
        { 
            AutomationControlType result; 

            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));

            try
            { 
                _publicCallInProgress = true;
                result = GetAutomationControlTypeCore(); 
            } 
            finally
            { 
                _publicCallInProgress = false;
            }
            return result;
        } 

        /// 
        public string GetLocalizedControlType() 
        {
            string result; 

            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try
            { 
                _publicCallInProgress = true; 
                result = GetLocalizedControlTypeCore();
            } 
            finally
            {
                _publicCallInProgress = false;
            } 
            return result;
        } 
 
        ///
        public bool IsContentElement() 
        {
            bool result;

            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try 
            {
                _publicCallInProgress = true; 
                result = IsContentElementCore();
            }
            finally
            { 
                _publicCallInProgress = false;
            } 
            return result; 
        }
 
        ///
        public bool IsControlElement()
        {
            bool result; 

            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 

            try 
            {
                _publicCallInProgress = true;
                result = IsControlElementCore();
            } 
            finally
            { 
                _publicCallInProgress = false; 
            }
            return result; 
        }

        ///
        public AutomationPeer GetLabeledBy() 
        {
            AutomationPeer result; 
 
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 

            try
            {
                _publicCallInProgress = true; 
                result = GetLabeledByCore();
            } 
            finally 
            {
                _publicCallInProgress = false; 
            }
            return result;
        }
 
        ///
        public string GetHelpText() 
        { 
            string result;
 
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));

            try 
            {
                _publicCallInProgress = true; 
                result = GetHelpTextCore(); 
            }
            finally 
            {
                _publicCallInProgress = false;
            }
            return result; 
        }
 
        /// 
        public string GetAcceleratorKey()
        { 
            string result;

            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 

            try 
            { 
                _publicCallInProgress = true;
                result = GetAcceleratorKeyCore(); 
            }
            finally
            {
                _publicCallInProgress = false; 
            }
            return result; 
        } 

        /// 
        public string GetAccessKey()
        {
            string result;
 
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 
 
            try
            { 
                _publicCallInProgress = true;
                result = GetAccessKeyCore();
            }
            finally 
            {
                _publicCallInProgress = false; 
            } 
            return result;
        } 

        ///
        public Point GetClickablePoint()
        { 
            Point result;
 
            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try
            {
                _publicCallInProgress = true;
                result = GetClickablePointCore(); 
            }
            finally 
            { 
                _publicCallInProgress = false;
            } 
            return result;
        }

        /// 
        public void SetFocus()
        { 
            if (_publicSetFocusInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try
            {
                _publicSetFocusInProgress = true;
                SetFocusCore(); 
            }
            finally 
            { 
                _publicSetFocusInProgress = false;
            } 
        }

        ///
        public AutomationPeer GetParent() 
        {
            return _parent; 
        } 

        /// 
        public List GetChildren()
        {
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 

            try 
            { 
                _publicCallInProgress = true;
                EnsureChildren(); 
            }
            finally
            {
                _publicCallInProgress = false; 
            }
            return _children; 
        } 

        /// 
        public void ResetChildrenCache()
        {
            UpdateChildren();
        } 

        /// 
        internal int[] GetRuntimeId() 
        {
            return new int [] { 7, SafeNativeMethods.GetCurrentProcessId(), this.GetHashCode() }; 
        }

        ///
        internal string GetFrameworkId() { return ("WPF"); } 

        // 
        internal AutomationPeer GetFirstChild() 
        {
            AutomationPeer peer = null; 

            EnsureChildren();

            if (_children != null && _children.Count > 0) 
            {
                peer = _children[0]; 
            } 

            return peer; 
        }

        //
        /// 
        ///     Critical - Accessing _hwnd
        ///     TreatAsSafe - _hwnd is used internally and not exposed. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        private void EnsureChildren() 
        {
            if(!_childrenValid)
            {
                _children = GetChildrenCore(); 
                if (_children != null)
                { 
                    int count = _children.Count; 
                    for (int i = 0; i < count; ++i)
                    { 
                        _children[i]._parent = this;
                        _children[i]._index = i;
                        _children[i]._hwnd = _hwnd;
                    } 
                }
                _childrenValid = true; 
            } 
        }
 
        //
        internal AutomationPeer GetLastChild()
        {
            AutomationPeer peer = null; 

            EnsureChildren(); 
 
            if (_children != null && _children.Count > 0)
            { 
                peer = _children[_children.Count - 1];
            }

            return peer; 
        }
 
        // 
        [FriendAccessAllowed] // Built into Core, also used by Framework.
        internal virtual InteropAutomationProvider GetInteropChild() 
        {
            return null;
        }
 
        //
        internal AutomationPeer GetNextSibling() 
        { 
            AutomationPeer sibling = null;
            AutomationPeer parent = GetParent(); 

            if (parent != null)
            {
                parent.EnsureChildren(); 

                if (    parent._children != null 
                    &&  _index + 1 < parent._children.Count 
                    &&  parent._children[_index] == this    )
                { 
                    sibling = parent._children[_index + 1];
                }
            }
 
            return sibling;
        } 
 
        //
        internal AutomationPeer GetPreviousSibling() 
        {
            AutomationPeer sibling = null;
            AutomationPeer parent = GetParent();
 
            if (parent != null)
            { 
                parent.EnsureChildren(); 

                if (    parent._children != null 
                    &&  _index - 1 >= 0
                    &&  _index < parent._children.Count
                    &&  parent._children[_index] == this    )
                { 
                    sibling = parent._children[_index - 1];
                } 
            } 

            return sibling; 
        }

        //
        internal ControlType GetControlType() 
        {
            ControlType controlType = null; 
 
            AutomationControlType type = GetAutomationControlTypeCore();
 
            switch (type)
            {
                case AutomationControlType.Button:        controlType = ControlType.Button;       break;
                case AutomationControlType.Calendar:      controlType = ControlType.Calendar;     break; 
                case AutomationControlType.CheckBox:      controlType = ControlType.CheckBox;     break;
                case AutomationControlType.ComboBox:      controlType = ControlType.ComboBox;     break; 
                case AutomationControlType.Edit:          controlType = ControlType.Edit;         break; 
                case AutomationControlType.Hyperlink:     controlType = ControlType.Hyperlink;    break;
                case AutomationControlType.Image:         controlType = ControlType.Image;        break; 
                case AutomationControlType.ListItem:      controlType = ControlType.ListItem;     break;
                case AutomationControlType.List:          controlType = ControlType.List;         break;
                case AutomationControlType.Menu:          controlType = ControlType.Menu;         break;
                case AutomationControlType.MenuBar:       controlType = ControlType.MenuBar;      break; 
                case AutomationControlType.MenuItem:      controlType = ControlType.MenuItem;     break;
                case AutomationControlType.ProgressBar:   controlType = ControlType.ProgressBar;  break; 
                case AutomationControlType.RadioButton:   controlType = ControlType.RadioButton;  break; 
                case AutomationControlType.ScrollBar:     controlType = ControlType.ScrollBar;    break;
                case AutomationControlType.Slider:        controlType = ControlType.Slider;       break; 
                case AutomationControlType.Spinner:       controlType = ControlType.Spinner;      break;
                case AutomationControlType.StatusBar:     controlType = ControlType.StatusBar;    break;
                case AutomationControlType.Tab:           controlType = ControlType.Tab;          break;
                case AutomationControlType.TabItem:       controlType = ControlType.TabItem;      break; 
                case AutomationControlType.Text:          controlType = ControlType.Text;         break;
                case AutomationControlType.ToolBar:       controlType = ControlType.ToolBar;      break; 
                case AutomationControlType.ToolTip:       controlType = ControlType.ToolTip;      break; 
                case AutomationControlType.Tree:          controlType = ControlType.Tree;         break;
                case AutomationControlType.TreeItem:      controlType = ControlType.TreeItem;     break; 
                case AutomationControlType.Custom:        controlType = ControlType.Custom;       break;
                case AutomationControlType.Group:         controlType = ControlType.Group;        break;
                case AutomationControlType.Thumb:         controlType = ControlType.Thumb;        break;
                case AutomationControlType.DataGrid:      controlType = ControlType.DataGrid;     break; 
                case AutomationControlType.DataItem:      controlType = ControlType.DataItem;     break;
                case AutomationControlType.Document:      controlType = ControlType.Document;     break; 
                case AutomationControlType.SplitButton:   controlType = ControlType.SplitButton;  break; 
                case AutomationControlType.Window:        controlType = ControlType.Window;       break;
                case AutomationControlType.Pane:          controlType = ControlType.Pane;         break; 
                case AutomationControlType.Header:        controlType = ControlType.Header;       break;
                case AutomationControlType.HeaderItem:    controlType = ControlType.HeaderItem;   break;
                case AutomationControlType.Table:         controlType = ControlType.Table;        break;
                case AutomationControlType.TitleBar:      controlType = ControlType.TitleBar;     break; 
                case AutomationControlType.Separator:     controlType = ControlType.Separator;    break;
                default: break; 
            } 

            return controlType; 
        }

        internal AutomationPeer GetPeerFromPoint(Point point)
        { 
            AutomationPeer found = null;
 
            if(!IsOffscreen()) 
            {
                List children = GetChildren(); 
                if(children != null)
                {
                    int count = children.Count;
                    for(int i = count-1; (i >= 0) && (found == null); --i) 
                    {
                        found = children[i].GetPeerFromPoint(point); 
                    } 
                }
 
                if(found == null)
                {
                    Rect bounds = GetBoundingRectangle();
                    if(bounds.Contains(point)) 
                        found = this;
                } 
           } 

            return found; 
        }

        ///
        /// Creates an element provider (proxy) from a peer. Some patterns require returning objects of type 
        /// IRawElementProviderSimple - this is an Automation-specific wrapper interface that corresponds to a peer.
        /// To wrap an AutomationPeer into the wrapper that exposes this interface, use this method. 
        /// 
        protected internal IRawElementProviderSimple ProviderFromPeer(AutomationPeer peer)
        { 
            AutomationPeer referencePeer = this;

            //replace itself with _eventsSource if we are aggregated and hidden from the UIA
            if((peer == this) && (_eventsSource != null)) 
            {
                referencePeer = peer = _eventsSource; 
            } 

            return ElementProxy.StaticWrap(peer, referencePeer); 
        }

        private IRawElementProviderSimple ProviderFromPeerNoDelegation(AutomationPeer peer)
        { 
            AutomationPeer referencePeer = this;
            return ElementProxy.StaticWrap(peer, referencePeer); 
        } 

        /// 
        /// When one AutomationPeer is using the pattern of another AutomationPeer instead of exposing
        /// it in the children collection (example - ListBox exposes IScrollProvider from internal ScrollViewer
        /// but does not expose the ScrollViewerAutomationPeer as its child) - then before returning the pattern
        /// interface from GetPattern, the "main" AutomationPeer should call this method to set up itself as 
        /// "source" for the events fired by the pattern on the subordinate AutomationPeer.
        /// Otherwise, the hidden subordinate AutomationPeer will fire pattern's events from its own identity which 
        /// will confuse UIA since its identity is not exposed to UIA. 
        ///
        public AutomationPeer EventsSource 
        {
            get { return _eventsSource; }
            set { _eventsSource = value; }
        } 

 
        /// 
        /// Returns AutomationPeer corresponding to the given provider.
        /// 
        protected AutomationPeer PeerFromProvider(IRawElementProviderSimple provider)
        {
            ElementProxy proxy = provider as ElementProxy;
            if (proxy != null) 
            {
                return (proxy.Peer); 
            } 

            return null; 
        }

        //called on a root peer of a tree when it's time to fire automation events
        //walks down the tree, updates caches and fires automation events 
        //
        internal void FireAutomationEvents() 
        { 
            UpdateSubtree();
        } 

        // internal handling of structure chanegd events
        private void RaisePropertyChangedInternal(IRawElementProviderSimple provider,
                                                             AutomationProperty propertyId, 
                                                             object oldValue,
                                                             object newValue) 
        { 
            // Callers have only checked if automation clients are present so filter for any interest in this particular event.
            if (  provider != null 
               && EventMap.HasRegisteredEvent(AutomationEvents.PropertyChanged) )
            {
                AutomationPropertyChangedEventArgs e = new AutomationPropertyChangedEventArgs(propertyId, oldValue, newValue);
                AutomationInteropProvider.RaiseAutomationPropertyChangedEvent(provider, e); 
            }
        } 
 
        // internal handling of structure changed events
        private void UpdateChildren() 
        {
            List oldChildren = _children;
            List addedChildren = null;
            Hashtable ht = null; 

            _childrenValid = false; 
            EnsureChildren(); 

            // Callers have only checked if automation clients are present so filter for any interest in this particular event. 
            if (!EventMap.HasRegisteredEvent(AutomationEvents.StructureChanged))
                return;

            //store old children in a hashtable 
            if(oldChildren != null)
            { 
                ht =  new Hashtable(); 
                for(int count = oldChildren.Count, i = 0; i < count; i++)
                { 
                    ht.Add(oldChildren[i], null);
                }
            }
 
            //walk over new children, remove the ones that were in the old collection from hash table
            //and add new ones into addedChildren list 
            int addedCount = 0; 

            if(_children != null) 
            {
                for(int count = _children.Count, i = 0; i < count; i++)
                {
                    AutomationPeer child = _children[i]; 
                    if(ht != null && ht.ContainsKey(child))
                    { 
                        ht.Remove(child); //same child, nothing to notify 
                    }
                    else 
                    {
                        if(addedChildren == null) addedChildren = new List();

                        //stop accumulatin new children here because the notification 
                        //is going to become "bulk anyways and exact set of chidlren is not
                        //needed, only count. 
                        ++addedCount; 
                        if(addedCount <= AutomationInteropProvider.InvalidateLimit)
                            addedChildren.Add(child); 
                    }
                }
            }
 
            //now the ht only has "removed" children. If the count does not yet
            //calls for "bulk" notification, use per-child notification, otherwise use "bulk" 
            int removedCount = (ht == null ? 0 : ht.Count); 

            if(removedCount + addedCount > AutomationInteropProvider.InvalidateLimit) //bilk invalidation 
            {
                StructureChangeType flags;

                // Set bulk event type depending on if these were adds, removes or a mix 
                if (addedCount == 0)
                    flags = StructureChangeType.ChildrenBulkRemoved; 
                else if ( removedCount == 0 ) 
                    flags = StructureChangeType.ChildrenBulkAdded;
                else 
                    flags = StructureChangeType.ChildrenInvalidated;

                IRawElementProviderSimple provider = ProviderFromPeerNoDelegation(this);
                if(provider != null) 
                {
                    int [] rid = this.GetRuntimeId(); //use runtimeID of parent for bulk notifications 
 
                    AutomationInteropProvider.RaiseStructureChangedEvent(
                                    provider, 
                                    new StructureChangedEventArgs(flags, rid));
                }
            }
            else if(removedCount > 0) 
            {
                //for children removed, provider is the parent 
                IRawElementProviderSimple provider = ProviderFromPeerNoDelegation(this); 
                if(provider != null)
                { 
                    //ht contains removed children by now
                    foreach(object key in ht.Keys)
                    {
                        AutomationPeer removedChild = (AutomationPeer)key; 

                        int [] rid = removedChild.GetRuntimeId(); 
 
                        AutomationInteropProvider.RaiseStructureChangedEvent(
                                        provider, 
                                        new StructureChangedEventArgs(StructureChangeType.ChildRemoved, rid));
                    }
                }
            } 
            else if(addedCount > 0)
            { 
                //ht contains removed children by now 
                foreach(AutomationPeer addedChild in addedChildren)
                { 
                    //for children added, provider is the child itself
                    IRawElementProviderSimple provider = ProviderFromPeerNoDelegation(addedChild);
                    if(provider != null)
                    { 
                        int [] rid = addedChild.GetRuntimeId();
 
                        AutomationInteropProvider.RaiseStructureChangedEvent( 
                                        provider,
                                        new StructureChangedEventArgs(StructureChangeType.ChildAdded, rid)); 
                    }
                }
            }
        } 

        // 
 

 



 

 
 

        [FriendAccessAllowed] // Built into Core, also used by Framework. 
        internal void UpdateSubtree()
        {
            ContextLayoutManager lm = ContextLayoutManager.From(this.Dispatcher);
            if(lm != null) 
            {
                lm.AutomationSyncUpdateCounter = lm.AutomationSyncUpdateCounter + 1; 
 
                try
                { 
                    IRawElementProviderSimple provider = null;


 

                    bool notifyPropertyChanged = EventMap.HasRegisteredEvent(AutomationEvents.PropertyChanged); 
                    bool notifyStructureChanged = EventMap.HasRegisteredEvent(AutomationEvents.StructureChanged); 

                    //  did anybody ask for property changed norification? 
                    if (notifyPropertyChanged)
                    {
                        string itemStatus = GetItemStatusCore();
                        if (itemStatus != _itemStatus) 
                        {
                            if(provider == null) 
                                provider = ProviderFromPeerNoDelegation(this); 
                            RaisePropertyChangedInternal(provider,
                                                         AutomationElementIdentifiers.ItemStatusProperty, 
                                                         _itemStatus,
                                                         itemStatus);
                            _itemStatus = itemStatus;
                        } 

                        string name = GetNameCore(); 
                        if (name != _name) 
                        {
                            if(provider == null) 
                                provider = ProviderFromPeerNoDelegation(this);
                            RaisePropertyChangedInternal(provider,
                                                         AutomationElementIdentifiers.NameProperty,
                                                         _name, 
                                                         name);
                            _name = name; 
                        } 

                        bool isOffscreen = IsOffscreenCore(); 
                        if (isOffscreen != _isOffscreen)
                        {
                            if(provider == null)
                                provider = ProviderFromPeerNoDelegation(this); 
                            RaisePropertyChangedInternal(provider,
                                                         AutomationElementIdentifiers.IsOffscreenProperty, 
                                                         _isOffscreen, 
                                                         isOffscreen);
                            _isOffscreen = isOffscreen; 
                        }

                        bool isEnabled = IsEnabledCore();
                        if (isEnabled != _isEnabled) 
                        {
                            if(provider == null) 
                                provider = ProviderFromPeerNoDelegation(this); 
                            RaisePropertyChangedInternal(provider,
                                                         AutomationElementIdentifiers.IsEnabledProperty, 
                                                         _isEnabled,
                                                         isEnabled);
                            _isEnabled = isEnabled;
                        } 
                    }
 
                    //  did anybody ask for structure changed norification? 
                    //  if somebody asked for property changed then structure must be updated
                    if (_childrenValid || notifyStructureChanged || notifyPropertyChanged) 
                    {
                        UpdateChildren();

                        for(AutomationPeer peer = GetFirstChild(); peer != null; peer = peer.GetNextSibling()) 
                        {
                            peer.UpdateSubtree(); 
                        } 
                    }
 
                    _invalidated = false;
                }
                finally
                { 
                    lm.AutomationSyncUpdateCounter = lm.AutomationSyncUpdateCounter - 1;
                } 
            } 
        }
 
        private static object UpdatePeer(object arg)
        {
            AutomationPeer peer = (AutomationPeer)arg;
            peer.UpdateSubtree(); 
            return null;
        } 
 
        internal void AddToAutomationEventList()
        { 
            if(!_addedToEventList)
            {
                ContextLayoutManager lm = ContextLayoutManager.From(this.Dispatcher);
                lm.AutomationEvents.Add(this); //this adds the root peer into the list of roots, for deferred event firing 
                _addedToEventList = true;
            } 
 
        }
 
        /// 
        ///     Critical - provides access to critial data.
        /// 
        internal IntPtr Hwnd 
        {
            [SecurityCritical] 
            get { return _hwnd; } 
            [SecurityCritical]
            set { _hwnd = value; } 
        }

        //
        internal object GetWrappedPattern(int patternId) 
        {
            object result = null; 
 
            PatternInfo info = (PatternInfo)s_patternInfo[patternId];
 
            if (info != null)
            {
                object iface = GetPattern(info.PatternInterface);
                if (iface != null) 
                {
                    result = info.WrapObject(this, iface); 
                } 
            }
 
            return result;
        }

        // 
        internal object GetPropertyValue(int propertyId)
        { 
            object result = null; 

            GetProperty getProperty = (GetProperty)s_propertyInfo[propertyId]; 

            if (getProperty != null)
            {
                result = getProperty(this); 
            }
 
            return result; 
        }
 
        //
        internal bool IsInteropPeer
        {
            get { return _isInteropPeer; } 
            set { _isInteropPeer = value; }
        } 
 
        private static void Initialize()
        { 
            //  initializeing patterns
            s_patternInfo = new Hashtable();
            s_patternInfo[InvokePatternIdentifiers.Pattern.Id]          = new PatternInfo(InvokePatternIdentifiers.Pattern.Id,          new WrapObject(InvokeProviderWrapper.Wrap),             PatternInterface.Invoke);
            s_patternInfo[SelectionPatternIdentifiers.Pattern.Id]       = new PatternInfo(SelectionPatternIdentifiers.Pattern.Id,       new WrapObject(SelectionProviderWrapper.Wrap),          PatternInterface.Selection); 
            s_patternInfo[ValuePatternIdentifiers.Pattern.Id]           = new PatternInfo(ValuePatternIdentifiers.Pattern.Id,           new WrapObject(ValueProviderWrapper.Wrap),              PatternInterface.Value);
            s_patternInfo[RangeValuePatternIdentifiers.Pattern.Id]      = new PatternInfo(RangeValuePatternIdentifiers.Pattern.Id,      new WrapObject(RangeValueProviderWrapper.Wrap),         PatternInterface.RangeValue); 
            s_patternInfo[ScrollPatternIdentifiers.Pattern.Id]          = new PatternInfo(ScrollPatternIdentifiers.Pattern.Id,          new WrapObject(ScrollProviderWrapper.Wrap),             PatternInterface.Scroll); 
            s_patternInfo[ScrollItemPatternIdentifiers.Pattern.Id]      = new PatternInfo(ScrollItemPatternIdentifiers.Pattern.Id,      new WrapObject(ScrollItemProviderWrapper.Wrap),         PatternInterface.ScrollItem);
            s_patternInfo[ExpandCollapsePatternIdentifiers.Pattern.Id]  = new PatternInfo(ExpandCollapsePatternIdentifiers.Pattern.Id,  new WrapObject(ExpandCollapseProviderWrapper.Wrap),     PatternInterface.ExpandCollapse); 
            s_patternInfo[GridPatternIdentifiers.Pattern.Id]            = new PatternInfo(GridPatternIdentifiers.Pattern.Id,            new WrapObject(GridProviderWrapper.Wrap),               PatternInterface.Grid);
            s_patternInfo[GridItemPatternIdentifiers.Pattern.Id]        = new PatternInfo(GridItemPatternIdentifiers.Pattern.Id,        new WrapObject(GridItemProviderWrapper.Wrap),           PatternInterface.GridItem);
            s_patternInfo[MultipleViewPatternIdentifiers.Pattern.Id]    = new PatternInfo(MultipleViewPatternIdentifiers.Pattern.Id,    new WrapObject(MultipleViewProviderWrapper.Wrap),       PatternInterface.MultipleView);
            s_patternInfo[WindowPatternIdentifiers.Pattern.Id]          = new PatternInfo(WindowPatternIdentifiers.Pattern.Id,          new WrapObject(WindowProviderWrapper.Wrap),             PatternInterface.Window); 
            s_patternInfo[SelectionItemPatternIdentifiers.Pattern.Id]   = new PatternInfo(SelectionItemPatternIdentifiers.Pattern.Id,   new WrapObject(SelectionItemProviderWrapper.Wrap),      PatternInterface.SelectionItem);
            s_patternInfo[DockPatternIdentifiers.Pattern.Id]            = new PatternInfo(DockPatternIdentifiers.Pattern.Id,            new WrapObject(DockProviderWrapper.Wrap),               PatternInterface.Dock); 
            s_patternInfo[TablePatternIdentifiers.Pattern.Id]           = new PatternInfo(TablePatternIdentifiers.Pattern.Id,           new WrapObject(TableProviderWrapper.Wrap),              PatternInterface.Table); 
            s_patternInfo[TableItemPatternIdentifiers.Pattern.Id]       = new PatternInfo(TableItemPatternIdentifiers.Pattern.Id,       new WrapObject(TableItemProviderWrapper.Wrap),          PatternInterface.TableItem);
            s_patternInfo[TogglePatternIdentifiers.Pattern.Id]          = new PatternInfo(TogglePatternIdentifiers.Pattern.Id,          new WrapObject(ToggleProviderWrapper.Wrap),             PatternInterface.Toggle); 
            s_patternInfo[TransformPatternIdentifiers.Pattern.Id]       = new PatternInfo(TransformPatternIdentifiers.Pattern.Id,       new WrapObject(TransformProviderWrapper.Wrap),          PatternInterface.Transform);
            s_patternInfo[TextPatternIdentifiers.Pattern.Id]            = new PatternInfo(TextPatternIdentifiers.Pattern.Id,            new WrapObject(TextProviderWrapper.Wrap),               PatternInterface.Text);

            //  initializeing properties 
            s_propertyInfo = new Hashtable();
            s_propertyInfo[AutomationElementIdentifiers.IsControlElementProperty.Id] = new GetProperty(IsControlElement); 
            s_propertyInfo[AutomationElementIdentifiers.ControlTypeProperty.Id] = new GetProperty(GetControlType); 
            s_propertyInfo[AutomationElementIdentifiers.IsContentElementProperty.Id] = new GetProperty(IsContentElement);
            s_propertyInfo[AutomationElementIdentifiers.LabeledByProperty.Id] = new GetProperty(GetLabeledBy); 
            s_propertyInfo[AutomationElementIdentifiers.NativeWindowHandleProperty.Id] = new GetProperty(GetNativeWindowHandle);
            s_propertyInfo[AutomationElementIdentifiers.AutomationIdProperty.Id] = new GetProperty(GetAutomationId);
            s_propertyInfo[AutomationElementIdentifiers.ItemTypeProperty.Id] = new GetProperty(GetItemType);
            s_propertyInfo[AutomationElementIdentifiers.IsPasswordProperty.Id] = new GetProperty(IsPassword); 
            s_propertyInfo[AutomationElementIdentifiers.LocalizedControlTypeProperty.Id] = new GetProperty(GetLocalizedControlType);
            s_propertyInfo[AutomationElementIdentifiers.NameProperty.Id] = new GetProperty(GetName); 
            s_propertyInfo[AutomationElementIdentifiers.AcceleratorKeyProperty.Id] = new GetProperty(GetAcceleratorKey); 
            s_propertyInfo[AutomationElementIdentifiers.AccessKeyProperty.Id] = new GetProperty(GetAccessKey);
            s_propertyInfo[AutomationElementIdentifiers.HasKeyboardFocusProperty.Id] = new GetProperty(HasKeyboardFocus); 
            s_propertyInfo[AutomationElementIdentifiers.IsKeyboardFocusableProperty.Id] = new GetProperty(IsKeyboardFocusable);
            s_propertyInfo[AutomationElementIdentifiers.IsEnabledProperty.Id] = new GetProperty(IsEnabled);
            s_propertyInfo[AutomationElementIdentifiers.BoundingRectangleProperty.Id] = new GetProperty(GetBoundingRectangle);
            s_propertyInfo[AutomationElementIdentifiers.ProcessIdProperty.Id] = new GetProperty(GetCurrentProcessId); 
            s_propertyInfo[AutomationElementIdentifiers.RuntimeIdProperty.Id] = new GetProperty(GetRuntimeId);
            s_propertyInfo[AutomationElementIdentifiers.ClassNameProperty.Id] = new GetProperty(GetClassName); 
            s_propertyInfo[AutomationElementIdentifiers.HelpTextProperty.Id] = new GetProperty(GetHelpText); 
            s_propertyInfo[AutomationElementIdentifiers.ClickablePointProperty.Id] = new GetProperty(GetClickablePoint);
            s_propertyInfo[AutomationElementIdentifiers.CultureProperty.Id] = new GetProperty(GetCultureInfo); 
            s_propertyInfo[AutomationElementIdentifiers.IsOffscreenProperty.Id] = new GetProperty(IsOffscreen);
            s_propertyInfo[AutomationElementIdentifiers.OrientationProperty.Id] = new GetProperty(GetOrientation);
            s_propertyInfo[AutomationElementIdentifiers.FrameworkIdProperty.Id] = new GetProperty(GetFrameworkId);
            s_propertyInfo[AutomationElementIdentifiers.IsRequiredForFormProperty.Id] = new GetProperty(IsRequiredForForm); 
            s_propertyInfo[AutomationElementIdentifiers.ItemStatusProperty.Id] = new GetProperty(GetItemStatus);
 
            s_initialized = true; 
        }
 
        private delegate object WrapObject(AutomationPeer peer, object iface);

        private class PatternInfo
        { 
            internal PatternInfo(int id, WrapObject wrapObject, PatternInterface patternInterface)
            { 
                Id = id; 
                WrapObject = wrapObject;
                PatternInterface = patternInterface; 
            }

            internal int Id;
            internal WrapObject WrapObject; 
            internal PatternInterface PatternInterface;
        } 
 
        private delegate object GetProperty(AutomationPeer peer);
 
        private static object IsControlElement(AutomationPeer peer)         {   return peer.IsControlElement(); }
        private static object GetControlType(AutomationPeer peer)           {   ControlType controlType = peer.GetControlType(); return controlType.Id;  }
        private static object IsContentElement(AutomationPeer peer)         {   return peer.IsContentElement(); }
        private static object GetLabeledBy(AutomationPeer peer)             {   AutomationPeer byPeer = peer.GetLabeledBy(); return ElementProxy.StaticWrap(byPeer, peer);  } 
        private static object GetNativeWindowHandle(AutomationPeer peer)    {   return null /* not used? */;    }
        private static object GetAutomationId(AutomationPeer peer)          {   return peer.GetAutomationId();  } 
        private static object GetItemType(AutomationPeer peer)              {   return peer.GetItemType();      } 
        private static object IsPassword(AutomationPeer peer)               {   return peer.IsPassword();       }
        private static object GetLocalizedControlType(AutomationPeer peer)  {   return peer.GetLocalizedControlType();  } 
        private static object GetName(AutomationPeer peer)                  {   return peer.GetName();          }
        private static object GetAcceleratorKey(AutomationPeer peer)        {   return peer.GetAcceleratorKey();    }
        private static object GetAccessKey(AutomationPeer peer)             {   return peer.GetAccessKey();     }
        private static object HasKeyboardFocus(AutomationPeer peer)         {   return peer.HasKeyboardFocus(); } 
        private static object IsKeyboardFocusable(AutomationPeer peer)      {   return peer.IsKeyboardFocusable();  }
        private static object IsEnabled(AutomationPeer peer)                {   return peer.IsEnabled();        } 
        private static object GetBoundingRectangle(AutomationPeer peer)     {   return peer.GetBoundingRectangle(); } 
        private static object GetCurrentProcessId(AutomationPeer peer)      {   return SafeNativeMethods.GetCurrentProcessId(); }
        private static object GetRuntimeId(AutomationPeer peer)             {   return peer.GetRuntimeId();     } 
        private static object GetClassName(AutomationPeer peer)             {   return peer.GetClassName();     }
        private static object GetHelpText(AutomationPeer peer)              {   return peer.GetHelpText();  }
        private static object GetClickablePoint(AutomationPeer peer)        {   Point pt = peer.GetClickablePoint(); return new double[] {pt.X, pt.Y};  }
        private static object GetCultureInfo(AutomationPeer peer)           {   return null;    } 
        private static object IsOffscreen(AutomationPeer peer)              {   return peer.IsOffscreen();  }
        private static object GetOrientation(AutomationPeer peer)           {   return peer.GetOrientation();   } 
        private static object GetFrameworkId(AutomationPeer peer)           {   return peer.GetFrameworkId();   } 
        private static object IsRequiredForForm(AutomationPeer peer)        {   return peer.IsRequiredForForm();    }
        private static object GetItemStatus(AutomationPeer peer)            {   return peer.GetItemStatus();    } 

        private static bool s_initialized;
        private static Hashtable s_patternInfo;
        private static Hashtable s_propertyInfo; 

        private int _index; 
        /// 
        ///     Critical - once stored, this hwnd will be used for subsequent automation operations.
        /// 
        [SecurityCritical]
        private IntPtr _hwnd;
        private List _children;
        private AutomationPeer _parent; 

        private AutomationPeer _eventsSource; 
 
        private Rect _boundingRectangle;
        private string _itemStatus; 
        private string _name;
        private bool _isOffscreen;
        private bool _isEnabled;
        private bool _invalidated; 
        private bool _childrenValid;
        private bool _addedToEventList; 
        private bool _publicCallInProgress; 
        private bool _publicSetFocusInProgress;
        private bool _isInteropPeer; 

        private static DispatcherOperationCallback _updatePeer = new DispatcherOperationCallback(UpdatePeer);
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
using System; 
using System.Collections;
using System.Security;
using System.Security.Permissions;
using System.Windows; 
using System.Windows.Interop;
using System.Windows.Media; 
using System.Windows.Threading; 
using System.Collections.Generic;
using System.Windows.Automation.Provider; 

using MS.Internal;
using MS.Internal.Automation;
using MS.Internal.Media; 
using MS.Internal.PresentationCore;
using MS.Win32; 
 
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID; 

namespace System.Windows.Automation.Peers
{
    /// 
    public enum PatternInterface
    { 
        /// 
        Invoke,
        /// 
        Selection,
        ///
        Value,
        /// 
        RangeValue,
        /// 
        Scroll, 
        ///
        ScrollItem, 
        ///
        ExpandCollapse,
        ///
        Grid, 
        ///
        GridItem, 
        /// 
        MultipleView,
        /// 
        Window,
        ///
        SelectionItem,
        /// 
        Dock,
        /// 
        Table, 
        ///
        TableItem, 
        ///
        Toggle,
        ///
        Transform, 
        ///
        Text, 
    } 

    /// 
    public enum AutomationOrientation
    {
        ///
        None = 0, 
        ///
        Horizontal, 
        /// 
        Vertical,
    } 

    ///
    public enum AutomationControlType
    { 
        ///
        Button, 
        /// 
        Calendar,
        /// 
        CheckBox,
        ///
        ComboBox,
        /// 
        Edit,
        /// 
        Hyperlink, 
        ///
        Image, 
        ///
        ListItem,
        ///
        List, 
        ///
        Menu, 
        /// 
        MenuBar,
        /// 
        MenuItem,
        ///
        ProgressBar,
        /// 
        RadioButton,
        /// 
        ScrollBar, 
        ///
        Slider, 
        ///
        Spinner,
        ///
        StatusBar, 
        ///
        Tab, 
        /// 
        TabItem,
        /// 
        Text,
        ///
        ToolBar,
        /// 
        ToolTip,
        /// 
        Tree, 
        ///
        TreeItem, 
        ///
        Custom,
        ///
        Group, 
        ///
        Thumb, 
        /// 
        DataGrid,
        /// 
        DataItem,
        ///
        Document,
        /// 
        SplitButton,
        /// 
        Window, 
        ///
        Pane, 
        ///
        Header,
        ///
        HeaderItem, 
        ///
        Table, 
        /// 
        TitleBar,
        /// 
        Separator,
    }

    /// 
    public enum AutomationEvents
    { 
        /// 
        ToolTipOpened,
        /// 
        ToolTipClosed,
        ///
        MenuOpened,
        /// 
        MenuClosed,
        /// 
        AutomationFocusChanged, 
        ///
        InvokePatternOnInvoked, 
        ///
        SelectionItemPatternOnElementAddedToSelection,
        ///
        SelectionItemPatternOnElementRemovedFromSelection, 
        ///
        SelectionItemPatternOnElementSelected, 
        /// 
        SelectionPatternOnInvalidated,
        /// 
        TextPatternOnTextSelectionChanged,
        ///
        TextPatternOnTextChanged,
        /// 
        AsyncContentLoaded,
        /// 
        PropertyChanged, 
        ///
        StructureChanged, 
    }


    /// This is a helper class to facilate the storage of Security critical data ( aka "Plutonium") 
    /// It's primary purpose is to do put a [SecurityCritical] on all access to the data.
    /// What is "critical data" ? This is any data created that required an Assert for it's creation. 
    /// As an example - the passage of hosted Hwnd between some AutomationPeer and UIA infrastructure. 
    public sealed class HostedWindowWrapper
    { 
        /// 
        /// This is the only public constructor on this class.
        /// It requires "Full Trust" level of security permissions to be executed, since this
        /// class is wrappign an HWND direct access to which is a critical asset. 
        /// 
        ///  
        /// Critical - as this accesses _hwnd which is Critical. 
        /// Safe - as the caller already got the critical value.
        /// In addition, we prevent creating this class by external callers who does not have UnmanagedCode permission. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        public HostedWindowWrapper(IntPtr hwnd)
        { 
            (new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)).Demand();
            _hwnd = hwnd; 
        } 

        //  
        //    Critical "by definition" - this class is intended to store critical data.
        // 
        [SecurityCritical]
        private HostedWindowWrapper() 
        {
            _hwnd = IntPtr.Zero; 
        } 

        //  
        //    Critical "by definition" - this class is intended to store critical data.
        // 
        [SecurityCritical]
        internal static HostedWindowWrapper CreateInternal(IntPtr hwnd) 
        {
            HostedWindowWrapper wrapper = new HostedWindowWrapper(); 
            wrapper._hwnd = hwnd; 
            return wrapper;
        } 

        // 
        //    Critical "by definition" - this class is intended to store critical data.
        //  
        internal IntPtr Handle
        { 
            [SecurityCritical] 
            get
            { 
                return _hwnd;
            }
        }
 
        /// 
        /// Critical - by definition as this is a wrapper for Critical data. 
        ///  
        [SecurityCritical]
        private IntPtr _hwnd; 
    }


    /// 
    public abstract class AutomationPeer: DispatcherObject
    { 
        /// 
        protected AutomationPeer()
        { 
            if (!s_initialized)
            {
                Initialize();
            } 
        }
 
        // 
        // VIRTUAL CALLBACKS
        // 

        ///
        abstract protected List GetChildrenCore();
 
        ///
        abstract public object GetPattern(PatternInterface patternInterface); 
 

        // 
        // PUBLIC METHODS
        //

        /// 
        public void InvalidatePeer()
        { 
            if(_invalidated) return; 

            Dispatcher.BeginInvoke(DispatcherPriority.Background, _updatePeer, this); 
            _invalidated = true;
        }

        /// 
        /// Used to check if Automation is indeed listening for the event.
        /// Typical usage is to check this before even creating the peer that will fire the event. 
        /// Basically, this is a performance measure since if the Automation does not listen for the event, 
        /// it does not make sense to create a peer to fire one.
        /// NOTE: the method is static and only answers if there is some listener in Automation, 
        /// not specifically for some element. The Automation can hook up "broadcast listeners" so the
        /// per-element info is basically unavailable.
        ///
        static public bool ListenerExists(AutomationEvents eventId) 
        {
            return (EventMap.HasRegisteredEvent(eventId)); 
        } 

        /// 
        /// Used by peer implementation to raise an event for Automation
        ///
        // Never inline, as we don't want to unnecessarily link the automation DLL.
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] 
        public void RaiseAutomationEvent(AutomationEvents eventId)
        { 
            AutomationEvent eventObject = EventMap.GetRegisteredEvent(eventId); 

            if (eventObject == null) 
            {
                // nobody is listening to this event
                return;
            } 

            IRawElementProviderSimple provider = ProviderFromPeer(this); 
            if (provider != null) 
            {
                AutomationInteropProvider.RaiseAutomationEvent( 
                    eventObject,
                    provider,
                    new AutomationEventArgs(eventObject));
            } 
        }
 
        ///  
        /// This method is called by implementation of the peer to raise the automation propertychange notifications
        /// Typically, the peers that implement automation patterns liek IScrollProvider need to raise events specified by 
        /// the particular pattern in case specific properties are changing.
        /// 
        // Never inline, as we don't want to unnecessarily link the automation DLL via the ScrollPattern reference.
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] 
        public void RaisePropertyChangedEvent(AutomationProperty property, object oldValue, object newValue)
        { 
            // Only send the event if there are listeners for this property change 
            if (AutomationInteropProvider.ClientsAreListening)
            { 
                RaisePropertyChangedInternal(ProviderFromPeer(this), property,oldValue,newValue);
            }
        }
 
        /// 
        /// This method is called by implementation of the peer to raise the automation "async content loaded" notifications 
        ///  
        // Never inline, as we don't want to unnecessarily link the automation DLL.
        [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] 
        public void RaiseAsyncContentLoadedEvent(AsyncContentLoadedEventArgs args)
        {
            if(args == null)
                throw new ArgumentNullException("args"); 

            if (EventMap.HasRegisteredEvent(AutomationEvents.AsyncContentLoaded)) 
            { 
                IRawElementProviderSimple provider = ProviderFromPeer(this);
                if(provider != null) 
                {
                    AutomationInteropProvider.RaiseAutomationEvent(
                        AutomationElementIdentifiers.AsyncContentLoadedEvent,
                        provider, 
                        args);
                } 
            } 
        }
 
        internal static void RaiseFocusChangedEventHelper(IInputElement newFocus)
        {
            // Callers have only checked if automation clients are present so filter for any interest in this particular event.
            if (EventMap.HasRegisteredEvent(AutomationEvents.AutomationFocusChanged)) 
            {
                AutomationPeer peer = AutomationPeerFromInputElement(newFocus); 
 
                if (peer != null)
                { 
                    peer.RaiseAutomationEvent(AutomationEvents.AutomationFocusChanged);
                }
                else //non-automated element got focus, same as focus lost
                { 
                    //No focused peer. Just don't report anything.
                } 
            } 
        }
 
        //  helper method. Makes attempt to find an automation peer corresponding to the given IInputElement...
        internal static AutomationPeer AutomationPeerFromInputElement(IInputElement focusedElement)
        {
            AutomationPeer peer = null; 

            UIElement uie = focusedElement as UIElement; 
            if (uie != null) 
            {
                peer = UIElementAutomationPeer.CreatePeerForElement(uie); 
            }
            else
            {
                ContentElement ce = focusedElement as ContentElement; 
                if (ce != null)
                { 
                    peer = ContentElementAutomationPeer.CreatePeerForElement(ce); 
                }
                else 
                {
                    UIElement3D uie3D = focusedElement as UIElement3D;
                    if (uie3D != null)
                    { 
                        peer = UIElement3DAutomationPeer.CreatePeerForElement(uie3D);
                    } 
                } 
            }
 
            if (peer != null)
            {
                //  ValidateConnected ensures that EventsSource is initialized
                peer.ValidateConnected(peer); 

                //  always use event source when available 
                if (peer.EventsSource != null) 
                {
                    peer = peer.EventsSource; 
                }
            }

            return peer; 
        }
 
        // We can only return peers to UIA that are properly connected to the UIA tree already 
        // This means they should have _hwnd and _parent already set and _parent should point to the
        // peer which would have this peer returned from its GetChildrenCore. This method checks if the 
        // peer is already connected, and if not then it walks the tree of peers from the top down, calling
        // GetChildren and trying to find itself in someone's children. Once this succeeds, the peer is connected
        // (because GetChildren will connect it). In this case this method will return "this".
        // However if the search does not find the peer, that means the peer 
        // would never be exposed by specific context even though it is createable on the element (the decision to expose
        // children is on parent peers and parent peer may decide not to expose subpart of itself). In this case, 
        // this method returns null. 
        // ConnectedPeer parameter is some peer which is known to be connected (typically root, but if not, this method will
        // walk up from the given connectedPeer up to find a root) 
        ///
        ///     Critical - Accessing _hwnd
        ///     TreatAsSafe - _hwnd is used internally and not exposed.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal AutomationPeer ValidateConnected(AutomationPeer connectedPeer) 
        { 
            if(connectedPeer == null)
                throw new ArgumentNullException("connectedPeer"); 

            if(_parent != null && _hwnd != IntPtr.Zero) return this;

            if((connectedPeer._hwnd) != IntPtr.Zero) 
            {
                while(connectedPeer._parent != null) connectedPeer = connectedPeer._parent; 
 
                //now connectedPeer is the root
                if ((connectedPeer == this) || isDescendantOf(connectedPeer)) 
                    return this;
            }

            //last effort - find across all roots 
            //only start fault in the tree from the root if we are not in the recursive [....] update
            //Otherwise it will go through the peers that are currently on the stack 
            ContextLayoutManager lm = ContextLayoutManager.From(this.Dispatcher); 
            if(lm != null && lm.AutomationSyncUpdateCounter == 0)
            { 
                AutomationPeer[] roots = lm.GetAutomationRoots();
                for(int i = 0; i < roots.Length; i++)
                {
                    AutomationPeer root = roots[i]; 

                    if (root != null) 
                    { 
                        if((root == this) || isDescendantOf(root))
                        return this; 
                    }
                }
            }
 
            return null;
        } 
 
        private bool isDescendantOf(AutomationPeer parent)
        { 
            if(parent == null)
                throw new ArgumentNullException("parent");

            List children  = parent.GetChildren(); 

            if(children == null) 
                return false; 

            int cnt = children.Count; 
            for(int i = 0; i < cnt; ++i)
            {
                AutomationPeer child = children[i];
 
                //depth first
                if(child == this || this.isDescendantOf(child)) 
                    return true; 
            }
 
            return false;
        }

        /// 
        /// Outside of hosting scenarios AutomationPeers shoudl not override this method.
        /// It is needed for peers that implement their own host HWNDs 
        /// for these HWNDs to appear in a proper place in the UIA tree. 
        /// Without this interface being omplemented, the HWND is parented by UIA as a child
        /// of the HwndSource that hosts whole Avalon app. Instead, it is usually desirable 
        /// to override this defautl behavior and tell UIA to parent hosted HWND as a child
        /// somewhere in Avlaon tree where it is actually hosted.
        /// 
        /// Automation infrastructure provides necessary hookup, the AutomationPeer of the element that 
        /// immediately hosts the HWND should implement this interface to be properly wired in.
        /// In addition to that, it should return this peer as IRawElementProviderSimple as a response to 
        /// WM_GETOBJECT coming to the hosted HWND. 
        /// 
        /// To obtain the IRawElementProviderSimple interface, the peer should use 
        /// System.Windows.Automation.AutomationInteropProvider.HostProviderFromHandle(hwnd).
        ///
        /// 
        ///     Critical    - Calls critical AutomationPeer.Hwnd. 
        ///     TreatAsSafe - Critical data is used internally and not explosed
        ///  
        [SecurityCritical, SecurityTreatAsSafe] 
        virtual protected HostedWindowWrapper GetHostRawElementProviderCore()
        { 
            HostedWindowWrapper host = null;

            //in normal Avalon subtrees, only root peers should return wrapped HWND
            if(GetParent() == null) 
            {
                // this way of creating HostedWindowWrapper does not require FullTrust 
                host = HostedWindowWrapper.CreateInternal(Hwnd); 
            }
 
            return host;
        }

        internal HostedWindowWrapper GetHostRawElementProvider() 
        {
            return GetHostRawElementProviderCore(); 
        } 

        /// 
        /// Returns 'true' only if this is a peer that hosts HWND in Avalon (WindowsFormsHost or Popup for example).
        /// Such peers also have to override GetHostRawElementProviderCore method.
        ///
        virtual protected internal bool IsHwndHost { get { return false; }} 

        // 
        // P R O P E R T I E S 
        //
 
        ///
        abstract protected Rect GetBoundingRectangleCore();

        /// 
        abstract protected bool IsOffscreenCore();
 
        /// 
        abstract protected AutomationOrientation GetOrientationCore();
 
        ///
        abstract protected string GetItemTypeCore();

        /// 
        abstract protected string GetClassNameCore();
 
        /// 
        abstract protected string GetItemStatusCore();
 
        ///
        abstract protected bool IsRequiredForFormCore();

        /// 
        abstract protected bool IsKeyboardFocusableCore();
 
        /// 
        abstract protected bool HasKeyboardFocusCore();
 
        ///
        abstract protected bool IsEnabledCore();

        /// 
        abstract protected bool IsPasswordCore();
 
        /// 
        abstract protected string GetAutomationIdCore();
 
        ///
        abstract protected string GetNameCore();

        /// 
        abstract protected AutomationControlType GetAutomationControlTypeCore();
 
        /// 
        virtual protected string GetLocalizedControlTypeCore()
        { 
            ControlType controlType = GetControlType();
            return controlType.LocalizedControlType;
        }
 
        ///
        abstract protected bool IsContentElementCore(); 
 
        ///
        abstract protected bool IsControlElementCore(); 

        ///
        abstract protected AutomationPeer GetLabeledByCore();
 
        ///
        abstract protected string GetHelpTextCore(); 
 
        ///
        abstract protected string GetAcceleratorKeyCore(); 

        ///
        abstract protected string GetAccessKeyCore();
 
        ///
        abstract protected Point GetClickablePointCore(); 
 
        ///
        abstract protected void SetFocusCore(); 

        //
        // INTERNAL STUFF - NOT OVERRIDABLE
        // 

 
        /// 
        public Rect GetBoundingRectangle()
        { 
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));

            try 
            {
                _publicCallInProgress = true; 
                _boundingRectangle = GetBoundingRectangleCore(); 
            }
            finally 
            {
                _publicCallInProgress = false;
            }
            return _boundingRectangle; 
        }
 
        /// 
        public bool IsOffscreen()
        { 
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));

            try 
            {
                _publicCallInProgress = true; 
                _isOffscreen = IsOffscreenCore(); 
            }
            finally 
            {
                _publicCallInProgress = false;
            }
            return _isOffscreen; 
        }
 
        /// 
        public AutomationOrientation GetOrientation()
        { 
            AutomationOrientation result;

            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 

            try 
            { 
                _publicCallInProgress = true;
                result = GetOrientationCore(); 
            }
            finally
            {
                _publicCallInProgress = false; 
            }
            return result; 
        } 

        /// 
        public string GetItemType()
        {
            string result;
 
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 
 
            try
            { 
                _publicCallInProgress = true;
                result = GetItemTypeCore();
            }
            finally 
            {
                _publicCallInProgress = false; 
            } 
            return result;
        } 

        ///
        public string GetClassName()
        { 
            string result;
 
            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try
            {
                _publicCallInProgress = true;
                result = GetClassNameCore(); 
            }
            finally 
            { 
                _publicCallInProgress = false;
            } 
            return result;
        }

        /// 
        public string GetItemStatus()
        { 
            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try
            {
                _publicCallInProgress = true;
                _itemStatus = GetItemStatusCore(); 
            }
            finally 
            { 
                _publicCallInProgress = false;
            } 
            return _itemStatus;
        }

        /// 
        public bool IsRequiredForForm()
        { 
            bool result; 

            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));

            try
            { 
                _publicCallInProgress = true;
                result = IsRequiredForFormCore(); 
            } 
            finally
            { 
                _publicCallInProgress = false;
            }
            return result;
        } 

        /// 
        public bool IsKeyboardFocusable() 
        {
            bool result; 

            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try
            { 
                _publicCallInProgress = true; 
                result = IsKeyboardFocusableCore();
            } 
            finally
            {
                _publicCallInProgress = false;
            } 
            return result;
        } 
 
        ///
        public bool HasKeyboardFocus() 
        {
            bool result;
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 

            try 
            { 
                _publicCallInProgress = true;
                result = HasKeyboardFocusCore(); 
            }
            finally
            {
                _publicCallInProgress = false; 
            }
            return result; 
        } 

        /// 
        public bool IsEnabled()
        {
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 

            try 
            { 
                _publicCallInProgress = true;
                _isEnabled = IsEnabledCore(); 
            }
            finally
            {
                _publicCallInProgress = false; 
            }
            return _isEnabled; 
        } 

        /// 
        public bool IsPassword()
        {
            bool result;
 
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 
 
            try
            { 
                _publicCallInProgress = true;
                result = IsPasswordCore();
            }
            finally 
            {
                _publicCallInProgress = false; 
            } 
            return result;
        } 

        ///
        public string GetAutomationId()
        { 
            string result;
 
            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try
            {
                _publicCallInProgress = true;
                result = GetAutomationIdCore(); 
            }
            finally 
            { 
                _publicCallInProgress = false;
            } 
            return result;
        }

        /// 
        public string GetName()
        { 
            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try
            {
                _publicCallInProgress = true;
                _name = GetNameCore(); 
            }
            finally 
            { 
                _publicCallInProgress = false;
            } 
            return _name;
        }

        /// 
        public AutomationControlType GetAutomationControlType()
        { 
            AutomationControlType result; 

            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));

            try
            { 
                _publicCallInProgress = true;
                result = GetAutomationControlTypeCore(); 
            } 
            finally
            { 
                _publicCallInProgress = false;
            }
            return result;
        } 

        /// 
        public string GetLocalizedControlType() 
        {
            string result; 

            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try
            { 
                _publicCallInProgress = true; 
                result = GetLocalizedControlTypeCore();
            } 
            finally
            {
                _publicCallInProgress = false;
            } 
            return result;
        } 
 
        ///
        public bool IsContentElement() 
        {
            bool result;

            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try 
            {
                _publicCallInProgress = true; 
                result = IsContentElementCore();
            }
            finally
            { 
                _publicCallInProgress = false;
            } 
            return result; 
        }
 
        ///
        public bool IsControlElement()
        {
            bool result; 

            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 

            try 
            {
                _publicCallInProgress = true;
                result = IsControlElementCore();
            } 
            finally
            { 
                _publicCallInProgress = false; 
            }
            return result; 
        }

        ///
        public AutomationPeer GetLabeledBy() 
        {
            AutomationPeer result; 
 
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 

            try
            {
                _publicCallInProgress = true; 
                result = GetLabeledByCore();
            } 
            finally 
            {
                _publicCallInProgress = false; 
            }
            return result;
        }
 
        ///
        public string GetHelpText() 
        { 
            string result;
 
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));

            try 
            {
                _publicCallInProgress = true; 
                result = GetHelpTextCore(); 
            }
            finally 
            {
                _publicCallInProgress = false;
            }
            return result; 
        }
 
        /// 
        public string GetAcceleratorKey()
        { 
            string result;

            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 

            try 
            { 
                _publicCallInProgress = true;
                result = GetAcceleratorKeyCore(); 
            }
            finally
            {
                _publicCallInProgress = false; 
            }
            return result; 
        } 

        /// 
        public string GetAccessKey()
        {
            string result;
 
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 
 
            try
            { 
                _publicCallInProgress = true;
                result = GetAccessKeyCore();
            }
            finally 
            {
                _publicCallInProgress = false; 
            } 
            return result;
        } 

        ///
        public Point GetClickablePoint()
        { 
            Point result;
 
            if (_publicCallInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try
            {
                _publicCallInProgress = true;
                result = GetClickablePointCore(); 
            }
            finally 
            { 
                _publicCallInProgress = false;
            } 
            return result;
        }

        /// 
        public void SetFocus()
        { 
            if (_publicSetFocusInProgress) 
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall));
 
            try
            {
                _publicSetFocusInProgress = true;
                SetFocusCore(); 
            }
            finally 
            { 
                _publicSetFocusInProgress = false;
            } 
        }

        ///
        public AutomationPeer GetParent() 
        {
            return _parent; 
        } 

        /// 
        public List GetChildren()
        {
            if (_publicCallInProgress)
                throw new InvalidOperationException(SR.Get(SRID.Automation_RecursivePublicCall)); 

            try 
            { 
                _publicCallInProgress = true;
                EnsureChildren(); 
            }
            finally
            {
                _publicCallInProgress = false; 
            }
            return _children; 
        } 

        /// 
        public void ResetChildrenCache()
        {
            UpdateChildren();
        } 

        /// 
        internal int[] GetRuntimeId() 
        {
            return new int [] { 7, SafeNativeMethods.GetCurrentProcessId(), this.GetHashCode() }; 
        }

        ///
        internal string GetFrameworkId() { return ("WPF"); } 

        // 
        internal AutomationPeer GetFirstChild() 
        {
            AutomationPeer peer = null; 

            EnsureChildren();

            if (_children != null && _children.Count > 0) 
            {
                peer = _children[0]; 
            } 

            return peer; 
        }

        //
        /// 
        ///     Critical - Accessing _hwnd
        ///     TreatAsSafe - _hwnd is used internally and not exposed. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        private void EnsureChildren() 
        {
            if(!_childrenValid)
            {
                _children = GetChildrenCore(); 
                if (_children != null)
                { 
                    int count = _children.Count; 
                    for (int i = 0; i < count; ++i)
                    { 
                        _children[i]._parent = this;
                        _children[i]._index = i;
                        _children[i]._hwnd = _hwnd;
                    } 
                }
                _childrenValid = true; 
            } 
        }
 
        //
        internal AutomationPeer GetLastChild()
        {
            AutomationPeer peer = null; 

            EnsureChildren(); 
 
            if (_children != null && _children.Count > 0)
            { 
                peer = _children[_children.Count - 1];
            }

            return peer; 
        }
 
        // 
        [FriendAccessAllowed] // Built into Core, also used by Framework.
        internal virtual InteropAutomationProvider GetInteropChild() 
        {
            return null;
        }
 
        //
        internal AutomationPeer GetNextSibling() 
        { 
            AutomationPeer sibling = null;
            AutomationPeer parent = GetParent(); 

            if (parent != null)
            {
                parent.EnsureChildren(); 

                if (    parent._children != null 
                    &&  _index + 1 < parent._children.Count 
                    &&  parent._children[_index] == this    )
                { 
                    sibling = parent._children[_index + 1];
                }
            }
 
            return sibling;
        } 
 
        //
        internal AutomationPeer GetPreviousSibling() 
        {
            AutomationPeer sibling = null;
            AutomationPeer parent = GetParent();
 
            if (parent != null)
            { 
                parent.EnsureChildren(); 

                if (    parent._children != null 
                    &&  _index - 1 >= 0
                    &&  _index < parent._children.Count
                    &&  parent._children[_index] == this    )
                { 
                    sibling = parent._children[_index - 1];
                } 
            } 

            return sibling; 
        }

        //
        internal ControlType GetControlType() 
        {
            ControlType controlType = null; 
 
            AutomationControlType type = GetAutomationControlTypeCore();
 
            switch (type)
            {
                case AutomationControlType.Button:        controlType = ControlType.Button;       break;
                case AutomationControlType.Calendar:      controlType = ControlType.Calendar;     break; 
                case AutomationControlType.CheckBox:      controlType = ControlType.CheckBox;     break;
                case AutomationControlType.ComboBox:      controlType = ControlType.ComboBox;     break; 
                case AutomationControlType.Edit:          controlType = ControlType.Edit;         break; 
                case AutomationControlType.Hyperlink:     controlType = ControlType.Hyperlink;    break;
                case AutomationControlType.Image:         controlType = ControlType.Image;        break; 
                case AutomationControlType.ListItem:      controlType = ControlType.ListItem;     break;
                case AutomationControlType.List:          controlType = ControlType.List;         break;
                case AutomationControlType.Menu:          controlType = ControlType.Menu;         break;
                case AutomationControlType.MenuBar:       controlType = ControlType.MenuBar;      break; 
                case AutomationControlType.MenuItem:      controlType = ControlType.MenuItem;     break;
                case AutomationControlType.ProgressBar:   controlType = ControlType.ProgressBar;  break; 
                case AutomationControlType.RadioButton:   controlType = ControlType.RadioButton;  break; 
                case AutomationControlType.ScrollBar:     controlType = ControlType.ScrollBar;    break;
                case AutomationControlType.Slider:        controlType = ControlType.Slider;       break; 
                case AutomationControlType.Spinner:       controlType = ControlType.Spinner;      break;
                case AutomationControlType.StatusBar:     controlType = ControlType.StatusBar;    break;
                case AutomationControlType.Tab:           controlType = ControlType.Tab;          break;
                case AutomationControlType.TabItem:       controlType = ControlType.TabItem;      break; 
                case AutomationControlType.Text:          controlType = ControlType.Text;         break;
                case AutomationControlType.ToolBar:       controlType = ControlType.ToolBar;      break; 
                case AutomationControlType.ToolTip:       controlType = ControlType.ToolTip;      break; 
                case AutomationControlType.Tree:          controlType = ControlType.Tree;         break;
                case AutomationControlType.TreeItem:      controlType = ControlType.TreeItem;     break; 
                case AutomationControlType.Custom:        controlType = ControlType.Custom;       break;
                case AutomationControlType.Group:         controlType = ControlType.Group;        break;
                case AutomationControlType.Thumb:         controlType = ControlType.Thumb;        break;
                case AutomationControlType.DataGrid:      controlType = ControlType.DataGrid;     break; 
                case AutomationControlType.DataItem:      controlType = ControlType.DataItem;     break;
                case AutomationControlType.Document:      controlType = ControlType.Document;     break; 
                case AutomationControlType.SplitButton:   controlType = ControlType.SplitButton;  break; 
                case AutomationControlType.Window:        controlType = ControlType.Window;       break;
                case AutomationControlType.Pane:          controlType = ControlType.Pane;         break; 
                case AutomationControlType.Header:        controlType = ControlType.Header;       break;
                case AutomationControlType.HeaderItem:    controlType = ControlType.HeaderItem;   break;
                case AutomationControlType.Table:         controlType = ControlType.Table;        break;
                case AutomationControlType.TitleBar:      controlType = ControlType.TitleBar;     break; 
                case AutomationControlType.Separator:     controlType = ControlType.Separator;    break;
                default: break; 
            } 

            return controlType; 
        }

        internal AutomationPeer GetPeerFromPoint(Point point)
        { 
            AutomationPeer found = null;
 
            if(!IsOffscreen()) 
            {
                List children = GetChildren(); 
                if(children != null)
                {
                    int count = children.Count;
                    for(int i = count-1; (i >= 0) && (found == null); --i) 
                    {
                        found = children[i].GetPeerFromPoint(point); 
                    } 
                }
 
                if(found == null)
                {
                    Rect bounds = GetBoundingRectangle();
                    if(bounds.Contains(point)) 
                        found = this;
                } 
           } 

            return found; 
        }

        ///
        /// Creates an element provider (proxy) from a peer. Some patterns require returning objects of type 
        /// IRawElementProviderSimple - this is an Automation-specific wrapper interface that corresponds to a peer.
        /// To wrap an AutomationPeer into the wrapper that exposes this interface, use this method. 
        /// 
        protected internal IRawElementProviderSimple ProviderFromPeer(AutomationPeer peer)
        { 
            AutomationPeer referencePeer = this;

            //replace itself with _eventsSource if we are aggregated and hidden from the UIA
            if((peer == this) && (_eventsSource != null)) 
            {
                referencePeer = peer = _eventsSource; 
            } 

            return ElementProxy.StaticWrap(peer, referencePeer); 
        }

        private IRawElementProviderSimple ProviderFromPeerNoDelegation(AutomationPeer peer)
        { 
            AutomationPeer referencePeer = this;
            return ElementProxy.StaticWrap(peer, referencePeer); 
        } 

        /// 
        /// When one AutomationPeer is using the pattern of another AutomationPeer instead of exposing
        /// it in the children collection (example - ListBox exposes IScrollProvider from internal ScrollViewer
        /// but does not expose the ScrollViewerAutomationPeer as its child) - then before returning the pattern
        /// interface from GetPattern, the "main" AutomationPeer should call this method to set up itself as 
        /// "source" for the events fired by the pattern on the subordinate AutomationPeer.
        /// Otherwise, the hidden subordinate AutomationPeer will fire pattern's events from its own identity which 
        /// will confuse UIA since its identity is not exposed to UIA. 
        ///
        public AutomationPeer EventsSource 
        {
            get { return _eventsSource; }
            set { _eventsSource = value; }
        } 

 
        /// 
        /// Returns AutomationPeer corresponding to the given provider.
        /// 
        protected AutomationPeer PeerFromProvider(IRawElementProviderSimple provider)
        {
            ElementProxy proxy = provider as ElementProxy;
            if (proxy != null) 
            {
                return (proxy.Peer); 
            } 

            return null; 
        }

        //called on a root peer of a tree when it's time to fire automation events
        //walks down the tree, updates caches and fires automation events 
        //
        internal void FireAutomationEvents() 
        { 
            UpdateSubtree();
        } 

        // internal handling of structure chanegd events
        private void RaisePropertyChangedInternal(IRawElementProviderSimple provider,
                                                             AutomationProperty propertyId, 
                                                             object oldValue,
                                                             object newValue) 
        { 
            // Callers have only checked if automation clients are present so filter for any interest in this particular event.
            if (  provider != null 
               && EventMap.HasRegisteredEvent(AutomationEvents.PropertyChanged) )
            {
                AutomationPropertyChangedEventArgs e = new AutomationPropertyChangedEventArgs(propertyId, oldValue, newValue);
                AutomationInteropProvider.RaiseAutomationPropertyChangedEvent(provider, e); 
            }
        } 
 
        // internal handling of structure changed events
        private void UpdateChildren() 
        {
            List oldChildren = _children;
            List addedChildren = null;
            Hashtable ht = null; 

            _childrenValid = false; 
            EnsureChildren(); 

            // Callers have only checked if automation clients are present so filter for any interest in this particular event. 
            if (!EventMap.HasRegisteredEvent(AutomationEvents.StructureChanged))
                return;

            //store old children in a hashtable 
            if(oldChildren != null)
            { 
                ht =  new Hashtable(); 
                for(int count = oldChildren.Count, i = 0; i < count; i++)
                { 
                    ht.Add(oldChildren[i], null);
                }
            }
 
            //walk over new children, remove the ones that were in the old collection from hash table
            //and add new ones into addedChildren list 
            int addedCount = 0; 

            if(_children != null) 
            {
                for(int count = _children.Count, i = 0; i < count; i++)
                {
                    AutomationPeer child = _children[i]; 
                    if(ht != null && ht.ContainsKey(child))
                    { 
                        ht.Remove(child); //same child, nothing to notify 
                    }
                    else 
                    {
                        if(addedChildren == null) addedChildren = new List();

                        //stop accumulatin new children here because the notification 
                        //is going to become "bulk anyways and exact set of chidlren is not
                        //needed, only count. 
                        ++addedCount; 
                        if(addedCount <= AutomationInteropProvider.InvalidateLimit)
                            addedChildren.Add(child); 
                    }
                }
            }
 
            //now the ht only has "removed" children. If the count does not yet
            //calls for "bulk" notification, use per-child notification, otherwise use "bulk" 
            int removedCount = (ht == null ? 0 : ht.Count); 

            if(removedCount + addedCount > AutomationInteropProvider.InvalidateLimit) //bilk invalidation 
            {
                StructureChangeType flags;

                // Set bulk event type depending on if these were adds, removes or a mix 
                if (addedCount == 0)
                    flags = StructureChangeType.ChildrenBulkRemoved; 
                else if ( removedCount == 0 ) 
                    flags = StructureChangeType.ChildrenBulkAdded;
                else 
                    flags = StructureChangeType.ChildrenInvalidated;

                IRawElementProviderSimple provider = ProviderFromPeerNoDelegation(this);
                if(provider != null) 
                {
                    int [] rid = this.GetRuntimeId(); //use runtimeID of parent for bulk notifications 
 
                    AutomationInteropProvider.RaiseStructureChangedEvent(
                                    provider, 
                                    new StructureChangedEventArgs(flags, rid));
                }
            }
            else if(removedCount > 0) 
            {
                //for children removed, provider is the parent 
                IRawElementProviderSimple provider = ProviderFromPeerNoDelegation(this); 
                if(provider != null)
                { 
                    //ht contains removed children by now
                    foreach(object key in ht.Keys)
                    {
                        AutomationPeer removedChild = (AutomationPeer)key; 

                        int [] rid = removedChild.GetRuntimeId(); 
 
                        AutomationInteropProvider.RaiseStructureChangedEvent(
                                        provider, 
                                        new StructureChangedEventArgs(StructureChangeType.ChildRemoved, rid));
                    }
                }
            } 
            else if(addedCount > 0)
            { 
                //ht contains removed children by now 
                foreach(AutomationPeer addedChild in addedChildren)
                { 
                    //for children added, provider is the child itself
                    IRawElementProviderSimple provider = ProviderFromPeerNoDelegation(addedChild);
                    if(provider != null)
                    { 
                        int [] rid = addedChild.GetRuntimeId();
 
                        AutomationInteropProvider.RaiseStructureChangedEvent( 
                                        provider,
                                        new StructureChangedEventArgs(StructureChangeType.ChildAdded, rid)); 
                    }
                }
            }
        } 

        // 
 

 



 

 
 

        [FriendAccessAllowed] // Built into Core, also used by Framework. 
        internal void UpdateSubtree()
        {
            ContextLayoutManager lm = ContextLayoutManager.From(this.Dispatcher);
            if(lm != null) 
            {
                lm.AutomationSyncUpdateCounter = lm.AutomationSyncUpdateCounter + 1; 
 
                try
                { 
                    IRawElementProviderSimple provider = null;


 

                    bool notifyPropertyChanged = EventMap.HasRegisteredEvent(AutomationEvents.PropertyChanged); 
                    bool notifyStructureChanged = EventMap.HasRegisteredEvent(AutomationEvents.StructureChanged); 

                    //  did anybody ask for property changed norification? 
                    if (notifyPropertyChanged)
                    {
                        string itemStatus = GetItemStatusCore();
                        if (itemStatus != _itemStatus) 
                        {
                            if(provider == null) 
                                provider = ProviderFromPeerNoDelegation(this); 
                            RaisePropertyChangedInternal(provider,
                                                         AutomationElementIdentifiers.ItemStatusProperty, 
                                                         _itemStatus,
                                                         itemStatus);
                            _itemStatus = itemStatus;
                        } 

                        string name = GetNameCore(); 
                        if (name != _name) 
                        {
                            if(provider == null) 
                                provider = ProviderFromPeerNoDelegation(this);
                            RaisePropertyChangedInternal(provider,
                                                         AutomationElementIdentifiers.NameProperty,
                                                         _name, 
                                                         name);
                            _name = name; 
                        } 

                        bool isOffscreen = IsOffscreenCore(); 
                        if (isOffscreen != _isOffscreen)
                        {
                            if(provider == null)
                                provider = ProviderFromPeerNoDelegation(this); 
                            RaisePropertyChangedInternal(provider,
                                                         AutomationElementIdentifiers.IsOffscreenProperty, 
                                                         _isOffscreen, 
                                                         isOffscreen);
                            _isOffscreen = isOffscreen; 
                        }

                        bool isEnabled = IsEnabledCore();
                        if (isEnabled != _isEnabled) 
                        {
                            if(provider == null) 
                                provider = ProviderFromPeerNoDelegation(this); 
                            RaisePropertyChangedInternal(provider,
                                                         AutomationElementIdentifiers.IsEnabledProperty, 
                                                         _isEnabled,
                                                         isEnabled);
                            _isEnabled = isEnabled;
                        } 
                    }
 
                    //  did anybody ask for structure changed norification? 
                    //  if somebody asked for property changed then structure must be updated
                    if (_childrenValid || notifyStructureChanged || notifyPropertyChanged) 
                    {
                        UpdateChildren();

                        for(AutomationPeer peer = GetFirstChild(); peer != null; peer = peer.GetNextSibling()) 
                        {
                            peer.UpdateSubtree(); 
                        } 
                    }
 
                    _invalidated = false;
                }
                finally
                { 
                    lm.AutomationSyncUpdateCounter = lm.AutomationSyncUpdateCounter - 1;
                } 
            } 
        }
 
        private static object UpdatePeer(object arg)
        {
            AutomationPeer peer = (AutomationPeer)arg;
            peer.UpdateSubtree(); 
            return null;
        } 
 
        internal void AddToAutomationEventList()
        { 
            if(!_addedToEventList)
            {
                ContextLayoutManager lm = ContextLayoutManager.From(this.Dispatcher);
                lm.AutomationEvents.Add(this); //this adds the root peer into the list of roots, for deferred event firing 
                _addedToEventList = true;
            } 
 
        }
 
        /// 
        ///     Critical - provides access to critial data.
        /// 
        internal IntPtr Hwnd 
        {
            [SecurityCritical] 
            get { return _hwnd; } 
            [SecurityCritical]
            set { _hwnd = value; } 
        }

        //
        internal object GetWrappedPattern(int patternId) 
        {
            object result = null; 
 
            PatternInfo info = (PatternInfo)s_patternInfo[patternId];
 
            if (info != null)
            {
                object iface = GetPattern(info.PatternInterface);
                if (iface != null) 
                {
                    result = info.WrapObject(this, iface); 
                } 
            }
 
            return result;
        }

        // 
        internal object GetPropertyValue(int propertyId)
        { 
            object result = null; 

            GetProperty getProperty = (GetProperty)s_propertyInfo[propertyId]; 

            if (getProperty != null)
            {
                result = getProperty(this); 
            }
 
            return result; 
        }
 
        //
        internal bool IsInteropPeer
        {
            get { return _isInteropPeer; } 
            set { _isInteropPeer = value; }
        } 
 
        private static void Initialize()
        { 
            //  initializeing patterns
            s_patternInfo = new Hashtable();
            s_patternInfo[InvokePatternIdentifiers.Pattern.Id]          = new PatternInfo(InvokePatternIdentifiers.Pattern.Id,          new WrapObject(InvokeProviderWrapper.Wrap),             PatternInterface.Invoke);
            s_patternInfo[SelectionPatternIdentifiers.Pattern.Id]       = new PatternInfo(SelectionPatternIdentifiers.Pattern.Id,       new WrapObject(SelectionProviderWrapper.Wrap),          PatternInterface.Selection); 
            s_patternInfo[ValuePatternIdentifiers.Pattern.Id]           = new PatternInfo(ValuePatternIdentifiers.Pattern.Id,           new WrapObject(ValueProviderWrapper.Wrap),              PatternInterface.Value);
            s_patternInfo[RangeValuePatternIdentifiers.Pattern.Id]      = new PatternInfo(RangeValuePatternIdentifiers.Pattern.Id,      new WrapObject(RangeValueProviderWrapper.Wrap),         PatternInterface.RangeValue); 
            s_patternInfo[ScrollPatternIdentifiers.Pattern.Id]          = new PatternInfo(ScrollPatternIdentifiers.Pattern.Id,          new WrapObject(ScrollProviderWrapper.Wrap),             PatternInterface.Scroll); 
            s_patternInfo[ScrollItemPatternIdentifiers.Pattern.Id]      = new PatternInfo(ScrollItemPatternIdentifiers.Pattern.Id,      new WrapObject(ScrollItemProviderWrapper.Wrap),         PatternInterface.ScrollItem);
            s_patternInfo[ExpandCollapsePatternIdentifiers.Pattern.Id]  = new PatternInfo(ExpandCollapsePatternIdentifiers.Pattern.Id,  new WrapObject(ExpandCollapseProviderWrapper.Wrap),     PatternInterface.ExpandCollapse); 
            s_patternInfo[GridPatternIdentifiers.Pattern.Id]            = new PatternInfo(GridPatternIdentifiers.Pattern.Id,            new WrapObject(GridProviderWrapper.Wrap),               PatternInterface.Grid);
            s_patternInfo[GridItemPatternIdentifiers.Pattern.Id]        = new PatternInfo(GridItemPatternIdentifiers.Pattern.Id,        new WrapObject(GridItemProviderWrapper.Wrap),           PatternInterface.GridItem);
            s_patternInfo[MultipleViewPatternIdentifiers.Pattern.Id]    = new PatternInfo(MultipleViewPatternIdentifiers.Pattern.Id,    new WrapObject(MultipleViewProviderWrapper.Wrap),       PatternInterface.MultipleView);
            s_patternInfo[WindowPatternIdentifiers.Pattern.Id]          = new PatternInfo(WindowPatternIdentifiers.Pattern.Id,          new WrapObject(WindowProviderWrapper.Wrap),             PatternInterface.Window); 
            s_patternInfo[SelectionItemPatternIdentifiers.Pattern.Id]   = new PatternInfo(SelectionItemPatternIdentifiers.Pattern.Id,   new WrapObject(SelectionItemProviderWrapper.Wrap),      PatternInterface.SelectionItem);
            s_patternInfo[DockPatternIdentifiers.Pattern.Id]            = new PatternInfo(DockPatternIdentifiers.Pattern.Id,            new WrapObject(DockProviderWrapper.Wrap),               PatternInterface.Dock); 
            s_patternInfo[TablePatternIdentifiers.Pattern.Id]           = new PatternInfo(TablePatternIdentifiers.Pattern.Id,           new WrapObject(TableProviderWrapper.Wrap),              PatternInterface.Table); 
            s_patternInfo[TableItemPatternIdentifiers.Pattern.Id]       = new PatternInfo(TableItemPatternIdentifiers.Pattern.Id,       new WrapObject(TableItemProviderWrapper.Wrap),          PatternInterface.TableItem);
            s_patternInfo[TogglePatternIdentifiers.Pattern.Id]          = new PatternInfo(TogglePatternIdentifiers.Pattern.Id,          new WrapObject(ToggleProviderWrapper.Wrap),             PatternInterface.Toggle); 
            s_patternInfo[TransformPatternIdentifiers.Pattern.Id]       = new PatternInfo(TransformPatternIdentifiers.Pattern.Id,       new WrapObject(TransformProviderWrapper.Wrap),          PatternInterface.Transform);
            s_patternInfo[TextPatternIdentifiers.Pattern.Id]            = new PatternInfo(TextPatternIdentifiers.Pattern.Id,            new WrapObject(TextProviderWrapper.Wrap),               PatternInterface.Text);

            //  initializeing properties 
            s_propertyInfo = new Hashtable();
            s_propertyInfo[AutomationElementIdentifiers.IsControlElementProperty.Id] = new GetProperty(IsControlElement); 
            s_propertyInfo[AutomationElementIdentifiers.ControlTypeProperty.Id] = new GetProperty(GetControlType); 
            s_propertyInfo[AutomationElementIdentifiers.IsContentElementProperty.Id] = new GetProperty(IsContentElement);
            s_propertyInfo[AutomationElementIdentifiers.LabeledByProperty.Id] = new GetProperty(GetLabeledBy); 
            s_propertyInfo[AutomationElementIdentifiers.NativeWindowHandleProperty.Id] = new GetProperty(GetNativeWindowHandle);
            s_propertyInfo[AutomationElementIdentifiers.AutomationIdProperty.Id] = new GetProperty(GetAutomationId);
            s_propertyInfo[AutomationElementIdentifiers.ItemTypeProperty.Id] = new GetProperty(GetItemType);
            s_propertyInfo[AutomationElementIdentifiers.IsPasswordProperty.Id] = new GetProperty(IsPassword); 
            s_propertyInfo[AutomationElementIdentifiers.LocalizedControlTypeProperty.Id] = new GetProperty(GetLocalizedControlType);
            s_propertyInfo[AutomationElementIdentifiers.NameProperty.Id] = new GetProperty(GetName); 
            s_propertyInfo[AutomationElementIdentifiers.AcceleratorKeyProperty.Id] = new GetProperty(GetAcceleratorKey); 
            s_propertyInfo[AutomationElementIdentifiers.AccessKeyProperty.Id] = new GetProperty(GetAccessKey);
            s_propertyInfo[AutomationElementIdentifiers.HasKeyboardFocusProperty.Id] = new GetProperty(HasKeyboardFocus); 
            s_propertyInfo[AutomationElementIdentifiers.IsKeyboardFocusableProperty.Id] = new GetProperty(IsKeyboardFocusable);
            s_propertyInfo[AutomationElementIdentifiers.IsEnabledProperty.Id] = new GetProperty(IsEnabled);
            s_propertyInfo[AutomationElementIdentifiers.BoundingRectangleProperty.Id] = new GetProperty(GetBoundingRectangle);
            s_propertyInfo[AutomationElementIdentifiers.ProcessIdProperty.Id] = new GetProperty(GetCurrentProcessId); 
            s_propertyInfo[AutomationElementIdentifiers.RuntimeIdProperty.Id] = new GetProperty(GetRuntimeId);
            s_propertyInfo[AutomationElementIdentifiers.ClassNameProperty.Id] = new GetProperty(GetClassName); 
            s_propertyInfo[AutomationElementIdentifiers.HelpTextProperty.Id] = new GetProperty(GetHelpText); 
            s_propertyInfo[AutomationElementIdentifiers.ClickablePointProperty.Id] = new GetProperty(GetClickablePoint);
            s_propertyInfo[AutomationElementIdentifiers.CultureProperty.Id] = new GetProperty(GetCultureInfo); 
            s_propertyInfo[AutomationElementIdentifiers.IsOffscreenProperty.Id] = new GetProperty(IsOffscreen);
            s_propertyInfo[AutomationElementIdentifiers.OrientationProperty.Id] = new GetProperty(GetOrientation);
            s_propertyInfo[AutomationElementIdentifiers.FrameworkIdProperty.Id] = new GetProperty(GetFrameworkId);
            s_propertyInfo[AutomationElementIdentifiers.IsRequiredForFormProperty.Id] = new GetProperty(IsRequiredForForm); 
            s_propertyInfo[AutomationElementIdentifiers.ItemStatusProperty.Id] = new GetProperty(GetItemStatus);
 
            s_initialized = true; 
        }
 
        private delegate object WrapObject(AutomationPeer peer, object iface);

        private class PatternInfo
        { 
            internal PatternInfo(int id, WrapObject wrapObject, PatternInterface patternInterface)
            { 
                Id = id; 
                WrapObject = wrapObject;
                PatternInterface = patternInterface; 
            }

            internal int Id;
            internal WrapObject WrapObject; 
            internal PatternInterface PatternInterface;
        } 
 
        private delegate object GetProperty(AutomationPeer peer);
 
        private static object IsControlElement(AutomationPeer peer)         {   return peer.IsControlElement(); }
        private static object GetControlType(AutomationPeer peer)           {   ControlType controlType = peer.GetControlType(); return controlType.Id;  }
        private static object IsContentElement(AutomationPeer peer)         {   return peer.IsContentElement(); }
        private static object GetLabeledBy(AutomationPeer peer)             {   AutomationPeer byPeer = peer.GetLabeledBy(); return ElementProxy.StaticWrap(byPeer, peer);  } 
        private static object GetNativeWindowHandle(AutomationPeer peer)    {   return null /* not used? */;    }
        private static object GetAutomationId(AutomationPeer peer)          {   return peer.GetAutomationId();  } 
        private static object GetItemType(AutomationPeer peer)              {   return peer.GetItemType();      } 
        private static object IsPassword(AutomationPeer peer)               {   return peer.IsPassword();       }
        private static object GetLocalizedControlType(AutomationPeer peer)  {   return peer.GetLocalizedControlType();  } 
        private static object GetName(AutomationPeer peer)                  {   return peer.GetName();          }
        private static object GetAcceleratorKey(AutomationPeer peer)        {   return peer.GetAcceleratorKey();    }
        private static object GetAccessKey(AutomationPeer peer)             {   return peer.GetAccessKey();     }
        private static object HasKeyboardFocus(AutomationPeer peer)         {   return peer.HasKeyboardFocus(); } 
        private static object IsKeyboardFocusable(AutomationPeer peer)      {   return peer.IsKeyboardFocusable();  }
        private static object IsEnabled(AutomationPeer peer)                {   return peer.IsEnabled();        } 
        private static object GetBoundingRectangle(AutomationPeer peer)     {   return peer.GetBoundingRectangle(); } 
        private static object GetCurrentProcessId(AutomationPeer peer)      {   return SafeNativeMethods.GetCurrentProcessId(); }
        private static object GetRuntimeId(AutomationPeer peer)             {   return peer.GetRuntimeId();     } 
        private static object GetClassName(AutomationPeer peer)             {   return peer.GetClassName();     }
        private static object GetHelpText(AutomationPeer peer)              {   return peer.GetHelpText();  }
        private static object GetClickablePoint(AutomationPeer peer)        {   Point pt = peer.GetClickablePoint(); return new double[] {pt.X, pt.Y};  }
        private static object GetCultureInfo(AutomationPeer peer)           {   return null;    } 
        private static object IsOffscreen(AutomationPeer peer)              {   return peer.IsOffscreen();  }
        private static object GetOrientation(AutomationPeer peer)           {   return peer.GetOrientation();   } 
        private static object GetFrameworkId(AutomationPeer peer)           {   return peer.GetFrameworkId();   } 
        private static object IsRequiredForForm(AutomationPeer peer)        {   return peer.IsRequiredForForm();    }
        private static object GetItemStatus(AutomationPeer peer)            {   return peer.GetItemStatus();    } 

        private static bool s_initialized;
        private static Hashtable s_patternInfo;
        private static Hashtable s_propertyInfo; 

        private int _index; 
        /// 
        ///     Critical - once stored, this hwnd will be used for subsequent automation operations.
        /// 
        [SecurityCritical]
        private IntPtr _hwnd;
        private List _children;
        private AutomationPeer _parent; 

        private AutomationPeer _eventsSource; 
 
        private Rect _boundingRectangle;
        private string _itemStatus; 
        private string _name;
        private bool _isOffscreen;
        private bool _isEnabled;
        private bool _invalidated; 
        private bool _childrenValid;
        private bool _addedToEventList; 
        private bool _publicCallInProgress; 
        private bool _publicSetFocusInProgress;
        private bool _isInteropPeer; 

        private static DispatcherOperationCallback _updatePeer = new DispatcherOperationCallback(UpdatePeer);
    }
} 

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