Sign in to follow this  
Followers 0
Hooch

Simple GUI wrapper for cmd.exe

15 posts in this topic

Heya folks,

As the topic suggests I am trying to provide a simple windows gui wrapper for the command line. The idea being to consolidate a procedure that involves 3-4 bat file operations into one central app that controls them.

More specific, I perform builds of a large java application using ANT and CruiseControl. I have a bat file for firing the main build process, one for a simple build that just does a compile with no deploy and another that fires up OC4J etc etc.

I want to create a central GUI that can fire these off and pipe the output from the bat file windows to a pretty edit control. Maybe provide some handy buttons to send some of the more common commands to the console.... that sort of thing.

So, I have been playing around with forum examples and so far I have this:

#include <GuiConstants.au3>
#include <Constants.au3>
GuiCreate("GUI")
$hEdit = GuiCtrlCreateEdit("", 5, 5, 300, )
$hInput = GUICtrlCreateInput("", 5,220)
GuiSetState()
$PID = Run(@ComSpec & " /c ping 2box", @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)

While 1
    $line = StdOutRead($PID) 
    
    While 1
        $line = StdoutRead($PID)    
        If @error = -1 Then ExitLoop        
        GUICtrlSetData($hEdit, $line, 1)        
    Wend
     
   $nMsg = GuiGetMsg()
   Select
      Case $nMsg = $GUI_EVENT_CLOSE
         ProcessClose($PID)
         Exit
   EndSelect
WEnd

The problem I currently have is that , in this example, after I get the output from the ping command the command line window process aborts with no message, no nothing.

I was hoping I could keep a console hidden and controlsend text commands to it to get more output back to the edit control.

Can anyone suggest what I am doing wrong?

Share this post


Link to post
Share on other sites



Hey, Hooch.

The things that I can see that would cause undesired results are:

While 1
    $line = StdOutRead($PID) 
    
    While 1
        $line = StdoutRead($PID)    
        If @error = -1 Then ExitLoop        
        GUICtrlSetData($hEdit, $line, 1)        
    Wend
;...
WEnd
There's the first call to StdoutRead with the output assigned to $line. Then before anything is done with anything that might have been read there's another call to StdoutRead with the output being assigned to $line, replacing and discarding the output of the first read.

The other thing that I see is more subtle, in that if you run a process with Run and then call StdoutRead on that process ID, then (assuming the STDOUT flag set in the fourth parameter to Run) the StdoutRead call doesn't return until there's something to read. If your script has a GUI component then it will appear that AutoIt has frozen because your GUI message loop (or events) are not being processed.

The way around this is to only try to read from STDOUT (or STDERR) if there's something there to read. You can do this by calling StdxxxRead with the the optional third "peek" parameter which tells it not to wait if there's nothing to be read.

Example:

#include <GuiConstants.au3>
#include <GuiConstants.au3>
#include <Constants.au3>
GuiCreate("GUI")
$hEdit = GuiCtrlCreateEdit("", 5, 5, 300, )
$hInput = GUICtrlCreateInput("", 5,220)
GuiSetState()
$PID = Run(@ComSpec & " /c ping 2box", @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)

While 1
  ; Check how many characters are waiting to be read
   $data = StdoutRead($PID, 0, 1)
   If $data Then
      While 1
         $line = StdoutRead($PID)
         If @error = -1 Then ExitLoop
         GUICtrlSetData($hEdit, $line, 1)
      Wend
   EndIf
   
   $nMsg = GuiGetMsg()
   Select
      Case $nMsg = $GUI_EVENT_CLOSE
         ProcessClose($PID)
         Exit
   EndSelect
WEnd

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

What is 2Box? Is this the name of another computer?

The example below may be helpful to you...$strcomputer = target computer.

RunWait(@ComSpec & " /C Ping -a -n 1 " & $strcomputer & "> Find_IP.txt",@MyDocumentsDir, @SW_HIDE)

I used switches with the Ping Command to only send one packet and resolve addresses to hostnames. I send the output to the Find_IP.txt file using the ">" symbol; The file is created on the fly or overwrites an existing one in "My Documents" folder.

Share this post


Link to post
Share on other sites

Yea 2box is just another box on my home network, the ping is just to test. I will actually be calling bat files later....

Share this post


Link to post
Share on other sites

Thanks for the replies guys, DaveF, your example runs great but if you change to @SW_SHOW you will see that the console window terminates once the ping command completes. I would like it to stay alive but hidden and maybe send text to it to gain further output.

Share this post


Link to post
Share on other sites

Change " /C" to "/K" in the line below...This will keep the console window open.

$PID = Run(@ComSpec & " /c ping 2box", @SystemDir, @SW_HIDE, $STDERR_CHILD + $STDOUT_CHILD)

Share this post


Link to post
Share on other sites

Tried the /k..... exact same results...

#include <GuiConstants.au3>
#include <GuiConstants.au3>
#include <Constants.au3>
GuiCreate("GUI")
$hEdit = GuiCtrlCreateEdit("", 5, 5, 300, )
$hInput = GUICtrlCreateInput("", 5,220)
GuiSetState()
$PID = Run(@ComSpec & " /k ping 2box", @SystemDir, @SW_SHOW, $STDERR_CHILD + $STDOUT_CHILD)

While 1
 ; Check how many characters are waiting to be read
   $data = StdoutRead($PID, 0, 1)
   If $data Then
      While 1
         $line = StdoutRead($PID)
         If @error = -1 Then ExitLoop
         GUICtrlSetData($hEdit, $line, 1)
      Wend
   EndIf
  
   $nMsg = GuiGetMsg()
   Select
      Case $nMsg = $GUI_EVENT_CLOSE
         ProcessClose($PID)
         Exit
   EndSelect
WEnd

Share this post


Link to post
Share on other sites

Can anyone else run that code and have the command window stay open? I just can't see why that process is being terminated.

Share this post


Link to post
Share on other sites

Seems to be related to the STD parameters. If you remove them, then the window will stay open.

Share this post


Link to post
Share on other sites

Works fine once I removed $STDERR_CHILD + $STDOUT_CHILD from the line.

Share this post


Link to post
Share on other sites

Works fine once I removed $STDERR_CHILD + $STDOUT_CHILD from the line.

<{POST_SNAPBACK}>

So do we want to call it a bug with stdout functions then? Can Jon or someone comment on whether that is intended behaivor?

Share this post


Link to post
Share on other sites

So do we want to call it a bug with stdout functions then? Can Jon or someone comment on whether that is intended behaivor?

I can comment.

I'm confess I'm not certain and haven't deeply pursued why the observed behavior occurs. I put the command line cmd /k c:\*.bat > foo.txt in a batch file and ran it. I got an apparently blank console window. I blindly typed a number of subsequent commands and the output of all the commands I typed into showed up in the foo.txt file.

However, when I ran this script:

Dim $output
; Redirecting STDOUT but not STDIN
$foo = Run(@Comspec & " /k dir c:\*.bat", @SystemDir, @SW_SHOW, 2)
MsgBox(0, "Debug", "Pause...")
While 1
    $output = $output & StdoutRead($foo)
    If @error = -1 Then ExitLoop
WEnd
MsgBox(0, "Debug", $output)

...I went to the open console window and paddled a number of commands (including exit) and got no response, though on the previous, batch-run file redirected test I could see the console window title change for each command run. I dismissed the "pause" MsgBox so that the AutoIt script would continue and it suspended before displaying the 2nd MsgBox, meaning that the console had no more output to be read, but that it hadn't written end-of-file, either. When I closed the console window the 2nd MsgBox immediately appeared (= AutoIt read EOF), but with only the output of the initial DIR command.

So, at the bottom of things, there's some disparity in the way that STDIN is handled for @COMSPEC /k depending whether it's spawned by the shell (a-la double-clicking a BAT file) or whether it's spawned from AutoIt. I acknowledge this.

However, this is only the case when AutoIt isn't managing STDIN itself.

Another code example:

Dim $output
; Run command providing STDIN and STDOUT
$foo = Run(@Comspec & " /k dir c:\*.bat", @SystemDir, @SW_SHOW, 3)
StdinWrite($foo, "netstat" & @CRLF)
StdinWrite($foo)

MsgBox(0, "Debug", "Pause...")

While 1
    $output = $output & StdoutRead($foo)
    If @error = -1 Then ExitLoop
WEnd

MsgBox(0, "Debug", $output)

In this example I get the output of both the initial command and the following NETSTAT command, and I see this as more of a practical example. Any subsequent commands would be written to the process with StdinWrite with the final aggregate output being read at the end.

For a more interactive command/response method I wouldn't use CMD /k at all; you can run as many commands with Run as you want and read and write to them as you will.

I don't see reason to pursue the issue above where STDIN is not redirected because I don't see any practical utility coming of it, but I'm open to discussion for other cases where the same issue might apply...

Cheers,

Dave


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

Thanks alot Dave, with your feedback I was able get something going in the manner that I was hoping for. I still have some problems but I can work them out. Thanks again!

Share this post


Link to post
Share on other sites

The only problem I can see with using seperate Run()'s is that you would have to keep track of the CWD yourself. Using a command such as "cd .." wouldn't be very practical, would it?

Share this post


Link to post
Share on other sites

The only problem I can see with using seperate Run()'s is that you would have to keep track of the CWD yourself. Using a command such as "cd .." wouldn't be very practical, would it?

You've the opportunity to declare a working directory every time you call Run; if you put the path in a variable at the head of the script you could just use it for the working dir on each call...

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