3

I know this has been answered one in another question, but I simply do not understand how it is done.

I am trying to get the output of a command line program (Aria2 downloader) into a HTA script so it can be parsed and the download percentage, file size etc can be obtained and updated into a DIV dynamically.

Here is the code I have adjusted and have been trying to use but it just locks up the interface until the command line has finished and THEN displays all the output, instead of displaying it as and when it comes through.

Const WshRunning = 0
Const WshFinished = 1
Const WshFailed = 2
strCommand = "ping.exe 127.0.0.1"

Set WshShell = CreateObject("WScript.Shell")
Set WshShellExec = WshShell.Exec(strCommand)

Do While WshShellExec.Status = WshRunning
    window.setTimeOut "", 100
Loop

Select Case WshShellExec.Status
    Case WshFinished
        strOutput = WshShellExec.StdOut.ReadAll()
    Case WshFailed
        strOutput = WshShellExec.StdErr.ReadAll()
End Select

Set objItem = Document.GetElementByID("status")
    objItem.InnerHTML = "" & strOutput & ""

How do I modify this so that it doesn't lock up my user interface and grabs the output and displays it in the "status" div as it comes through?

Ctrlaltdenied
  • 139
  • 3
  • 11
  • What's the basis for "Const WshFailed = 2"? The MS docs gove no such status code. https://msdn.microsoft.com/en-us/subscriptions/443b45a5(v=vs.84).aspx – ChrisJJ Oct 21 '16 at 10:31

1 Answers1

3

The problem is that your code does not end, returning the control to the browser. You don't leave the loop until the program ends and the perceived status is that the interface hangs until the subprocess ends.

You need to set a callback so the browser will periodically call your code where you will update the status and leave.

<html>
<head>
    <title>pingTest</title>
    <HTA:APPLICATION
        APPLICATIONNAME="pingTest"
        ID="pingTest"
        VERSION="1.0"
    />
</head>

<script language="VBScript">
    Const WshRunning = 0
    Const WshFinished = 1
    Const WshFailed = 2

    Dim WshShellExec, Interval

    Sub Window_onLoad
        LaunchProcess
    End Sub

    Sub LaunchProcess
        Set WshShellExec = CreateObject("WScript.Shell").Exec("ping -n 10 127.0.0.1")
        Interval = window.setInterval(GetRef("UpdateStatus"),500)
    End Sub    

    Sub UpdateStatus
    Dim status 
        Set status = Document.GetElementByID("status")
        Select Case WshShellExec.Status
            Case WshRunning
                status.InnerHTML = status.InnerHTML & "<br>" & WshShellExec.StdOut.ReadLine()
            Case WshFinished, WshFailed
                status.InnerHTML = status.InnerHTML & "<br>" & Replace(WshShellExec.StdOut.ReadAll(),vbCRLF,"<br>")
                window.clearInterval(Interval)
                Interval = Empty
        End Select
    End Sub
</script>

<body>
    <div id="status"></div>
</body>
</html>
MC ND
  • 69,615
  • 8
  • 84
  • 126
  • Thank you very much, I get the concept now, that was very eloquently put, thanks. Why is the WshRunning line written like so: status.InnerHTML = status.InnerHTML & "
    " & WshShellExec.StdOut.ReadLine() Would it not work as status.InnerHTML = WshShellExec.StdOut.ReadLine() ??
    – Ctrlaltdenied Oct 03 '15 at 14:08
  • 1
    @Ctrlaltdenied, I was trying to keep all the output from the command while reading it. Each time a `ReadLine` is used, only one line is retrieved, so, to keep all the output the new line is appended to the end of the existing information. Of course the code in your comment will work, but will not show the same information. For each line you discard the previously retrieved information and replace it with the new line. – MC ND Oct 03 '15 at 14:32
  • Ok, so the main reason behind this code, was to initiate a download, of which Aria2 is awesome at, http/s, bittorrent etc. I would like to expand this and have the entire log written to a log.txt file, whilst keeping key elements of the output to be displayed on the page. i.e the relevant download info like amount downloaded / total download size, speed, percentage etc. Thanks again for your help. – Ctrlaltdenied Oct 03 '15 at 15:32
  • Oh, just to query as final thing, the command in this example is ping -n 10 127.0.0.1, are there any characters or symbols (other than " that would not be accepted, and if I need to enter in a command that has a " in it as part of the string, do I need to make allowances here? – Ctrlaltdenied Oct 03 '15 at 19:26
  • 1
    @Ctrlaltdenied, if you are directly calling the `aria` executable there should not be any problematic character except `0x00` (null character). Quotes are allowed, but to include them in vbs strings you have to double them, just the vbs syntax way to escape quotes. – MC ND Oct 03 '15 at 19:38
  • Thank you. So, is it possible with this to create a sort of "console" window, as in I could technically submit a value from a form to be ran, and the output from it would appear in the appropriate DIV tag. Is that correct? – Ctrlaltdenied Oct 03 '15 at 20:26
  • @Ctrlaltdenied, I don't see why you could not do it. BUT (and this is just from memory) for the `aria` case, I think that once started you can talk with the `aria` executable using a http channel. If I'm not wrong, probably this will be easier to do. – MC ND Oct 03 '15 at 22:20
  • Actually other than downloading from HTTP or Bittorrent when called upon, I have no other use from Aria other than to grab it's output so I can keep a user informed in the GUI. This app is simply there to act as a downloader & installer for my launcher platform. It will only be used then to process updates as it can be given an option to download only newer files than what the host has. The http, bittorrent download, and that feature alone make it great for my purposes. Next challenge will be to integrate it into the launcher (node webkit) so I will likely need the JS equivalent sometime soon. – Ctrlaltdenied Oct 03 '15 at 23:09