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 » 26 Feb 2022, 13:59

BoBo wrote:
26 Feb 2022, 13:56
It's not using com.exe but diskpart.exe and its command set within its own shell, similar to a power-shell client.
Ah! In which case you could run a script?.. but that will defeat the purpose of RunCMD(). :roll:
BoBo
Posts: 6564
Joined: 13 May 2014, 17:15

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

Post by BoBo » 26 Feb 2022, 14:59

There's no way to get its stdout transferred into a variable without using a file. Kind of desperate attempt :lolno: :roll:
I've no idea why MS isn't allowing to use ' | Clip' but is restricting it to a file.
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 » 26 Feb 2022, 15:13

BoBo wrote:
26 Feb 2022, 14:59
There's no way to get its stdout transferred into a variable without using a file.
I see.
So if there is no single "command" to Run and capture StdOut, then RunCMD() isn't a candidate, IMO.
Finallf
Posts: 18
Joined: 30 Oct 2020, 13:52

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

Post by Finallf » 28 Feb 2022, 23:34

HotKeyIt wrote:
14 Apr 2020, 15:36
Nice :thumbup: and v2 compatible :D
I'm trying to use it and I have this error, I think it's not compatible with v2 beta3 :(

@SKAN
Do you know if it is possible to use it with v2 beta3?

I receive the following message:
Spoiler
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 » 01 Mar 2022, 06:01

Finallf wrote:
28 Feb 2022, 23:34
@SKAN
Do you know if it is possible to use it with v2 beta3?
This function cannot be ported to V2 owing to a change done to FileObj.ReadLine()
viewtopic.php?f=13&t=100656
thqby wrote:
01 Mar 2022, 01:49
viewtopic.php?f=83&t=93944

This is V2 version.@Finallf
Misinformation.
That isn't RunCMD() and wouldn't work correctly.
neogna2
Posts: 591
Joined: 15 Sep 2016, 15:44

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

Post by neogna2 » 01 Mar 2022, 08:20

SKAN wrote:
01 Mar 2022, 06:01
This function cannot be ported to V2 owing to a change done to FileObj.ReadLine()
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?
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 » 01 Mar 2022, 09:02

neogna2 wrote:
01 Mar 2022, 08:20
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

There will be no lines in the output.
or
Output is a single line.

Manually adding CRLF will be error prone.
neogna2
Posts: 591
Joined: 15 Sep 2016, 15:44

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

Post by neogna2 » 01 Mar 2022, 09:52

SKAN wrote:
01 Mar 2022, 09:02
There will be no lines in the output.
or
Output is a single line.

Manually adding CRLF will be error prone.
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")
}
with the non-global RunTerminal version I get tooltip output that looks like this.
tooltip.png
tooltip.png (10.54 KiB) Viewed 4454 times
The irregularity in if TTL gets on a separate line or not here illustrates the issue I suppose.

Use cases that don't care about linebreaks, for example parsing the stream until some string pattern appears, would still work ok.
Last edited by neogna2 on 01 Mar 2022, 09:55, edited 1 time in total.
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 » 01 Mar 2022, 09:54

RunTerminal is off-topic here. Ask its "author" for explanation.
neogna2
Posts: 591
Joined: 15 Sep 2016, 15:44

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

Post by neogna2 » 01 Mar 2022, 10:04

SKAN wrote:
01 Mar 2022, 09:54
RunTerminal is off-topic here. Ask its "author" for explanation.
You're right, I'm sorry. Please delete my post above. I moved it to the RunTerminal thread instead.
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 » 01 Mar 2022, 10:09

neogna2 wrote:
01 Mar 2022, 10:04
You're right, I'm sorry. Please delete my post above.
Not a problem.
I wouldn't even replied if it wasn't you. :thumbup:
neogna2
Posts: 591
Joined: 15 Sep 2016, 15:44

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

Post by neogna2 » 01 Mar 2022, 10:25

:)
It seems v2 method .Read() doesn't omit linebreak chars. So could a workaround be to change from File.ReadLine() to e.g. File.Read(2) and leave it to the outside function to merge data into lines if needed. But maybe that has other issues?
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 » 01 Mar 2022, 10:48

neogna2 wrote:
01 Mar 2022, 10:25
So could a workaround be to change from File.ReadLine() to e.g. File.Read(2) and leave it to the outside function to merge data into lines if needed.
Yes, but a kludge.
I prefer to wait for lexikos' reply.
viewtopic.php?f=13&t=100656
User avatar
SKAN
Posts: 1551
Joined: 29 Sep 2013, 16:58

RunCMD() v0.99 for ah2

Post by SKAN » 01 Mar 2022, 17:38

@Finallf
@neogna2

Here is a temp version for V2 (Updated: 13-July-2023)

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)
}
neogna2
Posts: 591
Joined: 15 Sep 2016, 15:44

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

Post by neogna2 » 02 Mar 2022, 06:49

SKAN wrote:
01 Mar 2022, 17:38
Here is a temp version for V2
Thank you.

The pipe object code does FileObj.Pos=0 but https://lexikos.github.io/v2/docs/commands/FileOpen.htm#Flags says
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.
Is that an issue?

And, since kludge is my middle name :lol:, I tried this modification. Worked in a quick test, but don't know if generally ok or performant.

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
                         )
                      : ""
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 » 02 Mar 2022, 07:28

neogna2 wrote:
02 Mar 2022, 06:49
The pipe object code does FileObj.Pos=0 but https://lexikos.github.io/v2/docs/commands/FileOpen.htm#Flags says
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.
Is that an issue?
I don't know. Doc also advises not to use FileObj.AtEOF with a pipe.
That is why I made the "wish" to restore the original behavior to FileObj.ReadLine().
User avatar
thqby
Posts: 408
Joined: 16 Apr 2021, 11:18
Contact:

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

Post by thqby » 02 Mar 2022, 08:14

SKAN wrote:
01 Mar 2022, 17:38
@Finallf
@neogna2

Here is a temp version for V2

Code: Select all

code removed by SKAN
In my tests, this will return right results when removing SetNamedPipeHandleState and adding `n. Invalid empty lines will not be read.
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 » 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?
Post Reply

Return to “Scripts and Functions (v1)”