public static List <AutomationElement> FindAll(AutomationElement root, TreeScope scope, Condition condition, int processId) { return((List <AutomationElement>) STAHelper.Invoke( delegate() { int elementProcessId = (int)root.GetCurrentPropertyValue(AutomationElement.ProcessIdProperty); if (elementProcessId != processId) { // This happens when the element represents the desktop. // We could just filter using the ProcessIdProperty but this searches all nodes and *then* filters, // which is incredibly slow if we're searching a lot of nodes (i.e. TreeScope is Descendant). // Instead we find all direct children with the right process id and then search them inclusively. // Helpfully, there's a Subtree TreeScope which does what we want Condition processCondition = new PropertyCondition2(AutomationElement.ProcessIdProperty, processId); if (scope == TreeScope.Descendants) { List <AutomationElement> roots = AutomationExtensions.FindAllRaw(root, TreeScope.Children, processCondition); List <AutomationElement> mergedResults = new List <AutomationElement>(); foreach (AutomationElement currentRoot in roots) { mergedResults.AddRange(FindAll(currentRoot, TreeScope.Subtree, condition, processId)); } return mergedResults; } else { condition = (condition == null) ? processCondition : new AndCondition(condition, processCondition); } } if (condition == null) { condition = Condition.TrueCondition; } return AutomationExtensions.FindAllRaw(root, scope, condition); } )); }