Re: RunCMD() v0.94 : Capture stdout to variable. Non-blocking version. Pre-process/omit individual lines.
Posted: 26 Feb 2022, 13:59
Let's help each other out
https://www.autohotkey.com/boards/
This function cannot be ported to V2 owing to a change done to FileObj.ReadLine()
Misinformation.
I've used RunTerminal (the v2 clone of your RunCMD) for a few things without noticing any issue, but due to luck and/or not paying enough attention it now seems. Do you have a short example script that shows how something goes wrong with RunTerminal() because of the v2 ReadLine() issue?
I didn't try the other code, but
Ok, yeah no linebreak chars. For example running this (which adds linebreak in the outside function)
Code: Select all
RunTerminal("ping 8.8.8.8 -n 20", , "UTF-8", PingToolTip)
PingToolTip(Line, LineNum, &PID) {
static Lines := ""
ToolTip(Lines .= Line "`n")
}
You're right, I'm sorry. Please delete my post above. I moved it to the RunTerminal thread instead.
Code: Select all
RunCMD(P_CmdLine, P_WorkingDir := "", P_Codepage := "CP0", P_Func := 0, P_Slow := 1)
{
; RunCMD Temp_v0.99 for ah2 By SKAN on D532/D67D @ autohotkey.com/r/?p=448912
Global G_RunCMD
If Not IsSet(G_RunCMD)
G_RunCMD := {}
G_RunCMD := {PID: 0, ExitCode: ""}
Local CRLF := Chr(13) Chr(10)
, hPipeR := 0
, hPipeW := 0
, PIPE_NOWAIT := 1
, HANDLE_FLAG_INHERIT := 1
, dwMask := HANDLE_FLAG_INHERIT
, dwFlags := HANDLE_FLAG_INHERIT
DllCall("Kernel32\CreatePipe", "ptrp",&hPipeR, "ptrp",&hPipeW, "ptr",0, "int",0)
, DllCall("Kernel32\SetHandleInformation", "ptr",hPipeW, "int",dwMask, "int",dwFlags)
, DllCall("Kernel32\SetNamedPipeHandleState", "ptr",hPipeR, "uintp",PIPE_NOWAIT, "ptr",0, "ptr",0)
Local B_OK := 0
, P8 := A_PtrSize=8
, STARTF_USESTDHANDLES := 0x100
, STARTUPINFO
, PROCESS_INFORMATION
PROCESS_INFORMATION := Buffer(P8 ? 24 : 16, 0) ; PROCESS_INFORMATION
, STARTUPINFO := Buffer(P8 ? 104 : 68, 0) ; STARTUPINFO
, NumPut("uint", P8 ? 104 : 68, STARTUPINFO) ; STARTUPINFO.cb
, NumPut("uint", STARTF_USESTDHANDLES, STARTUPINFO, P8 ? 60 : 44) ; STARTUPINFO.dwFlags
, NumPut("ptr", hPipeW, STARTUPINFO, P8 ? 88 : 60) ; STARTUPINFO.hStdOutput
, NumPut("ptr", hPipeW, STARTUPINFO, P8 ? 96 : 64) ; STARTUPINFO.hStdError
Local CREATE_NO_WINDOW := 0x08000000
, PRIORITY_CLASS := DllCall("Kernel32\GetPriorityClass", "ptr",-1, "uint")
B_OK := DllCall( "Kernel32\CreateProcessW"
, "ptr", 0 ; lpApplicationName
, "ptr", StrPtr(P_CmdLine) ; lpCommandLine
, "ptr", 0 ; lpProcessAttributes
, "ptr", 0 ; lpThreadAttributes
, "int", True ; bInheritHandles
, "int", CREATE_NO_WINDOW | PRIORITY_CLASS ; dwCreationFlags
, "int", 0 ; lpEnvironment
, "ptr", DirExist(P_WorkingDir) ? StrPtr(P_WorkingDir) : 0 ; lpCurrentDirectory
, "ptr", STARTUPINFO ; lpStartupInfo
, "ptr", PROCESS_INFORMATION ; lpProcessInformation
, "uint"
)
DllCall("Kernel32\CloseHandle", "ptr",hPipeW)
If Not B_OK
Return ( DllCall("Kernel32\CloseHandle", "ptr",hPipeR), "" )
G_RunCMD.PID := NumGet(PROCESS_INFORMATION, P8 ? 16 : 8, "uint")
Local FileObj
, Line := ""
, LineNum := 1
, sOutput := ""
, ExitCode := 0
FileObj := FileOpen(hPipeR, "h", P_Codepage)
, P_Slow := !! P_Slow
Sleep_() => (Sleep(P_Slow), G_RunCMD.PID)
While DllCall("Kernel32\PeekNamedPipe", "ptr",hPipeR, "ptr",0, "int",0, "ptr",0, "ptr",0, "ptr",0)
and Sleep_()
While G_RunCMD.PID and not FileObj.AtEOF
Line := FileObj.ReadLine()
, sOutput .= StrLen(Line)=0 and FileObj.Pos=0
? ""
: (
P_Func
? P_Func.Call(Line CRLF, LineNum++)
: Line CRLF
)
hProcess := NumGet(PROCESS_INFORMATION, 0, "ptr")
, hThread := NumGet(PROCESS_INFORMATION, A_PtrSize, "ptr")
, DllCall("Kernel32\GetExitCodeProcess", "ptr",hProcess, "ptrp",&ExitCode)
, DllCall("Kernel32\CloseHandle", "ptr",hProcess)
, DllCall("Kernel32\CloseHandle", "ptr",hThread)
, DllCall("Kernel32\CloseHandle", "ptr",hPipeR)
, G_RunCMD := {PID: 0, ExitCode: ExitCode}
Return RTrim(sOutput, CRLF)
}
Thank you.
Is that an issue?h ... Indicates that Filename is a file handle to wrap in an object ... Note that Seek, Pos and Length should not be used if Filename is a handle to a nonseeking device such as a pipe or a communications device.
Code: Select all
While Glob.RunCMD.PID and not FileObj.AtEOF
Sleep(-1)
, Chunks .= FileObj.Read(2)
, sOutput .= ( SubStr(Chunks,-1)="`n" && ( (Line := Chunks) && (Chunks := "") || 1) ) ; short-circuits
? (
P_Func
? P_Func.Call(Line, LineNum++)
: Line
)
: ""
I don't know. Doc also advises not to use FileObj.AtEOF with a pipe.neogna2 wrote: ↑02 Mar 2022, 06:49The pipe object code does FileObj.Pos=0 but https://lexikos.github.io/v2/docs/commands/FileOpen.htm#Flags saysIs that an issue?h ... Indicates that Filename is a file handle to wrap in an object ... Note that Seek, Pos and Length should not be used if Filename is a handle to a nonseeking device such as a pipe or a communications device.
In my tests, this will return right results when removing SetNamedPipeHandleState and adding `n. Invalid empty lines will not be read.SKAN wrote: ↑01 Mar 2022, 17:38@Finallf
@neogna2
Here is a temp version for V2
Code: Select all
code removed by SKAN
Code: Select all
cmd = vspipe --y4m "C:\i.vpy" - | ffmpeg -i pipe: -c:v libx264 -crf 19 "G:\o.mkv"
MsgBox, % RunCMD(cmd)
Code: Select all
Unknown argument: |