RunCMD() v0.97 : Capture stdout to variable. Non-blocking version. Pre-process/omit individual lines.
Re: RunCMD() v0.94 : Capture stdout to variable. Non-blocking version. Pre-process/omit individual lines.
SyncToy and many other folder syncing utilities appear to use it in the background if I'm not mistaken
EitherMouse - Multiple mice, individual settings . . . . www.EitherMouse.com . . . . forum . . . .
Re: RunCMD() v0.94 : Capture stdout to variable. Non-blocking version. Pre-process/omit individual lines.
Magnificent! Thank you for the streaming version SKAN.
Re: RunCMD() v0.94 : Capture stdout to variable. Non-blocking version. Pre-process/omit individual lines.
@SKAN
I can't thank you enough for this function!
Here is a short re-write compatible with AHK v2-a119. Haven't tested streaming yet. Just basic input / output is working on latest v2 alpha.
I can't thank you enough for this function!
Here is a short re-write compatible with AHK v2-a119. Haven't tested streaming yet. Just basic input / output is working on latest v2 alpha.
Code: Select all
RunCMD(CmdLine, WorkingDir:="", Codepage:="CP0", Fn:="RunCMD_Output") { ; RunCMD v0.94
Local ; RunCMD v0.94 by SKAN on D34E/D37C @ autohotkey.com/boards/viewtopic.php?t=74647
Global A_Args ; Based on StdOutToVar.ahk by Sean @ autohotkey.com/board/topic/15455-stdouttovar
Fn := IsFunc(Fn) ? Func(Fn) : 0
, DllCall("CreatePipe", "PtrP",hPipeR:=0, "PtrP",hPipeW:=0, "Ptr",0, "Int",0)
, DllCall("SetHandleInformation", "Ptr",hPipeW, "Int",1, "Int",1)
, DllCall("SetNamedPipeHandleState","Ptr",hPipeR, "UIntP",PIPE_NOWAIT:=1, "Ptr",0, "Ptr",0)
, P8 := (A_PtrSize=8)
, SI := BufferAlloc(P8 ? 104 : 68, 0) ; STARTUPINFO structure
, NumPut("UInt",P8 ? 104 : 68, SI) ; size of STARTUPINFO
, NumPut("UInt",STARTF_USESTDHANDLES:=0x100, SI, P8 ? 60 : 44) ; dwFlags
, NumPut("Ptr",hPipeW, SI, P8 ? 88 : 60) ; hStdOutput
, NumPut("Ptr",hPipeW, SI, P8 ? 96 : 64) ; hStdError
, PI := BufferAlloc(P8 ? 24 : 16) ; PROCESS_INFORMATION structure
If not DllCall("CreateProcess", "Ptr",0, "Str",CmdLine, "Ptr",0, "Int",0, "Int",True
,"Int",0x08000000 | DllCall("GetPriorityClass", "Ptr",-1, "UInt"), "Int",0
,"Ptr",WorkingDir ? StrPtr(WorkingDir) : 0, "Ptr",SI.ptr, "Ptr",PI.ptr)
Return Format("{1:}", "", ErrorLevel := -1
,DllCall("CloseHandle", "Ptr",hPipeW), DllCall("CloseHandle", "Ptr",hPipeR))
DllCall("CloseHandle", "Ptr",hPipeW)
, A_Args.RunCMD := { PID: NumGet(PI, P8? 16 : 8, "UInt") }
, File := FileOpen(hPipeR, "h", Codepage)
, LineNum := 1, sOutput := ""
While (A_Args.RunCMD.PID + DllCall("Sleep", "Int",0))
and DllCall("PeekNamedPipe", "Ptr",hPipeR, "Ptr",0, "Int",0, "Ptr",0, "Ptr",0, "Ptr",0)
While A_Args.RunCMD.PID and (Line := File.ReadLine())
sOutput .= Fn ? Fn.Call(Line, LineNum++) : Line
A_Args.RunCMD.PID := 0
, hProcess := NumGet(PI, 0, "Ptr")
, hThread := NumGet(PI, A_PtrSize, "Ptr")
, DllCall("GetExitCodeProcess", "Ptr",hProcess, "PtrP",ExitCode:=0)
, DllCall("CloseHandle", "Ptr",hProcess)
, DllCall("CloseHandle", "Ptr",hThread)
, DllCall("CloseHandle", "Ptr",hPipeR)
, ErrorLevel := ExitCode
Return sOutput
}
« AHK Portable Installer » | « CallTipsForAll » | « TheArkive AHK v1 Scripts » | « TheArkive AHK v2 Scrpts » | « TheArkive on GitHub »
Re: RunCMD() v0.94 : Capture stdout to variable. Non-blocking version. Pre-process/omit individual lines.
I'm happy too. It works fine at everything I so far have tested!
I guess I have to thank @Sam_ for motivating me to write this streaming version.
Here is a short re-write compatible with AHK v2-a119. Haven't tested streaming yet. Just basic input / output is working on latest v2 alpha.
Thank you. I will try and let know
Re: RunCMD()
My English is not good and I find it difficult to follow the event. Do we use this version as the streaming version. Is there a different version currently?My English is not good and I find it difficult to follow the event. Do we use this version as the streaming version. Is there a different version currently?SKAN wrote: ↑02 Jul 2020, 17:45Thank you.Sam_ wrote:This function is awesome! Thank you for sharing it.
Quickly written.. not well tested. I will try to post a proper demo later. (streaming to an edit control)Sam_ wrote:Will you pretty please also provide a streaming version?
Code: Select all
RunCmd_Stream(CmdLine, WorkingDir:="", Cp:="CP0") { ; v0.90 by SKAN on D34E/D373 Local ; @ tiny.cc/runcmd Global A_Args DllCall("CreatePipe", "PtrP",hPipeR:=0, "PtrP",hPipeW:=0, "Ptr",0, "UInt",0) , DllCall("SetHandleInformation", "Ptr",hPipeW, "UInt",1, "UInt",1) , P8 := (A_PtrSize=8), 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), pWorkingDir := (WorkingDir ? &WorkingDir : 0) 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:}", "", ErrorLevel := -1 , DllCall("CloseHandle", "Ptr",hPipeW) , DllCall("CloseHandle", "Ptr",hPipeR) ) DllCall("CloseHandle", "Ptr",hPipeW), A_Args.RunCMD := {"PID":NumGet(PI,P8?16:8,"UInt")} File := FileOpen(hPipeR, "h", Cp), Line := "" While (Line := File.ReadLine()) If not RunCmd_Output(Line, A_Index) Break A_Args.RunCMD.PID := 0, hProcess := NumGet(PI,0), hThread := NumGet(PI,4) , DllCall("GetExitCodeProcess", "Ptr",hProcess, "PtrP",ExitCode:=0) , DllCall("CloseHandle", "Ptr",hProcess), DllCall("CloseHandle", "Ptr",hThread) , DllCall("CloseHandle", "Ptr",hPipeR) Return ExitCode } ; Quick test follows: #NoEnv #Warn #SingleInstance, Force SetWorkingDir %A_ScriptDir% SetBatchLines -1 Process, Priority,,High RunCmd_Stream(A_Comspec . " /c Dir *.*", A_AhkPath . "\..\") SoundBeep Return ; end of auto-execute section RunCmd_Output(Line, LineNum) { Sleep 1 MsgBox % Line . "#" LineNum ;Return False ; Cancel Return True ; Continue }
Re: RunCMD()
hasantr wrote: ↑16 Aug 2020, 09:43
My English is not good and I find it difficult to follow the event. Do we use this version as the streaming version. Is there a different version currently?My English is not good and I find it difficult to follow the event.
Do we use this version as the streaming version. Is there a different version currently?
No!.
Sorry for the confusion. I've marked this temp code (a blocking version) as Obsolete.
Please use the new RunCMD() posted at the beginning of this topic and also try the examples.
https://www.autohotkey.com/boards/viewtopic.php?t=74647
The new version is non-blocking and all the examples posted throughout this topic should work with it without any errors.
Re: RunCMD()
Thank you for the explanation. You are so kind.SKAN wrote: ↑16 Aug 2020, 10:26hasantr wrote: ↑16 Aug 2020, 09:43
My English is not good and I find it difficult to follow the event. Do we use this version as the streaming version. Is there a different version currently?My English is not good and I find it difficult to follow the event.
Do we use this version as the streaming version. Is there a different version currently?
No!.
Sorry for the confusion. I've marked this temp code (a blocking version) as Obsolete.
Please use the new RunCMD() posted at the beginning of this topic and also try the examples.
https://www.autohotkey.com/boards/viewtopic.php?t=74647
The new version is non-blocking and all the examples posted throughout this topic should work with it without any errors.
(a blocking version) What exactly does it mean. It shows if it's streaming.
I apologize for learning so hard.
Re: RunCMD()
URLDownloadToFile is a blocking function (command).
When you call this function from a GUI application, and say your net connection is too slow or the server is too busy,
then the GUI will become unresponsive (cannot be moved/will not redraw etc.) until the requested data is returned (or refused).
This is not a a big problem nowadays as internet has become very fast.
Here is an example showing how a GUI becomes nonresponsive when a synchronous function is in wait state.
Code: Select all
#NoEnv
#SingleInstance, Force
Gui, Add, Text,, This window will NOT move/minimize for 5 seconds
Gui, Show, w480 h240
DllCall("Sleep", "Int",5000) ; <== This is a blocking function
; Sleep, 5000 ; <== This is a non-blocking function (command)
GuiControl,,Static1, It's okay now!
If you wondering why I mentioned about URLDownloadToFile:
URLDownloadToFile uses InternetReadFile
and StdOutToVar variants use ReadFile
Both functions wait for data and during the wait period they block a GUI from receiving messages.
Whats new in RunCMD() is that I've flagged the pipe to not wait.
That is, when ReadFile is called, the pipe would return immediately whatever data it has, which most of the time would be empty.
For example: Say, something.exe outputs 6 lines
A blocking version RunCMD() would loop only 6 times (or less) but will block a GUI during the period it waits for data to arrive.
A non-blocking version of RunCMD() will loop thousands of times to check for data but will never block GUI messages.
Within Loop, I have used smallest possible Sleep: DllCall("Sleep", "Int",0) which does spike CPU to 25% on my Quad core machine.
If one needs to run it on a single core machine, change it to DllCall("Sleep", "Int",1)
Re: RunCMD()
Thank you very much for the lighting. I am grateful to you. The Autohotkey team is really great.SKAN wrote: ↑17 Aug 2020, 06:40URLDownloadToFile is a blocking function (command).
When you call this function from a GUI application, and say your net connection is too slow or the server is too busy,
then the GUI will become unresponsive (cannot be moved/will not redraw etc.) until the requested data is returned (or refused).
This is not a a big problem nowadays as internet has become very fast.
Here is an example showing how a GUI becomes nonresponsive when a synchronous function is in wait state.
Code: Select all
#NoEnv #SingleInstance, Force Gui, Add, Text,, This window will NOT move/minimize for 5 seconds Gui, Show, w480 h240 DllCall("Sleep", "Int",5000) ; <== This is a blocking function ; Sleep, 5000 ; <== This is a non-blocking function (command) GuiControl,,Static1, It's okay now!
If you wondering why I mentioned about URLDownloadToFile:
URLDownloadToFile uses InternetReadFile
and StdOutToVar variants use ReadFile
Both functions wait for data and during the wait period they block a GUI from receiving messages.
Whats new in RunCMD() is that I've flagged the pipe to not wait.
That is, when ReadFile is called, the pipe would return immediately whatever data it has, which most of the time would be empty.
For example: Say, something.exe outputs 6 lines
A blocking version RunCMD() would loop only 6 times (or less) but will block a GUI during the period it waits for data to arrive.
A non-blocking version of RunCMD() will loop thousands of times to check for data but will never block GUI messages.
Within Loop, I have used smallest possible Sleep: DllCall("Sleep", "Int",0) which does spike CPU to 25% on my Quad core machine.
If one needs to run it on a single core machine, change it to DllCall("Sleep", "Int",1)
Re: RunCMD() v0.94 : Capture stdout to variable. Non-blocking version. Pre-process/omit individual lines.
Even though I have set it as UTF-8, the characters still sound corrupt.
What's wrong?
What's wrong?
Code: Select all
RunCmd( A_Comspec . " /c dir /S /B /A:-D *.doc | findstr /V /I /C:""""\\Microsoft\\"""" /C:""""$Recycle.Bin"""" /C:""""\\Windows\\""""" , "D:\","UTF-8")
Re: RunCMD() v0.94 : Capture stdout to variable. Non-blocking version. Pre-process/omit individual lines.
Hi @hasantrhasantr wrote: ↑22 Sep 2020, 07:44Even though I have set it as UTF-8, the characters still sound corrupt.
What's wrong?
Code: Select all
RunCmd( A_Comspec . " /c dir /S /B /A:-D *.doc | findstr /V /I /C:""""\\Microsoft\\"""" /C:""""$Recycle.Bin"""" /C:""""\\Windows\\""""" , "D:\","UTF-8")
I don't understand that line, but cmd.exe supports unicode with /U parameter.
Ref: https://www.autohotkey.com/boards/viewtopic.php?p=323980#p323980
Re: RunCMD() v0.94 : Capture stdout to variable. Non-blocking version. Pre-process/omit individual lines.
Thanks SKAN for the answer.SKAN wrote: ↑23 Sep 2020, 03:02Hi @hasantrhasantr wrote: ↑22 Sep 2020, 07:44Even though I have set it as UTF-8, the characters still sound corrupt.
What's wrong?
Code: Select all
RunCmd( A_Comspec . " /c dir /S /B /A:-D *.doc | findstr /V /I /C:""""\\Microsoft\\"""" /C:""""$Recycle.Bin"""" /C:""""\\Windows\\""""" , "D:\","UTF-8")
I don't understand that line, but cmd.exe supports unicode with /U parameter.
Ref: https://www.autohotkey.com/boards/viewtopic.php?p=323980#p323980
This cmd line lists the exe files on the disk.
CMD doesn't have a character problem anyway. When I call it with Runcmd, there is a character problem. When I open cmd and execute the code with cmd everything seems to be fine.
I think I ran into an unanswered problem.
Re: RunCMD() v0.94 : Capture stdout to variable. Non-blocking version. Pre-process/omit individual lines.
From command prompt execute CHCP command.hasantr wrote:CMD doesn't have a character problem anyway
What is the active code page?
Re: RunCMD() v0.94 : Capture stdout to variable. Non-blocking version. Pre-process/omit individual lines.
UTF-8 Instead @just me found a solution.
https://www.autohotkey.com/boards/viewtopic.php?f=76&t=81309&start=20#p354492
Using it is definitely a solution.
CP1
Re: RunCMD()
rommmcek wrote: ↑13 May 2020, 19:13… Purely theoretically, this would perform more efficient:… I'll probably do the test in days to come.Code: Select all
While A_Args.RunCMD.PID * DllCall("ReadFile", "Ptr",hPipeR, "Ptr",&Buff, "UInt",4094, "PtrP",nSz, "UInt",0)
Not in days... it took months to get at least to some extent consistent results.
Test should be run with zero or with as little as possible running apps and certainly not inside RunCmd().
Code: Select all
SetBatchLines, -1
DllCall("QueryPerformanceFrequency", "Int64P", Freq), fact:=1000/Freq
a:= b:= 1, c:= dif:= 0
loop, 10100000 {
if (Mod(A_Index,2)>0) {
DllCall("QueryPerformanceCounter", "Int64P", cBf)
, a&&b? c++: ""
, DllCall("QueryPerformanceCounter", "Int64P", cAf)
, A_Index>100000? dif+= cAf-cBf: ""
} else {
DllCall("QueryPerformanceCounter", "Int64P", cBf)
, a*b? c++: ""
, DllCall("QueryPerformanceCounter", "Int64P", cAf)
, A_Index>100000? dif-= cAf-cBf: ""
}
}
MsgBox % c "`n" dif*fact
c:= dif:= 0
loop, 10100000 {
Mod(A_Index,2)>0
? (DllCall("QueryPerformanceCounter", "Int64P", cBf)
, a&&b? c++: ""
, DllCall("QueryPerformanceCounter", "Int64P", cAf)
, A_Index>100000? dif+= cAf-cBf: "")
: (DllCall("QueryPerformanceCounter", "Int64P", cBf)
, a*b? c++: ""
, DllCall("QueryPerformanceCounter", "Int64P", cAf)
, A_Index>100000? dif-= cAf-cBf: "")
}
MsgBox % c "`n" dif*fact
-
- Posts: 486
- Joined: 03 Dec 2018, 20:02
Re: RunCMD() v0.94 : Capture stdout to variable. Non-blocking version. Pre-process/omit individual lines.
Hi SKAN, do you know why the output string of RunCMD does not equal to the same string content?
Code: Select all
str1 := RunCMD(A_ComSpec . " /c echo SKAN")
msgbox % str1
msgbox % (str1 = "SKAN") ;0
Re: RunCMD() v0.94 : Capture stdout to variable. Non-blocking version. Pre-process/omit individual lines.
@william_ahk, try this code. There's apparently a carriage return in the stdout from 'echo'.
Regards, burque505
Code: Select all
#Include RunCmd.ahk
str1 := RunCMD(A_ComSpec . " /c echo SKAN")
str1 := RegExReplace(str1, "`r`n")
msgbox % str1
If (str1 == "SKAN")
msgbox Equal
else
msgbox %str1% Is Not Equal to SKAN
-
- Posts: 486
- Joined: 03 Dec 2018, 20:02
Return to “Scripts and Functions (v1)”
Who is online
Users browsing this forum: No registered users and 217 guests