#include #include "..\ztna.au3" #include "wd_core.au3" #include "wd_helper.au3" Local Const $gIniPath = @ScriptDir & "\app-edge.ini" Local Const $gSection = "app" ; Read settings Local $debug = StringLower(IniRead($gIniPath, $gSection, "debug", "false")) = "true" Local $tPageLoadWait = Int(IniRead($gIniPath, $gSection, "page-load-wait", "2000")) ; wait after navigation for page to load Local $tAfterSubmitWait = Int(IniRead($gIniPath, $gSection, "after-submit-wait", "4000")) ; wait after each submit Local $tFocusWait = Int(IniRead($gIniPath, $gSection, "focus-wait", "500")) ; small pauses between focus/Send actions Func _KillAllEdge() Local $count = 0 $count += _KillProcessesByName("msedge.exe") $count += _KillProcessesByName("msedgedriver.exe") If $count > 0 Then ConsoleWrite("Closed " & $count & " Edge / EdgeDriver process(es)." & @CRLF) Sleep(1000) EndIf EndFunc Func _KillProcessesByName($processName) Local $list = ProcessList($processName) Local $count = 0 For $i = 1 To $list[0][0] Local $pid = $list[$i][1] ProcessClose($pid) $count += 1 Next Return $count EndFunc ; ------------------------ ; Helpers ; ------------------------ Func _PromptIfEmpty(ByRef $var, $prompt, $isPassword = False) If $var = "" Then If $isPassword Then $var = InputBox("Input required", $prompt, "", "", -1, -1, 0, 0) Else $var = InputBox("Input required", $prompt) EndIf If @error Then MsgBox($MB_ICONERROR, "Aborted", "User cancelled input.") Exit EndIf EndIf EndFunc Func FindFieldByIdOrName($session, $fieldName) Local $xpath = "//*[@id='" & $fieldName & "' or @name='" & $fieldName & "']" Local $element = _WD_FindElement($session, $_WD_LOCATOR_ByXPath, $xpath) If @error Then Return "" EndIf Return $element EndFunc Func ExecuteInputAction($session, $action, ByRef $pairs) ; Remove "{input:" prefix and closing "}" Local $body = StringTrimRight(StringTrimLeft($action, 7), 1) Local $parts = StringSplit($body, ":", $STR_NOCOUNT) If UBound($parts) <> 2 Then ConsoleWrite("Invalid input action format: " & $action & @CRLF) Return SetError(1) EndIf Local $fieldName = StringStripWS($parts[0], $STR_STRIPLEADING + $STR_STRIPTRAILING) Local $key = StringStripWS($parts[1], $STR_STRIPLEADING + $STR_STRIPTRAILING) If Not MapExists($pairs, $key) Then ConsoleWrite("Missing variable in pairs map: " & $key & @CRLF) Return SetError(2) EndIf Local $value = $pairs[$key] Local $element = FindFieldByIdOrName($session, $fieldName) If $element = "" Then ConsoleWrite("Field not found by id or name: " & $fieldName & @CRLF) Return SetError(3) EndIf _WD_ElementAction($session, $element, "click") _WD_ElementAction($session, $element, "clear") _WD_ElementAction($session, $element, "value", $value) Return 1 EndFunc Func ExecuteSequence($session, $seq, ByRef $pairs) Local $actions = StringSplit($seq, ",", $STR_NOCOUNT) For $i = 0 To UBound($actions) - 1 Local $action = StringStripWS($actions[$i], $STR_STRIPLEADING + $STR_STRIPTRAILING) Switch $action Case "{TAB}" Send("{TAB}") Case "{ENTER}" Send("{ENTER}") Case Else If StringLeft($action, 5) = "{var:" And StringRight($action, 1) = "}" Then Local $name = StringTrimRight(StringTrimLeft($action, 5), 1) If MapExists($pairs, $name) Then Send($pairs[$name], 1) Else ConsoleWrite("Missing variable in pairs map: " & $name & @CRLF) EndIf ElseIf StringLeft($action, 6) = "{wait:" And StringRight($action, 1) = "}" Then Local $millisecs = StringTrimRight(StringTrimLeft($action, 6), 1) If StringIsInt($millisecs) Then Sleep(Int($millisecs)) Else ConsoleWrite("Invalid wait value: " & $millisecs & @CRLF) EndIf ElseIf StringLeft($action, 7) = "{input:" And StringRight($action, 1) = "}" Then ExecuteInputAction($session, $action, $pairs) Else ConsoleWrite("Unknown action: " & $action & @CRLF) EndIf EndSwitch Next EndFunc Func _GetRandomPort() Return Random(20000, 65000, 1) EndFunc Func StartEdge($url) For $i = 1 To 10 Local $port = Random(20000, 65000, 1) _WD_Option("Driver", @ScriptDir & "\msedgedriver.exe") _WD_Option("Port", $port) _WD_Option("DriverParams", "--port=" & $port & " --silent") _WD_Option("DriverClose", True) _WD_Option("DriverDetect", False) _WD_Option("DriverVisible", False) _WD_Startup() Local $capabilities = _ '{"capabilities":{"alwaysMatch":{"browserName":"MicrosoftEdge",' & _ '"ms:edgeOptions":{' & _ '"detach":true,' & _ '"excludeSwitches":["enable-automation"],' & _ '"args":["--start-maximized"]' & _ '}}}}' Local $session = _WD_CreateSession($capabilities) If Not @error Then _WD_Navigate($session, $url) Return $session EndIf ConsoleWrite("Failed to start Edge WebDriver on port " & $port & ", trying another port..." & @CRLF) _WD_Shutdown() Sleep(250) Next ConsoleWrite("Failed to start Edge WebDriver after several port attempts." & @CRLF) Return SetError(1, 0, "") EndFunc Func StopEdge(ByRef $session) If $session <> "" Then _WD_DeleteSession($session) $session = "" EndIf _WD_Shutdown() Sleep(500) ; Fallback cleanup in case driver is still alive _KillProcessesByName("msedgedriver.exe") EndFunc Func WaitUntilBrowserClosedThenStop(ByRef $session) While 1 Sleep(1000) ; Check whether WebDriver still sees browser windows. Local $handles = _WD_Window($session, "handles") If @error Then ConsoleWrite("Browser session is no longer available." & @CRLF) ExitLoop EndIf If IsArray($handles) And UBound($handles) = 0 Then ConsoleWrite("No browser windows remain." & @CRLF) ExitLoop EndIf WEnd StopEdge($session) EndFunc Func ReleaseEdgeToUser(ByRef $session) ; Do not call _WD_DeleteSession() here if you want Edge to stay open. ; With detach=true, shutting down the driver should leave the browser open. $session = "" _WD_Shutdown() Sleep(500) _KillProcessesByName("msedgedriver.exe") EndFunc Local $pairs = GetConnectionParams() _KillAllEdge() ; -------------------------- ; Access asset parameters ; -------------------------- Local $script = MapExists($pairs, "Script") ? $pairs["Script"] : "Script" Local $url = $pairs["Host"] Local $seq = IniRead($gIniPath, $gSection, $script, "{USER}") ; --------------------------------- ; Applicaiton specific logic: BEGIN ; --------------------------------- ; --- config --- ; INI format expected (same folder as script): ; [app] ; debug=true AutoItSetOption("WinTitleMatchMode", 2) ; substring matching for Win* functions Opt("SendKeyDelay", 40) Opt("SendKeyDownDelay", 5) If $debug Then Local $text = "" For $key In MapKeys($pairs) Local $value = $pairs[$key] If StringLower($key) = "password" Then $value = "****" EndIf $text &= $key & " = " & $value & @CRLF Next $text &= "Sequence = " & $seq & @CRLF ; Shows popup for 10 seconds, then closes automatically MsgBox(64, "Debug: $pairs values", $text, 10) EndIf ; Launch Edge and navigate Local $session = StartEdge($url) If $session = "" Then Exit EndIf ExecuteSequence($session, $seq, $pairs) ; Stop WebDriver/driver process and leave browser for the RDS user. ReleaseEdgeToUser($session) ; --------------------------------- ; Applicaiton specific logic: END ; --------------------------------- UnblockInput()