ClientEventManager.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / UIAutomation / UIAutomationClient / MS / Internal / Automation / ClientEventManager.cs / 1305600 / ClientEventManager.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: Manages the listeners for one accessibility aid or test application. 
//
// History: 
//  06/17/2003 : BrendanM Ported to WCP
//
//---------------------------------------------------------------------------
 
using System.Windows;
using System.Collections; 
using System.Diagnostics; 
using System.Windows.Automation;
using System.Windows.Automation.Provider; 
using MS.Win32;

using System;
 
// PRESHARP: In order to avoid generating warnings about unkown message numbers and unknown pragmas.
#pragma warning disable 1634, 1691 
 
namespace MS.Internal.Automation
{ 
     // Manages the listeners for one accessibility aid or test application.  Locking
     // is used in all public methods to allow for multiple threads in a client process.
    internal static class ClientEventManager
    { 
        //-----------------------------------------------------
        // 
        //  Constructors 
        //
        //----------------------------------------------------- 

        #region Constructors

        // Static class, no ctor 

        #endregion Constructors 
 

        //------------------------------------------------------ 
        //
        //  Internal Methods
        //
        //----------------------------------------------------- 

        #region Internal Methods 
 
        // AddFocusListener - Adds a focus listener for this client.
        internal static void AddFocusListener(Delegate eventCallback, EventListener l) 
        {
            AddRootListener(Tracker.Focus, eventCallback, l);
        }
 
        // RemoveFocusListener - Removes a focus change listener from this client
        // and notifies the UIAccess server 
        internal static void RemoveFocusListener(Delegate eventCallback) 
        {
            RemoveRootListener(AutomationElement.AutomationFocusChangedEvent, Tracker.Focus, eventCallback); 
        }

        // AddListener - Adds a listener for this client and notifies the UIA server.  All event
        // handler additions call through to this method. 
        internal static void AddListener(AutomationElement rawEl, Delegate eventCallback, EventListener l)
        { 
            lock (_classLock) 
            {
                // If we are adding a listener then a proxy could be created as a result of an event so make sure they are loaded 
                ProxyManager.LoadDefaultProxies();

                if (_listeners == null)
                { 
                    // enough space for 16 AddXxxListeners (100 bytes)
                    _listeners = new ArrayList(16); 
                } 

                // Start the callback queue that gets us off the server's 
                // UI thread when events arrive cross-proc
                CheckStartCallbackQueueing();

                // 
                // The framework handles some events on behalf of providers; do those here
                // 
 
                // If listening for BoundingRectangleProperty then may need to start listening on the
                // client-side for LocationChange WinEvent (only use *one* BoundingRectTracker instance). 
                if (_winEventTrackers[(int)Tracker.BoundingRect] == null && HasProperty(AutomationElement.BoundingRectangleProperty, l.Properties))
                {
                    //
 

 
 

 

                    AddWinEventListener(Tracker.BoundingRect, new BoundingRectTracker());
                }
 
                // Start listening for menu event in order to raise MenuOpened/Closed events.
                if ( _winEventTrackers [(int)Tracker.MenuOpenedOrClosed] == null && (l.EventId == AutomationElement.MenuOpenedEvent || l.EventId == AutomationElement.MenuClosedEvent) ) 
                { 
                    AddWinEventListener( Tracker.MenuOpenedOrClosed, new MenuTracker( new MenuHandler( OnMenuEvent ) ) );
                } 

                // Begin watching for hwnd open/close/show/hide so can advise of what events are being listened for.
                // Only advise UI contexts of events being added if the event might be raised by a provider.
                // TopLevelWindow event is raised by UI Automation framework so no need to track new UI. 
                //
                if (_winEventTrackers[(int)Tracker.WindowShowOrOpen] == null ) 
                { 
                    AddWinEventListener( Tracker.WindowShowOrOpen, new WindowShowOrOpenTracker( new WindowShowOrOpenHandler( OnWindowShowOrOpen ) ) );
                    AddWinEventListener( Tracker.WindowHideOrClose, new WindowHideOrCloseTracker( new WindowHideOrCloseHandler( OnWindowHideOrClose ) ) ); 
                }

                // If listening for WindowInteractionStateProperty then may need to start listening on the
                // client-side for ObjectStateChange WinEvent. 
                if (_winEventTrackers[(int)Tracker.WindowInteractionState] == null && HasProperty(WindowPattern.WindowInteractionStateProperty, l.Properties))
                { 
                    AddWinEventListener(Tracker.WindowInteractionState, new WindowInteractionStateTracker()); 
                }
 
                // If listening for WindowVisualStateProperty then may need to start listening on the
                // client-side for ObjectLocationChange WinEvent.
                if (_winEventTrackers[(int)Tracker.WindowVisualState] == null && HasProperty(WindowPattern.WindowVisualStateProperty, l.Properties))
                { 
                    AddWinEventListener(Tracker.WindowVisualState, new WindowVisualStateTracker());
                } 
 
                // Wrap and store this record on the client...
                EventListenerClientSide ec = new EventListenerClientSide(rawEl, eventCallback, l); 
                _listeners.Add(ec);

                // Only advise UI contexts of events being added if the event might be raised by
                // a provider.  TopLevelWindow event is raised by UI Automation framework. 
                if (ShouldAdviseProviders( l.EventId ))
                { 
                    // .. then let the server know about this listener 
                    ec.EventHandle = UiaCoreApi.UiaAddEvent(rawEl.RawNode, l.EventId.Id, ec.CallbackDelegate, l.TreeScope, PropertyArrayToIntArray(l.Properties), l.CacheRequest);
                } 
            }
        }

        private static int[] PropertyArrayToIntArray(AutomationProperty[] properties) 
        {
            if (properties == null) 
                return null; 
            int[] propertiesAsInts = new int[properties.Length];
            for (int i = 0; i < properties.Length; i++) 
            {
                propertiesAsInts[i] = properties[i].Id;
            }
            return propertiesAsInts; 
        }
 
 
        // RemoveListener - Removes a listener from this client and notifies the UIAutomation server-side
        internal static void RemoveListener( AutomationEvent eventId, AutomationElement el, Delegate eventCallback ) 
        {
            lock( _classLock )
            {
                if( _listeners != null ) 
                {
                    bool boundingRectListeners = false; // if not removing BoundingRect listeners no need to do check below 
                    bool menuListeners = false; // if not removing MenuOpenedOrClosed listeners no need to do check below 
                    bool windowInteracationListeners = false; // if not removing WindowsIntercation listeners no need to do check below
                    bool windowVisualListeners = false; // if not removing WindowsVisual listeners no need to do check below 

                    for (int i = _listeners.Count - 1; i >= 0; i--)
                    {
                        EventListenerClientSide ec = (EventListenerClientSide)_listeners[i]; 
                        if( ec.IsListeningFor( eventId, el, eventCallback ) )
                        { 
                            EventListener l = ec.EventListener; 

                            // Only advise UI contexts of events being removed if the event might be raised by 
                            // a provider.  TopLevelWindow event is raised by UI Automation framework.
                            if ( ShouldAdviseProviders(eventId) )
                            {
                                // Notify the server-side that this event is no longer interesting 
                                try
                                { 
                                    ec.EventHandle.Dispose(); // Calls UiaCoreApi.UiaRemoveEvent 
                                }
// PRESHARP: Warning - Catch statements should not have empty bodies 
#pragma warning disable 6502
                                catch (ElementNotAvailableException)
                                {
                                    // the element is gone already; continue on and remove the listener 
                                }
#pragma warning restore 6502 
                            } 

                            // before removing, check if this delegate was listening for the below events 
                            // and see if we can stop clientside WinEvent trackers.
                            if (HasProperty(AutomationElement.BoundingRectangleProperty, l.Properties))
                            {
                                boundingRectListeners = true; 
                            }
 
                            if( eventId == AutomationElement.MenuOpenedEvent || eventId == AutomationElement.MenuClosedEvent ) 
                            {
                                menuListeners = true; 
                            }

                            if (HasProperty(WindowPattern.WindowInteractionStateProperty, l.Properties))
                            { 
                                windowInteracationListeners = true;
                            } 
 
                            if (HasProperty(WindowPattern.WindowVisualStateProperty, l.Properties))
                            { 
                                windowVisualListeners = true;
                            }

                            // delete this one 
                            _listeners.RemoveAt( i );
                        } 
                    } 

                    // Check listeners bools to see if clientside listeners can be removed 
                    if (boundingRectListeners)
                    {
                        RemovePropertyTracker(AutomationElement.BoundingRectangleProperty, Tracker.BoundingRect);
                    } 

                    if (menuListeners) 
                    { 
                        RemoveMenuListeners();
                    } 

                    if (windowInteracationListeners)
                    {
                        RemovePropertyTracker(WindowPattern.WindowInteractionStateProperty, Tracker.WindowInteractionState); 
                    }
 
                    if (windowVisualListeners) 
                    {
                        RemovePropertyTracker(WindowPattern.WindowVisualStateProperty, Tracker.WindowVisualState); 
                    }

                    // See if we can cleanup completely
                    if (_listeners.Count == 0) 
                    {
                        // as long as OnWindowShowOrOpen is static can just use new here and get same object instance 
                        // (if there's no WindowShowOrOpen listener, this method just returns) 
                        RemoveWinEventListener(Tracker.WindowShowOrOpen, new WindowShowOrOpenHandler(OnWindowShowOrOpen));
                        RemoveWinEventListener( Tracker.WindowHideOrClose, new WindowHideOrCloseHandler( OnWindowHideOrClose ) ); 

                        _listeners = null;
                    }
                } 
            }
        } 
 
        private static void RemovePropertyTracker(AutomationProperty property, Tracker tracker)
        { 
            bool foundListener = false;     // assume none
            foreach (EventListenerClientSide l in _listeners)
            {
                if (HasProperty(property, l.EventListener.Properties)) 
                {
                    foundListener = true;  // delegate is still interested so can't 
                    break;                 // stop the WinEvent tracking 
                }
            } 
            if (!foundListener)
            {
                RemoveWinEventListener(tracker, null);
            } 
        }
 
        private static void RemoveMenuListeners() 
        {
            bool menuListeners = false; // assume none 
            foreach (EventListenerClientSide l in _listeners)
            {
                if (l.EventListener.EventId == AutomationElement.MenuOpenedEvent || l.EventListener.EventId == AutomationElement.MenuClosedEvent)
                { 
                    menuListeners = true;  // delegate is still interested so can't
                    break;                       // stop the WinEvent tracking 
                } 
            }
            if (!menuListeners) 
            {
                // as long as OnMenuEvent is static can just use new here and get same object instance
                RemoveWinEventListener(Tracker.MenuOpenedOrClosed, new MenuHandler(OnMenuEvent));
            } 
        }
 
        // RemoveAllListeners - Removes all listeners from this client and notifies the 
        // UIAccess server
        internal static void RemoveAllListeners() 
        {
            lock (_classLock)
            {
                if (_listeners == null) 
                    return;
 
                // Stop all WinEvent tracking 
                StopWinEventTracking();
 
                // Must remove from back to front when calling RemoveAt because ArrayList
                // elements are compressed after each RemoveAt.
                for (int i = _listeners.Count - 1; i >= 0; i--)
                { 
                    EventListenerClientSide ec = (EventListenerClientSide)_listeners[i];
 
                    // Notify the server-side UIAccess that this event is no longer interesting 
                    EventListener l = ec.EventListener;
                    // Only advise UI contexts of events being removed if the event might be raised by 
                    // a provider.  TopLevelWindow event is raised by UI Automation framework.
                    if ( ShouldAdviseProviders(l.EventId) )
                    {
                        ec.EventHandle.Dispose(); // Calls RemoveEvent 
                    }
                    // delete this one 
                    _listeners.RemoveAt(i); 
                }
 
                _listeners = null;
                CheckStopCallbackQueueing();
            }
        } 

        #endregion Internal Methods 
 

        //------------------------------------------------------ 
        //
        //  Internal Properties
        //
        //------------------------------------------------------ 

        #region Internal Properties 
 
        // return the queue class instance
        internal static QueueProcessor CBQ 
        {
            get
            {
                return _callbackQueue; 
            }
        } 
 
        #endregion Internal Properties
 

        //-----------------------------------------------------
        //
        //  Private Methods 
        //
        //------------------------------------------------------ 
 
        #region Private Methods
 
        // check queue is started, or start if necessary (always called w/in a lock)
        private static void CheckStartCallbackQueueing()
        {
            if (!_isBkgrdThreadRunning) 
            {
                _isBkgrdThreadRunning = true; 
               _callbackQueue = new QueueProcessor(); 
               _callbackQueue.StartOnThread();
            } 
        }


        // check if queue is still needed, stop if necessary (always called w/in a lock) 
        private static void CheckStopCallbackQueueing()
        { 
            // anything to stop? 
            if (!_isBkgrdThreadRunning)
                return; 

            // if there are listeners then can't stop
            if (_listeners != null)
                return; 

            // Are any WinEvents currently being tracked for this client? 
            foreach (WinEventWrap eventWrapper in _winEventTrackers) 
            {
                if (eventWrapper != null) 
                {
                    return;
                }
            } 

            // OK to stop the queue now 
            _isBkgrdThreadRunning = false; 
            _callbackQueue.PostQuit();
            // Intentionally not setting _callbackQueue null here; don't want to mess with it from this thread. 
        }

        // StopWinEventTracking is called when we just want to quit (RemoveAllListeners)
        private static void StopWinEventTracking() 
        {
            int i; 
            for (i=0; i<(int)Tracker.NumEventTrackers; i++) 
            {
                WinEventWrap eventWrapper = _winEventTrackers[i]; 
                if (eventWrapper != null)
                {
                    eventWrapper.StopListening();
                    _winEventTrackers[i] = null; 
                }
            } 
        } 

        // Raise events for rawEl 
        internal static void RaiseEventInThisClientOnly(AutomationEvent eventId, AutomationElement rawEl, AutomationEventArgs e)
        {
            // This version of RaiseEventInThisClientOnly can be called with a local (proxied) or remote (native)AutomationElement
            lock (_classLock) 
            {
                if ( _listeners == null ) 
                    return; 

                AutomationElement el = rawEl; 
                foreach (EventListenerClientSide listener in _listeners)
                {
                    // Is this event a type this listener is interested in?
                    if (listener.EventListener.EventId == eventId) 
                    {
                        // Did this event happen on an element this listener is interested in? 
                        if (rawEl == null || listener.WithinScope( rawEl )) 
                        {
                            UiaCoreApi.UiaCacheRequest cacheRequest = listener.EventListener.CacheRequest; 
                            CBQ.PostWorkItem(new ClientSideQueueItem(listener.ClientCallback, el, cacheRequest, e));
                        }
                    }
                } 
            }
        } 
 
        // Raise events for the element that has RuntimeId == rid (special case for events where the element is no longer available)
        internal static void RaiseEventInThisClientOnly( AutomationEvent eventId, int [] rid, AutomationEventArgs e) 
        {
            // This version of RaiseEventInThisClientOnly can be called with a local (proxied) or remote (native)AutomationElement
            lock ( _classLock )
            { 
                if ( _listeners == null )
                    return; 
 
                foreach ( EventListenerClientSide listener in _listeners )
                { 
                    // Is this event a type this listener is interested in?
                    if ( listener.EventListener.EventId == eventId )
                    {
                        // Did this event happen on an element this listener is interested in? 
                        if ( listener.WithinScope( rid ) )
                        { 
                            CBQ.PostWorkItem(new ClientSideQueueItem(listener.ClientCallback, null, null, e)); 
                        }
                    } 
                }
            }
        }
 
        // GetNewRootTracker - Returns a new WinEvent wrapped object for events that are
        // always based on the RootElement (e.g. AutomationFocusChanged or TopWindow events) 
        private static WinEventWrap GetNewRootTracker(Tracker idx) 
        {
            if (idx == Tracker.Focus) 
            {
                return new FocusTracker();
            }
 
            Debug.Assert(false, "GetNewRootTracker internal error: Unexpected Tracker value!");
            return null; 
        } 

        // AddRootListener - Add a listener for an event whose reference is always the 
        // root and scope is all elements
        private static void AddRootListener(Tracker idx, Delegate eventCallback, EventListener l)
        {
            lock ( _classLock ) 
            {
                // Add this listener to client-side store of listeners and give the server 
                // a chance to enable accessibility for this event 
                AddListener( AutomationElement.RootElement, eventCallback, l );
 
                // Track WinEvents
                WinEventWrap eventWrapper = _winEventTrackers[(int)idx];

                if ( eventWrapper == null ) 
                {
                    // First time create a WinEvent tracker and start listening 
                    AddWinEventListener( idx, GetNewRootTracker( idx ) ); 
                }
                else 
                {
                    // Subsequent times just add the callback to the existing WinEvent
                    eventWrapper.AddCallback( eventCallback );
                } 
            }
        } 
 
        // RemoveRootListener - Remove a listener for an event whose reference is always
        // the root and scope is all elements 
        private static void RemoveRootListener(AutomationEvent eventId, Tracker idx, Delegate eventCallback)
        {
            lock (_classLock)
            { 
                RemoveListener(eventId, AutomationElement.RootElement, eventCallback);
                RemoveWinEventListener(idx, eventCallback); 
            } 
        }
 
        // AddWinEventListener - add an event callback for a global listener
        private static void AddWinEventListener(Tracker idx, WinEventWrap eventWrapper)
        {
            // make sure we can queue items 
            CheckStartCallbackQueueing();
 
            _winEventTrackers[(int)idx] = eventWrapper; 
            _callbackQueue.PostSyncWorkItem(new WinEventQueueItem(eventWrapper, WinEventQueueItem.StartListening));
        } 

        // RemoveWinEventListener - remove an event callback for a global listener
        private static void RemoveWinEventListener(Tracker idx, Delegate eventCallback)
        { 
            WinEventWrap eventWrapper = _winEventTrackers[(int)idx];
            if (eventWrapper == null) 
                return; 

            bool fRemovedLastListener = eventWrapper.RemoveCallback(eventCallback); 
            if (fRemovedLastListener)
            {
                _callbackQueue.PostSyncWorkItem(new WinEventQueueItem(eventWrapper, WinEventQueueItem.StopListening));
                _winEventTrackers[(int)idx] = null; 

                CheckStopCallbackQueueing(); 
            } 
        }
 
        // HasProperty - helper to check for a property in an AutomationProperty array
        private static bool HasProperty(AutomationProperty p, AutomationProperty [] properties)
        {
            if (properties == null) 
                return false;
 
            foreach (AutomationProperty p1 in properties) 
            {
                if (p1 == p) 
                {
                    return true;
                }
            } 
            return false;
        } 
 
        // OnWindowHideOrClose - Called by the WindowHideOrCloseTracker class when UI is hidden or destroyed
        private static void OnWindowHideOrClose( IntPtr hwnd, AutomationElement rawEl, int [] runtimeId ) 
        {
            bool doWindowClosedEvent = false;
            bool doStructureChangedEvent = false;
 
            lock ( _classLock )
            { 
                if (_listeners != null) 
                {
 
                    // if an hwnd is hidden or closed remove event listeners for the window's provider
                    for (int i = 0; i < _listeners.Count; i++)
                    {
                        EventListenerClientSide ec = (EventListenerClientSide)_listeners[i]; 

                        EventListener l = ec.EventListener; 
                        if ( l.EventId == WindowPattern.WindowClosedEvent ) 
                            doWindowClosedEvent = true;
                        if ( l.EventId == AutomationElement.StructureChangedEvent ) 
                            doStructureChangedEvent = true;

                        // Only advise UI contexts if the provider still exists
                        // (but keep looking to see if need to do a WindowClosedEvent) 
                        if (rawEl == null)
                            continue; 
 
                        // Only advise UI contexts if the provider might raise that event.
                        if (!ShouldAdviseProviders(l.EventId)) 
                            continue;

                        // Only advise UI contexts if the element is w/in scope of the reference element
                        if (!ec.WithinScope(rawEl)) 
                            continue;
 
                        // Notify the server-side that this event is no longer interesting 
                        UiaCoreApi.UiaEventRemoveWindow(ec.EventHandle, hwnd);
                    } 
                }
            }

            // Piggy-back on the listener for Windows hiding or closing to raise WindowClosed and StructureChanged events. 
            // When the hwnd behind rawEl is being destroyed, it can't be determined that rawEl once had the
            // WindowPattern interface.  Therefore raise an event for any window close. 
            if ( doWindowClosedEvent ) 
            {
                // When the hwnd is just hidden, rawEl will not be null, so can test if this would support WindowPattern 
                // and throw this event away if the window doesn't support that CP
                if ( rawEl != null && !HwndProxyElementProvider.IsWindowPatternWindow( NativeMethods.HWND.Cast( hwnd ) ) )
                    return;
 
                // Go ahead and raise a client-side only WindowClosedEvent (if anyone is listening)
                WindowClosedEventArgs e = new WindowClosedEventArgs( runtimeId ); 
                RaiseEventInThisClientOnly(WindowPattern.WindowClosedEvent, runtimeId, e); 
            }
            if ( doStructureChangedEvent ) 
            {
                // Raise an event for structure changed.  This element has essentially gone away so there isn't an
                // opportunity to do filtering here.  So, just like WindowClosed, this event will be very noisy.
                StructureChangedEventArgs e = new StructureChangedEventArgs( StructureChangeType.ChildRemoved, runtimeId ); 
                RaiseEventInThisClientOnly(AutomationElement.StructureChangedEvent, runtimeId, e);
            } 
        } 

        // OnWindowShowOrOpen - Called by the WindowShowOrOpenTracker class when UI is shown or created 
        private static void OnWindowShowOrOpen( IntPtr hwnd, AutomationElement rawEl )
        {
            bool doWindowOpenedEvent = false;
            bool doStructureChangedEvent = false; 

            lock ( _classLock ) 
            { 
                if (_listeners != null)
                { 

                    // if rawEl is w/in the scope of any listeners then register for events in the new UI
                    for (int i = 0; i < _listeners.Count; i++)
                    { 
                        EventListenerClientSide ec = (EventListenerClientSide)_listeners[i];
 
                        EventListener l = ec.EventListener; 
                        if ( l.EventId == WindowPattern.WindowOpenedEvent )
                            doWindowOpenedEvent = true; 
                        if ( l.EventId == AutomationElement.StructureChangedEvent )
                            doStructureChangedEvent = true;

                        // Only advise UI contexts if the provider might raise that event. 
                        if (!ShouldAdviseProviders( l.EventId ))
                            continue; 
 
                        // Only advise UI contexts if the element is w/in scope of the reference element
                        if (!ec.WithinScope( rawEl )) 
                            continue;

                        // Notify the server side
                        UiaCoreApi.UiaEventAddWindow(ec.EventHandle, hwnd); 
                    }
                } 
            } 

            // Piggy-back on the listener for Windows hiding or closing to raise WindowClosed and StructureChanged events. 
            if ( doWindowOpenedEvent )
            {
                if ( HwndProxyElementProvider.IsWindowPatternWindow( NativeMethods.HWND.Cast( hwnd ) ) )
                { 
                    // Go ahead and raise a client-side only WindowOpenedEvent (if anyone is listening)
                    AutomationEventArgs e = new AutomationEventArgs( WindowPattern.WindowOpenedEvent ); 
                    RaiseEventInThisClientOnly( WindowPattern.WindowOpenedEvent, rawEl, e); 
                }
            } 
            if ( doStructureChangedEvent )
            {
                // Filter on the control elements.  Otherwise, this is extremely noisy.  Consider not filtering if there is feedback.
                //ControlType ct = (ControlType)rawEl.GetPropertyValue( AutomationElement.ControlTypeProperty ); 
                //if ( ct != null )
                { 
                    // Last,raise an event for structure changed 
                    StructureChangedEventArgs e = new StructureChangedEventArgs( StructureChangeType.ChildAdded, rawEl.GetRuntimeId() );
                    RaiseEventInThisClientOnly(AutomationElement.StructureChangedEvent, rawEl, e); 
                }
            }
        }
 
        // OnMenuEvent - Called by MenuTracker class
        private static void OnMenuEvent( AutomationElement rawEl, bool menuHasOpened ) 
        { 
            AutomationEvent eventId = menuHasOpened ? AutomationElement.MenuOpenedEvent : AutomationElement.MenuClosedEvent;
            AutomationEventArgs e = new AutomationEventArgs( eventId ); 

            RaiseEventInThisClientOnly(eventId, rawEl, e);
        }
 

        private static bool ShouldAdviseProviders( AutomationEvent eventId ) 
        { 
            foreach (AutomationEvent ev in _doNotShouldAdviseProviders)
            { 
                if (ev == eventId)
                    return false;
            }
 
            return true;
        } 
 
        #endregion Private Methods
 

        //-----------------------------------------------------
        //
        //  Private Fields 
        //
        //----------------------------------------------------- 
 
        #region Private Fields
 
        // Indices into ClientEventManager._winEventTrackers.  How wrapped WinEvents are added
        // and removed is common code; using an array makes it easier to add, remove and do
        // cleanup on client exit.
        private enum Tracker 
        {
            Focus = 0, 
            WindowShowOrOpen, 
            WindowHideOrClose,
            BoundingRect, 
            MenuOpenedOrClosed,
            WindowInteractionState,
            WindowVisualState,
            // insert additional indices here... 
            NumEventTrackers,
        } 
 
        //
 
        private static AutomationEvent[] _doNotShouldAdviseProviders = new AutomationEvent[] {
            WindowPattern.WindowOpenedEvent, WindowPattern.WindowClosedEvent
        };
 
        private static WinEventWrap [] _winEventTrackers = new WinEventWrap[(int)Tracker.NumEventTrackers];
 
        private static QueueProcessor _callbackQueue;      // callbacks are queued on this class to avoid deadlocks 
        private static bool _isBkgrdThreadRunning = false; // is there a background thread for queueing and recieving WinEvents?
        private static ArrayList _listeners;               // data representing events the client is listening for 
        private static object _classLock = new object();   // use lock object vs typeof(class) for perf reasons

        #endregion Private Fields
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// 
// Description: Manages the listeners for one accessibility aid or test application. 
//
// History: 
//  06/17/2003 : BrendanM Ported to WCP
//
//---------------------------------------------------------------------------
 
using System.Windows;
using System.Collections; 
using System.Diagnostics; 
using System.Windows.Automation;
using System.Windows.Automation.Provider; 
using MS.Win32;

using System;
 
// PRESHARP: In order to avoid generating warnings about unkown message numbers and unknown pragmas.
#pragma warning disable 1634, 1691 
 
namespace MS.Internal.Automation
{ 
     // Manages the listeners for one accessibility aid or test application.  Locking
     // is used in all public methods to allow for multiple threads in a client process.
    internal static class ClientEventManager
    { 
        //-----------------------------------------------------
        // 
        //  Constructors 
        //
        //----------------------------------------------------- 

        #region Constructors

        // Static class, no ctor 

        #endregion Constructors 
 

        //------------------------------------------------------ 
        //
        //  Internal Methods
        //
        //----------------------------------------------------- 

        #region Internal Methods 
 
        // AddFocusListener - Adds a focus listener for this client.
        internal static void AddFocusListener(Delegate eventCallback, EventListener l) 
        {
            AddRootListener(Tracker.Focus, eventCallback, l);
        }
 
        // RemoveFocusListener - Removes a focus change listener from this client
        // and notifies the UIAccess server 
        internal static void RemoveFocusListener(Delegate eventCallback) 
        {
            RemoveRootListener(AutomationElement.AutomationFocusChangedEvent, Tracker.Focus, eventCallback); 
        }

        // AddListener - Adds a listener for this client and notifies the UIA server.  All event
        // handler additions call through to this method. 
        internal static void AddListener(AutomationElement rawEl, Delegate eventCallback, EventListener l)
        { 
            lock (_classLock) 
            {
                // If we are adding a listener then a proxy could be created as a result of an event so make sure they are loaded 
                ProxyManager.LoadDefaultProxies();

                if (_listeners == null)
                { 
                    // enough space for 16 AddXxxListeners (100 bytes)
                    _listeners = new ArrayList(16); 
                } 

                // Start the callback queue that gets us off the server's 
                // UI thread when events arrive cross-proc
                CheckStartCallbackQueueing();

                // 
                // The framework handles some events on behalf of providers; do those here
                // 
 
                // If listening for BoundingRectangleProperty then may need to start listening on the
                // client-side for LocationChange WinEvent (only use *one* BoundingRectTracker instance). 
                if (_winEventTrackers[(int)Tracker.BoundingRect] == null && HasProperty(AutomationElement.BoundingRectangleProperty, l.Properties))
                {
                    //
 

 
 

 

                    AddWinEventListener(Tracker.BoundingRect, new BoundingRectTracker());
                }
 
                // Start listening for menu event in order to raise MenuOpened/Closed events.
                if ( _winEventTrackers [(int)Tracker.MenuOpenedOrClosed] == null && (l.EventId == AutomationElement.MenuOpenedEvent || l.EventId == AutomationElement.MenuClosedEvent) ) 
                { 
                    AddWinEventListener( Tracker.MenuOpenedOrClosed, new MenuTracker( new MenuHandler( OnMenuEvent ) ) );
                } 

                // Begin watching for hwnd open/close/show/hide so can advise of what events are being listened for.
                // Only advise UI contexts of events being added if the event might be raised by a provider.
                // TopLevelWindow event is raised by UI Automation framework so no need to track new UI. 
                //
                if (_winEventTrackers[(int)Tracker.WindowShowOrOpen] == null ) 
                { 
                    AddWinEventListener( Tracker.WindowShowOrOpen, new WindowShowOrOpenTracker( new WindowShowOrOpenHandler( OnWindowShowOrOpen ) ) );
                    AddWinEventListener( Tracker.WindowHideOrClose, new WindowHideOrCloseTracker( new WindowHideOrCloseHandler( OnWindowHideOrClose ) ) ); 
                }

                // If listening for WindowInteractionStateProperty then may need to start listening on the
                // client-side for ObjectStateChange WinEvent. 
                if (_winEventTrackers[(int)Tracker.WindowInteractionState] == null && HasProperty(WindowPattern.WindowInteractionStateProperty, l.Properties))
                { 
                    AddWinEventListener(Tracker.WindowInteractionState, new WindowInteractionStateTracker()); 
                }
 
                // If listening for WindowVisualStateProperty then may need to start listening on the
                // client-side for ObjectLocationChange WinEvent.
                if (_winEventTrackers[(int)Tracker.WindowVisualState] == null && HasProperty(WindowPattern.WindowVisualStateProperty, l.Properties))
                { 
                    AddWinEventListener(Tracker.WindowVisualState, new WindowVisualStateTracker());
                } 
 
                // Wrap and store this record on the client...
                EventListenerClientSide ec = new EventListenerClientSide(rawEl, eventCallback, l); 
                _listeners.Add(ec);

                // Only advise UI contexts of events being added if the event might be raised by
                // a provider.  TopLevelWindow event is raised by UI Automation framework. 
                if (ShouldAdviseProviders( l.EventId ))
                { 
                    // .. then let the server know about this listener 
                    ec.EventHandle = UiaCoreApi.UiaAddEvent(rawEl.RawNode, l.EventId.Id, ec.CallbackDelegate, l.TreeScope, PropertyArrayToIntArray(l.Properties), l.CacheRequest);
                } 
            }
        }

        private static int[] PropertyArrayToIntArray(AutomationProperty[] properties) 
        {
            if (properties == null) 
                return null; 
            int[] propertiesAsInts = new int[properties.Length];
            for (int i = 0; i < properties.Length; i++) 
            {
                propertiesAsInts[i] = properties[i].Id;
            }
            return propertiesAsInts; 
        }
 
 
        // RemoveListener - Removes a listener from this client and notifies the UIAutomation server-side
        internal static void RemoveListener( AutomationEvent eventId, AutomationElement el, Delegate eventCallback ) 
        {
            lock( _classLock )
            {
                if( _listeners != null ) 
                {
                    bool boundingRectListeners = false; // if not removing BoundingRect listeners no need to do check below 
                    bool menuListeners = false; // if not removing MenuOpenedOrClosed listeners no need to do check below 
                    bool windowInteracationListeners = false; // if not removing WindowsIntercation listeners no need to do check below
                    bool windowVisualListeners = false; // if not removing WindowsVisual listeners no need to do check below 

                    for (int i = _listeners.Count - 1; i >= 0; i--)
                    {
                        EventListenerClientSide ec = (EventListenerClientSide)_listeners[i]; 
                        if( ec.IsListeningFor( eventId, el, eventCallback ) )
                        { 
                            EventListener l = ec.EventListener; 

                            // Only advise UI contexts of events being removed if the event might be raised by 
                            // a provider.  TopLevelWindow event is raised by UI Automation framework.
                            if ( ShouldAdviseProviders(eventId) )
                            {
                                // Notify the server-side that this event is no longer interesting 
                                try
                                { 
                                    ec.EventHandle.Dispose(); // Calls UiaCoreApi.UiaRemoveEvent 
                                }
// PRESHARP: Warning - Catch statements should not have empty bodies 
#pragma warning disable 6502
                                catch (ElementNotAvailableException)
                                {
                                    // the element is gone already; continue on and remove the listener 
                                }
#pragma warning restore 6502 
                            } 

                            // before removing, check if this delegate was listening for the below events 
                            // and see if we can stop clientside WinEvent trackers.
                            if (HasProperty(AutomationElement.BoundingRectangleProperty, l.Properties))
                            {
                                boundingRectListeners = true; 
                            }
 
                            if( eventId == AutomationElement.MenuOpenedEvent || eventId == AutomationElement.MenuClosedEvent ) 
                            {
                                menuListeners = true; 
                            }

                            if (HasProperty(WindowPattern.WindowInteractionStateProperty, l.Properties))
                            { 
                                windowInteracationListeners = true;
                            } 
 
                            if (HasProperty(WindowPattern.WindowVisualStateProperty, l.Properties))
                            { 
                                windowVisualListeners = true;
                            }

                            // delete this one 
                            _listeners.RemoveAt( i );
                        } 
                    } 

                    // Check listeners bools to see if clientside listeners can be removed 
                    if (boundingRectListeners)
                    {
                        RemovePropertyTracker(AutomationElement.BoundingRectangleProperty, Tracker.BoundingRect);
                    } 

                    if (menuListeners) 
                    { 
                        RemoveMenuListeners();
                    } 

                    if (windowInteracationListeners)
                    {
                        RemovePropertyTracker(WindowPattern.WindowInteractionStateProperty, Tracker.WindowInteractionState); 
                    }
 
                    if (windowVisualListeners) 
                    {
                        RemovePropertyTracker(WindowPattern.WindowVisualStateProperty, Tracker.WindowVisualState); 
                    }

                    // See if we can cleanup completely
                    if (_listeners.Count == 0) 
                    {
                        // as long as OnWindowShowOrOpen is static can just use new here and get same object instance 
                        // (if there's no WindowShowOrOpen listener, this method just returns) 
                        RemoveWinEventListener(Tracker.WindowShowOrOpen, new WindowShowOrOpenHandler(OnWindowShowOrOpen));
                        RemoveWinEventListener( Tracker.WindowHideOrClose, new WindowHideOrCloseHandler( OnWindowHideOrClose ) ); 

                        _listeners = null;
                    }
                } 
            }
        } 
 
        private static void RemovePropertyTracker(AutomationProperty property, Tracker tracker)
        { 
            bool foundListener = false;     // assume none
            foreach (EventListenerClientSide l in _listeners)
            {
                if (HasProperty(property, l.EventListener.Properties)) 
                {
                    foundListener = true;  // delegate is still interested so can't 
                    break;                 // stop the WinEvent tracking 
                }
            } 
            if (!foundListener)
            {
                RemoveWinEventListener(tracker, null);
            } 
        }
 
        private static void RemoveMenuListeners() 
        {
            bool menuListeners = false; // assume none 
            foreach (EventListenerClientSide l in _listeners)
            {
                if (l.EventListener.EventId == AutomationElement.MenuOpenedEvent || l.EventListener.EventId == AutomationElement.MenuClosedEvent)
                { 
                    menuListeners = true;  // delegate is still interested so can't
                    break;                       // stop the WinEvent tracking 
                } 
            }
            if (!menuListeners) 
            {
                // as long as OnMenuEvent is static can just use new here and get same object instance
                RemoveWinEventListener(Tracker.MenuOpenedOrClosed, new MenuHandler(OnMenuEvent));
            } 
        }
 
        // RemoveAllListeners - Removes all listeners from this client and notifies the 
        // UIAccess server
        internal static void RemoveAllListeners() 
        {
            lock (_classLock)
            {
                if (_listeners == null) 
                    return;
 
                // Stop all WinEvent tracking 
                StopWinEventTracking();
 
                // Must remove from back to front when calling RemoveAt because ArrayList
                // elements are compressed after each RemoveAt.
                for (int i = _listeners.Count - 1; i >= 0; i--)
                { 
                    EventListenerClientSide ec = (EventListenerClientSide)_listeners[i];
 
                    // Notify the server-side UIAccess that this event is no longer interesting 
                    EventListener l = ec.EventListener;
                    // Only advise UI contexts of events being removed if the event might be raised by 
                    // a provider.  TopLevelWindow event is raised by UI Automation framework.
                    if ( ShouldAdviseProviders(l.EventId) )
                    {
                        ec.EventHandle.Dispose(); // Calls RemoveEvent 
                    }
                    // delete this one 
                    _listeners.RemoveAt(i); 
                }
 
                _listeners = null;
                CheckStopCallbackQueueing();
            }
        } 

        #endregion Internal Methods 
 

        //------------------------------------------------------ 
        //
        //  Internal Properties
        //
        //------------------------------------------------------ 

        #region Internal Properties 
 
        // return the queue class instance
        internal static QueueProcessor CBQ 
        {
            get
            {
                return _callbackQueue; 
            }
        } 
 
        #endregion Internal Properties
 

        //-----------------------------------------------------
        //
        //  Private Methods 
        //
        //------------------------------------------------------ 
 
        #region Private Methods
 
        // check queue is started, or start if necessary (always called w/in a lock)
        private static void CheckStartCallbackQueueing()
        {
            if (!_isBkgrdThreadRunning) 
            {
                _isBkgrdThreadRunning = true; 
               _callbackQueue = new QueueProcessor(); 
               _callbackQueue.StartOnThread();
            } 
        }


        // check if queue is still needed, stop if necessary (always called w/in a lock) 
        private static void CheckStopCallbackQueueing()
        { 
            // anything to stop? 
            if (!_isBkgrdThreadRunning)
                return; 

            // if there are listeners then can't stop
            if (_listeners != null)
                return; 

            // Are any WinEvents currently being tracked for this client? 
            foreach (WinEventWrap eventWrapper in _winEventTrackers) 
            {
                if (eventWrapper != null) 
                {
                    return;
                }
            } 

            // OK to stop the queue now 
            _isBkgrdThreadRunning = false; 
            _callbackQueue.PostQuit();
            // Intentionally not setting _callbackQueue null here; don't want to mess with it from this thread. 
        }

        // StopWinEventTracking is called when we just want to quit (RemoveAllListeners)
        private static void StopWinEventTracking() 
        {
            int i; 
            for (i=0; i<(int)Tracker.NumEventTrackers; i++) 
            {
                WinEventWrap eventWrapper = _winEventTrackers[i]; 
                if (eventWrapper != null)
                {
                    eventWrapper.StopListening();
                    _winEventTrackers[i] = null; 
                }
            } 
        } 

        // Raise events for rawEl 
        internal static void RaiseEventInThisClientOnly(AutomationEvent eventId, AutomationElement rawEl, AutomationEventArgs e)
        {
            // This version of RaiseEventInThisClientOnly can be called with a local (proxied) or remote (native)AutomationElement
            lock (_classLock) 
            {
                if ( _listeners == null ) 
                    return; 

                AutomationElement el = rawEl; 
                foreach (EventListenerClientSide listener in _listeners)
                {
                    // Is this event a type this listener is interested in?
                    if (listener.EventListener.EventId == eventId) 
                    {
                        // Did this event happen on an element this listener is interested in? 
                        if (rawEl == null || listener.WithinScope( rawEl )) 
                        {
                            UiaCoreApi.UiaCacheRequest cacheRequest = listener.EventListener.CacheRequest; 
                            CBQ.PostWorkItem(new ClientSideQueueItem(listener.ClientCallback, el, cacheRequest, e));
                        }
                    }
                } 
            }
        } 
 
        // Raise events for the element that has RuntimeId == rid (special case for events where the element is no longer available)
        internal static void RaiseEventInThisClientOnly( AutomationEvent eventId, int [] rid, AutomationEventArgs e) 
        {
            // This version of RaiseEventInThisClientOnly can be called with a local (proxied) or remote (native)AutomationElement
            lock ( _classLock )
            { 
                if ( _listeners == null )
                    return; 
 
                foreach ( EventListenerClientSide listener in _listeners )
                { 
                    // Is this event a type this listener is interested in?
                    if ( listener.EventListener.EventId == eventId )
                    {
                        // Did this event happen on an element this listener is interested in? 
                        if ( listener.WithinScope( rid ) )
                        { 
                            CBQ.PostWorkItem(new ClientSideQueueItem(listener.ClientCallback, null, null, e)); 
                        }
                    } 
                }
            }
        }
 
        // GetNewRootTracker - Returns a new WinEvent wrapped object for events that are
        // always based on the RootElement (e.g. AutomationFocusChanged or TopWindow events) 
        private static WinEventWrap GetNewRootTracker(Tracker idx) 
        {
            if (idx == Tracker.Focus) 
            {
                return new FocusTracker();
            }
 
            Debug.Assert(false, "GetNewRootTracker internal error: Unexpected Tracker value!");
            return null; 
        } 

        // AddRootListener - Add a listener for an event whose reference is always the 
        // root and scope is all elements
        private static void AddRootListener(Tracker idx, Delegate eventCallback, EventListener l)
        {
            lock ( _classLock ) 
            {
                // Add this listener to client-side store of listeners and give the server 
                // a chance to enable accessibility for this event 
                AddListener( AutomationElement.RootElement, eventCallback, l );
 
                // Track WinEvents
                WinEventWrap eventWrapper = _winEventTrackers[(int)idx];

                if ( eventWrapper == null ) 
                {
                    // First time create a WinEvent tracker and start listening 
                    AddWinEventListener( idx, GetNewRootTracker( idx ) ); 
                }
                else 
                {
                    // Subsequent times just add the callback to the existing WinEvent
                    eventWrapper.AddCallback( eventCallback );
                } 
            }
        } 
 
        // RemoveRootListener - Remove a listener for an event whose reference is always
        // the root and scope is all elements 
        private static void RemoveRootListener(AutomationEvent eventId, Tracker idx, Delegate eventCallback)
        {
            lock (_classLock)
            { 
                RemoveListener(eventId, AutomationElement.RootElement, eventCallback);
                RemoveWinEventListener(idx, eventCallback); 
            } 
        }
 
        // AddWinEventListener - add an event callback for a global listener
        private static void AddWinEventListener(Tracker idx, WinEventWrap eventWrapper)
        {
            // make sure we can queue items 
            CheckStartCallbackQueueing();
 
            _winEventTrackers[(int)idx] = eventWrapper; 
            _callbackQueue.PostSyncWorkItem(new WinEventQueueItem(eventWrapper, WinEventQueueItem.StartListening));
        } 

        // RemoveWinEventListener - remove an event callback for a global listener
        private static void RemoveWinEventListener(Tracker idx, Delegate eventCallback)
        { 
            WinEventWrap eventWrapper = _winEventTrackers[(int)idx];
            if (eventWrapper == null) 
                return; 

            bool fRemovedLastListener = eventWrapper.RemoveCallback(eventCallback); 
            if (fRemovedLastListener)
            {
                _callbackQueue.PostSyncWorkItem(new WinEventQueueItem(eventWrapper, WinEventQueueItem.StopListening));
                _winEventTrackers[(int)idx] = null; 

                CheckStopCallbackQueueing(); 
            } 
        }
 
        // HasProperty - helper to check for a property in an AutomationProperty array
        private static bool HasProperty(AutomationProperty p, AutomationProperty [] properties)
        {
            if (properties == null) 
                return false;
 
            foreach (AutomationProperty p1 in properties) 
            {
                if (p1 == p) 
                {
                    return true;
                }
            } 
            return false;
        } 
 
        // OnWindowHideOrClose - Called by the WindowHideOrCloseTracker class when UI is hidden or destroyed
        private static void OnWindowHideOrClose( IntPtr hwnd, AutomationElement rawEl, int [] runtimeId ) 
        {
            bool doWindowClosedEvent = false;
            bool doStructureChangedEvent = false;
 
            lock ( _classLock )
            { 
                if (_listeners != null) 
                {
 
                    // if an hwnd is hidden or closed remove event listeners for the window's provider
                    for (int i = 0; i < _listeners.Count; i++)
                    {
                        EventListenerClientSide ec = (EventListenerClientSide)_listeners[i]; 

                        EventListener l = ec.EventListener; 
                        if ( l.EventId == WindowPattern.WindowClosedEvent ) 
                            doWindowClosedEvent = true;
                        if ( l.EventId == AutomationElement.StructureChangedEvent ) 
                            doStructureChangedEvent = true;

                        // Only advise UI contexts if the provider still exists
                        // (but keep looking to see if need to do a WindowClosedEvent) 
                        if (rawEl == null)
                            continue; 
 
                        // Only advise UI contexts if the provider might raise that event.
                        if (!ShouldAdviseProviders(l.EventId)) 
                            continue;

                        // Only advise UI contexts if the element is w/in scope of the reference element
                        if (!ec.WithinScope(rawEl)) 
                            continue;
 
                        // Notify the server-side that this event is no longer interesting 
                        UiaCoreApi.UiaEventRemoveWindow(ec.EventHandle, hwnd);
                    } 
                }
            }

            // Piggy-back on the listener for Windows hiding or closing to raise WindowClosed and StructureChanged events. 
            // When the hwnd behind rawEl is being destroyed, it can't be determined that rawEl once had the
            // WindowPattern interface.  Therefore raise an event for any window close. 
            if ( doWindowClosedEvent ) 
            {
                // When the hwnd is just hidden, rawEl will not be null, so can test if this would support WindowPattern 
                // and throw this event away if the window doesn't support that CP
                if ( rawEl != null && !HwndProxyElementProvider.IsWindowPatternWindow( NativeMethods.HWND.Cast( hwnd ) ) )
                    return;
 
                // Go ahead and raise a client-side only WindowClosedEvent (if anyone is listening)
                WindowClosedEventArgs e = new WindowClosedEventArgs( runtimeId ); 
                RaiseEventInThisClientOnly(WindowPattern.WindowClosedEvent, runtimeId, e); 
            }
            if ( doStructureChangedEvent ) 
            {
                // Raise an event for structure changed.  This element has essentially gone away so there isn't an
                // opportunity to do filtering here.  So, just like WindowClosed, this event will be very noisy.
                StructureChangedEventArgs e = new StructureChangedEventArgs( StructureChangeType.ChildRemoved, runtimeId ); 
                RaiseEventInThisClientOnly(AutomationElement.StructureChangedEvent, runtimeId, e);
            } 
        } 

        // OnWindowShowOrOpen - Called by the WindowShowOrOpenTracker class when UI is shown or created 
        private static void OnWindowShowOrOpen( IntPtr hwnd, AutomationElement rawEl )
        {
            bool doWindowOpenedEvent = false;
            bool doStructureChangedEvent = false; 

            lock ( _classLock ) 
            { 
                if (_listeners != null)
                { 

                    // if rawEl is w/in the scope of any listeners then register for events in the new UI
                    for (int i = 0; i < _listeners.Count; i++)
                    { 
                        EventListenerClientSide ec = (EventListenerClientSide)_listeners[i];
 
                        EventListener l = ec.EventListener; 
                        if ( l.EventId == WindowPattern.WindowOpenedEvent )
                            doWindowOpenedEvent = true; 
                        if ( l.EventId == AutomationElement.StructureChangedEvent )
                            doStructureChangedEvent = true;

                        // Only advise UI contexts if the provider might raise that event. 
                        if (!ShouldAdviseProviders( l.EventId ))
                            continue; 
 
                        // Only advise UI contexts if the element is w/in scope of the reference element
                        if (!ec.WithinScope( rawEl )) 
                            continue;

                        // Notify the server side
                        UiaCoreApi.UiaEventAddWindow(ec.EventHandle, hwnd); 
                    }
                } 
            } 

            // Piggy-back on the listener for Windows hiding or closing to raise WindowClosed and StructureChanged events. 
            if ( doWindowOpenedEvent )
            {
                if ( HwndProxyElementProvider.IsWindowPatternWindow( NativeMethods.HWND.Cast( hwnd ) ) )
                { 
                    // Go ahead and raise a client-side only WindowOpenedEvent (if anyone is listening)
                    AutomationEventArgs e = new AutomationEventArgs( WindowPattern.WindowOpenedEvent ); 
                    RaiseEventInThisClientOnly( WindowPattern.WindowOpenedEvent, rawEl, e); 
                }
            } 
            if ( doStructureChangedEvent )
            {
                // Filter on the control elements.  Otherwise, this is extremely noisy.  Consider not filtering if there is feedback.
                //ControlType ct = (ControlType)rawEl.GetPropertyValue( AutomationElement.ControlTypeProperty ); 
                //if ( ct != null )
                { 
                    // Last,raise an event for structure changed 
                    StructureChangedEventArgs e = new StructureChangedEventArgs( StructureChangeType.ChildAdded, rawEl.GetRuntimeId() );
                    RaiseEventInThisClientOnly(AutomationElement.StructureChangedEvent, rawEl, e); 
                }
            }
        }
 
        // OnMenuEvent - Called by MenuTracker class
        private static void OnMenuEvent( AutomationElement rawEl, bool menuHasOpened ) 
        { 
            AutomationEvent eventId = menuHasOpened ? AutomationElement.MenuOpenedEvent : AutomationElement.MenuClosedEvent;
            AutomationEventArgs e = new AutomationEventArgs( eventId ); 

            RaiseEventInThisClientOnly(eventId, rawEl, e);
        }
 

        private static bool ShouldAdviseProviders( AutomationEvent eventId ) 
        { 
            foreach (AutomationEvent ev in _doNotShouldAdviseProviders)
            { 
                if (ev == eventId)
                    return false;
            }
 
            return true;
        } 
 
        #endregion Private Methods
 

        //-----------------------------------------------------
        //
        //  Private Fields 
        //
        //----------------------------------------------------- 
 
        #region Private Fields
 
        // Indices into ClientEventManager._winEventTrackers.  How wrapped WinEvents are added
        // and removed is common code; using an array makes it easier to add, remove and do
        // cleanup on client exit.
        private enum Tracker 
        {
            Focus = 0, 
            WindowShowOrOpen, 
            WindowHideOrClose,
            BoundingRect, 
            MenuOpenedOrClosed,
            WindowInteractionState,
            WindowVisualState,
            // insert additional indices here... 
            NumEventTrackers,
        } 
 
        //
 
        private static AutomationEvent[] _doNotShouldAdviseProviders = new AutomationEvent[] {
            WindowPattern.WindowOpenedEvent, WindowPattern.WindowClosedEvent
        };
 
        private static WinEventWrap [] _winEventTrackers = new WinEventWrap[(int)Tracker.NumEventTrackers];
 
        private static QueueProcessor _callbackQueue;      // callbacks are queued on this class to avoid deadlocks 
        private static bool _isBkgrdThreadRunning = false; // is there a background thread for queueing and recieving WinEvents?
        private static ArrayList _listeners;               // data representing events the client is listening for 
        private static object _classLock = new object();   // use lock object vs typeof(class) for perf reasons

        #endregion Private Fields
    } 
}

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