Sign in to follow this  
Followers 0
Hilary

Text blank with $STDOUT_CHILD

11 posts in this topic

Hi,

When I use the Run command with the $STDOUT_CHILD flag the text in the (DOS) window disappears from view and user input doesnt seem to be accepted. Is there any way to change this? I need the AutoIT script to be able to read the text and send some keystrokes, but then I need to return control to the user.

More details:

Im trying to write an AutoIT script which runs a program which brings up a DOS window. The program brings up a Please press any key to continue message then connects to a server and brings up a login screen. Id like the AutoIT script to log the user in, then return control to the user.

The problem I have is knowing when the login screen has come up. Using a Sleep command would be unreliable and there would be a risk that the login details get entered at the wrong time which could mean the user would be locked out. (The reason for the AutoIT script is to stop that problem happening when the user mistypes the password.)

Ive tried:

WinWaitActive ( "title" [, "text" [, timeout]] ) - this works for a DOS window, but only with the title. It doesnt seem to detect the text within the DOS window.

WinGetCaretPos() (to get the cursor position because when the cursor is in the middle of the window instead of at the top we know the login screen has appeared.) but this doesnt seem to work for a DOS window.

I think StdOutRead will work (havent been able to test properly yet as I dont have access to a test system yet, but it seems to work with cmd.exe). However, the problem with this is that when I use

Run(abc.exe, , $STDOUT_CHILD)

which I need in order to be able to use StdOutRead, it hides the text on the screen, so when the login is finished the user wont be able to see anything on the screen or type anything in. (When I tried it with an ordinary DOS window nothing I typed in showed or appeared to be recognised.)

It also seems WinWaitActive and WinWaitClose wont work when $STDOUT_CHILD flag is used. (I wanted to use WinWaitActive to wait for the window to appear initially and WinWaitClose to wait for the window to close before terminating the script otherwise when the script terminates the window closes straight away.) ProcessWait and ProcessWaitClose seem to work OK, though.

This is something like the code I have:

; Block user input
;BlockInput(1)

; Run exe (cmd.exe here for testing)
$PID = run("cmd.exe", "",@SW_MAXIMIZE, 2); , $STDOUT_CHILD)

;#comments-start
; Wait for window to appear before continuing.  If it doesn't appear, exit.
If ProcessWait($PID, 10) = 0 Then
    MsgBox(0, "Timeout", "Error - application has timed out.", 5)
    Exit
EndIf


; "Press any key to continue" - Continue to connect screen
Send("a")
Sleep(2000)
;#comments-end

;While 1
    $line = StdoutRead($PID)
;   If @error Then ExitLoop
    MsgBox(0, "STDOUT read:", $line)
;Wend

If StringInStr($line, "Login") Then
; Login details here:
    Send("12{Tab}abc{Enter}")
Else
    MsgBox(0, "Unable to Connect", "Unable to connect to server at this time")
;Exit
EndIf



; Allow user input again
;BlockInput(0)

ProcessWaitClose($PID)

Share this post


Link to post
Share on other sites



When you use StdOutRead, you are redirecting output from the screen to your script. This will make your Send()'s useless as the screen (command prompt) will not accept it AFAIK. You will need to look at using StdInWrite() to return a reply to cmd.exe.

With the above info, I consider you may need to reconsider your plan.

:whistle:

Share this post


Link to post
Share on other sites

When you use StdOutRead, you are redirecting output from the screen to your script. This will make your Send()'s useless as the screen (command prompt) will not accept it AFAIK. You will need to look at using StdInWrite() to return a reply to cmd.exe.

With the above info, I consider you may need to reconsider your plan.

:whistle:

Yes, I suspected I may have to use StdInWrite, and that shouldn't be a problem to change the script to do that.

However, the main issue is with regard to user input after the script has finished (or while the script is still running, because I think ending the script also ends the Run process, which is why I put in the ProcessWaitClose at the end).

Do you think it's possible to redirect output back to the screen (and input from the keyboard) in the current process so that a user can interact with it?

Share this post


Link to post
Share on other sites

Do you think it's possible to redirect output back to the screen (and input from the keyboard) in the current process so that a user can interact with it?

Changing redirection midway through it's life is not something that I have ever seen or learnt of. It is a child process of your script and can only continue while your script runs.

Share this post


Link to post
Share on other sites

#5 ·  Posted (edited)

Do you think it's possible to redirect output back to the screen (and input from the keyboard) in the current process so that a user can interact with it?

About these last two issues, it should be possible... I tried to find an example but then decided to try myself, since what I found quickly involved COM and I didn't want that. So I came up with this.,, What do you think?

; First create a file called c:\test.bat which contains something which takes some seconds, and then waits for user input.

FileDelete ("c:\test.bat") Then
FileWrite ("c:\test.bat","dir c:\windows\*.* /s /a > null"&@CRLF&"pause"&@CRLF&"exit") Then
If Not FileExists("c:\test.bat") Then
    MsgBox(0,"test","filewrite error")
    Exit
EndIf

; Run it and wait for some line like from the pause command, then send a key to the dos window
$command = Run(@ComSpec&' /c c:\test.bat',"",@SW_SHOW,3)  ;<-- 3 = handle to input AND handle to output, really useful here :)

$read = ""

Do
    If StdoutRead($command,1,True) Then
        $read = StdoutRead($command)
        If @error Then ExitLoop
        MsgBox(0,"test",$read)
        If Not StringInStr($read,"Druk op een toets om door te gaan. . .") Then $read = "" ; <-- Change for your language's exact output of 'pause'
    EndIf
Until $read <> ""

MsgBox(0,'test','the last 100 characters read: '&StringRight($read,100)) ; <-- this means that the pause output from the batchfile has actually been read, now to output last read stdout to screen

$key = InputBox("Enter a key to send to the pause command.","Enter a key to send to the pause command.","X") ; <-- now to input some keyboard user input back into the dos box

StdinWrite($command,$key)

MsgBox(0,"test"," all done, dos box should be gone ")

/edit: added comment

Edited by SadBunny

Roses are FF0000, violets are 0000FF... All my base are belong to you.

Share this post


Link to post
Share on other sites

MHz and SadBunny,

Many thanks for your replies.

MHz:

Changing redirection midway through it's life is not something that I have ever seen or learnt of. It is a child process of your script and can only continue while your script runs.

:-( StdoutRead was the only way I could see of reading the text in the window, and it needs to run as a child process for that, I think. But I'm new to AutoIt, so I wondered if there was another way. :-(

SadBunny, that's neat. I won't be able to try it out until I return to work on Wednesday.

The first "press any screen.." and the subsequent login screen would be handled without interaction from the user, but I guess I could use the MsgBox / InputBox to handle the interaction after that.

My worry, though, is that StdoutRead can't read all the output on the screen (I have already seen some messages this app sends which StdoutRead can't read) so I really would prefer it if the user could interact directly with the screen.

Share this post


Link to post
Share on other sites

My worry, though, is that StdoutRead can't read all the output on the screen (I have already seen some messages this app sends which StdoutRead can't read) so I really would prefer it if the user could interact directly with the screen.

It is use STDOutRead/StdInWrite or the old fashioned way of doing it manually. there is no miracles here that we can do above all with this Microsoft stuff other then follow their rules which they leave for us, sorry. :whistle:

But someone may have a better idea?

Share this post


Link to post
Share on other sites

#8 ·  Posted (edited)

I'm going to have a go with copying the text to the Clipboard:

$CopyScreen = "{ALTDOWN}{SPACE}{ALTUP}ES{ENTER}"

Send($CopyScreen)
$Count = 0
While StringInStr(clipget(), "WARNING") = False and $count < 10
    Sleep(500)
    $Count = $Count + 1
    Send($CopyScreen)
WEnd

I had thought this wouldn't work, but it may after all.

Edited by Hilary

Share this post


Link to post
Share on other sites

Have you looked at presenting your own console? Create the shell with SW_HIDE or SW_MINIMIZE, and the standard_i/o_flag = 7. Pop your own GUI with a big edit box in the middle of it, and as your loop reads STSOUT, copy it to your GUI. With some tweaking of your GUI (white text on black) you could even make it LOOK like the CMD shell console!

:shocked:


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

Have you looked at presenting your own console? Create the shell with SW_HIDE or SW_MINIMIZE, and the standard_i/o_flag = 7. Pop your own GUI with a big edit box in the middle of it, and as your loop reads STSOUT, copy it to your GUI. With some tweaking of your GUI (white text on black) you could even make it LOOK like the CMD shell console!

:shocked:

That's actually what I tried to do in my code... Present a Windows GUI way of showing dos box output, and then put the user input from also a Win GUI way back into the dos box... Seemed to work fine.

But Hilary said:

My worry, though, is that StdoutRead can't read all the output on the screen (I have already seen some messages this app sends which StdoutRead can't read) so I really would prefer it if the user could interact directly with the screen.

... so I guess that will not work because there is this spooky uncatcheable output. So probably the DOS app outputs stuff that Hilary needs but can't catch in some way. I wouldn't know how to fix that through Stdoutput stuff since I don't know how to create uncatcheable output :P

But, selecting & copying all text from the dos window is a neat idea. Seems to work just fine too. Only catch is that if there are multiple interactions you might need to discard old text from the total output to need the new input. But that could probably be solved by clever StringRight, StringInStr and StringLen use ;)

/Edit: I :( our old pal StringSplit too :sorcerer:

Edited by SadBunny

Roses are FF0000, violets are 0000FF... All my base are belong to you.

Share this post


Link to post
Share on other sites

But Hilary said:

... so I guess that will not work because there is this spooky uncatcheable output. So probably the DOS app outputs stuff that Hilary needs but can't catch in some way. I wouldn't know how to fix that through Stdoutput stuff since I don't know how to create uncatcheable output :(

Some of that "uncatcheable" text might be STDERR vice STDOUT. You have two choices:

1. Get a handle to the $STDERR_CHILD along with $STDOUT_CHILD and read it with StdErrRead() along with StdOutRead().

2. Use the optional DOS redirector '2>&1' to send STDERR to the STDOUT stream.

Outside of that, there shouldn't be anything "uncatcheable" from the console. Another possibility is that you are not making good use of the 'peek' option in StdOutRead() to make sure there is something to read:

$ProcID = Run($BatchFile & ' 2>&1', @TempDir, @SW_MINIMIZE, $STDOUT_CHILD) ; Redirects STDERR to STDOUT
$ConsoleData = ""

While 1
    $CharCount = StdOutRead($ProcID, 0, 1)
    If @error Then ExitLoop
    If $CharCount Then $ConsoleData &= StdoutRead($ProcID)
    Sleep(25)
Wend

MsgBox(64, "Console Data", $ConsoleData)

:shocked:


Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law

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  
Followers 0