Jump to content
Sign in to follow this  
dubi

Interprocess communcation breaks down with StdinWrite and StdoutRead

Recommended Posts

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



Share this post


Link to post
Share on other sites
RTFC

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.

Share this post


Link to post
Share on other sites
dubi

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 :-)

Share this post


Link to post
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
Sign in to follow this  

  • Similar Content

    • ModemJunki
      By ModemJunki
      OK, the odd stuff seems to happen to me. Not sure if this belongs here or in the deployment forum.
      The Question: Why would the console output results from a command-line tool need to know the working dir on one system but not the other?
      Though in the end I solved the issue I still am not understanding why StdoutRead seems to behave differently as I describe below.
      Preamble: Windows 10 image deployment to two different HP workstation hardware platforms. After deployment set up some disk space using Intel RAID. I script the Intel RSTe client (Intel® Rapid Storage Technology enterprise). Same version of the RSTe client and same storage controller hardware (Intel C600+/C220+ series chipset SATA RAID controller). The only difference is in the driver - one system has 4.2.0.1136 and the other has 5.2.0.1194, but even after I update the older driver the anomaly persists. There are of course other differences - the older system has different CPUs (Xeon E5-2620 vs Xeon Silver 4108), different chipsets, different SMBIOS, etc..). Both have Nvidia Quadro cards with driver 385.90, but the older has 3x P2000 cards and the newer has 3x Quadro M4000 and a Quadro K1200.
      To script RAID creation and maintenance I have a function that uses StdoutRead with Intels command line client tool "rstcli64.exe".
      On the older system, the below call to StdoutRead fails. On the newer system, it works. This only started happening on the older hardware when I updated the Windows version 1607 image to build 14393.2189 (but the Windows image used is the same for both hardware targets).
      $s_DoRST = Run(@ComSpec & " /c " & $s_RSTcmd, "", @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) But if I change it to use @ScriptDir as the working dir, it works for both systems.
      $s_DoRST = Run(@ComSpec & " /c " & $s_RSTcmd, @ScriptDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)  The code below is the one that works on both systems (hint: the comment " ; this only deals with one device" is because I've no hardware with more than one ATAPI device to test with).
      $s_RSTExe = ".\rstcli64.exe" ; for production (compiled executable) ; #FUNCTION# ==================================================================================================================== ; Name ..........: GetDiskInfoFromRSTE() ; Description ...: Queries for hard disks attached to the controller ; Syntax ........: GetDiskInfoFromRSTE() ; Parameters ....: None ; Return value...: An array of attached hard disk datas from the RST command line tool without ATAPI devices such as optical drives ; =============================================================================================================================== Func _GetDiskInfoFromRSTE() Local $s_RSTcmd = $s_RSTExe & " -I -d" Local $s_DoRST, $a_RSTDisksTemp, $s_rawdata, $numDISK = 0 If $Debug <> 0 Then ConsoleWrite("Get disk info: " & $s_RSTcmd & @CRLF) ; useful during dev but cannot be used if #requireadmin $s_DoRST = Run(@ComSpec & " /c " & $s_RSTcmd, @ScriptDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD) ProcessWaitClose($s_DoRST) $s_rawdata = StdoutRead($s_DoRST) $a_RSTDisksTemp = StringSplit($s_rawdata, @CRLF) For $i = $a_RSTDisksTemp[0] To 1 Step -1 ; since we are deleting items, we have to go backwards through the array If $a_RSTDisksTemp[$i] = "" Or $a_RSTDisksTemp[$i] = "--DISK INFORMATION--" Then _ArrayDelete($a_RSTDisksTemp, $i) EndIf Next $a_RSTDisksTemp[0] = UBound($a_RSTDisksTemp) If IsArray($a_RSTDisksTemp) Then For $j = $a_RSTDisksTemp[0] - 1 To 1 Step -1 ; we need to remove the ATAPI device(s), since we delete we have to step through in reverse If StringInStr($a_RSTDisksTemp[$j], "Disk Type: SATA") Then $numDISK = $numDISK + 1 EndIf Next For $j = $a_RSTDisksTemp[0] - 1 To 1 Step -1 ; we need to remove the ATAPI device(s), since we delete we have to step through in reverse If StringInStr($a_RSTDisksTemp[$j], "ATAPI") Then ; we have to delete the ID entry BEFORE and AFTER the ATAPI entry to remove the ATAPI device (always delete from the bottom up!). _ArrayDelete($a_RSTDisksTemp, $j + 1) ; delete entry below _ArrayDelete($a_RSTDisksTemp, $j) ; delete entry _ArrayDelete($a_RSTDisksTemp, $j - 1) ; delete entry above ExitLoop ; this only deals with one device. If there were more we would need to capture all ATAPI device ID locations into another array then delete the original array entries based on the index numbers in the new array. EndIf Next $a_RSTDisksTemp[0] = UBound($a_RSTDisksTemp) If $a_RSTDisksTemp[0] <> 1 Then If $Debug <> 0 Then ConsoleWrite("Found " & $numDISK & " disk(s) attached to controller." & @CRLF) _infoLog("_GetDiskInfoFromRSTE() found " & $numDISK & " disk(s) attached to controller.", $msgSource) Else If $Debug <> 0 Then ConsoleWrite("No disks found to be attached to controller." & @CRLF) _infoLog("No disks found to be attached to controller.", $msgSource) EndIf Else If $Debug <> 0 Then ConsoleWrite("Unable to query RAID controller. Check hardware and version of RST client software." & @CRLF) _errorLog("Unable to query RAID controller. Check hardware.", $msgSource) Exit EndIf Return $a_RSTDisksTemp EndFunc ;==>_GetDiskInfoFromRSTE  
    • argumentum
      By argumentum
      I was in need of an IPC (Interprocess communication) between system, admin and user levels, and ended up writing this UDF to suit my wantings.
      Hope you find it useful too.
      Works from WinXP/Server2003 to the now current Win10/Server2016.
      It communicates between any mix of x32, x64, Admin, User.

      In the zip file, there is the UDF and an example: FMIPC(v0.2018.04.04).zip
      Special thanks to @RTFC for the help in the support forum   
    • argumentum
      By argumentum
      There is this topic on Examples about IPC. My question is: What is the best IPC to work with between a script running as SYSTEM level, User level, and Administrator level to interact with each other ? 
      Thanks
    • JohnWIlling
      By JohnWIlling
      IPC_IO.AU3
      I am in the need for a simple synchronous Client/Server communication.  I found several examples and references to various kinds of Inter-Process Communications such as TCP, Named Pipes, Mail Slots, Shared Memory, Memory Mapped Files, and simple Files.  I wanted to see what the best solutions would be.  I began developing a library and slowly began adding each of the IPC methods and ended up with a library with a very simple synchronous “ASCII” API where the application can choose which method to use at startup.
      For the Server side, a Server app must initialize communication by calling:
      Func InitConnection($cType = $cDefaultType, $ResourceName = "", $bBlock = $cDefaultBlocking, $fSleepFunc = "", $iBufSize = $DEFAULT_BUFSIZE)
      The optional arguments allow the app to specify the connection type (such as: $cNamedPipe, $cFile, $cTCP, $cSharedMem, $cMailSlot), a value for the resource name (such as the file, named pipe name, TCP port number, etc.), the communication buffer size, and a callback function for when the “read” is waiting for data.
      A “File Descriptor” is returned and must be used in the future API calls.
      The Server side must then call:
      Func StartConnection($iFD)
      This call waits for a Client to connect.  The Server then calls:
                      Func ReadData($iFD, ByRef $sData)
      To read a Request from the Client and then calls:
                      Func WriteData($iFD, ByRef $sData)
      To send the reply back to the Client.
      When communication with the Client is done, the Server app will call:
      Func StopConnection($iFD)
      When the Server app is done with the communications it will call:
      Func EndConnection($iFD)
       
      For the Client side, a Client app must open the communication by calling:
      Func OpenConnection($cType = $cDefaultType, $ResourceName = "", $bBlock = $cDefaultBlocking, $fSleepFunc = "", $iBufSize = $DEFAULT_BUFSIZE)
      The optional arguments allow the app to specify the connection type (such as: $cNamedPipe, $cFile, $cTCP, $cSharedMem, $cMailSlot), a value for the resource name (such as the file, named pipe name, TCP port number, etc.), the communication buffer size, and a callback function for when the “read” is waiting for data.
      A “File Descriptor” is returned and must be used in the future API calls.
      The Client side then send a request to the Server app by calling:
                      Func WriteData($iFD, ByRef $sData)
      To read a Response from the Server by calling:
                      Func ReadData($iFD, ByRef $sData)
      To end the connection to the Server by calling:
      Func CloseConnection($iFD)
       
      Within the IPC_IO.AU3 library, each IPC method is ether:
      ·         “stream” based where data is read/written by calling _WinAPI_ReadFile/TCPRecv or _WinAPI_WriteFile/ TCPSend
      ·         “direct” based for Shared memory where the Client reads the data directly from the Server App’s memory and the Server directly reads the Client App’s memory
      In processing a request, the “ReadData” process starts by checking if data is ready to be read by calling the routine: “ReadStart”, then it reads in the size of the request by calling “ReadSize”, it then reads in the Ascii Request by calling “ReadBuffer”, then the sequence is completed by calling “ReadEnd”. 
      The Write Process follows the same sequence with “WriteData” calling “WriteStart”, “WriteSize”, “WriteBuffer”, “WriteEnd”.
       
      Results
      My testing showed that the performance of sending and receiving of a 10k file took:
      ·         "Shared Memory" was the fastest, at 0.007468 Sec
      ·         “Named Pipes” at 0.015954
      ·         “Mail Slots” at 0.016427
      ·         “File Based” at 0.270287
      ·         “TCP” at 0.994884
       
      IPC_IO.au3
      Client.au3
      Server.au3
    • OGA
      By OGA
      Hi, I'm new.
      Anyways, I'm using the RunBinary.au3 script by trancexx and I want to re-direct the STDOUT of the "child process" back to the autoit script that launches it. I'm attempting to do so using named pipes. If its possible to use StdoutRead instead of namedpipes please let me know. I'm just unsure of how to provide a handle of the childs STDOUT stream to that function. Though DllCall("kernel32.dll", "ptr", "GetStdHandle", "dword", "STD_OUTPUT_HANDLE") seems to get the handle?
      Please excuse any foolish mistakes because I'm new to STDOUT, runbinary and namedpipes. Here's the parts of the code I'm trying to use that are relevent:
      ;~~~Firstly I think I need to make a pipe that's inheritable.. which I may have done wrong Local $_SECURITY_ATTRIBUTES = DllStructCreate("dword Length;" & _ "int lpSecurityDescriptor;" & _ "bool InheritHandle;") ;***Not positive if bool works correctly here? DLLStructSetData($_SECURITY_ATTRIBUTES, "Length", DllStructGetSize($_SECURITY_ATTRIBUTES)) DLLStructSetData($_SECURITY_ATTRIBUTES, "lpSecurityDescriptor", 0) ;***This sets default state; "If the value of this member is NULL, the object is assigned the default security descriptor associated with the access token of the calling process." but I'm unsure if this is what I should use DLLStructSetData($_SECURITY_ATTRIBUTES, "InheritHandle", true);***True = Inheritable(but again I'm not positive the bool works correctly?) Global $hNamedPipe = _NamedPipes_CreateNamedPipe("\\.\pipe\poopp", _;Name 2, _;Direction: 2=both ;I only need 1 direction but I'm just using this for testing 1, _;Flags: 1=no extra instances of pipe are allowed to run 0, _;Security: No ACL Security 0, _;Type: 0=byte 0, _;ReadType: 0=byte 1, _;Wait: 0=Block(wait) 1=No block(no wait) 1, _;Max Instances of pipe allowed 4096, _;out size 4096, _;in size 9000, _;timeout DllStructGetPtr($_SECURITY_ATTRIBUTES));Default=0 which wouldn't make the handle inheritable ;~~~Next I would need to set the STARTUPINFO of the process ;code used by trancexx for the _STARTUPINFO Global $tSTARTUPINFO = DllStructCreate("dword cbSize;" & _ "ptr Reserved;" & _ "ptr Desktop;" & _ "ptr Title;" & _ "dword X;" & _ "dword Y;" & _ "dword XSize;" & _ "dword YSize;" & _ "dword XCountChars;" & _ "dword YCountChars;" & _ "dword FillAttribute;" & _ "dword Flags;" & _ "word ShowWindow;" & _ "word Reserved2;" & _ "ptr Reserved2;" & _ "ptr hStdInput;" & _ "ptr hStdOutput;" & _ "ptr hStdError") ;Attempting to set the values for namedpipe redirection DllStructSetData($tSTARTUPINFO, "Flags", 0x00000100) ;***Flag = STARTF_USESTDHANDLES (I think I set it correctly?) DllStructSetData($tSTARTUPINFO, "hStdOutput", $hNamedPipe) ;***Currently setting the output handle to the SERVER end of the NamePipe I'm creating (which I'm pretty sure is wrong but idk how to use the Client End) ;~~~code used by trancexx for CreateProcess Global $aCall = DllCall("kernel32.dll", "bool", "CreateProcessW", _ "wstr", $sExeModule, _ "wstr", $sCommandLine, _ "ptr", 0, _ "ptr", 0, _ "bool", true, _ ;***changed to inherit handles (not positive I did so correctly) was int 0 before "dword", 4, _ ; CREATE_SUSPENDED ; <- this is essential "ptr", 0, _ "ptr", 0, _ "ptr", DllStructGetPtr($tSTARTUPINFO), _ "ptr", DllStructGetPtr($tPROCESS_INFORMATION)) ;~~~~~Code used in a loop to try to see if anything is being written into the pipe If _IsPressed(35, $hDLL) Then Local $pipeData = _NamedPipes_PeekNamedPipe($hNamedPipe) If @Error Then MsgBox(1,"PipeData Error",@Error & " | " & $pipeData) Else Local $r = _ArrayDisplay($pipeData) If @Error Then MsgBox(1,"Array Error",@Error & " | " & $pipeData) EndIf EndIf  
      I'm not using this exact code cause I changed it around some for the post. I'm mainly wondering how to correctly use the client end of the name pipe? I also had some values I wasn't sure if I set correctly because I don't have experience with com objects. And It seems the process launched needs to be the child?.. Can the process started through the autoitscript can be considered the child process and the script the parent process?
       
      Guides I'm using for this:
      https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx
      https://support.microsoft.com/en-us/help/190351/how-to-spawn-console-processes-with-redirected-standard-handles
×