//------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------

        #region Constructors

        internal CalloutQueueItem(Delegate clientCallback, UiaCoreApi.UiaCacheResponse cacheResponse, AutomationEventArgs e, UiaCoreApi.UiaCacheRequest cacheRequest)
        {
            _clientCallback = clientCallback;
            _cacheResponse  = cacheResponse;
            _e            = e;
            _cacheRequest = cacheRequest;
        }
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------

        #region Constructors

        internal ClientSideQueueItem(Delegate clientCallback, AutomationElement srcEl, UiaCoreApi.UiaCacheRequest request, AutomationEventArgs e)
        {
            _clientCallback = clientCallback;
            _srcEl          = srcEl;
            _request        = request;
            _e = e;
        }
        //------------------------------------------------------
        //
        //  Public Methods
        //
        //------------------------------------------------------

        #region Public Methods

        /// <summary>
        /// Push this CacheRequest onto this thread's stack of CacheRequests,
        /// making it the current CacheRequest for this thread.
        /// </summary>
        /// <remarks>
        /// Use Pop to remove this CacheRequest from the stack, making the previously
        /// active CacheRequest active again. CacheRequests can be pushed multiple times,
        /// and on multiple threads; but for each thread, must be popped off in the
        /// same order as they were pushed.
        ///
        /// A CacheRequest cannot be modified while it is pushed on any thread; attempting
        /// to modify it will generate an InvalidOperationException.
        /// </remarks>
        public void Push()
        {
            // pushing multiple times is legal,
            // and pushing on different threads is also legal,
            // so no preconditions to check for here.

            AutomationProperty[] propertyArray = (AutomationProperty[])_properties.ToArray(typeof(AutomationProperty));
            AutomationPattern[]  patternArray  = (AutomationPattern[])_patterns.ToArray(typeof(AutomationPattern));

            // _threadStack is thread local storage (TLS) based, so can be
            // accessed outside of the lock.
            if (_threadStack == null)
            {
                _threadStack = new Stack();
            }

            _threadStack.Push(this);

            lock (_instanceLock)
            {
                _refCount++;

                // Generate a new UiaCacheRequest
                if (_uiaCacheRequest == null)
                {
                    _uiaCacheRequest = new UiaCoreApi.UiaCacheRequest(_viewCondition, _scope, propertyArray, patternArray, _automationElementMode);
                }
            }
        }
Esempio n. 4
0
        // 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));
                        }
                    }
                }
            }
        }
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------

        #region Internal Methods

        internal static AutomationElement BuildAutomationElementsFromResponse(
            UiaCoreApi.UiaCacheRequest cacheRequest,
            UiaCoreApi.UiaCacheResponse response)
        {
            if (response.TreeStructure == null)
            {
                Debug.Assert(response.RequestedData == null, "both RequestedData and TreeStructure should be null or non-null");
                return(null);
            }

            // FrozenCacheRequest should not be null one new AE code, but may
            // still be null on old code paths - eg. top level window events - where
            // prefetching is not yet enabled.
            if (cacheRequest == null)
            {
                cacheRequest = CacheRequest.DefaultUiaCacheRequest;
            }

            // ParseTreeDescription is the method that parses the returned data
            // and builds up the tree, setting properties on each node as it goes along...
            // index and propIndex keep track of where it is, and we check afterwards
            // that all are pointing to the end, to ensure that everything matched
            // up as expected.
            int  index               = 0;
            int  propIndex           = 0;
            bool askedForChildren    = (cacheRequest.TreeScope & TreeScope.Children) != 0;
            bool askedForDescendants = (cacheRequest.TreeScope & TreeScope.Descendants) != 0;
            AutomationElement root   = ParseTreeDescription(response.TreeStructure, response.RequestedData,
                                                            ref index,
                                                            ref propIndex,
                                                            cacheRequest,
                                                            askedForChildren,
                                                            askedForDescendants);

            if (index != response.TreeStructure.Length)
            {
                Debug.Assert(false, "Internal error: got malformed tree description string (extra chars at end)");
                return(null);
            }

            if (response.RequestedData != null && propIndex != response.RequestedData.GetLength(0))
            {
                Debug.Assert(false, "Internal error: mismatch between count of property buckets and nodes claiming them");
                return(null);
            }

            // Properties are wrapped (eg. pattern classes inserted in front of interface) as
            // they are being returned to the caller, in the AutomationElement accessors, not here.

            return(root);
        }
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------

        #region Internal Methods

        internal UiaCoreApi.UiaCacheRequest GetUiaCacheRequest()
        {
            if (_uiaCacheRequest == null)
            {
                AutomationProperty[] propertiesArray = (AutomationProperty[])_properties.ToArray(typeof(AutomationProperty));
                AutomationPattern[]  patternsArray   = (AutomationPattern[])_patterns.ToArray(typeof(AutomationPattern));
                lock (_instanceLock)
                {
                    _uiaCacheRequest = new UiaCoreApi.UiaCacheRequest(_viewCondition, _scope, propertiesArray, patternsArray, _automationElementMode);
                }
            }

            return(_uiaCacheRequest);
        }
        // Private ctor used by Clone()
        private CacheRequest(Condition viewCondition,
                             TreeScope scope,
                             ArrayList properties,
                             ArrayList patterns,
                             AutomationElementMode automationElementMode,
                             UiaCoreApi.UiaCacheRequest uiaCacheRequest)
        {
            _instanceLock = new object();

            _viewCondition         = viewCondition;
            _scope                 = scope;
            _properties            = properties;
            _patterns              = patterns;
            _automationElementMode = automationElementMode;
            _uiaCacheRequest       = uiaCacheRequest;
        }
Esempio n. 8
0
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------

        #region Constructors

        // full ctor
        internal EventListener(
            AutomationEvent eventId,
            TreeScope scope,
            AutomationProperty [] properties,
            UiaCoreApi.UiaCacheRequest cacheRequest
            )
        {
            _eventId = eventId;
            _scope   = scope;
            if (properties != null)
            {
                _properties = (AutomationProperty[])properties.Clone();
            }
            else
            {
                _properties = null;
            }
            _cacheRequest = cacheRequest;
        }
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------
 
        #region Internal Methods

        internal UiaCoreApi.UiaCacheRequest GetUiaCacheRequest()
        {
            if (_uiaCacheRequest == null)
            {
                AutomationProperty[] propertiesArray = (AutomationProperty[])_properties.ToArray(typeof(AutomationProperty));
                AutomationPattern[] patternsArray = (AutomationPattern[])_patterns.ToArray(typeof(AutomationPattern));
                lock (_instanceLock)
                {
                    _uiaCacheRequest = new UiaCoreApi.UiaCacheRequest(_viewCondition, _scope, propertiesArray, patternsArray, _automationElementMode);
                }
            }

            return _uiaCacheRequest;
        }
Esempio n. 10
0
        //------------------------------------------------------
        //
        //  Public Methods
        //
        //------------------------------------------------------
 
        #region Public Methods

        /// <summary>
        /// Push this CacheRequest onto this thread's stack of CacheRequests,
        /// making it the current CacheRequest for this thread.
        /// </summary>
        /// <remarks>
        /// Use Pop to remove this CacheRequest from the stack, making the previously
        /// active CacheRequest active again. CacheRequests can be pushed multiple times,
        /// and on multiple threads; but for each thread, must be popped off in the
        /// same order as they were pushed.
        /// 
        /// A CacheRequest cannot be modified while it is pushed on any thread; attempting
        /// to modify it will generate an InvalidOperationException.
        /// </remarks>
        public void Push()
        {
            // pushing multiple times is legal,
            // and pushing on different threads is also legal,
            // so no preconditions to check for here.

            AutomationProperty[] propertyArray = (AutomationProperty[])_properties.ToArray(typeof(AutomationProperty));
            AutomationPattern[] patternArray = (AutomationPattern[])_patterns.ToArray(typeof(AutomationPattern));

            // _threadStack is thread local storage (TLS) based, so can be
            // accessed outside of the lock.
            if (_threadStack == null)
            {
                _threadStack = new Stack();
            }

            _threadStack.Push(this);

            lock (_instanceLock)
            {
                _refCount++;

                // Generate a new UiaCacheRequest
                if (_uiaCacheRequest == null)
                {
                    _uiaCacheRequest = new UiaCoreApi.UiaCacheRequest(_viewCondition, _scope, propertyArray, patternArray, _automationElementMode);
                }
            }
        }
        //------------------------------------------------------
        //
        //  Private Methods
        //
        //------------------------------------------------------

        #region Private Methods

        // Parses the string as returned from ElementSearcher - see ElementSearcher.cs
        // for a description of the format string. Summary is that it is a lisp-like
        // set of parens indicating tree structure (eg. "(()())" indicates a node containing
        // two child nodes), but uses 'P' instead of an open paran to indicate that the
        // corresonding node has a property array that needs to be associated with it.
        //
        // index is the current position in the tree strucure string,
        // propIndex is the current position in the array of property arrays
        // (an array of properties returned for each element that matches the
        // condition specified in the Searcher condition.)
        private static AutomationElement ParseTreeDescription(string treeDescription,
                                                              object[,] properties,
                                                              ref int index,
                                                              ref int propIndex,
                                                              UiaCoreApi.UiaCacheRequest cacheRequest,
                                                              bool askedForChildren,
                                                              bool askedForDescendants)
        {
            // Check that this is a 'begin node' tag (with or without properties)...
            if (string.IsNullOrEmpty(treeDescription))
            {
                return(null);
            }
            char c = treeDescription[index];

            if (c != '(' && c != 'P')
            {
                return(null);
            }

            bool havePropertiesForThisNode = c == 'P';

            index++;

            SafeNodeHandle hnode = null;

            // If we have information for this node, and we want full remote
            // references back, then extract the hnode from the first slot of that
            // element's property row...
            if (havePropertiesForThisNode && cacheRequest.AutomationElementMode == AutomationElementMode.Full)
            {
                hnode = (SafeNodeHandle)properties[propIndex, 0];
            }

            // Attach properties if present...
            object[,] cachedValues = null;
            int cachedValueIndex = 0;

            if (havePropertiesForThisNode)
            {
                cachedValues     = properties;
                cachedValueIndex = propIndex;
                propIndex++;
            }

            AutomationElement node = new AutomationElement(hnode, cachedValues, cachedValueIndex, cacheRequest);

            if (askedForChildren || askedForDescendants)
            {
                // If we did request children or descendants at this level, then set the
                // cached first child to null - it may get overwritten with
                // an actual value later; but the key thing is that it gets
                // set so we can distinguish the "asked, but doesn't have one" from
                // the "didn't ask" case. (Internally, AutomationElement uses
                // 'this' to indicate the later case, and throws an exception if
                // you ask for the children without having previously asked
                // for them in a CacheRequest.)
                node.SetCachedFirstChild(null);
            }

            // Add in children...
            AutomationElement prevChild = null;

            for (; ;)
            {
                // Recursively parse the string...
                AutomationElement child = ParseTreeDescription(treeDescription, properties,
                                                               ref index, ref propIndex, cacheRequest,
                                                               askedForDescendants, askedForDescendants);

                if (child == null)
                {
                    break;
                }

                // Then link child node into tree...
                child.SetCachedParent(node);

                if (prevChild == null)
                {
                    node.SetCachedFirstChild(child);
                }
                else
                {
                    prevChild.SetCachedNextSibling(child);
                }

                prevChild = child;
            }

            // Ensure that end node tag is present...
            if (treeDescription[index] != ')')
            {
                Debug.Assert(false, "Internal error: Got malformed tree description string, missing closing paren");
                return(null);
            }

            index++;
            return(node);
        }