GPAL - Generally Positive Automation Library v1.0
GPAL The Fluent Automation LIbrary
Loading...
Searching...
No Matches
managedAutomationElementExtension.cs
1// =============================================================================
2// GPAL - Generally Positive Automation Library
3// Copyright © 2026 Software Decisions, Inc. All rights reserved.
4//
5// This file is part of GPAL.
6// Licensed under the Business Source License 1.1
7//
8// Primary development, architecture, and vision by Michael B. Vederman,
9// CEO of Software Decisions, Inc., Texas.
10//
11// Internal development maintained privately.
12// Public releases appear on GitHub: https://github.com/SoftwareDecisionsInc/GPAL.
13//
14// See LICENSE for full terms, including Additional Use Grant.
15// =============================================================================
16
17//extern alias mUIA;
18//extern alias mUIAtypes;
19//using mUIA::System.Windows.Automation;
20using System;
21using System.Collections.Generic;
22using System.Collections.ObjectModel;
23using System.Diagnostics;
24using System.Linq;
25using System.Text;
26using System.Threading.Tasks;
27using System.Windows.Automation.Peers;
29using static GenerallyPositive.Enums;
30using System.Drawing;
31using System.Threading;
32
34{
35 internal class ManagedAutomationElementHelper
36 {
37 /*
38 public static ReadOnlyCollection<IGPALAutomationElement> FindElements(IApplication application, mUIA::System.Windows.Automation.AutomationElement element, string findByString, ConditionPropertyType conditionPropertyType,
39 int idx = 0, bool isRoot = false)
40 {
41 ReadOnlyCollection<IGPALAutomationElement> elems = null;
42 List<IGPALAutomationElement> tmpElems = new List<IGPALAutomationElement>();
43 mUIA::System.Windows.Automation.PropertyCondition condition = null;
44 mUIAtypes::System.Windows.Automation.ControlType controlType = null;
45
46 if (true == isRoot)
47 element = (mUIA::System.Windows.Automation.AutomationElement)(application.ManagedRootAutomationElement = mUIA::System.Windows.Automation.AutomationElement.FromHandle(application.Process.Handle));
48
49 switch (conditionPropertyType)
50 {
51 case ConditionPropertyType.AutomationID:
52 condition = new mUIA::System.Windows.Automation.PropertyCondition(mUIA::System.Windows.Automation.AutomationElement.AutomationIdProperty, findByString);
53 break;
54 case ConditionPropertyType.ClassID:
55 condition = new mUIA::System.Windows.Automation.PropertyCondition(mUIA::System.Windows.Automation.AutomationElement.ClassNameProperty, findByString);
56 break;
57 case ConditionPropertyType.ControlType:
58 controlType = GetControlType(findByString);
59 condition = new mUIA::System.Windows.Automation.PropertyCondition(mUIA::System.Windows.Automation.AutomationElement.ControlTypeProperty, controlType);
60 break;
61 case ConditionPropertyType.Name:
62 condition = new mUIA::System.Windows.Automation.PropertyCondition(mUIA::System.Windows.Automation.AutomationElement.NameProperty, findByString);
63 break;
64 case ConditionPropertyType.Value:
65 condition = new mUIA::System.Windows.Automation.PropertyCondition(mUIA::System.Windows.Automation.ValuePattern.ValueProperty, findByString);
66 break;
67 }
68 mUIAtypes::System.Windows.Automation.TreeScope treeScope = mUIAtypes::System.Windows.Automation.TreeScope.Children;
69 if (true == isRoot)
70 treeScope = mUIAtypes::System.Windows.Automation.TreeScope.Subtree;
71
72 List<mUIA::System.Windows.Automation.AutomationElement> automationElements = new List<mUIA::System.Windows.Automation.AutomationElement>();
73 mUIA::System.Windows.Automation.AutomationElement automationElement;
74
75 if (true == isRoot)
76 {
77 automationElement = element.FindFirst(treeScope, condition);
78 tmpElems.Add(new GPALAutomationElement(null, null, automationElement));
79 }
80 else
81 {
82 automationElements = GetAllChildren(element, idx, controlType);
83 foreach (mUIA::System.Windows.Automation.AutomationElement elem in automationElements)
84 tmpElems.Add(new GPALAutomationElement(null, null, elem));
85 }
86
87 elems = new ReadOnlyCollection<IGPALAutomationElement>(tmpElems);
88 return elems;
89 }
90 public static List<mUIA::System.Windows.Automation.AutomationElement> GetAllChildren(mUIA::System.Windows.Automation.AutomationElement rootElement, int idx, mUIAtypes::System.Windows.Automation.ControlType controlType)
91 {
92 mUIA::System.Windows.Automation.Condition condition = new mUIA::System.Windows.Automation.PropertyCondition(mUIA::System.Windows.Automation.AutomationElement.IsControlElementProperty, true);
93 mUIA::System.Windows.Automation.TreeWalker walker = new mUIA::System.Windows.Automation.TreeWalker(condition);
94 mUIA::System.Windows.Automation.AutomationElement elementNode = walker.GetFirstChild(rootElement);
95 int cnt = 0;
96
97 if (null == elementNode) return null;
98
99 List<mUIA::System.Windows.Automation.AutomationElement> automationElements = new List<mUIA::System.Windows.Automation.AutomationElement>();
100
101 while (elementNode != null && cnt <= idx) // only get as many children as we require
102 {
103 if (controlType == elementNode.Current.ControlType)
104 {
105 automationElements.Add(elementNode);
106 cnt++;
107 }
108
109 elementNode = walker.GetNextSibling(elementNode);
110 }
111 return automationElements;
112 }
113 public static string GetText(mUIA::System.Windows.Automation.AutomationElement element)
114 {
115 object patternObj;
116 if (element.TryGetCurrentPattern(mUIA::System.Windows.Automation.ValuePattern.Pattern, out patternObj))
117 {
118 var valuePattern = (mUIA::System.Windows.Automation.ValuePattern)patternObj;
119 return valuePattern.Current.Value;
120 }
121 else if (element.TryGetCurrentPattern(mUIA::System.Windows.Automation.TextPattern.Pattern, out patternObj))
122 {
123 var textPattern = (mUIA::System.Windows.Automation.TextPattern)patternObj;
124 return textPattern.DocumentRange.GetText(-1).TrimEnd('\r'); // often there is an extra '\r' hanging off the end.
125 }
126 else
127 {
128 return element.Current.Name;
129 }
130 }
131
132 internal static mUIAtypes::System.Windows.Automation.ControlType GetControlType(string controlTypeString)
133 {
134 mUIAtypes::System.Windows.Automation.ControlType retControlType;
135 mUIAtypes::System.Windows.Automation.ControlType controlType;
136 if (null == controlTypeString) return null;
137
138 System.Windows.Automation.Peers.AutomationControlType typeEnum;
139 bool result = Enum.TryParse(controlTypeString, true, out typeEnum);
140 if (result) typeEnum = (AutomationControlType)Enum.Parse(typeof(AutomationControlType), controlTypeString);
141 int enumId = (int)typeEnum + 50000;
142 controlType = mUIAtypes::System.Windows.Automation.ControlType.LookupById(enumId);
143
144 retControlType = mUIAtypes::System.Windows.Automation.ControlType.LookupById(controlType.Id);
145
146 return retControlType;
147 }
148 public static Rectangle GetBoundingRect(object managedAutomationElement)
149 {
150 return new Rectangle(new Point((int)((mUIA::System.Windows.Automation.AutomationElement)managedAutomationElement).Current.BoundingRectangle.Location.X, (int)((mUIA::System.Windows.Automation.AutomationElement)managedAutomationElement).Current.BoundingRectangle.Location.Y), new Size((int)((mUIA::System.Windows.Automation.AutomationElement)managedAutomationElement).Current.BoundingRectangle.Size.Width, (int)((mUIA::System.Windows.Automation.AutomationElement)managedAutomationElement).Current.BoundingRectangle.Size.Height));
151 }
152 public static void ExpandMenuItem(IApplication application, object managedAutomationElement = null, bool simulateMouse = false)
153 {
154 mUIA::System.Windows.Automation.AutomationElement automationElement = (mUIA::System.Windows.Automation.AutomationElement)managedAutomationElement;
155
156 if (true == GPAL.SimulateMouse || true == application.CurrentUOW.CurrentSelector?.SimulateMouse)
157 {
158 Rectangle rect = GetBoundingRect(managedAutomationElement);
159 HardwareHelper.MoveMouse(rect.X, rect.Y, 10, 10); // source didn't define values for rx, ry }
160 HardwareHelper.LeftClick(rect.X, rect.Y);
161 Thread.Sleep(250); // wait for display before trying to find elements
162 }
163 else
164 {
165 try
166 {
167 if (null != automationElement)
168 {
169 ExpandCollapsePattern pattern = automationElement.GetCurrentPattern(ExpandCollapsePattern.Pattern) as ExpandCollapsePattern;
170 pattern.Expand();
171 }
172 else
173 {
174 mUIA::System.Windows.Automation.ExpandCollapsePattern pattern = automationElement.GetCurrentPattern(mUIA::System.Windows.Automation.ExpandCollapsePattern.Pattern) as mUIA::System.Windows.Automation.ExpandCollapsePattern;
175 pattern.Expand();
176 }
177 }
178 catch (Exception ex)
179 {
180 GPAL.PublishSimpleEvent($"Unable to expand menuitem for Control [{automationElement.Current.LocalizedControlType}], trying InvokePattern.", application, GPALObjectType.Application, ex);
181 try
182 {
183 if (null != automationElement)
184 {
185 InvokePattern pattern = automationElement.GetCurrentPattern(ExpandCollapsePattern.Pattern) as InvokePattern;
186 pattern.Invoke();
187 }
188 else
189 {
190 mUIA::System.Windows.Automation.InvokePattern pattern = automationElement.GetCurrentPattern(mUIA::System.Windows.Automation.InvokePattern.Pattern) as mUIA::System.Windows.Automation.InvokePattern;
191 pattern.Invoke();
192 }
193 }
194 catch (Exception ex2)
195 {
196 GPAL.PublishSimpleEvent($"Unable to expand menuitem for Control [{automationElement.Current.LocalizedControlType}], using hardware fallback.", application, GPALObjectType.Application, ex2);
197
198 Random random = new Random(10007);
199
200 if (null != automationElement)
201 {
202 int offsetX = random.Next(1, (int)automationElement.Current.BoundingRectangle.Width - 2);
203 int offsetY = random.Next(1, (int)automationElement.Current.BoundingRectangle.Height - 2);
204 ElementHelper.HardwareClick(null, new GPALAutomationElement((System.Windows.Automation.AutomationElement)managedAutomationElement, null, automationElement), Enums.ClickType.LeftClick, Enums.ModifierKeys.None, offsetX, offsetY);
205 }
206 else
207 {
208 int offsetX = random.Next(1, (int)automationElement.Current.BoundingRectangle.Width - 2);
209 int offsetY = random.Next(1, (int)automationElement.Current.BoundingRectangle.Height - 2);
210 ElementHelper.HardwareClick(null, new GPALAutomationElement((System.Windows.Automation.AutomationElement)managedAutomationElement, null, automationElement), Enums.ClickType.LeftClick, Enums.ModifierKeys.None, offsetX, offsetY);
211 }
212 }
213 }
214 }
215 }
216 public static List<AutomationElement> GetAllChildren(AutomationElement rootElement, int idx, System.Windows.Automation.ControlType controlType)
217 {
218 mUIA::System.Windows.Automation.Condition condition = new mUIA::System.Windows.Automation.PropertyCondition(mUIA::System.Windows.Automation.AutomationElement.IsControlElementProperty, true);
219 mUIA::System.Windows.Automation.TreeWalker walker = new mUIA::System.Windows.Automation.TreeWalker(condition);
220 mUIA::System.Windows.Automation.AutomationElement elementNode = walker.GetFirstChild(rootElement);
221 int cnt = 0;
222
223 if (null == elementNode) return null;
224
225 List<mUIA::System.Windows.Automation.AutomationElement> automationElements = new List<mUIA::System.Windows.Automation.AutomationElement>();
226
227 while (elementNode != null && cnt <= idx) // only get as many children as we require
228 {
229 //if (controlType == elementNode.Current.ControlType)
230 //{
231 // automationElements.Add(elementNode);
232 // cnt++;
233 //}
234
235 elementNode = walker.GetNextSibling(elementNode);
236 }
237 return automationElements;
238 }
239 */
240 }
241}
242
243