GPAL - Generally Positive Automation Library v1.0
GPAL The Fluent Automation LIbrary
Loading...
Searching...
No Matches
FormHelper.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.Diagnostics;
20using System.Linq;
21using System.Runtime.InteropServices;
22using System.Text;
23using System.Text.RegularExpressions;
24using System.Threading;
25using System.Threading.Tasks;
26using System.Windows.Forms;
27using static GenerallyPositive.Enums;
29using HWND = System.IntPtr;
30
32{
33 internal class FormHelper
34 {
35 public static void FillInFrom(GPALControl controlEntry, string useText, WriteMode writeMode)
36 {
37 switch (controlEntry.ControlType)
38 {
39 case FormControlType.Input:
40 case FormControlType.TextArea:
41 ((TextBox)controlEntry.WindowsControl).Text = useText;
42 break;
43
44
45 }
46
47 }
48 public static void FillInWithTokens(GPALForm myForm, List<IGPALGrid<string>> tokenList, WriteMode writeMode)
49 {
50 foreach (IGPALGrid<string> tokens in tokenList)
51 {
52 // iterate over every row of tokens, filling in the form's editable controls a row at a time
53 for (int tokenIdx = 0; tokenIdx < tokens.Count(); tokenIdx++)
54 {
55 int elementIdx = 0;
56 List<string> currentRow = tokens[tokenIdx];
57
58 foreach (string token in currentRow) // iterate over tokens, filling in the corresponding input/textarea webelement
59 {
60 bool textFilled = false;
61
62 while (false == textFilled && elementIdx < myForm.ControlList.Count)
63 {
64 switch (myForm.ControlList[elementIdx].ControlType)
65 {
66 case FormControlType.TextArea:
67 case FormControlType.Input:
68 myForm.Form.SwitchToTab(myForm.ControlList[elementIdx]); // bring the control's tab into view so the change is visible as it happens
69 FillInFrom(myForm.ControlList[elementIdx], token, writeMode);
70 textFilled = true;
71 break;
72
73 default:
74 break;
75 }
76 elementIdx++;
77 }
78
79 // detect if we have too many tokens to consume and publish an information event [entirely possible this scenario is fine]
80 if (elementIdx == myForm.ControlList.Count && false == textFilled)
81 GPAL.PublishSimpleEvent(GPALEventType.WARNING, $"Unused token: [{token}]", myForm, GPALObjectType.GPALForm);
82 }
83
84 // detect if we do not have enough tokens for all the form fields [entirely possible this scenario is fine]
85 while (elementIdx < myForm.ControlList.Count)
86 {
87 switch (myForm.ControlList[elementIdx].ControlType)
88 {
89 case FormControlType.TextArea:
90 case FormControlType.Input:
91 GPAL.PublishSimpleEvent(GPALEventType.WARNING, $"No token for control: [{myForm.ControlList[elementIdx].Name}]", myForm, GPALObjectType.GPALForm);
92 break;
93
94 default:
95 break;
96 }
97 elementIdx++;
98 }
99
100 // CAVEAT: Handled/NotHandled are both ignored here, the handler can request to exit by returning CallIfStatus.Terminate
101 if (null != myForm.Form.CallAfterFillIn)
102 {
103 CallIfStatus handled = myForm.Form.CallAfterFillIn(myForm, tokens, tokenIdx);
104
105 if (CallIfStatus.Terminate == handled)
106 {
107 GPAL.PublishSimpleEvent(GPALEventType.INFO, $"CallAfterFillIn handler [{myForm.Form.CallAfterFillIn.GetInvocationList()[0].Method.Name}] requested program termination.", myForm, GPALObjectType.GPALForm);
108 throw new GPALException($"{GPAL.MyMethodName()}: CallAfterFillIn handler [{myForm.Form.CallAfterFillIn.GetInvocationList()[0].Method.Name}] requested program termination.");
109 }
110 }
111 }
112 }
113 }
114 public static HWND WaitForWindow(string windowTitle, int waitTimeInSeconds = 10)
115 {
116 return WaitForWindowGeneric(windowTitle, false, waitTimeInSeconds);
117 }
118
119 public static HWND WaitForWindowRegex(string windowTitleRegex, int waitTimeInSeconds)
120 {
121 return WaitForWindowGeneric(windowTitleRegex, true, waitTimeInSeconds);
122 }
123
124 public static HWND WaitForWindowGeneric(string waitForTitle, bool useRegex, int waitTimeInSeconds)
125 {
126 bool found = false;
127 HWND retHWND = IntPtr.Zero;
128
129 for (int cnt = 0; cnt < waitTimeInSeconds && false == found; cnt++)
130 {
131 Thread.Sleep(1000); // best to sleep first and give a second more for the window to appear
132 IDictionary<HWND, string> windows = GetOpenWindows();
133 foreach (var entry in windows)
134 {
135 if (true == useRegex)
136 {
137 MatchCollection mc = Regex.Matches(entry.Value, waitForTitle);
138 if (0 < mc.Count)
139 {
140 found = true;
141 retHWND = entry.Key;
142 break;
143 }
144 }
145 else
146 {
147 if (true == waitForTitle.Equals(entry.Value))
148 {
149 found = true;
150 retHWND = entry.Key;
151 break;
152 }
153 }
154 }
155 }
156 return retHWND;
157 }
158
159 // https://stackoverflow.com/questions/7268302/get-the-titles-of-all-open-windows
163 public static IDictionary<HWND, string> GetOpenWindows()
164 {
165 HWND shellWindow = GetShellWindow();
166 Dictionary<HWND, string> windows = new Dictionary<HWND, string>();
167
168 EnumWindows(delegate (HWND hWnd, int lParam)
169 {
170 if (hWnd == shellWindow) return true;
171 if (!IsWindowVisible(hWnd)) return true;
172
173 int length = GetWindowTextLength(hWnd);
174 if (length == 0) return true;
175
176 StringBuilder builder = new StringBuilder(length);
177 GetWindowText(hWnd, builder, length + 1);
178
179 windows[hWnd] = builder.ToString();
180 return true;
181
182 }, 0);
183
184 return windows;
185 }
186
187 private delegate bool EnumWindowsProc(HWND hWnd, int lParam);
188
189 [DllImport("USER32.DLL")]
190 private static extern bool EnumWindows(EnumWindowsProc enumFunc, int lParam);
191
192 [DllImport("USER32.DLL")]
193 private static extern int GetWindowText(HWND hWnd, StringBuilder lpString, int nMaxCount);
194
195 [DllImport("USER32.DLL")]
196 private static extern int GetWindowTextLength(HWND hWnd);
197
198 [DllImport("USER32.DLL")]
199 private static extern bool IsWindowVisible(HWND hWnd);
200
201 [DllImport("USER32.DLL")]
202 private static extern IntPtr GetShellWindow();
203 }
204}
205
Thrown where GPAL deliberately ends the workflow, such as a CallIf handler returning CallIfStatus....
Base class for all GPAL form controls.
FormControlType ControlType
The control type of WindowsControl. Set when the control is instantiated with GPAL.
dynamic WindowsControl
Underlying Windows form control, Button, Checkbox, Textbox, etc. NOTE: Use GPAL to instantiate form ...
Form object that contains the fluent methods to create interactive forms. Instatiated using GPAL....
Definition GPALForm.cs:64
Everything starts here, all the GPAL controls and global settings using fluent syntax are here....
Definition GPAL.cs:49
static void PublishSimpleEvent(GPALEventType gPALEventType, string msg, dynamic gPALObject=null, Enums.GPALObjectType gPALObjectType=GPALObjectType.None, Exception ex=null)
Publish a message to either the information channel or exception channel (if exception passed in) Pub...
Definition GPAL.cs:2406