RunCMD() v0.97 : Capture stdout to variable. Non-blocking version. Pre-process/omit individual lines.

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
Cerberus
Posts: 172
Joined: 12 Jan 2016, 15:46

Re: RunCMD()

21 Apr 2020, 22:08

@SKAN Ah, I'm sorry, I misunderstood: you were approaching the issue systematically. Thanks again.
User avatar
Cerberus
Posts: 172
Joined: 12 Jan 2016, 15:46

Re: RunCMD()

21 Apr 2020, 22:11

Perfect! I'm really looking forward to the next version now! Hoping Lexikos will find the time to approve of your addition soon (I'm assuming he has to).
burque505
Posts: 1731
Joined: 22 Jan 2017, 19:37

Re: RunCMD()

22 Apr 2020, 11:56

For what it's worth, I compiled AHK_L on Win10 with @HotKeyIt's fix, and ran a test on Win7 after copying over the executable.
Code:

Code: Select all

#Include RunCmd.ahk
msgbox % RunCmd("AutoHotkey-U64-10.exe /iLib NUL /ErrorStdOut " . "eurotest.ahk" . " 2>&1 |more", "", "UTF-8")
Result:

Code: Select all

C:\Users\burque505\Desktop\AHK\Command Prompt\Cerberus\eurotest.ahk (1) : ==> This line does not contain a recognized action.

     Specifically: €msgbox, This is a test of UTF-8 in error messages
Success, apparently.
Thank you very much for fixing this issue, @HotKeyIt, I hope your pull request gets incorporated! :bravo:

Regards,
burque505
User avatar
Cerberus
Posts: 172
Joined: 12 Jan 2016, 15:46

Re: RunCMD()

22 Apr 2020, 12:44

@burque505
Excellent, thank you for testing.
hasantr
Posts: 933
Joined: 05 Apr 2016, 14:18
Location: İstanbul

Re: RunCMD()

23 Apr 2020, 12:08

Thanks Skan you have updated a useful function that I have used too much.
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: RunCMD()

23 Apr 2020, 12:29

@hasantr

Just rename the function name in your working example. It should work.

Code: Select all

data := RunCMD("7za.exe e -so " chr(34) A_LoopFileFullPath chr(34) " content.xml")
My Scripts and Functions: V1  V2
hasantr
Posts: 933
Joined: 05 Apr 2016, 14:18
Location: İstanbul

Re: RunCMD()

23 Apr 2020, 14:23

SKAN wrote:
23 Apr 2020, 12:29
@hasantr

Just rename the function name in your working example. It should work.

Code: Select all

data := RunCMD("7za.exe e -so " chr(34) A_LoopFileFullPath chr(34) " content.xml")
It works now. Thanks.
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: RunCMD()

23 Apr 2020, 14:33

hasantr wrote:
23 Apr 2020, 14:23
It works now. Thanks.
:thumbup:
My Scripts and Functions: V1  V2
garry
Posts: 3740
Joined: 22 Dec 2013, 12:50

Re: RunCMD()

23 Apr 2020, 16:36

example with wget.exe , downloads a small mp3 file / script creates a folder >>> a_desktop . "\Downloads"
I can't see streaming in Edit (Ed1) , I see when finished
what is the differend between :
-Runwait,%var%
-RunCMD(var)

Code: Select all

#warn
#Noenv
setworkingdir,%a_scriptdir%
Gui,2:default
Gui,2: -DPIScale
Gui,2:color,black,black
Gui,2:Font,s12 cYellow,Lucida Console
setbatchlines,-1
DetectHiddenWindows On
wa:=A_screenwidth
ha:=A_screenHeight
xx:=100
;-------------------- test for WGET.exe --------------------------------
f1:="http://74.136.132.35/MUSIC/RHAPSODY/J/Johnny%20Horton/American%20Originals/02%20-%20North%20To%20Alaska.mp3"
SplitPath,f1, name, dir, ext, name_no_ext, drive
name:= URLdecode(name)
wget1  =%a_scriptdir%\wget.exe
 loop,%wget1%                                 ;- create shortpath
   SP1= %A_loopFileShortPath%
folderx2:= a_desktop . "\Downloads"
ifnotexist,%folderx2%
 filecreatedir,%folderx2%
f2  := folderx2 . "\" . name           ;- where file
VAR     =%sp1%  --output-document="%f2%" %f1%
;Runwait,%comspec% /k %var%
;exitapp
;----------------------------------------------------------------------
x:=(wa*1)/xx,y:=(ha*1)/xx,h:=(ha*3)/xx,w:=(wa*70)/xx
Gui,2:Add, Edit  , x%x%  y%y%   h%h%   w%w% vVAR ,%VAR%
x:=(wa*72)/xx,y:=(ha*1)/xx,h:=(ha*2.5)/xx,w:=(wa*5)/xx
Gui,2:Add, Button, x%x%  y%y%  w%w%  h%h%  gSTART1,Start
x:=(wa*1)/xx,y:=(ha*6)/xx,h:=(ha*50)/xx,w:=(wa*70)/xx
Gui,2:Add,Edit, x%x%   y%y%  h%h%  w%w% vED1 cYellow,
Gui,2:add,Text,x0 y0 w0 h0 vTT
x:=(wa*.1)/xx,y:=(ha*.1)/xx,h:=(ha*70)/xx,w:=(wa*80)/xx
Gui,2:Show, x%x% y%y% w%w% h%h% ,SendToDOS & Copy
GuiControl,2:Focus,TT
return
;----------------------------------------------
2Guiescape:
2Guiclose:
xx=wget.exe
process,exist,%xx%
pps:=errorlevel
if pps<>0
 Process, Close, %pid2%
exitapp
;----------------------------------------------
start1:
gui,2:submit,nohide
GuiControl,2:,ED1,
settimer,aa,on
;Runwait,%sp1% --output-document="%f2%" %f1% -o logfile.txt ,,hide,pid2
;Runwait,%var%,,hide,pid2
data:=""
data .= RunCMD(var)                     ;- <<<<<<<<<<<< SKAN OK
;settimer,aa,off
;GuiControl,2:,ED1,ENDED`nNow Start file = %name%
;try
;run,%f2%
return
;----------------------------------------------
aa:
gui,2:submit,nohide
;---------------------------------------------
;WinActivate ahk_pid %PID2%
;ClipBoard =
;send,^a{Enter}                      ;- <<< copy hidden DOS Windows-10 ( Runwait,%var%,,hide,pid2 )
;ClipWait
;GuiControl,2:,ED1,%Clipboard%
;sleep,100
;---------------------------------------------
; GuiControl,2: Focus,ed1
; sleep,100
; GuiControl,2:,ED1,%data%             ;<<< don't see streaming data
; ControlSetText,edit2,%data%,ahk_class AutoHotkeyGUI
xx=wget.exe
process,exist,%xx%
pps:=errorlevel
if (pps=0)
 {
 GuiControl,2: Focus,ed1
 sleep,100
 GuiControl,2:,ED1,%data%`n----------------- ENDED -------------`n
 sleep,100
 send, ^{end}
 settimer,aa,off
 data:=""
 try
 run,%f2%
 }
return
;------------------------- SKAN ------------------------------------------------------------------
;-https://www.autohotkey.com/boards/viewtopic.php?f=6&t=74647
RunCmd(CmdLine, WorkingDir:="", Cp:="CP0") { ; Thanks Sean!  SKAN on D34E @ tiny.cc/runcmd 
  Local P8 := (A_PtrSize=8),  pWorkingDir := (WorkingDir ? &WorkingDir : 0)                                                
  Local SI, PI,  hPipeR:=0, hPipeW:=0, Buff, sOutput:="",  ExitCode:=0,  hProcess, hThread
                   
  DllCall("CreatePipe", "PtrP",hPipeR, "PtrP",hPipeW, "Ptr",0, "UInt",0)
, DllCall("SetHandleInformation", "Ptr",hPipeW, "UInt",1, "UInt",1)
    
  VarSetCapacity(SI, P8? 104:68,0),      NumPut(P8? 104:68, SI)
, NumPut(0x100, SI,  P8? 60:44,"UInt"),  NumPut(hPipeW, SI, P8? 88:60)
, NumPut(hPipeW, SI, P8? 96:64)   

, VarSetCapacity(PI, P8? 24:16)               

  If not DllCall("CreateProcess", "Ptr",0, "Str",CmdLine, "Ptr",0, "UInt",0, "UInt",True
              , "UInt",0x08000000 | DllCall("GetPriorityClass", "Ptr",-1,"UInt"), "UInt",0
              , "Ptr",pWorkingDir, "Ptr",&SI, "Ptr",&PI )  
     Return Format( "{1:}", "" 
          , DllCall("CloseHandle", "Ptr",hPipeW)
          , DllCall("CloseHandle", "Ptr",hPipeR)
          , ErrorLevel := -1 )
  DllCall( "CloseHandle", "Ptr",hPipeW)

, VarSetCapacity(Buff, 4096, 0), nSz:=0   
  While DllCall("ReadFile",  "Ptr",hPipeR, "Ptr",&Buff, "UInt",4094, "PtrP",nSz, "UInt",0)
    sOutput .= StrGet(&Buff, nSz, Cp)

  hProcess := NumGet(PI, 0),  hThread := NumGet(PI,4)
, DllCall("GetExitCodeProcess", "Ptr",hProcess, "PtrP",ExitCode)
, DllCall("CloseHandle", "Ptr",hProcess),    DllCall("CloseHandle", "Ptr",hThread)
, DllCall("CloseHandle", "Ptr",hPipeR),      ErrorLevel := ExitCode  
Return sOutput  
}

URLdecode(str) {
   Loop
      If RegExMatch(str, "i)(?<=%)[\da-f]{1,2}", hex)
         StringReplace, str, str, `%%hex%, % Chr("0x" . hex), All
      Else Break
   Return, str
}
return
;======================== END SCRIPT wget.exe TEST ==========================
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: RunCMD()

23 Apr 2020, 16:55

garry wrote:I can't see streaming in Edit (Ed1) , I see when finished
This is not a streaming version. I didn't write one since no one asked for it.
Also: I don't remember how wget displays.. If it displays download progress on the same line
it isn't possible to capture with this function.
what is the differend between :
-Runwait,%var%
-RunCMD(var)
With RunWait console program outputs to stdout which can be redirected to a text file and read from it.
With RunCMD you get the text directly into a var avoiding a temp file creation.
Also, RunCMD can start the console utility with High process priority.
CPU intensive console apps like ffmpeg might benefit

:thumbup:
My Scripts and Functions: V1  V2
garry
Posts: 3740
Joined: 22 Dec 2013, 12:50

Re: RunCMD()

23 Apr 2020, 17:36

@SKAN, thank you for explanation , short summarized : not streaming version , see result when finished in a variable and it's better for CPU intensive programs ....
burque505
Posts: 1731
Joined: 22 Jan 2017, 19:37

Re: RunCMD()

23 Apr 2020, 18:20

@garry, I get the feeling from your example you might like TheArkive's CliSAK (CLI Swiss Army Knife) for it. It has a callback function that _may_ work with wget.exe, although I haven't tested it. The examples on the posting page are pretty comprehensive.
Regards,
burque505
garry
Posts: 3740
Joined: 22 Dec 2013, 12:50

Re: RunCMD()

24 Apr 2020, 01:58

@burque505, thank you , I'll try CliSAK , at the moment was playing with a dos-help script and RunCMD()
hasantr
Posts: 933
Joined: 05 Apr 2016, 14:18
Location: İstanbul

Re: RunCMD()

11 May 2020, 12:05

How can I interrupt after starting my work. If the process takes too long, I would like to be able to cancel it.
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: RunCMD()

11 May 2020, 23:40

Hi @hasantr,
Since there is no console involved in this method,
I can't imagine how to interrupt the process.
I will let know if I come up with a solution.

:)
My Scripts and Functions: V1  V2
User avatar
rommmcek
Posts: 1470
Joined: 15 Aug 2014, 15:18

Re: RunCMD()

12 May 2020, 03:25

@hasantr & @SKAN: This

Code: Select all

  While !GetKeyState("Pause", "P") && DllCall("ReadFile",  "Ptr",hPipeR, "Ptr",&Buff, "UInt",4094, "PtrP",nSz, "UInt",0)
    sOutput .= StrGet(&Buff, nSz, Cp)
seems to work…, however it will slow down the function a bit.
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

RunCMD() - Code updated

13 May 2020, 15:53

rommmcek wrote:GetKeyState("Pause", "P")
Thanks. :)
Works well.. but I feel uncomfortable to use it. I've updated the code to use the global A_Args array instead.
A_Args.RunCMD.PID will now contain the PID of the console process.
I'm not sure whether it will create a problem in a race condition.


@hasantr
Function updated.
You may call A_Args.RunCMD.PID := 0 from a hotkey or routine to exit gracefully... or
call Process, Close, % A_Args.RunCMD.PID to terminate.


If anyone needs a long running process to test the updated function, try this: MsgBox % RunCmd(A_Comspec . " /c Dir *.* /s", "C:")
My Scripts and Functions: V1  V2
User avatar
rommmcek
Posts: 1470
Joined: 15 Aug 2014, 15:18

Re: RunCMD()

13 May 2020, 19:13

Great! Purely theoretically, this would perform more efficient:

Code: Select all

While A_Args.RunCMD.PID
     * DllCall("ReadFile",  "Ptr",hPipeR, "Ptr",&Buff, "UInt",4094, "PtrP",nSz, "UInt",0)
But piping by itself might be slower then additional condition check...
I'll probably do the test in days to come.
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

Re: RunCMD()

14 May 2020, 00:20

rommmcek wrote:Great! Purely theoretically, this would perform more efficient:

Code: Select all

While A_Args.RunCMD.PID
     * DllCall("ReadFile",  "Ptr",hPipeR, "Ptr",&Buff, "UInt",4094, "PtrP",nSz, "UInt",0)
Very nice! I like it. :D. I might use it in my personal version.
rommmcek wrote:But piping by itself might be slower then additional condition check...
I'll probably do the test in days to come.
Please do. Thanks for your valuable feedback! :thumbup:
My Scripts and Functions: V1  V2

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: No registered users and 129 guests