Example #1
0
        //------------------------------------------------------
        //
        //  Constructors
        //
        //------------------------------------------------------
 
        #region Constructors

        // Private ctor, used mostly by CacheHelper when reconstructing AutomationElements from
        // a CacheResponse.
        internal AutomationElement(SafeNodeHandle hnode, object[,] cachedValues, int cachedValuesIndex, UiaCoreApi.UiaCacheRequest request)
        {
            _hnode = hnode; // Can be IntPtr.Zero for a lightweight object
            _cachedValues = cachedValues; // Can be null if there are no cached properties for this node
            _cachedValuesIndex = cachedValuesIndex;
            _request = request;

            // Set RuntimeId (if available; 'as int[]' filters out AutomationElement.NotAvailable)
            _runtimeId = LookupCachedValue(AutomationElement.RuntimeIdProperty, false, true) as int[];

            // 




            // One scenario that allows for null runtimeID - doing UpdatedCache() on a node and asking only
            // for children - gives us back a placeholder node that only has valid .CachedChildren,
            // the node itself doesn't have any cached properties or a node.

            // Since null is a valid value for these, we need another value to
            // indicate that they were not requested - it's a bit obscure, but
            // 'this' works well here, since these can never have it as legal value.
            _cachedParent = this;
            _cachedFirstChild = this;
            _cachedNextSibling = this;
        }
Example #2
0
 internal static object ConvertToElementArray(object value)
 {
     // Convert each item to an AutomationElement...
     object[]            objArr = (object[])value;
     AutomationElement[] els    = new AutomationElement[objArr.Length];
     for (int i = 0; i < objArr.Length; i++)
     {
         if (objArr[i] == null)
         {
             els[i] = null;
         }
         else
         {
             SafeNodeHandle hnode = UiaCoreApi.UiaHUiaNodeFromVariant(objArr[i]);
             els[i] = AutomationElement.Wrap(hnode);
         }
     }
     return(els);
 }
Example #3
0
        // Used by methods that return non-cached AutomationElements - examples currently include
        // AutomationElements returned as properties (SelecitonContainer, RowHeaders).
        internal static AutomationElement Wrap(SafeNodeHandle hnode)
        {
            if (hnode == null || hnode.IsInvalid)
            {
                return null;
            }

            return new AutomationElement(hnode, null, 0, null);
        }
Example #4
0
        // We need to treat MSAA's FOCUS winevents differently depending on the OBJID -
        // OBJID_CLIENT gets routed to the proxies; _MENU and _SYSMENU get speical treatment.
        private AutomationElement GetFocusedElementFromWinEvent(IntPtr hwnd, int idObject, int idChild)
        {
            try
            {
                IRawElementProviderSimple provider = null;
                // These are the only object types that oleacc proxies allow to take focus.
                // (Native IAccessibles can send focus for other custom OBJID valus, but those are no use
                // to us.)
                // Try and get providers for them ourself - if we don't get anything, then
                // defer to core to get the element for the HWND itself.
                if (idObject == UnsafeNativeMethods.OBJID_CLIENT)
                {
                    // regular focus - pass it off to a proxy...
                    provider = ProxyManager.ProxyProviderFromHwnd(NativeMethods.HWND.Cast(hwnd), idChild, UnsafeNativeMethods.OBJID_CLIENT);
                }
                else if (idObject == UnsafeNativeMethods.OBJID_MENU)
                {
                    // menubar focus - see if there's a menubar pseudo-proxy registered...
                    ClientSideProviderFactoryCallback factory = ProxyManager.NonClientMenuBarProxyFactory;
                    if (factory != null)
                    {
                        provider = factory(hwnd, idChild, idObject);
                    }
                }
                else if (idObject == UnsafeNativeMethods.OBJID_SYSMENU)
                {
                    // system menu box focus - see if there's a sysmenu pseudo-proxy registered...
                    ClientSideProviderFactoryCallback factory = ProxyManager.NonClientSysMenuProxyFactory;
                    if (factory != null)
                    {
                        provider = factory(hwnd, idChild, idObject);
                    }
                }
                else if (idObject <= 0)
                {
                    return(null);
                }
                else
                {
                    // This covers OBJID_CLIENT and custom OBJID cases.
                    // Pass it to the proxy manager: most proxies will just handle OBJID_CLIENT,
                    // but the MSAA proxy can potentally handle other OBJID values.
                    provider = ProxyManager.ProxyProviderFromHwnd(NativeMethods.HWND.Cast(hwnd), idChild, idObject);
                }

                if (provider != null)
                {
                    // Ask the fragment root if any of its children really have the focus
                    IRawElementProviderFragmentRoot fragment = provider as IRawElementProviderFragmentRoot;
                    if (fragment != null)
                    {
                        // if we get back something that is different than what we started with and its not null
                        // use that instead.  This is here to get the subset link in the listview but could be usefull
                        // for listview subitems as well.
                        IRawElementProviderSimple realFocus = fragment.GetFocus();
                        if (realFocus != null && !Object.ReferenceEquals(realFocus, provider))
                        {
                            provider = realFocus;
                        }
                    }

                    SafeNodeHandle hnode = UiaCoreApi.UiaNodeFromProvider(provider);
                    return(AutomationElement.Wrap(hnode));
                }
                else
                {
                    // Didn't find a proxy to handle this hwnd - pass off to core...
                    return(AutomationElement.FromHandle(hwnd));
                }
            }
            catch (Exception e)
            {
                if (Misc.IsCriticalException(e))
                {
                    throw;
                }

                return(null);
            }
        }
Example #5
0
        private static object ConvertToElement(object value)
        {
            SafeNodeHandle hnode = UiaCoreApi.UiaHUiaNodeFromVariant(value);

            return(AutomationElement.Wrap(hnode));
        }
        //------------------------------------------------------
        //
        //  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);
        }