private IUIAutomationElement GetNearbyElement(GetElementDelegate getNextElement)
        {
            var currentElement = GetCurrentElement();

            if (currentElement == null)
            {
                return(null);
            }

            var treeWalker = A11yAutomation.GetTreeWalker(this.TreeViewMode);

            var retVal = getNextElement?.Invoke(treeWalker, currentElement);

            // make sure that we skip an element from current process while walking tree.
            // this code should be hit only at App level. but for sure.
            if (DesktopElement.IsFromCurrentProcess(retVal))
            {
                var tmp = retVal;

                retVal = getNextElement?.Invoke(treeWalker, retVal);

                // since element is not in use, release.
                Marshal.ReleaseComObject(tmp);
            }

            Marshal.ReleaseComObject(treeWalker);

            return(retVal);
        }
        /// <summary>
        /// Constructor DesktopElementAncestry
        /// Get Ancestry Tree elements up to Desktop(at best)
        /// </summary>
        /// <param name="walker"></param>
        /// <param name="e"></param>
        public DesktopElementAncestry(TreeViewMode mode, A11yElement e, bool setMem = false)
        {
            this.TreeWalker     = A11yAutomation.GetTreeWalker(mode);
            this.TreeWalkerMode = mode;
            this.Items          = new List <A11yElement>();
            this.SetMembers     = setMem;
            SetParent(e, -1);

            if (Items.Count != 0)
            {
                this.First = Items.Last();
                this.Last  = Items.First();
                if (this.Last.IsRootElement() == false)
                {
                    this.Last.Children.Clear();
                    this.NextId = PopulateSiblingTreeNodes(this.Last, e);
                }
                else
                {
                    this.NextId = 1;
                }
            }

            Marshal.ReleaseComObject(this.TreeWalker);
        }
        /// <summary>
        /// Populate tree by retrieving all children at once.
        /// </summary>
        /// <param name="rootNode"></param>
        private void PopulateChildrenTreeNode(A11yElement rootNode, int startId)
        {
            int childId = startId;

            IUIAutomationTreeWalker walker = A11yAutomation.GetTreeWalker(this.WalkerMode);
            IUIAutomationElement    child  = (IUIAutomationElement)rootNode.PlatformObject;

            if (child != null)
            {
                try
                {
                    child = walker.GetFirstChildElement(child);
                }
#pragma warning disable CA1031 // Do not catch general exception types
                catch (Exception ex)
                {
                    ex.ReportException();
                    child = null;
                    System.Diagnostics.Trace.WriteLine("Tree walker exception: " + ex);
                }
#pragma warning restore CA1031 // Do not catch general exception types

                while (child != null)
                {
#pragma warning disable CA2000 // childNode will be disposed by the parent node
                    // Create child without populating basic property. it will be set all at once in parallel.
                    var childNode = new DesktopElement(child, true, false)
                    {
                        UniqueId = childId++
                    };
#pragma warning restore CA2000 // childNode will be disposed by the parent node

                    rootNode.Children.Add(childNode);

                    childNode.Parent         = rootNode;
                    childNode.TreeWalkerMode = this.WalkerMode;

                    this.Elements.Add(childNode);
                    try
                    {
                        child = walker.GetNextSiblingElement(child);
                    }
#pragma warning disable CA1031 // Do not catch general exception types
                    catch (Exception ex)
                    {
                        ex.ReportException();
                        child = null;
                        System.Diagnostics.Trace.WriteLine("Tree walker exception: " + ex);
                    }
#pragma warning restore CA1031 // Do not catch general exception types
                }
            }

            Marshal.ReleaseComObject(walker);
        }
        /// <summary>
        /// Populate tree by retrieving all children at once.
        /// </summary>
        /// <param name="rootNode"></param>
        /// <param name="parentNode"></param>
        /// <param name="startChildId"></param>
        private int PopulateChildrenTreeNode(A11yElement rootNode, A11yElement parentNode, int startChildId)
        {
            this.Elements.Add(rootNode);

            rootNode.Parent         = parentNode;
            rootNode.TreeWalkerMode = this.WalkerMode; // set tree walker mode.

            IUIAutomationTreeWalker walker = A11yAutomation.GetTreeWalker(this.WalkerMode);
            IUIAutomationElement    child  = (IUIAutomationElement)rootNode.PlatformObject;

            if (child != null)
            {
                try
                {
                    child = walker.GetFirstChildElement(child);
                }
#pragma warning disable CA1031 // Do not catch general exception types
                catch (Exception ex)
                {
                    ex.ReportException();
                    child = null;
                    System.Diagnostics.Trace.WriteLine("Tree walker exception: " + ex);
                }
#pragma warning restore CA1031 // Do not catch general exception types

                while (child != null && _elementCounter.TryIncrement())
                {
                    // Create child without populating basic property. it will be set all at once in parallel.
                    var childNode = new DesktopElement(child, true, false);

                    rootNode.Children.Add(childNode);
                    childNode.Parent   = rootNode;
                    childNode.UniqueId = startChildId++;
                    startChildId       = PopulateChildrenTreeNode(childNode, rootNode, startChildId);
                    try
                    {
                        child = walker.GetNextSiblingElement(child);
                    }
#pragma warning disable CA1031 // Do not catch general exception types
                    catch (Exception ex)
                    {
                        ex.ReportException();
                        child = null;
                        System.Diagnostics.Trace.WriteLine("Tree walker exception: " + ex);
                    }
#pragma warning restore CA1031 // Do not catch general exception types
                }
            }

            Marshal.ReleaseComObject(walker);

            return(startChildId);
        }
        /// <summary>
        /// Populate tree by retrieving all children at once.
        /// </summary>
        /// <param name="rootNode"></param>
        private void PopulateChildrenTreeNode(A11yElement rootNode, int startId)
        {
            int childId = startId;

            IUIAutomationTreeWalker walker = A11yAutomation.GetTreeWalker(this.WalkerMode);
            IUIAutomationElement    child  = (IUIAutomationElement)rootNode.PlatformObject;

            if (child != null)
            {
                try
                {
                    child = walker.GetFirstChildElement(child);
                }
                catch (Exception ex)
                {
                    child = null;
                    System.Diagnostics.Trace.WriteLine("Tree walker exception: " + ex);
                }

                while (child != null)
                {
                    // Create child without populating basic property. it will be set all at once in parallel.
                    var childNode = new DesktopElement(child, true, false)
                    {
                        UniqueId = childId++
                    };

                    rootNode.Children.Add(childNode);

                    childNode.Parent         = rootNode;
                    childNode.TreeWalkerMode = this.WalkerMode;

                    this.Elements.Add(childNode);
                    try
                    {
                        child = walker.GetNextSiblingElement(child);
                    }
                    catch (Exception ex)
                    {
                        child = null;
                        System.Diagnostics.Trace.WriteLine("Tree walker exception: " + ex);
                    }
                }
            }

            Marshal.ReleaseComObject(walker);
        }