AutomationPeer.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Core / CSharp / System / Windows / Automation / Peers / AutomationPeer.cs / 1600594 / 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, 
        /// 
        ItemContainer,
        /// 
        VirtualizedItem,
        ///
        SynchronizedInput,
    } 

    /// 
    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, 
        /// 
        InputReachedTarget,
        /// 
        InputReachedOtherElement,
        ///
        InputDiscarded,
    } 

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

        /// 
        /// This is responsible for adding parent info like the parent window handle
        /// and the parent itself to it's child. This is by definition is a securitycritical operation 
        /// for two reasons
        /// 1. it's doing an action which is securitycritical 
        /// 2. it can not be treated as safe as it doesn't know whether 
        ///    the peer is actually this objects's parent or not and must be used by methods which has
        ///    this information and hence are[SecurityTreatAsSafe]. 
        /// 
        /// Critical - access _hwnd
        /// 
        ///  
        /// 
        [SecurityCritical] 
        internal bool TrySetParentInfo(AutomationPeer peer) 
        {
            Invariant.Assert((peer != null)); 

            if(peer._hwnd == IntPtr.Zero)
            {
                // parent is not yet part of Automation Tree itself 
                return false;
            } 
 
            _hwnd = peer._hwnd;
            _parent = peer; 

            return true;
        }
 
        // To determine if the peer corresponds to DataItem
        virtual internal bool IsDataItemAutomationPeer() 
        { 
            return false;
        } 

        // This is mainly for enabling ITemsControl to keep the Cache of the Item's Proxy Weak Ref to
        // re-use the item peers being passed to clinet and still exist in memory
        virtual internal void AddToParentProxyWeakRefCache() 
        {
            //do nothing 
        } 
        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
        // 
        virtual internal Rect GetVisibleBoundingRectCore()
        { 
            // Too late to add abstract methods, since this class has already shipped(using default definition)! 
            return GetBoundingRectangle();
        } 


        ///
        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 or _ancestorsInvalid,  indicates that the automation tree under this peer is not up to date, so requires 
            //  rebuilding before navigating. This usually is the case when the peer is re-parented because of UI changes but
            // UpdateSubtree is not called on it yet. 
            if (!_childrenValid || _ancestorsInvalid)
            {
                _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;
            } 
        } 

        // Use to update the Children irrespective of the _childrenValid flag. 
        internal void ForceEnsureChildren()
        {
            _childrenValid = false;
            EnsureChildren(); 
        }
 
        // 
        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 virtual 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 = GetVisibleBoundingRect(); 
                    if (bounds.Contains(point))
                        found = this;
                }
           } 

            return found; 
        } 

        ///  
        /// inherited by item peers to return just visible part of bounding rectangle.
        /// 
        /// 
        internal Rect GetVisibleBoundingRect() 
        {
            return GetVisibleBoundingRectCore(); 
        } 

        /// 
        /// 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);
            }
        }
 
        // InvalidateLimit � lower bound for  raising ChildrenInvalidated StructureChange event
        internal void UpdateChildrenInternal(int invalidateLimit) 
        { 
            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++)
                { 
                    if(!ht.Contains(oldChildren[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 <= 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 > 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));
                        }
                    }
                } 
                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)); 
                        }
                    }
                }
            } 
        }
 
        // internal handling of structure changed events 
        virtual internal void UpdateChildren()
        { 
            UpdateChildrenInternal(AutomationInteropProvider.InvalidateLimit);
        }

        // 

 
 

 



 

 
        [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 (this._childrenValid? (this.AncestorsInvalid || (ControlType.Custom == this.GetControlType())) : (notifyStructureChanged || notifyPropertyChanged))
                    { 
                        UpdateChildren();

                        AncestorsInvalid = false;
 
                        for(AutomationPeer peer = GetFirstChild(); peer != null; peer = peer.GetNextSibling())
                        { 
                            peer.UpdateSubtree(); 
                        }
                    } 
                    AncestorsInvalid = false;
                    _invalidated = false;
                }
                finally 
                {
                    lm.AutomationSyncUpdateCounter = lm.AutomationSyncUpdateCounter - 1; 
                } 
            }
        } 

        /// 
        /// propagate the new value for AncestorsInvalid through the parent chain,
        /// use EventSource (wrapper) peers whenever available as it�s the one connected to the tree. 
        /// 
        internal void InvalidateAncestorsRecursive() 
        { 
            if (!AncestorsInvalid)
            { 
                AncestorsInvalid = true;
                if (EventsSource != null)
                {
                    EventsSource.InvalidateAncestorsRecursive(); 
                }
 
                if (_parent != null) 
                    _parent.InvalidateAncestorsRecursive();
            } 
        }

        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 virtual bool AncestorsInvalid 
        {
            get { return _ancestorsInvalid; } 
            set { _ancestorsInvalid = value; } 
        }
 
        //
        internal bool ChildrenValid
        {
            get { return _childrenValid; } 
            set { _childrenValid = value; }
        } 
 
        //
        internal bool IsInteropPeer 
        {
            get { return _isInteropPeer; }
            set { _isInteropPeer = value; }
        } 

        // 
        internal int Index 
        {
            get { return _index; } 
        }

        //
        internal List Children 
        {
            get { return _children; } 
        } 

        // To Keep the WeakRefernce of ElementProxy wrapper for this peer so that it can be reused 
        // rather than creating the new Wrapper object if there is need and it still exist.
        internal WeakReference ElementProxyWeakReference
        {
            get{ return _elementProxyWeakReference; } 
            set
            { 
                if(value.Target as ElementProxy != null) 
                    _elementProxyWeakReference = 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); 
 
            // To avoid the worst situation on legacy systems which may not have new unmanaged core. with this change with old unmanaged core
            // this will these patterns will be null and won't be added and hence reponse will be as it is not present at all rather than any crash. 
            if (VirtualizedItemPatternIdentifiers.Pattern != null)
                s_patternInfo[VirtualizedItemPatternIdentifiers.Pattern.Id] = new PatternInfo(VirtualizedItemPatternIdentifiers.Pattern.Id, new WrapObject(VirtualizedItemProviderWrapper.Wrap), PatternInterface.VirtualizedItem);
            if (ItemContainerPatternIdentifiers.Pattern != null)
                s_patternInfo[ItemContainerPatternIdentifiers.Pattern.Id] = new PatternInfo(ItemContainerPatternIdentifiers.Pattern.Id, new WrapObject(ItemContainerProviderWrapper.Wrap), PatternInterface.ItemContainer); 
            if (SynchronizedInputPatternIdentifiers.Pattern != null)
            { 
                s_patternInfo[SynchronizedInputPatternIdentifiers.Pattern.Id] = new PatternInfo(SynchronizedInputPatternIdentifiers.Pattern.Id, new WrapObject(SynchronizedInputProviderWrapper.Wrap), PatternInterface.SynchronizedInput); 
            }
 
            //  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 = -1;
        /// 
        ///     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 _ancestorsInvalid;
        private bool _childrenValid;
        private bool _addedToEventList; 
        private bool _publicCallInProgress;
        private bool _publicSetFocusInProgress; 
        private bool _isInteropPeer; 
        private WeakReference _elementProxyWeakReference = null;
 
        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, 
        /// 
        ItemContainer,
        /// 
        VirtualizedItem,
        ///
        SynchronizedInput,
    } 

    /// 
    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, 
        /// 
        InputReachedTarget,
        /// 
        InputReachedOtherElement,
        ///
        InputDiscarded,
    } 

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

        /// 
        /// This is responsible for adding parent info like the parent window handle
        /// and the parent itself to it's child. This is by definition is a securitycritical operation 
        /// for two reasons
        /// 1. it's doing an action which is securitycritical 
        /// 2. it can not be treated as safe as it doesn't know whether 
        ///    the peer is actually this objects's parent or not and must be used by methods which has
        ///    this information and hence are[SecurityTreatAsSafe]. 
        /// 
        /// Critical - access _hwnd
        /// 
        ///  
        /// 
        [SecurityCritical] 
        internal bool TrySetParentInfo(AutomationPeer peer) 
        {
            Invariant.Assert((peer != null)); 

            if(peer._hwnd == IntPtr.Zero)
            {
                // parent is not yet part of Automation Tree itself 
                return false;
            } 
 
            _hwnd = peer._hwnd;
            _parent = peer; 

            return true;
        }
 
        // To determine if the peer corresponds to DataItem
        virtual internal bool IsDataItemAutomationPeer() 
        { 
            return false;
        } 

        // This is mainly for enabling ITemsControl to keep the Cache of the Item's Proxy Weak Ref to
        // re-use the item peers being passed to clinet and still exist in memory
        virtual internal void AddToParentProxyWeakRefCache() 
        {
            //do nothing 
        } 
        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
        // 
        virtual internal Rect GetVisibleBoundingRectCore()
        { 
            // Too late to add abstract methods, since this class has already shipped(using default definition)! 
            return GetBoundingRectangle();
        } 


        ///
        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 or _ancestorsInvalid,  indicates that the automation tree under this peer is not up to date, so requires 
            //  rebuilding before navigating. This usually is the case when the peer is re-parented because of UI changes but
            // UpdateSubtree is not called on it yet. 
            if (!_childrenValid || _ancestorsInvalid)
            {
                _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;
            } 
        } 

        // Use to update the Children irrespective of the _childrenValid flag. 
        internal void ForceEnsureChildren()
        {
            _childrenValid = false;
            EnsureChildren(); 
        }
 
        // 
        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 virtual 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 = GetVisibleBoundingRect(); 
                    if (bounds.Contains(point))
                        found = this;
                }
           } 

            return found; 
        } 

        ///  
        /// inherited by item peers to return just visible part of bounding rectangle.
        /// 
        /// 
        internal Rect GetVisibleBoundingRect() 
        {
            return GetVisibleBoundingRectCore(); 
        } 

        /// 
        /// 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);
            }
        }
 
        // InvalidateLimit � lower bound for  raising ChildrenInvalidated StructureChange event
        internal void UpdateChildrenInternal(int invalidateLimit) 
        { 
            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++)
                { 
                    if(!ht.Contains(oldChildren[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 <= 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 > 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));
                        }
                    }
                } 
                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)); 
                        }
                    }
                }
            } 
        }
 
        // internal handling of structure changed events 
        virtual internal void UpdateChildren()
        { 
            UpdateChildrenInternal(AutomationInteropProvider.InvalidateLimit);
        }

        // 

 
 

 



 

 
        [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 (this._childrenValid? (this.AncestorsInvalid || (ControlType.Custom == this.GetControlType())) : (notifyStructureChanged || notifyPropertyChanged))
                    { 
                        UpdateChildren();

                        AncestorsInvalid = false;
 
                        for(AutomationPeer peer = GetFirstChild(); peer != null; peer = peer.GetNextSibling())
                        { 
                            peer.UpdateSubtree(); 
                        }
                    } 
                    AncestorsInvalid = false;
                    _invalidated = false;
                }
                finally 
                {
                    lm.AutomationSyncUpdateCounter = lm.AutomationSyncUpdateCounter - 1; 
                } 
            }
        } 

        /// 
        /// propagate the new value for AncestorsInvalid through the parent chain,
        /// use EventSource (wrapper) peers whenever available as it�s the one connected to the tree. 
        /// 
        internal void InvalidateAncestorsRecursive() 
        { 
            if (!AncestorsInvalid)
            { 
                AncestorsInvalid = true;
                if (EventsSource != null)
                {
                    EventsSource.InvalidateAncestorsRecursive(); 
                }
 
                if (_parent != null) 
                    _parent.InvalidateAncestorsRecursive();
            } 
        }

        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 virtual bool AncestorsInvalid 
        {
            get { return _ancestorsInvalid; } 
            set { _ancestorsInvalid = value; } 
        }
 
        //
        internal bool ChildrenValid
        {
            get { return _childrenValid; } 
            set { _childrenValid = value; }
        } 
 
        //
        internal bool IsInteropPeer 
        {
            get { return _isInteropPeer; }
            set { _isInteropPeer = value; }
        } 

        // 
        internal int Index 
        {
            get { return _index; } 
        }

        //
        internal List Children 
        {
            get { return _children; } 
        } 

        // To Keep the WeakRefernce of ElementProxy wrapper for this peer so that it can be reused 
        // rather than creating the new Wrapper object if there is need and it still exist.
        internal WeakReference ElementProxyWeakReference
        {
            get{ return _elementProxyWeakReference; } 
            set
            { 
                if(value.Target as ElementProxy != null) 
                    _elementProxyWeakReference = 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); 
 
            // To avoid the worst situation on legacy systems which may not have new unmanaged core. with this change with old unmanaged core
            // this will these patterns will be null and won't be added and hence reponse will be as it is not present at all rather than any crash. 
            if (VirtualizedItemPatternIdentifiers.Pattern != null)
                s_patternInfo[VirtualizedItemPatternIdentifiers.Pattern.Id] = new PatternInfo(VirtualizedItemPatternIdentifiers.Pattern.Id, new WrapObject(VirtualizedItemProviderWrapper.Wrap), PatternInterface.VirtualizedItem);
            if (ItemContainerPatternIdentifiers.Pattern != null)
                s_patternInfo[ItemContainerPatternIdentifiers.Pattern.Id] = new PatternInfo(ItemContainerPatternIdentifiers.Pattern.Id, new WrapObject(ItemContainerProviderWrapper.Wrap), PatternInterface.ItemContainer); 
            if (SynchronizedInputPatternIdentifiers.Pattern != null)
            { 
                s_patternInfo[SynchronizedInputPatternIdentifiers.Pattern.Id] = new PatternInfo(SynchronizedInputPatternIdentifiers.Pattern.Id, new WrapObject(SynchronizedInputProviderWrapper.Wrap), PatternInterface.SynchronizedInput); 
            }
 
            //  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 = -1;
        /// 
        ///     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 _ancestorsInvalid;
        private bool _childrenValid;
        private bool _addedToEventList; 
        private bool _publicCallInProgress;
        private bool _publicSetFocusInProgress; 
        private bool _isInteropPeer; 
        private WeakReference _elementProxyWeakReference = null;
 
        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