GPAL - Generally Positive Automation Library v1.0
GPAL The Fluent Automation LIbrary
Loading...
Searching...
No Matches
WindowHelper.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
17using System;
18using System.Collections.Generic;
19using System.Linq;
20using System.Text;
21using System.Threading.Tasks;
23
24namespace GenerallyPositive
25{
27 {
28 // TODO: iimplement in GPAL, different methods to close windows
34 private bool CloseMultipleWindows(Selector selectors)
35 {
36 logger?.Log(LogLevel.Info, "Enter CloseMultipleWindows");
37 try
38 {
39 if (uiAutomation.AdvancedWaitForElement(selectors))
40 {
41 int attempt = 1;
42 bool areOpen = false;
43 do
44 {
45 logger?.Log(LogLevel.Info, "Scanning for and closing {0} windows, attempt: {1}", selectors.Count, attempt);
46 foreach (string selector in selectors)
47 {
48 this.CloseWindow(selector);
49 }
50 areOpen = uiAutomation.AdvancedWaitForElement(selectors, 500);
51 } while (areOpen && attempt++ < 3);
52
53 if (areOpen)
54 {
55 logger?.Log(LogLevel.Warn, "Failed to completely close all {0} windows", selectors.Count);
56 return false;
57 }
58 }
59 logger?.Log(LogLevel.Debug, "{0} windows are closed", selectors.Count);
60 return true;
61 }
62 catch (Exception ex)
63 {
64 logger?.Log(LogLevel.Info, $"Exception trying to close multiple windows [{ex.Message}]");
65 return false;
66 }
67 }
68
76 private bool CloseWindow(string selector, params string[] additionalCloseButtons)
77 {
78 logger?.Log(LogLevel.Info, "Enter CloseWindow");
79 try
80 {
81 if (additionalCloseButtons.Count() > 0)
82 {
83 CloseButtons.AddRange(additionalCloseButtons);
84 }
85
86 if (uiAutomation.WaitForElement(selector, maxWait: 500))
87 {
88 List<Func<bool>> closeMethods = new List<Func<bool>> {
89 ()=>this.ImageClose(selector,CloseButtons),()=> this.BoundClose(selector),
90 ()=> this.HardClose(selector), ()=> this.HardClose(selector,useHardwareEvent:true)
91 };
92 int attempt = 1;
93 bool isClose = false;
94 do
95 {
96 logger?.Log(LogLevel.Info, "Closing window, attempt {0}", attempt);
97 foreach (Func<bool> method in closeMethods)
98 {
99 if (method())
100 {
101 isClose = uiAutomation.WaitForElementDisappear(selector, 2000);
102 break;
103 }
104 }
105 } while (!isClose && attempt++ < 3);
106 return isClose;
107 }
108
109 logger?.Log(LogLevel.Debug, "Window is close");
110 return true;
111 }
112 catch (Exception ex)
113 {
114 // ignore
115 logger?.Log(LogLevel.Error, $"Error CloseWindow {ex.Message}");
116 return false; // what's the point of a return for this helper? mbv
117 }
118 finally
119 {
120 CloseButtons.RemoveAll(btn => additionalCloseButtons.Contains(btn));
121 }
122 }
123
130 private bool HardClose(string selector, bool useHardwareEvent = false)
131 {
132 try
133 {
134 string methodName = useHardwareEvent ? "HardClose with hardware event" : "HardClose";
135 logger?.Log(LogLevel.Debug, "{0}: closing window", methodName);
136 if (uiAutomation.WaitForElement(selector))
137 {
138 Action closeAction = delegate {
139 uiAutomation.SetForegroundWindow(selector);
140 uiAutomation.CloseElement(selector, useHardwareEvents: useHardwareEvent);
141 };
142
143 if (!Extend.StopWatchLoop(closeAction, () => uiAutomation.WaitForElementDisappear(selector, maxWait: 1000), 15000))
144 {
145 return false;
146 }
147 }
148 logger?.Log(LogLevel.Debug, "{0}: Window is closed", methodName);
149 return true;
150 }
151 catch (Exception ex)
152 {
153 // ignore
154 logger?.Log(LogLevel.Error, $"Error HardClose {ex.Message}");
155 return false; // what's the point of a return for this helper? mbv
156 }
157 }
158
164 private bool BoundClose(string selector)
165 {
166 try
167 {
168 if (uiAutomation.WaitForElement(selector))
169 {
170 AutomationElement windowElement = uiAutomation.SelectorToElement(selector);
171 if (windowElement == null || !windowElement.Exists())
172 {
173 logger?.Log(LogLevel.Error, "BoundClose: window element of selector is not exist");
174 return false;
175 }
176 Rectangle windowBound = windowElement.Bounds();
177 if (windowBound.IsEmpty)
178 {
179 logger?.Log(LogLevel.Error, "BoundClose: window bounds are empty");
180 return false;
181 }
182
183 Action closeAction = delegate {
184 uiAutomation.SetForegroundWindow(selector);
185 InputSimulator.MouseClick(windowBound.Right - 20, windowBound.Top + 10);
186 };
187
188 if (!Extend.StopWatchLoop(closeAction, () => uiAutomation.WaitForElementDisappear(selector, maxWait: 1000), 15000))
189 {
190 return false;
191 }
192 }
193
194 logger?.Log(LogLevel.Debug, "BoundClose: Window is closed");
195 return true;
196 }
197 catch (Exception ex)
198 {
199 // ignore
200 logger?.Log(LogLevel.Error, $"Error BoundClose {ex.Message}");
201 return false; // what's the point of a return for this helper? mbv
202 }
203 }
204
211 private bool ImageClose(string selector, List<string> closeImages)
212 {
213 try
214 {
215 logger?.Log(LogLevel.Debug, "ImageClose: closing window");
216 if (uiAutomation.WaitForElement(selector))
217 {
218 AutomationElement windowElement = uiAutomation.SelectorToElement(selector);
219 if (windowElement == null || !windowElement.Exists())
220 {
221 logger?.Log(LogLevel.Error, "ImageClose: window element of selector is not exist");
222 return false;
223 }
224 Rectangle windowBound = windowElement.Bounds();
225 if (windowBound.IsEmpty)
226 {
227 logger?.Log(LogLevel.Error, "ImageClose: window bounds are empty");
228 return false;
229 }
230
231 Action closeAction = delegate {
232 uiAutomation.SetForegroundWindow(selector);
233 imageHelper.ClickAnyWhenPresentInRegion(closeImages, windowBound, maxWait: 1000);
234 };
235
236 if (!Extend.StopWatchLoop(closeAction, () => uiAutomation.WaitForElementDisappear(selector, maxWait: 1000), 15000))
237 {
238 return false;
239 }
240 }
241 logger?.Log(LogLevel.Debug, "ImageClose: window is close");
242 return true;
243 }
244 catch (Exception ex)
245 {
246 // ignore
247 logger?.Log(LogLevel.Error, $"Error ImageClose {ex.Message}");
248 return false; // what's the point of a return for this helper? mbv
249 }
250 }
251
252 }
253}
254
GPAL Selector used to locate Application and Browser elements. Instantiated with GPAL....
Definition Selector.cs:56