By
dubi
Hi,
Background: i have a number of instances of the same application that I want to automate in parallel.
Unfortunately, I cannot completely automate these instances in the background. So, from time to time these instances need to have the focus so that I can interact with the controls via “send” directly.
Each of the application instances is controlled by a au3 complied script. Each script (called with a parameter) manages the automation of the respective application-instance. Each of the (complied) script (instances) is called by a (central) front end with a gui. The front end controls if the “focus” is available to do the “send” and “mouseclick” modifications. The central front end either allows a child to have the focus or prevents it to get the focus (in which case the child will wait and checks again). The code for the front end is included. Apologies for the lengthy explanation.
#RequireAdmin
#include <ButtonConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <EditConstants.au3>
#include <GUIEdit.au3>
#include <ScrollBarConstants.au3>
#include <Array.au3>
Global Const $APF_ALLOWMULTILINE = 1
Global Const $APF_RIGHTALIGN = 6
Global Const $APF_RIGHTALIGNCOL = 2
Global Const $APF_RIGHTALIGNDATA = 4
Global Const $APF_PRINTROWNUM = 8
Global Const $APF_DEFAULT = $APF_PRINTROWNUM
Global $PID[9], $FocusAvailable = True, $previousEditMsg
Global $PID_waiting[0][2], $logfile
$logfile = "D:\MultiInstance\Logfiles\FrontEnd.txt"
If FileExists($logfile) Then FileDelete($logfile)
#Region ### START Koda GUI section ### Form=
$hGui_1 = GUICreate("Instanzenmanager", 493, 1226, 1807, 93)
$grpInst1 = GUICtrlCreateGroup(" 1 ", 8, 8, 233, 121)
$btnPause01 = GUICtrlCreateCheckbox("Pause", 16, 64, 50, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$tbnStop01 = GUICtrlCreateCheckbox("Stop", 16, 96, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$btnMin01 = GUICtrlCreateCheckbox("Minimize", 72, 64, 66, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$btnWdh01 = GUICtrlCreateCheckbox("Restore", 144, 64, 90, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$btnStart01 = GUICtrlCreateCheckbox("Start", 16, 32, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
GUICtrlSetBkColor(-1, 0x00FF00)
GUICtrlCreateGroup("", -99, -99, 1, 1)
$grpInst3 = GUICtrlCreateGroup(" 3 ", 8, 136, 233, 121)
$btnPause03 = GUICtrlCreateCheckbox("Pause", 16, 192, 50, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$tbnStop03 = GUICtrlCreateCheckbox("Stop", 16, 224, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$btnMin03 = GUICtrlCreateCheckbox("Minimize", 72, 192, 66, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$btnWdh03 = GUICtrlCreateCheckbox("Restore", 144, 192, 90, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$btnStart03 = GUICtrlCreateCheckbox("Start", 16, 160, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
GUICtrlSetBkColor(-1, 0x00FF00)
GUICtrlCreateGroup("", -99, -99, 1, 1)
$grpInst2 = GUICtrlCreateGroup(" 2 ", 248, 8, 233, 121)
$btnPause02 = GUICtrlCreateCheckbox("Pause", 256, 64, 50, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$tbnStop02 = GUICtrlCreateCheckbox("Stop", 256, 96, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$btnMin02 = GUICtrlCreateCheckbox("Minimize", 312, 64, 66, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$btnWdh02 = GUICtrlCreateCheckbox("Restore", 384, 64, 90, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$btnStart02 = GUICtrlCreateCheckbox("Start", 256, 32, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
GUICtrlSetBkColor(-1, 0x00FF00)
GUICtrlCreateGroup("", -99, -99, 1, 1)
$grpInst4 = GUICtrlCreateGroup(" 4 ", 248, 136, 233, 121)
$btnPause04 = GUICtrlCreateCheckbox("Pause", 256, 192, 50, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$tbnStop04 = GUICtrlCreateCheckbox("Stop", 256, 224, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$btnMin04 = GUICtrlCreateCheckbox("Minimize", 312, 192, 66, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$btnWdh04 = GUICtrlCreateCheckbox("Restore", 384, 192, 90, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$btnStart04 = GUICtrlCreateCheckbox("Start", 256, 160, 218, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
GUICtrlSetBkColor(-1, 0x00FF00)
$Edit1 = GUICtrlCreateEdit("", 8, 720, 473, 497)
$btnPauseAll = GUICtrlCreateCheckbox("Pause all", 8, 656, 474, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
$btnStopAll = GUICtrlCreateCheckbox("Stop all", 7, 688, 474, 25, BitOR($GUI_SS_DEFAULT_CHECKBOX, $BS_PUSHLIKE))
GUISetState(@SW_SHOW)
#EndRegion ### END Koda GUI section ###
While 1
CheckGuiMsg()
FileWrite($logfile, @HOUR & ":" & @MIN & ":" & @SEC & "> " & "CheckGuiMsg" & @CRLF)
CheckClientMessages()
FileWrite($logfile, @HOUR & ":" & @MIN & ":" & @SEC & "> " & "CheckClientMessages" & @CRLF)
WEnd
Func CheckGuiMsg()
$nMsg = GUIGetMsg()
Switch $nMsg
Case $GUI_EVENT_CLOSE
Exit
Case $btnStart01
AddTextToEdit("Starting Instance 1")
$PID[0] = Run("D:\XVM05\Entwicklung_FilterTest_Multi_ToFileV001.exe 1", @ScriptDir, Default, 3)
Case $btnStart02
AddTextToEdit("Starting Instance 2")
$PID[1] = Run("D:\XVM05\Entwicklung_FilterTest_Multi_ToFileV001.exe 2", @ScriptDir, Default, 3)
Case $btnStart03
AddTextToEdit("Starting Instance 3")
$PID[2] = Run("D:\XVM05\Entwicklung_FilterTest_Multi_ToFileV001.exe 3", @ScriptDir, Default, 3)
Case $btnStart04
AddTextToEdit("Starting Instance 4")
$PID[3] = Run("D:\XVM05\Entwicklung_FilterTest_Multi_ToFileV001.exe 4", @ScriptDir, Default, 3)
Case $btnPause01
AddTextToEdit("Send Pause to Instance 1")
StdinWrite($PID[0], "Pause")
Case $btnPause02
StdinWrite($PID[1], "Pause")
Case $btnPause03
StdinWrite($PID[2], "Pause")
Case $btnPause04
StdinWrite($PID[3], "Pause")
Case $tbnStop01
StdinWrite($PID[0], "Stop")
Case $tbnStop02
StdinWrite($PID[1], "Stop")
Case $tbnStop03
StdinWrite($PID[2], "Stop")
Case $tbnStop04
StdinWrite($PID[3], "Stop")
Case $btnPauseAll
AddTextToEdit(@CRLF & "************Pause All not yet implemented**************" & @CRLF)
Case $btnStopAll
AddTextToEdit(@CRLF & "************Stop All not yet implemented***************" & @CRLF)
EndSwitch
EndFunc ;==>CheckGuiMsg
Func CheckClientMessages()
For $i = 0 To 3
FileWrite($logfile, @HOUR & ":" & @MIN & ":" & @SEC & "> " & $i & @CRLF)
Local $a = TimerInit()
$p = $PID[$i]
$streamRead = StdoutRead($p)
If $streamRead <> "" Then
Switch $streamRead
Case StringInStr($streamRead, "Focus Needed") > 0
If $FocusAvailable Then
$FocusAvailable = False
StdinWrite($p, "Focus Granted")
Else
EndIf
Case StringInStr($streamRead, "Release Focus") > 0
StdinWrite($p, "Release Focus Received")
$FocusAvailable = True
Case Else
EndSwitch
EndIf
FileWrite($logfile, @HOUR & ":" & @MIN & ":" & @SEC & "> " & $i & " " & round(TimerDiff($a),2) & @CRLF)
Next
EndFunc ;==>CheckClientMessages
Func AddTextToEdit($text)
If $previousEditMsg <> $text Then
$previousEditMsg = $text
GUICtrlSetData($Edit1, GUICtrlRead($Edit1) & @YEAR & "." & @MON & "." & @MDAY & " - " & @HOUR & ":" & @MIN & ":" & @SEC & "> " & $text & @CRLF)
_GUICtrlEdit_Scroll($Edit1, $SB_SCROLLCARET)
EndIf
EndFunc ;==>AddTextToEdit
My issue now is that the mechanism with with StdoutRead and StdinWrite is not efficient at all. The more instances I start the slower it gets. This is not just a bit slower (like a fraction of a second), but to the degree that the front end is not responding at all any longer (with 3 instances handling).
So my questions are:
1. Is there a flaw in my implementation with StdoutRead and StdinWrite? (note that all works fine with 1 and also (slower) with 2 instances running) but actually breaks down with 3 instances running.
2. Can I optimize the currently used implementation so that I can control 30+ instances?
3. What other implementation do you see suitable for this approach?
a. I have already tried it with communication through files but observed that this is not sufficiently reliable with multiple instances.
b. Is Named Pipes a more performant approach (I am a bit scared of the effort to learn and implement this)
c. Any other method?
Many thanks in advance
-dubi