Note: Development on this version has currently been discontinued. The current version of CMDret can be found here (dll version).
Stream - version 0.03 beta
RunReturn - version 1.10 beta
Here you will find AutoHotkey code based on cmdret.dll, provided as functions :!: instead of having to include the cmdret.dll file.
CMDret can be used to retrieve and store output from console programs in a variable without displaying the console window.
Although it's not directly included in AutoHotkey yet, the functionaility in cmdret.dll can be accomplished with AHK code. As time permits, I'll be porting other functions in cmdret.dll to AHK functions also. If anyone would like to contribute, please feel free to add, modify, make suggestions, report bugs, etc...
Please be aware: If you use these functions you do so at your own risk.
As changes are made I will continue to update the code in this post with the current versions. As updates can sometimes produce undesirable results, a zip file can be downloaded here that contains the current versions, previous versions and a changelog. A brief changelog will also be added at the end of this post.
Here's the current version of the CMDret_Stream Function. Either save as a separate file and use #Include or add to the end of an existing script. This function has been designed to be able to retrieve and display data as it would become available in a CMD window instead of having to wait until the command's process has completed.
; ****************************************************************** ; CMDret-AHK functions by corrupt ; ; CMDret_Stream ; version 0.03 beta ; Updated: Feb 19, 2007 ; ; CMDret code modifications and/or contributions have been made by: ; Laszlo, shimanov, toralf, Wdb ; ****************************************************************** ; Usage: ; CMDin - command to execute ; CMDname - type of output to process (Optional) ; WorkingDir - full path to working directory (Optional) ; ****************************************************************** ; Known Issues: ; - If using dir be sure to specify a path (example: cmd /c dir c:\) ; or specify a working directory ; - Running 16 bit console applications may not produce output. Use ; a 32 bit application to start the 16 bit process to receive output ; ****************************************************************** ; Additional requirements: ; - Your script must also contain a CMDret_Output function ; ; CMDret_Output(CMDout, CMDname="") ; Usage: ; CMDout - each line of output returned (1 line each time) ; CMDname - type of output to process (Optional) ; ****************************************************************** ; Code Start ; ****************************************************************** CMDret_Stream(CMDin, CMDname="", WorkingDir=0) { Global cmdretPID tcWrk := WorkingDir=0 ? "Int" : "Str" idltm := A_TickCount + 20 LivePos = 1 VarSetCapacity(CMDout, 1, 32) VarSetCapacity(sui,68, 0) VarSetCapacity(pi, 16, 0) VarSetCapacity(pa, 12, 0) Loop, 4 { DllCall("RtlFillMemory", UInt,&pa+A_Index-1, UInt,1, UChar,12 >> 8*A_Index-8) DllCall("RtlFillMemory", UInt,&pa+8+A_Index-1, UInt,1, UChar,1 >> 8*A_Index-8) } IF (DllCall("CreatePipe", "UInt*",hRead, "UInt*",hWrite, "UInt",&pa, "Int",0) <> 0) { Loop, 4 DllCall("RtlFillMemory", UInt,&sui+A_Index-1, UInt,1, UChar,68 >> 8*A_Index-8) DllCall("GetStartupInfo", "UInt", &sui) Loop, 4 { DllCall("RtlFillMemory", UInt,&sui+44+A_Index-1, UInt,1, UChar,257 >> 8*A_Index-8) DllCall("RtlFillMemory", UInt,&sui+60+A_Index-1, UInt,1, UChar,hWrite >> 8*A_Index-8) DllCall("RtlFillMemory", UInt,&sui+64+A_Index-1, UInt,1, UChar,hWrite >> 8*A_Index-8) DllCall("RtlFillMemory", UInt,&sui+48+A_Index-1, UInt,1, UChar,0 >> 8*A_Index-8) } IF (DllCall("CreateProcess", Int,0, Str,CMDin, Int,0, Int,0, Int,1, "UInt",0, Int,0, tcWrk, WorkingDir, UInt,&sui, UInt,&pi) <> 0) { Loop, 4 cmdretPID += *(&pi+8+A_Index-1) << 8*A_Index-8 Loop { idltm2 := A_TickCount - idltm If (idltm2 < 15) { DllCall("Sleep", Int, 15) Continue } IF (DllCall("PeekNamedPipe", "uint", hRead, "uint", 0, "uint", 0, "uint", 0, "uint*", bSize, "uint", 0 ) <> 0 ) { Process, Exist, %cmdretPID% IF (ErrorLevel OR bSize > 0) { IF (bSize > 0) { VarSetCapacity(lpBuffer, bSize+1, 0) IF (DllCall("ReadFile", "UInt",hRead, "Str", lpBuffer, "Int",bSize, "UInt*",bRead, "Int",0) > 0) { IF (bRead > 0) { IF (StrLen(lpBuffer) < bRead) { VarSetCapacity(CMcpy, bRead, 32) bRead2 = %bRead% Loop { DllCall("RtlZeroMemory", "UInt", &CMcpy, Int, bRead) NULLptr := StrLen(lpBuffer) cpsize := bread - NULLptr DllCall("RtlMoveMemory", "UInt", &CMcpy, "UInt", (&lpBuffer + NULLptr + 2), "Int", (cpsize - 1)) DllCall("RtlZeroMemory", "UInt", (&lpBuffer + NULLptr), Int, cpsize) DllCall("RtlMoveMemory", "UInt", (&lpBuffer + NULLptr), "UInt", &CMcpy, "Int", cpsize) bRead2 -- IF (StrLen(lpBuffer) > bRead2) break } } VarSetCapacity(lpBuffer, -1) CMDout .= lpBuffer bRead = 0 } } } } ELSE break } ELSE break idltm := A_TickCount LiveFound := RegExMatch(CMDout, "m)^(.*)", LiveOut, LivePos) If (LiveFound) SetTimer, cmdretSTR, 5 } cmdretPID= DllCall("CloseHandle", UInt, hWrite) DllCall("CloseHandle", UInt, hRead) } } StringTrimLeft, LiveRes, CMDout, %LivePos% If LiveRes <> Loop, Parse, LiveRes, `n { FileLine = %A_LoopField% StringTrimRight, FileLine, FileLine, 1 CMDret_Output(FileLine, CMDname) } StringTrimLeft, CMDout, CMDout, 1 cmdretPID = 0 Return, CMDout cmdretSTR: SetTimer, cmdretSTR, Off If (LivePosLast <> LiveFound) { FileLine = %LiveOut1% LivePos := LiveFound + StrLen(FileLine) + 1 LivePosLast := LivePos CMDret_Output(FileLine, CMDname) } Return }
Here's the current version of the CMDret_RunReturn function. Either save as a separate file and use #Include or add to the end of an existing script.
; ****************************************************************** ; CMDret-AHK functions ; version 1.10 beta ; ; Updated: Dec 5, 2006 ; by: corrupt ; Code modifications and/or contributions made by: ; Laszlo, shimanov, toralf, Wdb ; ****************************************************************** ; Usage: ; CMDin - command to execute ; WorkingDir - full path to working directory (Optional) ; ****************************************************************** ; Known Issues: ; - If using dir be sure to specify a path (example: cmd /c dir c:\) ; or specify a working directory ; - Running 16 bit console applications may not produce output. Use ; a 32 bit application to start the 16 bit process to receive output ; ****************************************************************** ; Additional requirements: ; - none ; ****************************************************************** ; Code Start ; ****************************************************************** CMDret_RunReturn(CMDin, WorkingDir=0) { Global cmdretPID tcWrk := WorkingDir=0 ? "Int" : "Str" idltm := A_TickCount + 20 CMsize = 1 VarSetCapacity(CMDout, 1, 32) VarSetCapacity(sui,68, 0) VarSetCapacity(pi, 16, 0) VarSetCapacity(pa, 12, 0) Loop, 4 { DllCall("RtlFillMemory", UInt,&pa+A_Index-1, UInt,1, UChar,12 >> 8*A_Index-8) DllCall("RtlFillMemory", UInt,&pa+8+A_Index-1, UInt,1, UChar,1 >> 8*A_Index-8) } IF (DllCall("CreatePipe", "UInt*",hRead, "UInt*",hWrite, "UInt",&pa, "Int",0) <> 0) { Loop, 4 DllCall("RtlFillMemory", UInt,&sui+A_Index-1, UInt,1, UChar,68 >> 8*A_Index-8) DllCall("GetStartupInfo", "UInt", &sui) Loop, 4 { DllCall("RtlFillMemory", UInt,&sui+44+A_Index-1, UInt,1, UChar,257 >> 8*A_Index-8) DllCall("RtlFillMemory", UInt,&sui+60+A_Index-1, UInt,1, UChar,hWrite >> 8*A_Index-8) DllCall("RtlFillMemory", UInt,&sui+64+A_Index-1, UInt,1, UChar,hWrite >> 8*A_Index-8) DllCall("RtlFillMemory", UInt,&sui+48+A_Index-1, UInt,1, UChar,0 >> 8*A_Index-8) } IF (DllCall("CreateProcess", Int,0, Str,CMDin, Int,0, Int,0, Int,1, "UInt",0, Int,0, tcWrk, WorkingDir, UInt,&sui, UInt,&pi) <> 0) { Loop, 4 cmdretPID += *(&pi+8+A_Index-1) << 8*A_Index-8 Loop { idltm2 := A_TickCount - idltm If (idltm2 < 10) { DllCall("Sleep", Int, 10) Continue } IF (DllCall("PeekNamedPipe", "uint", hRead, "uint", 0, "uint", 0, "uint", 0, "uint*", bSize, "uint", 0 ) <> 0 ) { Process, Exist, %cmdretPID% IF (ErrorLevel OR bSize > 0) { IF (bSize > 0) { VarSetCapacity(lpBuffer, bSize+1) IF (DllCall("ReadFile", "UInt",hRead, "Str", lpBuffer, "Int",bSize, "UInt*",bRead, "Int",0) > 0) { IF (bRead > 0) { TRead += bRead VarSetCapacity(CMcpy, (bRead+CMsize+1), 0) CMcpy = a DllCall("RtlMoveMemory", "UInt", &CMcpy, "UInt", &CMDout, "Int", CMsize) DllCall("RtlMoveMemory", "UInt", &CMcpy+CMsize, "UInt", &lpBuffer, "Int", bRead) CMsize += bRead VarSetCapacity(CMDout, (CMsize + 1), 0) CMDout=a DllCall("RtlMoveMemory", "UInt", &CMDout, "UInt", &CMcpy, "Int", CMsize) VarSetCapacity(CMDout, -1) ; fix required by change in autohotkey v1.0.44.14 } } } } ELSE break } ELSE break idltm := A_TickCount } cmdretPID= DllCall("CloseHandle", UInt, hWrite) DllCall("CloseHandle", UInt, hRead) } } IF (StrLen(CMDout) < TRead) { VarSetCapacity(CMcpy, TRead, 32) TRead2 = %TRead% Loop { DllCall("RtlZeroMemory", "UInt", &CMcpy, Int, TRead) NULLptr := StrLen(CMDout) cpsize := Tread - NULLptr DllCall("RtlMoveMemory", "UInt", &CMcpy, "UInt", (&CMDout + NULLptr + 2), "Int", (cpsize - 1)) DllCall("RtlZeroMemory", "UInt", (&CMDout + NULLptr), Int, cpsize) DllCall("RtlMoveMemory", "UInt", (&CMDout + NULLptr), "UInt", &CMcpy, "Int", cpsize) TRead2 -- IF (StrLen(CMDout) > TRead2) break } } StringTrimLeft, CMDout, CMDout, 1 Return, CMDout }
Recent Changes:
Stream - Version 0.03 beta
- Initial release
RunReturn - Version 1.10 beta
- Added the ability to specify the working directory (optional)
RunReturn - Version 1.09 beta
- bumped version to 1.09 since a fix was necessary to maintain functionality (Thanks Wdb, Chris - for the fix and update to the code posted )
- A VarSetCapacity line was added after a DllCall line to make it compatible with AutoHotkey v1.0.44.14 and later
RunReturn - Version 1.08 beta
- Fixed truncated output when output contained null characters (Thanks evl)
Enjoy