Jump to content
Sign in to follow this  
Seth28

The old Problem: How to control a dos-window

Recommended Posts

Seth28

Hello,

I know it is an known problem, but I can't manage it.

I want to control a dos window.

I send with AutoIt this command:

$foo=Run(@ComSpec & " /c " & 'command parameter parameter parameter, "",@SW_MAXIMIZE,$STDOUT_CHILD)

Here begins my first Problem:

I want to see the content of the box. But with @SW_Hide, I can't see the box. With @SW_Maximize I can see the box, but not the content.

The next problem is, that I want to react, when a certain text appears in the box.

A text like that can be: "Do you want to make this". When this text appears I want that AutoIT send "y" to the box.

Then a process begins. After that, a text appears like that: "Do you want to send?" then I want to send a "y" to the box.

Another process begins. Then I want to wait until this text appeas: "Finished" then I want to send "ENTER" to the box.

Then the box is closed.

How can I manage this?

I tried this:

$foo=Run(@ComSpec & " /c " & 'command parameter parameter parameter', "",@SW_MAXIMIZE,$STDOUT_CHILD)

While 1

$line=StdoutRead($foo)

FileWrite($file, $line)

If StringInStr($line, "Do you want to make") Then send ("n{ENTER}")

If StringInStr($line, "Do you want to send") Then send ("y{ENTER}")

If StringInStr($line, "Finished") Then send ("n{ENTER}") ExitLoop

WEnd

But this doesn't work!

Thank you very much!

Share this post


Link to post
Share on other sites
DaveF

Automating an app like this in an expect/respond fashion is more difficult than you'd think, because there's no guarantee that the output that you're expecting is written all at once. On one pass you might read "Congr" and on the next "atulations!", so if you're discarding previous output on every pass and testing your current output for the whole word you'll never see it. A solution is to use two or more loops, with criteria in each one judging when there's been enough output to test for the expected string, and then what input to send based on what is seen.

If words aren't inspiration enough I'll try to post an example script when I get a moment.


Yes yes yes, there it was. Youth must go, ah yes. But youth is only being in a way like it might be an animal. No, it is not just being an animal so much as being like one of these malenky toys you viddy being sold in the streets, like little chellovecks made out of tin and with a spring inside and then a winding handle on the outside and you wind it up grrr grrr grrr and off it itties, like walking, O my brothers. But it itties in a straight line and bangs straight into things bang bang and it cannot help what it is doing. Being young is like being like one of these malenky machines.

Share this post


Link to post
Share on other sites
Richard Robertson

When did you get the idea that "If StringInStr($line, "Finished") Then send ("n{ENTER}") ExitLoop" would work?

If statements when used on one line, call one command. You would use an If block instead.

If StringInStr($line, "Finished") Then

Send("n{ENTER}")

ExitLoop

EndIf

Share this post


Link to post
Share on other sites
Richard Robertson

Yes, ExitLoop accepts a parameter that denotes the number of loops to drop from. Which means you could screw up the whole script flow.

Share this post


Link to post
Share on other sites
Seth28

Okay, I tried this, but it doesn't work. Another problem ist, that I can't see the box control. I read, that this happens, because I send the content of the dos-box to a string.

Okay, I tired this:

$foo=Run(@ComSpec & " /c " & 'command parameter', "",@SW_MAXIMIZE,$STDOUT_CHILD)

sleep (5000)

While 1

$line=StdoutRead($foo)

FileWrite($file, $line)

If StringInStr($line, "Um abzubrechen oder") Then ExitLoop

WEnd

StdinWrite($foo, "n{ENTER}")

While 1

$line=StdoutRead($foo)

FileWrite($file, $line)

If StringInStr($line, "Um abzubrechen drücken") Then ExitLoop

WEnd

StdinWrite($foo, "y{ENTER}")

Thanks

Share this post


Link to post
Share on other sites
Seth28

Another idea is to use another dos-programm, not normal windows-used.

Have you got an idea of a dos emulater or something else, which can generate a Logfile?

Share this post


Link to post
Share on other sites
dabus

Try tee, that should generate a logfile from the output of a "dos"program...

Share this post


Link to post
Share on other sites
DaveF

Belated, promised example script.

; Declare our variables
Dim $ourApp, $ourOutput, $ourCmdline, $ourTest, $ourResult

; Randomly pick either the TIME or DATE command
; (so that we can have contrived, variable output for our example.)
If Random() < 0.5 Then
    $ourCmdline = @ComSpec & " /c TIME"
Else
    $ourCmdline = @ComSpec & " /c DATE"
EndIf

; Tell the user what command line we're using
MsgBox(64, "Debug  --  " & @ScriptName, "Using command line: " & $ourCmdline)

; Run the command line, with AutoIt managing the STDIN and STDOUT connections
$ourApp = Run($ourCmdline, @SystemDir, @SW_HIDE, 3)

; Test the child process's STDOUT for expected output using the _StdoutExpect
; function (defined below). The first parameter is the PID of the process
; we wish to read from, the second parameter is a group of substrings,
; seperated by |, that we would expect to see as possible output.
; In this example the substrings are the last few characters of the output
; of the DATE or TIME commands (in US English)).
$ourTest = _StdoutExpect($ourApp, "yy)|me:")

; Act according to the result of _StdoutExpect
If $ourTest = 0 Then
    $ourResult = "_StdoutExpect timed out waiting for output..."
ElseIf $ourTest = 1 Then
    $ourResult = "We saw output corresponding to the DATE command, acting accordingly..."
    ; Simply send ENTER and close the STDIN connection (for our example).
    StdinWrite($ourApp, @CRLF)
    StdinWrite($ourApp)
ElseIf $ourTest = 2 Then
    $ourResult = "We saw output corresponding to the TIME command, acting accordingly..."
    ; Simply send ENTER and close the STDIN connection (for our example).
    StdinWrite($ourApp, @CRLF)
    StdinWrite($ourApp)
EndIf

; Inform the user of our test result
MsgBox(64, "Debug  --  " & @ScriptName, $ourResult)


; _StdoutExpect ===============================================================
;
; Description:      Tests STDOUT of a child process for specific output within a timeout period
; Parameter(s):     $hOurProcess   - ID of child process to read from.
;                   $sOurExpected  - String of the possible expected output substrings, seperated
;                                     by the | character (by default).
;                   $iOurTimeout   - Time to wait for one of the substrings before giving up.
;                                     Defaults to 100.
;                   $sOurSeparator - Alternate seperator character, e.g. if your substrings have
;                                     the | character in them.
; Requirement(s):   None
; Return Value(s):  On Success     - Position in $sOurExpected of the substring that was found
;                                     (starting with 1).
;                   On Failure     - 0  and set @error to 1 if timeout period passed.
;
; Author(s):        DaveF
;
; Notes: Intended for use with AutoIt3 v3.2.12.0 and later
;        Default timeout of 100ms is probably too short for most apps
;        Only intended and appropriate for console apps that produce
;         regular, predictable output and then pause for input.
;===============================================================================

Func _StdoutExpect($hOurProcess, $sOurExpected, $iOurTimeout = 100, $sOurSeparator = "|")
    Local $iOurTimer, $sOurOutput, $asOurExpected
    ; Explode the expected substrings into a StringSplit array
    $asOurExpected = StringSplit($sOurExpected, $sOurSeparator)
    ; Record the time to test vs our tiumeout.
    $iOurTimer = TimerInit()
    ; Loop
    While 1
        ; Return empty-handed of the timeout has elapsed
        If TimerDiff($iOurTimer) > $iOurTimeout Then
            SetError(1)
            Return 0
        EndIf
        ; Read and save available output from STDOUT
        $sOurOutput &= StdoutRead($hOurProcess)
        ; Step through provided substrings and test vs output
        For $incr = 1 To $asOurExpected[0]
            If StringInStr($sOurOutput, $asOurExpected[$incr]) Then
                ; Found this substring, so return its index
                Return $incr
            EndIf
        Next
    WEnd
EndFunc

I've wrestled for a long time with the idea of creating a UDF for purposes like this, with the argument against being that using and learning such a UDF would be only marginally less complicated than writing a custom script for every need that arises.


Yes yes yes, there it was. Youth must go, ah yes. But youth is only being in a way like it might be an animal. No, it is not just being an animal so much as being like one of these malenky toys you viddy being sold in the streets, like little chellovecks made out of tin and with a spring inside and then a winding handle on the outside and you wind it up grrr grrr grrr and off it itties, like walking, O my brothers. But it itties in a straight line and bangs straight into things bang bang and it cannot help what it is doing. Being young is like being like one of these malenky machines.

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  

×

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.