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
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

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

Post by SKAN » 06 Mar 2022, 20:42

pond_pop wrote:
06 Mar 2022, 15:54
wow great~! :bravo:

but, i'm try to use this

Code: Select all

cmd = vspipe --y4m "C:\i.vpy" - | ffmpeg -i pipe: -c:v libx264 -crf 19 "G:\o.mkv"
MsgBox, % RunCMD(cmd)
and.. get this

Code: Select all

Unknown argument: |

have any hope?



@pond_pop

Maybe your cmd should start with cmd /c

pond_pop
Posts: 11
Joined: 04 Jun 2019, 08:01

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

Post by pond_pop » 07 Mar 2022, 00:46

SKAN wrote:
06 Mar 2022, 20:42
pond_pop wrote:
06 Mar 2022, 15:54
wow great~! :bravo:

but, i'm try to use this

Code: Select all

cmd = vspipe --y4m "C:\i.vpy" - | ffmpeg -i pipe: -c:v libx264 -crf 19 "G:\o.mkv"
MsgBox, % RunCMD(cmd)
and.. get this

Code: Select all

Unknown argument: |

have any hope?



@pond_pop

Maybe your cmd should start with cmd /c
wow thank, it's work now
:dance: :dance:

hasantr
Posts: 933
Joined: 05 Apr 2016, 14:18
Location: İstanbul

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

Post by hasantr » 14 Mar 2022, 14:45

Hello. I am using Runcmd to run an external script with AHKh.Exe. (Because I see that it reacts faster.) But the script causes constant CPU usage. CPU usage is normal when run with normal cmd command.
Any idea?
Thanks.

Code: Select all

ScriptfileH	:= A_ScriptDir . "\dizinizleAHKh.ahk" 
ExeFileH 		:= A_ScriptDir . "\WatchFileChangeAHKH.exe"
CombinScriptExe := Chr(34) . ExeFileH . Chr(34) . A_Space . Chr(34) . ScriptfileH . Chr(34)

;This option works fine.
;if(GetScriptPID(ScriptfileH) == "") 
;Run, %CombinScriptExe%,A_ScriptDir

;When I use it with Run Cmd, a heavy processor usage occurs. I can't see why.
if(GetScriptPID(ScriptfileH) == "")
RunCMD(CombinScriptExe,A_ScriptDir) ; Normal run ile çalıştırınca çok yavaş çalışıyor


;I also tried these commands but not the solution.
/*
Process, Close, % A_Args.RunCMD.PID
A_Args.RunCMD.PID := 0
*/

peameedo112
Posts: 6
Joined: 12 Feb 2020, 19:14

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

Post by peameedo112 » 01 Apr 2022, 04:40

I found the method for reading bytearray of png from ADB, but it reads very slowly...

Code: Select all

While (A_Args.RunCMD.PID + DllCall("Sleep", "Int", 1)) and DllCall("PeekNamedPipe", "Ptr",hPipeR, "Ptr",0, "Int",0, "Ptr",0, "Ptr",0, "Ptr",0) {
    While A_Args.RunCMD.PID {
        Line := File.ReadUChar()
        HEX := Format("{:02X}", Line)
        if (sOutput="" and Hex="00")
            Continue
        if (Line="")
            break
        sOutput .= Fn ? Fn.Call(HEX " ", LineNum++) : HEX " "
    }
}
Last edited by peameedo112 on 06 Apr 2022, 03:31, edited 1 time in total.

gianozdp
Posts: 8
Joined: 29 Feb 2020, 23:36

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

Post by gianozdp » 05 Apr 2022, 01:42

Many many thanks to your great work!

teadrinker
Posts: 4309
Joined: 29 Mar 2015, 09:41
Contact:

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

Post by teadrinker » 06 Apr 2022, 02:15

SKAN wrote:

Code: Select all

While A_Args.RunCMD.PID and (Line := File.ReadLine())
What if Line is "0" ?

sanmaodo
Posts: 45
Joined: 28 Aug 2020, 01:39

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

Post by sanmaodo » 17 May 2022, 03:54

How to run RunCMD as administrator ?
I want to execute mklink with it .

sanmaodo
Posts: 45
Joined: 28 Aug 2020, 01:39

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

Post by sanmaodo » 18 May 2022, 07:59

Find an approach that works .

Code: Select all

if !A_IsAdmin
Run, *RunAs "%A_ScriptFullPath%" /restart

hughman
Posts: 18
Joined: 17 Jun 2014, 09:39

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

Post by hughman » 20 May 2022, 20:02

it's better to add a parameter for timeout to prevent from endless loop.
becuase I found some cmd about network will be blocked if can't connect.

sanmaodo
Posts: 45
Joined: 28 Aug 2020, 01:39

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

Post by sanmaodo » 25 May 2022, 10:38

How can I get complete feedback information like cmd ?
clip.jpg
clip.jpg (522.54 KiB) Viewed 4064 times

blue83
Posts: 157
Joined: 11 Apr 2018, 06:38

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

Post by blue83 » 02 Jun 2022, 06:02

Hi @SKAN ,

Can you help me with wait function, I mean how to wait RunCMD for lets say 10 seconds and if is not finished than close it and give msgbox that something is wrong, if is under 10s than everything is fine and script can continue.

Thanks,
blue

robodesign
Posts: 934
Joined: 30 Sep 2017, 03:59
Location: Romania
Contact:

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

Post by robodesign » 05 Aug 2022, 04:11

@blue83

I added what you requested.

Code: Select all

Cli_RunCMD(CmdLine, WorkingDir:="", Codepage:="CP850", Fn:="RunCMD_Output", maxDelay:=15250) {
; modified by Marius Șucan
  Local         ; RunCMD v0.94 by SKAN on D34E/D37C @ https://www.autohotkey.com/boards/viewtopic.php?t=74647                                                             
  Global A_Args ; Based on StdOutToVar.ahk by Sean @ https://www.autohotkey.com/board/topic/15455-stdouttovar

  Fn := IsFunc(Fn) ? Func(Fn) : 0
  r := DllCall("CreatePipe", "UPtr*",hPipeR:=0, "UPtr*",hPipeW:=0, "UPtr",0, "Int",0)
  If (r=0 || r="")
     Return

  DllCall("SetHandleInformation", "UPtr",hPipeW, "Int",1, "Int",1)
  DllCall("SetNamedPipeHandleState","UPtr",hPipeR, "UInt*",PIPE_NOWAIT:=1, "UPtr",0, "UPtr",0)

  P8 := (A_PtrSize=8) ? 1 : 0
  VarSetCapacity(SI, P8 ? 104 : 68, 0)                          ; STARTUPINFO structure      
  NumPut(P8 ? 104 : 68, SI)                                     ; size of STARTUPINFO
  NumPut(STARTF_USESTDHANDLES:=0x100, SI, P8 ? 60 : 44,"UInt")  ; dwFlags
  NumPut(hPipeW, SI, P8 ? 88 : 60)                              ; hStdOutput
  NumPut(hPipeW, SI, P8 ? 96 : 64)                              ; hStdError
  VarSetCapacity(PI, P8 ? 24 : 16)                              ; PROCESS_INFORMATION structure
  g := DllCall("GetPriorityClass", "UPtr",-1, "UInt")
  r := DllCall("CreateProcess", "UPtr",0, "Str",CmdLine, "UPtr",0, "Int",0, "Int",1
            ,"Int",0x08000000 | g, "Int",0
            ,"UPtr",WorkingDir ? &WorkingDir : 0, "UPtr",&SI, "UPtr",&PI)

  If (r=0 || r="")
  {
     z := ErrorLevel "|" A_LastError
     DllCall("CloseHandle", "UPtr",hPipeW)
     DllCall("CloseHandle", "UPtr",hPipeR)
     Return ; z
  }

  DllCall("CloseHandle", "UPtr",hPipeW)
  PIDu := NumGet(PI, P8? 16 : 8, "UInt")
  A_Args.RunCMD := {"PID": PIDu}
  FileObj := FileOpen(hPipeR, "h", Codepage)
  startTime := A_TickCount
  LineNum := 1,  sOutput := ""
  timeOut := 0
  While ((A_Args.RunCMD.PID + DllCall("Sleep", "Int",0)) && DllCall("PeekNamedPipe", "UPtr",hPipeR, "UPtr",0, "Int",0, "UPtr",0, "UPtr",0, "UPtr",0))
  {
       If (A_TickCount - startTime>maxDelay)
       {
          timeOut := 1
          Break
       }
       While (A_Args.RunCMD.PID and (Line := FileObj.ReadLine()))
       {
            sOutput .= Fn ? Fn.Call(Line, LineNum++) : Line
            If (A_TickCount - startTime>maxDelay)
            {
               timeOut := 1
               Break
            }
       }
  }

  If (timeOut=1)
  {
     SoundBeep 300, 100
     Process, Close, % PIDu
  }

  A_Args.RunCMD.PID := 0
  hProcess := NumGet(PI, 0)
  hThread  := NumGet(PI, A_PtrSize)

  DllCall("GetExitCodeProcess", "UPtr",hProcess, "UPtr*",ExitCode:=0)
  DllCall("CloseHandle", "UPtr",hProcess)
  DllCall("CloseHandle", "UPtr",hThread)
  DllCall("CloseHandle", "UPtr",hPipeR)
  FileObj.Close()
  ErrorLevel := ExitCode
  Return sOutput
}

MaxDelay is in miliseconds. It will stop the execution after the delay you set.

Best regards, Marius.
-------------------------
KeyPress OSD v4: GitHub or forum. (presentation video)
Quick Picto Viewer: GitHub or forum.
AHK GDI+ expanded / compilation library (on GitHub)
My home page.

ozzii
Posts: 481
Joined: 30 Oct 2013, 06:04

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

Post by ozzii » 05 Aug 2022, 23:44

Thank you Marius, this can be helpful.


william_ahk
Posts: 481
Joined: 03 Dec 2018, 20:02

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

Post by william_ahk » 19 Oct 2022, 02:15

Is it possible to continuously write stdin to the same process? For example to the python interpreter. I've looked around the forum but couldn't find any relevant code about this.

tester
Posts: 84
Joined: 10 Jun 2021, 23:03

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

Post by tester » 19 Oct 2022, 23:14

Very nice function. Thank you.

It would be great if the callback parameter accepts a bound function created with ObjBindMethod().

tester
Posts: 84
Joined: 10 Jun 2021, 23:03

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

Post by tester » 21 Oct 2022, 02:17

I'm just reporting that while A_Args.RunCMD.PID := 0 makes the callback function return, it doesn't close the console process.

Code: Select all

#Persistent
msgbox % RunCMD( "ping www.google.com -t",,, "log" )
log( sLine, iLineNum ) {
    Tooltip, % iLineNum ": " sLine
    FileAppend, % "[" A_Year "-" A_MM "-" A_DD " " A_Hour ":" A_Min ":" A_Sec "] [" A_Args.RunCMD.PID "] " iLineNum ": " sLine, % A_ScriptDir "\test.log"
    if ( iLineNum >= 10 ) {
        A_Args.RunCMD.PID := 0 ; cancel
        ; Process, Close, % A_Args.RunCMD.PID   ; <-- without this PING.exe doesn't exit
    }
    return sLine
}


Is there a way to send ^c to the console program?

MrDoge
Posts: 151
Joined: 27 Apr 2020, 21:29

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

Post by MrDoge » 22 Oct 2022, 23:07

william_ahk wrote:
19 Oct 2022, 02:15
Is it possible to continuously write stdin to the same process? For example to the python interpreter. I've looked around the forum but couldn't find any relevant code about this.

Code: Select all

#SingleInstance force
ListLines 0
KeyHistory 0
SendMode "Input" ; Recommended for new scripts due to its superior speed and reliability.
SetWorkingDir A_ScriptDir ; Ensures a consistent starting directory.


f3::Exitapp

StrBuf(str, encoding)
{
    ; Calculate required size and allocate a buffer.
    buf := Buffer(StrPut(str, encoding))
    ; Copy or convert the string.
    StrPut(str, buf, encoding)
    return buf
}

class ChildProcess {
    static counter:=0

    __New(CmdLine, WorkingDir:="") { ;from zig : std.ChildProcess.exec() : https://github.com/ziglang/zig/blob/4624c818991f161fc6a7021119e4d071b6e40e6c/lib/std/child_process.zig#L373
        ChildProcess.counter++
        pipe_path:="\\.\pipe\ahk-childprocess-" DllCall("GetCurrentProcessId") "-" ChildProcess.counter

        saAttr:=Buffer(24)
        NumPut("Uint",saAttr.Size,saAttr,0) ;nLength
        NumPut("Ptr",0,saAttr,8) ;lpSecurityDescriptor
        NumPut("Int",1,saAttr,16) ;bInheritHandle

        ;https://learn.microsoft.com/en-us/windows/win32/procthread/creating-a-child-process-with-redirected-input-and-output
        DllCall("CreatePipe"
            ,"Ptr*",&g_hChildStd_IN_Rd:=0
            ,"Ptr*",&g_hChildStd_IN_Wr:=0
            ,"Ptr",saAttr
            ,"Uint",0
        )

        bool:=DllCall("SetHandleInformation"
            ,"Ptr",g_hChildStd_IN_Wr
            ,"Uint",1 ;HANDLE_FLAG_INHERIT
            ,"Uint",0
        )

        read_handle:=DllCall("CreateNamedPipe"
            ,"Str",pipe_path
            ,"Uint",0x40000001 ;0x00000001 | 0x40000000 ;PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED
            ,"Uint",0 ;0x00000000 ;PIPE_TYPE_BYTE
            ,"Uint",1
            ,"Uint",4096
            ,"Uint",4096
            ,"Uint",0
            ,"Ptr",saAttr
        )

        write_handle:=DllCall("CreateFile"
            ,"Str",pipe_path
            ,"Uint",0x40000000 ;GENERIC_WRITE
            ,"Uint",0
            ,"Ptr",saAttr
            ,"Uint",3 ;OPEN_EXISTING
            ,"Uint",0x80 ;FILE_ATTRIBUTE_NORMAL
            ,"Ptr",0
        )

        bool:=DllCall("SetHandleInformation"
            ,"Ptr",read_handle
            ,"Uint",1 ;HANDLE_FLAG_INHERIT
            ,"Uint",0
        )

        P8 := (A_PtrSize==8)
        , SI:=Buffer(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", g_hChildStd_IN_Rd, SI, P8 ? 80 : 56) ; hStdInput
        , NumPut("Ptr", write_handle, SI, P8 ? 88 : 60) ; hStdOutput
        , NumPut("Ptr", write_handle, SI, P8 ? 96 : 64) ; hStdError
        , PI:=Buffer(P8 ? 24 : 16) ; PROCESS_INFORMATION structure

        bool:=DllCall("CreateProcess"
            ,"Ptr",0
            ,"Str",CmdLine
            ,"Ptr",0 ;lpProcessAttributes: *SECURITY_ATTRIBUTES
            ,"Int",0 ;lpThreadAttributes: *SECURITY_ATTRIBUTES
            ,"Int",True
            ,"Uint",0x08000400 ;dwCreationFlags: CREATE_NO_WINDOW=0x08000000, CREATE_UNICODE_ENVIRONMENT=0x00000400
            ,"Int",0 ;lpEnvironment
            ,"Ptr",WorkingDir ? StrPtr(WorkingDir) : 0
            ,"Ptr",SI
            ,"Ptr",PI
        )

        bool:=DllCall("CloseHandle", "Ptr",write_handle) ;THIS IS MUST, THIS IS IN FACT SO NECESSARY THAT WaitForSingleObject WILL ALWAYS HANG/BE WAITING
        bool:=DllCall("CloseHandle", "Ptr",g_hChildStd_IN_Rd)

        this.g_hChildStd_IN_Wr := g_hChildStd_IN_Wr
        this.read_handle:=read_handle
    }

    writeToStdIn(str) {
        ; Calculate required size and allocate a buffer.
        wowBuf := Buffer(StrPut(str, "UTF-8"))
        ; Copy or convert the string.
        StrPut(str, wowBuf, "UTF-8")

        DllCall("WriteFile"
            ,"Ptr",this.g_hChildStd_IN_Wr
            ,"Ptr",wowBuf
            ,"Uint",wowBuf.Size - 1
            ,"Ptr*",&byteswritten:=0
            ,"Ptr",0
        )
    }

    stopAndGetStr() {
        bool:=DllCall("CloseHandle", "Ptr",this.g_hChildStd_IN_Wr)

        read_handle:=this.read_handle

        overlapped:=Buffer(32, 0)

        bump_amt:=512
        finalStr:=""

        outer1:
        while (true) {
            while (true) {
                next_buf:=Buffer(bump_amt)
                bool:=DllCall("ReadFile"
                    ,"Ptr",read_handle
                    ,"Ptr",next_buf
                    ,"Uint",next_buf.Size
                    ,"Uint*",&read_bytes:=0
                    ,"Ptr",overlapped
                )
                if (bool == 1) {
                    bump_amt+=read_bytes
                    finalStr.=StrGet(next_buf,read_bytes,"UTF-8")
                } else {
                    switch (A_LastError) {
                        case 997: ;IO_PENDING
                            break
                        case 109: ;BROKEN_PIPE: The pipe has been ended.
                            break outer1
                        default:
                            MsgBox "h89fh2398h4`nA_LastError: " A_LastError
                    }
                }
            }
            ; status:=DllCall("WaitForSingleObject"
                ; ,"Ptr",read_handle
                ; ,"Uint",4294967295 ;INFINITE ;If dwMilliseconds is INFINITE, the function will return only when the object is signaled.
            ; )
            while (true) { ;this is faster but maybe more expensive???
                status:=DllCall("WaitForSingleObject"
                    ,"Ptr",read_handle
                    ,"Uint",0
                )
                ; ToolTip status
                if (status == 258) {
                    DllCall("Sleep", "Uint",0)
                    continue
                } else if (status == 0) {
                    break
                } else {
                    MsgBox "no way: " status
                }
            }

            bool:=DllCall("GetOverlappedResult"
                ,"Ptr",read_handle
                ,"Ptr",overlapped
                ,"Uint*", &Overlapped_read_bytes:=0
                ,"Int",0
            )
            bump_amt+=Overlapped_read_bytes
            finalStr.=StrGet(next_buf,Overlapped_read_bytes,"UTF-8")

        }

        return finalStr
    }
}

pythonProcess := ChildProcess("python")
pythonProcess.writeToStdIn("print(2**20)`n")
sleep 500
; this is "continuously write stdin"
pythonProcess.writeToStdIn("print(2**20)")
MsgBox pythonProcess.stopAndGetStr()
; if you want to read stdout in real time then I'd have to think of something else
ahk_v2 btw

william_ahk
Posts: 481
Joined: 03 Dec 2018, 20:02

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

Post by william_ahk » 23 Oct 2022, 04:07

@MrDoge Thanks for answering! But yeah I do intend to read the stdout in real time too. My apologies for not describing it well. I'm trying to leverage the power of Python interactive console with AHK. Is there any other way? I probably have to resort to using ControlSend to cmd.exe

User avatar
TheArkive
Posts: 1027
Joined: 05 Aug 2016, 08:06
Location: The Construct
Contact:

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

Post by TheArkive » 23 Oct 2022, 06:56

william_ahk wrote:
23 Oct 2022, 04:07
@MrDoge Thanks for answering! But yeah I do intend to read the stdout in real time too. My apologies for not describing it well. I'm trying to leverage the power of Python interactive console with AHK. Is there any other way? I probably have to resort to using ControlSend to cmd.exe

My cli lib should be able to achieve what you want, but it's a beast.

CliSAK for AHK v1
CliSAK for AHK v2

There's several examples to get you started. The nature of what it seems you are trying to do is async (stdin, stdout, and stderr separately), and that is what CliSAK is built for.

Post Reply

Return to “Scripts and Functions (v1)”