Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

CMDret - return output from console progs [DLL version]


  • Please log in to reply
175 replies to this topic
corrupt
  • Members
  • 2558 posts
  • Last active: Nov 01 2014 03:23 PM
  • Joined: 29 Dec 2004
Updated to version 3.1.2
- tweaked RunReturn function
- Added a new function (RunWEx) to allow StdInput, StdOutput, StdError

RunWEx(CMD, CMDdir, CMDin, CMDout, CMDerr)
- CMD - the console program/command to execute (str)
- CMDdir - Future Use (working directory - not currently functional) (str)
- CMDin - StdInput String (str)
- CMDout - the variable used to store StdOutput output (str)
- CMDerr - the variable used to store StdError output (str)
= If the function fails, the return value is zero

Please report any bugs if found. Comments, suggestions welcome...

Finstr.exe StdInput Example:
; cmdret - Findstr.exe test script (dll version 3.1.2 or greater required)
;
; RunWEx Function
; StdIn, StdOut

Gui, Add, Edit, x6 y10 w380 h150 vTextIn,  ;
Gui, Add, Edit, x6 y170 w270 h20 vFindit,  ;
Gui, Add, Button, x286 y170 w100 h20 +Default gGoFind, Find String
Gui, Show, h203 w399, findstr CMDret test
NULL=
CMDout=
CMDerr=
Return

GoFind:
Gui, Submit, NoHide
Findit = "%Findit%"
Findit := "findstr.exe /I /C:" Findit

Ret := RunWaitEx(Findit, NULL, TextIn, CMDout, CMDerr) 
MsgBox, Return Value: %Ret% `r`n`r`nStdError: `r`n%CMDerr%`r`nStdOutput: `r`n%CMDout%
Return

RunWaitEx(CMD, CMDdir, CMDin, ByRef CMDout, ByRef CMDerr)
{
  VarSetCapacity(CMDOut, 100000)
  VarSetCapacity(CMDerr, 100000) 
  RetVal := DllCall("cmdret.dll\RunWEx", "str", CMD, "str", CMDdir, "str", CMDin, "str", CMDout, "str", CMDerr)
  Return, %RetVal%
}


GuiClose:
ExitApp

Test script:
- Enter lines of text in the Edit control above
- Enter a search string in the Edit control below
- Click the 'Find String' button to retrieve results

:)

JBensimon
  • Members
  • 167 posts
  • Last active: May 08 2017 10:25 PM
  • Joined: 16 Nov 2004
corrupt, my hero! :D

This looks amazing -- I'll download the new version and play with the new function some time today and report back. As Chris said once before, your DLL is becoming irresistible!

Thanks for your efforts.

Jacques.

JBensimon
  • Members
  • 167 posts
  • Last active: May 08 2017 10:25 PM
  • Joined: 16 Nov 2004
Well, the new RunWEx function certainly works as advertised -- great job!

Question: Is the command line argument parsed in the same way as AHKparses the first RunWait argument? i.e. does it recognize the .exe extension as the end of the executable part (without the need for double-quotes) and whatever follows as the executable's command line parameters, or are double-quotes required around the executable's path when it contains spaces? [This question is the reason I was thinking of separating out the command line parameters as a separate function parameter, to avoid ambiguity without the need for double-quotes.]

Did you say something about making the DLL's code available? I'm still amazed at the small size of the DLL, even with its 4 separate functions :!: :?: :?:

Thanks again.

Jacques.

JBensimon
  • Members
  • 167 posts
  • Last active: May 08 2017 10:25 PM
  • Joined: 16 Nov 2004
Oh, one more question I forgot to ask:

What is the meaning of the RunWEx call's return value? It sometimes seems to reflect the size of the StdOut output, but you stated that 0 should be interpreted as some sort of failure. Is the launched command's exit code (ErrorLevel) lost?

Jacques.

corrupt
  • Members
  • 2558 posts
  • Last active: Nov 01 2014 03:23 PM
  • Joined: 29 Dec 2004
Sorry for the delayed response. ( hard drive issues :( again... )

corrupt, my hero! :D

This looks amazing -- I'll download the new version and play with the new function some time today and report back. As Chris said once before, your DLL is becoming irresistible!

Thanks for your efforts.

Jacques.

Thanks :)

Question: Is the command line argument parsed in the same way as AHKparses the first RunWait argument? i.e. does it recognize the .exe extension as the end of the executable part (without the need for double-quotes) and whatever follows as the executable's command line parameters, or are double-quotes required around the executable's path when it contains spaces?

AFAIK the command line argument should be compatible with the way you would run the program from a cmd prompt. Please let me know if anything doesn't work as expected.

Did you say something about making the DLL's code available? I'm still amazed at the small size of the DLL, even with its 4 separate functions :!: :?: :?:

Yes, that is planned for the near future :) . The current size could probably be reduced a bit more. Yes, the functions are currently separate. I have left them this way to allow easier modification and for backwards compatibility. This way I can add new functions for testing without affecting the stability of functions from a previous version.

What is the meaning of the RunWEx call's return value? It sometimes seems to reflect the size of the StdOut output, but you stated that 0 should be interpreted as some sort of failure. Is the launched command's exit code (ErrorLevel) lost?

At the moment it returns the number of characters returned in StdOut + characters in StdErr + 1 or 0 if the command line fails (nothing particularily useful...). GetLastError may give a bit more info if the return value is 0. I'll look into returning the exit code instead. Thanks.

corrupt
  • Members
  • 2558 posts
  • Last active: Nov 01 2014 03:23 PM
  • Joined: 29 Dec 2004
Note: only 32 bit console applications will currently work with the dll version of CMDret (v3.1.2 or lower). Calls that require command.com will likely not produce any output and may crash. The next version should hopefully fix this issue.

corrupt
  • Members
  • 2558 posts
  • Last active: Nov 01 2014 03:23 PM
  • Joined: 29 Dec 2004
Updated download: version 3.1.2
- Added cmdstub.exe to the download to support 16 bit console applications

; CMDret DLL version 3.1.2 (or greater) required
; cmdstub.exe required if using command.com 

 ret1 := CMDret("cmdstub.exe command.com /C set") 
 MsgBox, %ret1% 

CMDret(CMD) 
{ 
  VarSetCapacity(StrOut, 100000) 
  RetVal := DllCall("cmdret.dll\RunReturn", "str", CMD, "str", StrOut) 
  Return, %StrOut% 
}

; cmdret - Find.exe test script (dll version 3.1.2 or greater required) 
; Win9.x test - cmdstub.exe required
; 
; RunWEx Function 
; StdIn, StdOut 

Gui, Add, Edit, x6 y10 w380 h150 vTextIn,  ; 
Gui, Add, Edit, x6 y170 w270 h20 vFindit,  ; 
Gui, Add, Button, x286 y170 w100 h20 +Default gGoFind, Find String 
Gui, Show, h203 w399, find - CMDret test 
NULL= 
CMDout= 
CMDerr= 
Return 

GoFind: 
Gui, Submit, NoHide 
Findit = "%Findit%" 
Findit := "cmdstub.exe find.exe /I " Findit 

Ret := RunWaitEx(Findit, NULL, TextIn, CMDout, CMDerr) 
MsgBox, Return Value: %Ret% `r`n`r`nStdError: `r`n%CMDerr%`r`nStdOutput: `r`n%CMDout% 
Return 

RunWaitEx(CMD, CMDdir, CMDin, ByRef CMDout, ByRef CMDerr) 
{ 
  VarSetCapacity(CMDOut, 100000) 
  VarSetCapacity(CMDerr, 100000) 
  RetVal := DllCall("cmdret.dll\RunWEx", "str", CMD, "str", CMDdir, "str", CMDin, "str", CMDout, "str", CMDerr) 
  Return, %RetVal% 
} 


GuiClose: 
ExitApp
Test second script:
- Enter lines of text in the Edit control above
- Enter a search string in the Edit control below
- Click the 'Find String' button to retrieve results


Please let me know if any bugs are found using this method with Win9.x systems.

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Looks good. In case you ever need to have the variable's memory size unrestricted, the following approach should work:

1) The DLL allocates dynamic memory, enlarging as needed to fit the text it retrieves.

2) The DLL returns the address of that memory along with the length of its contents.

3) The script uses VarSetCapacity to set the indicated size, then uses lstrcpy() to copy the text from the address into the variable.

I forget exactly how dynamic memory works in DLLs: If the memory vanishes when the DLL is unloaded, you would have to go back to using LoadLibrary and FreeLibrary.

corrupt
  • Members
  • 2558 posts
  • Last active: Nov 01 2014 03:23 PM
  • Joined: 29 Dec 2004

Looks good. In case you ever need to have the variable's memory size unrestricted, the following approach should work:

1) The DLL allocates dynamic memory, enlarging as needed to fit the text it retrieves.

2) The DLL returns the address of that memory along with the length of its contents.

3) The script uses VarSetCapacity to set the indicated size, then uses lstrcpy() to copy the text from the address into the variable.

I forget exactly how dynamic memory works in DLLs: If the memory vanishes when the DLL is unloaded, you would have to go back to using LoadLibrary and FreeLibrary.

That sounds like it might work nicely with the RunRedirect function. Thanks :) . Another method that should currently work ok for programs/commands that should produce the same output if run twice in a row (but will take longer...) , would be to call the function without the string variables first then use the return value of the function to set the size of the string variable.
; CMDret DLL version 3.1.2 (or greater) required 
; cmdstub.exe required if using command.com 

 ret1 := CMDret("cmdstub.exe command.com /C set") 
 MsgBox, %ret1% 

CMDret(CMD) 
{ 
  RetVal := DllCall("cmdret.dll\RunReturn", "str", CMD, "str", "")
  VarSetCapacity(StrOut, %RetVal%) 
  RetVal := DllCall("cmdret.dll\RunReturn", "str", CMD, "str", StrOut)
  Return, %StrOut% 
}

Another method that should currently work ok if the return size is unknown would be to use the RunInControl function to output to and edit style control (optionally hidden). If a RichEdit control is used (and Extended) a couple of Gig of output should be possible :) .

JBensimon
  • Members
  • 167 posts
  • Last active: May 08 2017 10:25 PM
  • Joined: 16 Nov 2004

... RichEdit control ...

There isn't a RichEdit control option in AutoHotkey GUIs, is there? I'd hate to have missed that capability (which would be great for "message of the day"-type applications, if it had a Read-Only option like Edit controls do, and many other purposes).

Jacques.

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Not yet, but it's on the list.

Rabiator
  • Members
  • 292 posts
  • Last active: Aug 29 2016 09:29 PM
  • Joined: 17 Apr 2005

AFAIK the command line argument should be compatible with the way you would run the program from a cmd prompt. Please let me know if anything doesn't work as expected.

Is it possible to get the errorlevel of a program called with RunWEx?

(I wrote a small console application that uses the RunWEx function of CMDRet, which works excellent. The program uses stderr and stdout to return status and values to the script, and RunWEx separates these streams, very well.
But my program should also run in the command line environment, which does not separate stderr and stdout - they get mixed. Therefore I'd like to return the status via errorlevel rather than via stderr.)

JBensimon
  • Members
  • 167 posts
  • Last active: May 08 2017 10:25 PM
  • Joined: 16 Nov 2004

my program should also run in the command line environment, which does not separate stderr and stdout - they get mixed

If you're running the program in the command line environment of Windows NT/2000/XP/2003, you can use the "2>" syntax to redirect error output and separate it from standard output, as in
Program parameters >StdOut.txt 2>StdErr.txt
Jacques.

corrupt
  • Members
  • 2558 posts
  • Last active: Nov 01 2014 03:23 PM
  • Joined: 29 Dec 2004

But my program should also run in the command line environment, which does not separate stderr and stdout - they get mixed. Therefore I'd like to return the status via errorlevel rather than via stderr.)

Returning errorlevel is planned (possibly next release). Thanks :) .

Rabiator
  • Members
  • 292 posts
  • Last active: Aug 29 2016 09:29 PM
  • Joined: 17 Apr 2005

my program should also run in the command line environment, which does not separate stderr and stdout - they get mixed

If you're running the program in the command line environment of Windows NT/2000/XP/2003, you can use the "2>" syntax to redirect error output and separate it from standard output, as in
Program parameters >StdOut.txt 2>StdErr.txt

Thanks for the hint! :idea: I am a Win98 dinosaur. :)

Returning errorlevel is planned (possibly next release). Thanks :) .

I'm looking forward to this. :D