AutoHotkey Community

It is currently May 27th, 2012, 1:01 am

All times are UTC [ DST ]




Post new topic Reply to topic  [ 56 posts ]  Go to page 1, 2, 3, 4  Next
Author Message
PostPosted: August 9th, 2008, 1:13 pm 
Offline

Joined: August 8th, 2008, 3:29 am
Posts: 121
This is ConsoleApps, the script previously known as RunRedStdio.

Retrieves the standard output (StdOut) of a program.
The functions included are:
    RunConsoleAppWait() Runs a program and returns its standard output when it exits.
    RunConsoleApp() Runs a program and returns immediately. The program's standard output can be retrieved using GetConsoleAppStdOut(). The return value of this function must be passed to the CloseConsoleAppHandle() function when no longer needed.
    GetConsoleAppStdOut() Retrieves the standard output of a program that was started using the RunConsoleApp() function.
    CloseConsoleAppHandle() Must be called to free resources allocated by calls to RunConsoleApp()
Here is an example using the RunConsoleAppWait() function:

SIMPLE EXAMPLE
Code:
MsgBox, % RunConsoleAppWait("cmd.exe /c echo Hello World.")


Here is an example using the RunConsoleApp() function:

REAL-TIME EXAMPLE
Code:
#NoEnv  ; Recommended for performance and compatibility with future AutoHotkey releases.
#Include ConsoleApps.ahk

;Create GUI window with an edit control to print the output.
Gui, Add, Edit, x15 y15 w460 h300 -Wrap ReadOnly hscroll vtxtStdout,
Gui, Show, w490 h330, Standard Input/Output Redirection Example

; Create the process
ConsoleAppHandle := RunConsoleApp("ConsoleApps_TestFile.bat -p nothing", A_ScriptDir)
; In reality, this function will never return with a ConsoleAppHandle value of 0, but
; it is good to check for this possibility in case future versions do return a value of
; 0 for failure.
if (ConsoleAppHandle == 0)
{
    MsgBox, Error running cmd.exe
    ExitApp
}

/* Continuously retrieve the process's output and write it to the edit control
 * in a loop as it arrives.
 */
Loop
{
    ; Append the ConsoleApps standard output to StdOut.
    ConsoleAppStillRunning := GetConsoleAppStdOut(ConsoleAppHandle, StdOut, BytesAppended, ExitCode)
    ; If StdOut was appended with new text, write it to the GUI window.
    if (BytesAppended)
       GuiControl, , txtStdOut, %StdOut%  ; append the output to the edit control.
    ; If the ConsoleApp is no longer running, then stop checking for output.
    if (!ConsoleAppStillRunning)
       break
    ; Give up remainder of time-slice to give the child process a chance to generate more output
    ; before checking again.
    sleep 0
}
; This function must be called when the ConsoleAppHandle is no longer needed.
CloseConsoleAppHandle(ConsoleAppHandle)
if (!ExitCode)
    MsgBox, The program has completed successfully.
else
    MsgBox, The program has exitted with an error code of %ExitCode%.
return

; The following label is receives control when the user closes the GUI window.
GuiClose:
ExitApp


Here is the code for the latest version of the script:

http://www.autohotkey.net/~mark/ConsoleApps.2.1.1.zip

CHANGES
Version 2.1.1
    NEW: Script now initializes itself regardless of how it is loaded.
    Version 2.1
      FIX: Script can now initialize properly on startup when loaded as a library by calling the CONSOLEAPPS() function.
    Version 2.0
      NEW: Functions renamed to be loaded from as a library.
    Version 1.2
      FIX: Now correctly redirects the StdErr stream.
      DOC: Updated and revised documentation.
    Version 1.1
      DOC: Revised example code.

KNOWN ISSUES/RESOLUTION

ConsoleApps fails to capture error messages produced by applications.
CAUSE: This is caused by a bug in the design of the script, because of which output is not captured from the StdErr stream of the application.
RESOLUTION: Download and include version 1.2 of this script.


Last edited by drifter on March 9th, 2010, 4:31 am, edited 14 times in total.

Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: August 9th, 2008, 1:44 pm 
Very nice. Works well on Win98 and XP. I will have to do some comparisons to cmdret.ahk.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: August 10th, 2008, 1:01 am 
Thx. :D


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: January 3rd, 2010, 5:40 am 
I'm trying to change the directory by entering it or passing it as a variable to the RunRed function.

Code:
hRedProcess := RunRed("MyApp.exe arg1","C:\Documents and Settings\Uname\Desktop\Sub folder\bin")

; also no luck with..

hRedProcess := RunRed("MyApp.exe arg1",WorkingDir="C:\Documents and Settings\Uname\Desktop\Sub folder\bin")


I have to run the commandline application from the script directory or the system32 folder. All other configurations fail.

I've tried setworkingDir, changing to cmd.exe and adding a working directory, scriptDir, all with no luck.

So am I to assume I cannot pass directory and arguments as variables to the function?

Also is there no way to use RunWait for the function?

Some clarification please.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: January 3rd, 2010, 9:26 am 
Offline

Joined: August 8th, 2008, 3:29 am
Posts: 121
RunRed's failure to set the working directory is unintended behavior. Thank you for the bug report. I have updated the script in the first post. If you paste the new code into your current version of RedStdio, it should produce the behavior you expected. I am currently unable to test it, however, so let me know if it's still not working and I will take a closer look.

This function cannot be used with RunWait. However, the desired result can be achieved with the following code:

Code:
RedStdio_StdOutToVar(CmdLine, WorkingDir="")
{
   ;Create the process
   hRedProcess := RunRed(CmdLine, WorkingDir)
   if (hRedProcess == 0)
      return

   ;Retrieve the process's output and append it to the edit control in a loop.  Break when the process
   ;has closed.
   Loop
   {
      retv := GetChildStdout(hRedProcess, strStdout, BytesAppended)  ; append output of child process to strStdout
      if (BytesAppended)
         var := var . strStdout  ; append the output to the var
      if (retv == 1)
         return var  ; a return value of 1 indicates the process no longer exists.
      else if (retv >= 2)
      {
         MsgBox % "Unexpected error in RedStdio_StdOutToVar"
         RedStdioDestroy()
         return var
      }
      sleep 0  ; Give up remainder of time-slice to give the child process a chance to generate more output.
   }
}


Call the above function from within your code and it will return with the text the process sent to StdOut after it has finished executing. Again, I am not able to test it at this time, but if you have any trouble, let me know.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 3rd, 2010, 10:56 pm 
ImageThank you so much for the fast response!

drifter wrote:
RunRed's failure to set the working directory is unintended behavior. Thank you for the bug report. I have updated the script in the first post. If you paste the new code into your current version of RedStdio, it should produce the behavior you expected.
I'm surprised that no one else reported this (I was thinking it was just my syntax). Do I have to specify ,WorkingDir="" ? Correct me if I'm wrong but I also cannot pass variables to the parameters?

drifter wrote:
Call the above function from within your code and it will return with the text the process sent to StdOut
As I'm fairly new to using functions, I had a hard enough time figuring out the 1st one was strStdout.
Your saying in the case of this new 'RunWait' func, that I should replace strStdout with StdOut?

I will try everything out and let you know it goes.

Thanks again drifter for these functions and your continued support of them :)!


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: January 3rd, 2010, 11:21 pm 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
WorkingDir="..." in a function paramenter is a comparision, evaluated to 0 or 1. You need here ":=".


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 4th, 2010, 12:33 am 
Laszlo wrote:
WorkingDir="..." in a function paramenter is a comparision, evaluated to 0 or 1. You need here ":=".

:shock: What you said probably make total sense but you just lost me there..


I replaced the entire function with the update and again tried both:
Code:
hRedProcess := RunRed("MyApp.exe arg1","C:\Documents and Settings\Uname\Desktop\Sub folder\bin")

; also no luck with..

hRedProcess := RunRed("MyApp.exe arg1",WorkingDir="C:\Documents and Settings\Uname\Desktop\Sub folder\bin")
I still get the error message
Quote:
Unable to start MyApp.exe
So now I'm stumped and will have to resort to 1st moving/installing everything to the script dir, calling the function, then removing everything after parsing. Should not add too much to cycles and process times so it'l be a feasible alternative until this gets fully resolved.

I Will check back often as it still may just be the way I'm entering the dir.

Also thanks drifter for the RunWait function.
Can I just add its code to the main functions file? Or does it have to be in a certain place?

Anyway going to try that one now ;D


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: January 4th, 2010, 2:19 am 
Offline

Joined: August 8th, 2008, 3:29 am
Posts: 121
The first syntax will work fine for this situation:
Code:
hRedProcess := RunRed("MyApp.exe arg1","C:\Documents and Settings\Uname\Desktop\Sub folder\bin")

As opposed to the other syntax, which will not correctly pass the parameter:
Code:
hRedProcess := RunRed("MyApp.exe arg1",WorkingDir="C:\Documents and Settings\Uname\Desktop\Sub folder\bin")


The WorkingDir parameter specifies which directory the program will be running in, and not which directory the program is located. It is much like A_WorkingDir in AutoHotkey.

For example, the following code will look in your script directory for the file "MyApp.exe" and attempt to run it (passing "arg1" as a command line argument). Then, if successful, it will immediately set the new program's working directory to "C:\Documents and Settings\Uname\Desktop\Sub folder\bin":
Code:
hRedProcess := RunRed("MyApp.exe arg1","C:\Documents and Settings\Uname\Desktop\Sub folder\bin")

If you meant to look for the program in the "C:\Documents and Settings\Uname\Desktop\Sub folder\bin" folder, try this code instead:
Code:
hRedProcess := RunRed("C:\Documents and Settings\Uname\Desktop\Sub folder\bin\MyApp.exe arg1")

Also, as you can see, the WorkingDir parameter is optional and does not need to be specified.

Quote:
Can I just add its code to the main functions file?

I think adding the RunWait function to the main functions file would be very appropriate. Please, let me know if this does not solve your problem.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 4th, 2010, 4:05 am 
drifter wrote:
If you meant to look for the program in the "C:\Documents and Settings\Uname\Desktop\Sub folder\bin" folder, try this code instead:
Code:
hRedProcess := RunRed("C:\Documents and Settings\Uname\Desktop\Sub folder\bin\MyApp.exe arg1")

Also, as you can see, the WorkingDir parameter is optional and does not need to be specified.
I was somewhat aware that the parameters were optional but your clarification is much appreciated ;)!
I tried writing it the way you showed above (also before the update) and again its still giving me the error message :?.
Actually now only the original version of redstdio.ahk works, no matter what I write.
Hrm I'm now thoroughly confused.
I will go back to the original way I was thinking: Move the files into place, call the function, parse the data, remove the files.

drifter wrote:
I think adding the RunWait function to the main functions file would be very appropriate. Please, let me know if this does not solve your problem.
Sorry, I misinterpreted the code you supplied to resolve for RunWait as a function that I could just add to the original.
As you can see I still have a lot to learn!

Not to be a nuisance but its ideal for me to be able to run a command from any folder. I'm sure its probably something I'm doing but I haven't the faintest clue.

I will check back on this later.


Report this post
Top
  
Reply with quote  
 Post subject:
PostPosted: January 4th, 2010, 8:55 am 
Offline

Joined: February 14th, 2005, 4:05 pm
Posts: 4710
Location: Boulder, CO
drifter wrote:
...the other syntax, which will not correctly pass the parameter:
Code:
hRedProcess := RunRed("MyApp.exe arg1",WorkingDir="C:\Documents and Settings\Uname\Desktop\Sub folder\bin")
It does. The 2nd parameter is an expression, an x=y comparison of two strings: the content of the WorkingDir variable and the literal string "C:\Documents and Settings\Uname\Desktop\Sub folder\bin". Since WorkingDir has not been assigned a value, the two strings are not equal, therefore the comparison returns FALSE, which is 0. The calling syntax correctly passes the number 0 in the second parameter of the RunRed function.

If the intent was to pass an expression, to be dynamically evaluated, the second parameter has to be
Code:
"WorkingDir=C:\Documents and Settings\Uname\Desktop\Sub folder\bin"
If the intent was to pass the path, and also assign it to a variable, the second parameter has to be
Code:
WorkingDir := "C:\Documents and Settings\Uname\Desktop\Sub folder\bin"


If the 2nd parameter of the RunRed function is defined ByRef, the whole function call could be ignored in the current AHK version (which can be explained, but it is counterintuitive):
Code:
f(1,x=2) ; MsgBox shows '0'

f(a,x) {
   Msgbox %x%
}
but:
Code:
f(1,x=2) ; no MsgBox

f(a,ByRef x) {
   Msgbox %x%
}


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 7th, 2010, 3:26 am 
Offline

Joined: August 8th, 2008, 3:29 am
Posts: 121
Thank you for clarifying, Laszlo. When I said the other syntax will not correctly pass the parameter, I meant that it would not pass the string that he intended to pass.

Thank you for your posts, disFunc_tnl. Because you have taken interest in this script I have refactored the code with the following improvements:
    Increased reliability
    Better error reporting
    Improved readability
    Increased performance
    Additional functionality
    More meaningful documentation
    More meaningful file and function names
The documentation is in XML format (similar to Visual Studio's documentation format). This is to make the documentation machine readable. I recommend using this version over the previous version, as several bugs were eliminated from the previous version. Again, thank you for taking an interest in this script.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 7th, 2010, 8:57 am 
Offline

Joined: January 12th, 2007, 4:30 am
Posts: 531
Location: Norway
Can someone clarify the similarities/differences between this and cmdret?


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 8th, 2010, 3:44 am 
Offline

Joined: August 8th, 2008, 3:29 am
Posts: 121
To answer your question I reviewed CMDret and ran some performance tests. Here is what I've come up with:

Differences
    ConsoleApps reports an error and aborts the script if it is passed invalid input, whereas RunReturn and Stream (the CMDret scripts) return without indicating whether an error occurred.
    Stream sends the StdOut line-by-line to a user defined callback function named 'CMDret_Output', whereas RunConsoleApp returns immediately and the user calls GetConsoleAppStdOut to retrieve the StdOut.
    ConsoleApps appears to execute 1.4x faster than RunReturn and 2x faster than Stream on my PC.
    CMDret scripts are 5k in size each, whereas ConsoleApps is 22k in size.
Similarities
    RunReturn is similar to the RunConsoleAppWait function in ConsoleApps.
    Stream and RunConsoleApp both allow a user to process the StdOut as it comes through the stream.


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: January 8th, 2010, 8:37 am 
Offline

Joined: January 12th, 2007, 4:30 am
Posts: 531
Location: Norway
drifter: Thanks for the quick and concise clarification! So your script has superior error reporting and better performance at the cost of a few kbs, I'll definitely give this a try.


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 56 posts ]  Go to page 1, 2, 3, 4  Next

All times are UTC [ DST ]


Who is online

Users browsing this forum: Bing [Bot] and 6 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group