Jump to content

Set $STDOUT_CHILD of already existing process.


Recommended Posts

As the title reads, if I already have a Command Prompt running how can I get the StdoutRead? As the helpfile mentions you need to call a Run function with the opt_flag  $STDOUT_CHILD (Get's the standard output stream of the child process) but I am hung up on retrieving that PID if it was not called with Run. This is for a dedicated server, and when launching the server via AutoIt, has no issues but if the server is already up and running it would be beneficial to recognize that and begin capturing the stream without having to shut the server down and relaunch it with AutoIt. Secondly, some exe's launch a command line after a quick splash screen or user input, therefore Run does not allow you to obtain the correct Child Process as another example of wanting to retrieve the Stream of an already running process.

I have looked through _WinAPI UDFs and found _WinAPI_GetParent but did not see anything for a Child (not that I believe this is the same thing anyways?). There must be a way?

I can retrieve the handle and process ID of the Console Window but it will not return any output with StdoutRead because to my understanding it is just a graphic window from the console stream.

Summary: Retrieve StdOutRead of an existing console application which was not called by AutoIt.

Edited by kjpolker
Link to post
Share on other sites

I know I have an option to highjack the text and paste it into my edit box but this is not the workaround I would like to use, if the above is achievable. It is very finicky, slow, and requires the command prompt window to enter focus.

Example:

#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiRichEdit.au3>

$Form1 = GUICreate("Output", 618, 290, 192, 124)
$Edit1 = _GUICtrlRichEdit_Create($Form1, "", 0, 0, 617, 289, BitOR($ES_AUTOVSCROLL,$WS_VSCROLL,$ES_MULTILINE,$ES_WANTRETURN))
GUICtrlSetData(-1, "")
GUISetState(@SW_SHOW)

HotKeySet("{F5}","getstream") ;Call function to get stream

$handle = ""

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

Func getstream()
    $aWinList = WinList("[REGEXPTITLE:(?i)(.*cmd.*)]") ;find first handle of cmd window
    If UBound($aWinList) = 0 Then
        Return
    Else
        $handle = $aWinList[1][1]
        _GUICtrlRichEdit_AppendText($Edit1, "Handle: " & $handle & @CRLF) ;write handle to RichEdit
        WinActivate($handle) ;cmd must be activated to get contents
        ControlSend($handle,"", "",  "! es{Enter}") ;brings up hidden menu to select and copy text. Alt+SPACE E S COPY
        $clip = ClipGet() ;Sets clipboard to variable
        _GUICtrlRichEdit_AppendText($Edit1, $clip & @CRLF) ;pastes clipboard
    EndIf
EndFunc

 

Link to post
Share on other sites

I have not, but after reading through it appears a lot of that is for capturing the set amount of characters or chunk of the console and storing that information. Unless I am wrong, my example above mimics that although not as fluently and silent. If there isn't a method or UDF to essentially intercept the Console Application and utilize StdoutRead then I will probably conclude a server restart is required if I want to utilize my program at all.

Link to post
Share on other sites

Food for thought, and I apologize if I should have just edited my post above to include this rather than comment new; but I am currently trying to understand what the $STDOUT_CHILD parameter is literally doing? So I can try and find a solution and do more research. Is it storing another value in the returned array of Run()? Is it setting the window properties of the STD I/O? Is it intercepting the I/O through a DLL call?

I started to think about why I couldn't open a ComSpec window within AutoIt , stream the output, close AutoIt program, reopen AutoIt program and reattach it to the PID? Once AutoIt is closed the comspec window is in limbo especially if hidden and there is no way to view the stream, even if a /k and @SW_SHOW are used. It's basically executing whatever was called and you must force close it and reopen it with AutoIt. I even tried looking through the AutoIt directory for the guts of the Run functions, but unfortunately it is a built in function and does not require a a dependency (#include) to look through. I really am trying here, not looking for a free handout.

Edited by kjpolker
Link to post
Share on other sites
  • 2 weeks later...
Link to post
Share on other sites
12 minutes ago, kjpolker said:

Thank you for the post! Although I am unfamiliar with C++ that looks very interesting and maybe I can learn from it and get myself into C++ with the example provided.

Those functions exist in autoit already.   

Just call this is probably the ticket.   https://www.autoitscript.com/autoit3/docs/functions/StdinWrite.htm

 

Pid can be had via getprocessid, or if it's an autoit script @autoitpid.  You can always build a process information structure or use the tool help snap in my signature. 

Link to post
Share on other sites

I am familiar with those functions but to my understanding, and testing you must relay the $STDIN_CHILD parameter with the run function in order to capture the steam and write to it. If the process was not called via AutoIt then you cannot intercept the STDIN/OUT of the child process (command window).

Link to post
Share on other sites
10 minutes ago, kjpolker said:

I am familiar with those functions but to my understanding, and testing you must relay the $STDIN_CHILD parameter with the run function in order to capture the steam and write to it. If the process was not called via AutoIt then you cannot intercept the STDIN/OUT of the child process (command ca

Can you write to the console? I only ask bc if you can then there's a problem with your implementation of the stdoutread function.   It does not block (or pause) to receive a message.  It won't even read the whole buffer so you basically have to call it continuously in a loop until you get the desired message.  

Creating a named pipe is the actual solution.   That's that it was made for remote connection communication. 

Link to post
Share on other sites
Posted (edited)
Quote

Creating a named pipe is the actual solution.   That's that it was made for remote connection communication. 

I am not certain what this statement is referencing but it sounds like the right track.

Essentially my tests have been to open up Command prompt window and interact with it (write to the console) while seeing if I can capture the output in a RichEdit GUI window. I get no results and I am certain I am attaching it to the correct PID, at least of the cmd.exe process running as I have referenced it to the task manager. That is where my small understanding comes into play of the console being a graphic display of input/output and is not the actual stream. The real world use I have is a dedicated server that shows input output of the status/backups/etc in a standard Command Window. Hope this helps.

P.S. I have not tried writing to the console via AutoIt, only Read what is already there.

Edited by kjpolker
Answered question
Link to post
Share on other sites

Create pipe won't work bc noone is listening for a message on the other side with your test.

Make a cui script that opens up console,  and THEN attempt to get the handle and write to it.  I believe the system kernel owns the command prompt window and you probably won't ever get access to it.  

Easy IPC is clipput clipget

Edited by markyrocks
Link to post
Share on other sites
Posted (edited)
#include <EditConstants.au3>
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiRichEdit.au3>

$Form1 = GUICreate("Output", 618, 290, 192, 124)
$Edit1 = _GUICtrlRichEdit_Create($Form1, "", 0, 0, 617, 289, BitOR($ES_AUTOVSCROLL,$WS_VSCROLL,$ES_MULTILINE,$ES_WANTRETURN))
GUICtrlSetData(-1, "")
WinSetOnTop($Form1, "", 1)
GUISetState(@SW_SHOW)

HotKeySet("{F5}","stream") ;Call function to get stream

$handle = ""

Run("cmd.exe")

While 1
    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
    EndSwitch
WEnd

Func stream()
    $aWinList = WinList("[REGEXPTITLE:(?i)(.*cmd.*)]") ;find first handle of cmd window
    If UBound($aWinList) = 0 Then
        Return
    Else
        $handle = $aWinList[1][1] ;obtain handle of first cmd.exe window
        $apid = WinGetProcess($handle) ;obtain PID of handle
        _GUICtrlRichEdit_AppendText($Edit1, "Handle: " & $handle & @CRLF) ;write handle to RichEdit
        _GUICtrlRichEdit_AppendText($Edit1, "PID: " & $apid & @CRLF) ;write PID to RichEdit
        StdinWrite($apid, "Ping 127.0.0.1") ;Writes to console or executes?
        $timer = TimerInit() ;begin timer
        Local $output = ""
        Do
            Sleep(100)
            $output = StdoutRead($apid)
            _GUICtrlRichEdit_AppendText($Edit1, @CRLF & $output) ;write stream to RichEdit
        Until TimerDiff($timer) > 5000 ;read stream until 5 seconds has passed
    EndIf
EndFunc

I know there are other ways to test but I had the majority of this available from previous tests so I changed it up to simply launch a console window and attempt to write/read. I get empty lines as a result. Is this what you had in mind and you expected it to fail as per your last sentence?

Edited by kjpolker
Link to post
Share on other sites
5 hours ago, kjpolker said:

I know there are other ways to test but I had the majority of this available from previous tests so I changed it up to simply launch a console window and attempt to write/read. I get empty lines as a result. Is this what you had in mind and you expected it to fail as per your last sentence?

I was kinda busy when i wrote the last reply.  I meant make a "dummy" script that all it does is start running and loop forever with a sleep in there so it doesn't hog the cpu

.  Then compile that script checking the box that says create CUI instead or GUI exe.  That means the program will open the console window automatically.  you can even have it echo a msg every few seconds or something.  Once you have a separate process running with a console use it to practice hooking into the running process.  the cmd prompt is a system process and not going to be easy to manipulate.  You don't even have to use the console you can just open a temp file mapped to memory and use that to send messages back and forth.  Let me see if I can make something happen with this.

Link to post
Share on other sites

  You could try using a dll call to ...https://docs.microsoft.com/en-us/windows/console/freeconsole

which would be as simple as.  This code is untested and barely checked for spelling, syntax etc

$res = DllCall("Kernel32.dll","bool","FreeConsole","none") 

if not isarray($res) or not $res[0] then exit ;failed

THEN you can attach to the second threads console . using...  https://www.autoitscript.com/autoit3/docs/libfunctions/_WinAPI_AttachConsole.htm. thats the best i got.

 

Edited by markyrocks
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
  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...