Jump to content

Interprocess communcation breaks down with StdinWrite and StdoutRead


dubi
 Share

Recommended Posts

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



Link to comment
Share on other sites

1. don't see any obvious mistakes (but haven't looked carefully)

2. probably not the way to go.

3. You could make your central script a TCP server, and the other mpdules hook up as TCP clients. NamedPipes can be a bit confusing to set up. Alternatively, MailSlots are super simple. Or you could give my Pool environment (link in my sig) a spin. The keyword to search the forums with is IPC (inter-process communication). Beware that your anti-virus software may interfere with various IPC communication channels, so may have to be explicitly enabled.

Link to comment
Share on other sites

Thank you RTFC!

I have done more testing and have now detected that the EditControl is the culprit of the delay. I was sending quite a number of messages to this control which slowed things down so significantly that eventually nothing worked any longer. I wanted to use this as a logging window for some messages during testing. The moment I removed the control everything works perfectly again.

23 hours ago, dubi said:

$Edit1 = GUICtrlCreateEdit("", 8, 720, 473, 497)

So for the moment there is no need to implement another means of IPC.
Thanks to all that were reading :-)

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...