2012-06-16 3 views
1

Я использую JScript (такой же, как VBScript) изнутри .hta-файла, чтобы открыть новую команду оболочки и захватить ее вывод. Вот что я получил до сих пор после того, как Googling немного:Захват вывода из WScript.Shell в реальном времени

var shell = new ActiveXObject("WScript.Shell") 
var e = shell.Exec("%comspec% /c ping google.com 2>&1 ") 
while(!e.StdOut.AtEndofStream) { 
    var line = e.StdOut.ReadLine() 
    document.getElementById('log').value = line 
} 

Это работает. Однако он не является асинхронным. Цикл while заставляет мой .hta-интерфейс просто блокироваться (пользовательский интерфейс становится непригодным), пока команда оболочки не завершится. Если я удалю while loop, команда shell.Exec, похоже, не блокируется, поэтому проблема находится где-то внутри цикла.

Я думаю, что проблема блокировки возникает только потому, что я вхожу в среду .hta. Кажется, это не происходит, если я запускаю свой скрипт через командную строку, используя cscript.exe

Как я могу избежать поведения блокировки и получить доступ к выводам моей команды в режиме реального времени?

+0

Цикл все еще блокируется в cscript.exe, но поскольку консольное окно управляется вспомогательным процессом (conhost/csrss), вы не замечаете блокировку (это нормально и нормально для консольного приложения) – Anders

ответ

1

Вы, вероятно, придется fake a background thread по телефону setTimeOut раз и только делает небольшое количество работы в функции обратного вызова таймера ...

+0

Не могли бы вы немного расширить? Где понадобится 'setTimeout'? Разве это не асинхронно? Так как это имеет значение? –

+0

Замените цикл while кодом, на который я связан. Цикл while не позволяет хост-приложению HTA обрабатывать сообщения, setTimeout будет ... – Anders

+0

Проблема на самом деле глубже, чем я думал. ReadLine() будет блокироваться, пока не появится что-то для чтения. Вот почему интерфейс закрывается.Любые идеи, как я могу обойти это? –

0

Как Андерс отметил, что вам нужно реализовать стратегию псевдо многопоточный, потому что ваш GUI выиграл 't реагировать на любой пользовательский ввод, пока выполняется код JScript (любая функция) .

Я использовал setInterval() вместо setTimeout() по указанным причинам here.

Это .hta

<html> 
<head> 
    <title>Ping HTA (JScript)</title> 
    <HTA:APPLICATION 
    APPLICATIONNAME="PingHTA" 
    > 
    <SCRIPT Language="JScript" src="ping.js"></SCRIPT> 
</head> 
<body onload="onLoadBody()"> 
    <form name="anonymous"> 
    <h2>Ping HTA (JScript)</h2> 
    <hr> 
    <input id="bttStartPing" type="BUTTON" value="StartPing" onclick="startPing()"> 
    <hr> 
    <textarea id="taDisplay" rows="25" cols="80"></textarea> 
    </form> 
</body> 
</html> 

и .js

//= app globals 
g_sCmd  = '%comspec% /c ping.exe /n 8 google.com 2>&1'; 
g_taDisplay = null; 
g_PSIHandle = 0; 
g_PSILock = false; 
g_oExec  = null; 

//= prep for log 
function onLoadBody() { 
    g_taDisplay = window.document.getElementById("taDisplay"); 
    log("OnLoadBody() done."); 
} 

//= log 
function log(msg) { 
    g_taDisplay.value = new Date().toString() + "\n " + msg + "\n" + g_taDisplay.value; 
} 

//= start job 
function startPing() { 
    if (0 == g_PSIHandle) { 
    g_PSIHandle = setInterval(stepPing, 100); 
    log('setInterval(stepPing, 100)'); 
    g_oExec = new ActiveXObject("WScript.Shell").Exec(g_sCmd); 
    log("started " + g_sCmd); 
    } else { 
    log('***** Ping is running!'); 
    } 
} 

//= one step of job 
function stepPing() { 
    if (! g_PSILock) { 
    g_PSILock = true; 
    if (null !== g_oExec) { 
     if (g_oExec.StdOut.AtEndofStream) { 
      clearInterval(g_PSIHandle); 
      g_PSIHandle = 0; 
      log('StdOut.AtEndofStream, terminate ping'); 
      g_oExec.Terminate(); 
      g_oExec = null; 
     } else { 
      log(g_oExec.StdOut.ReadLine()); 
     } 
    } 
    g_PSILock = false; 
    } 
} 

должен продемонстрировать:

  1. с использованием .Exec в .hta откроется окно оболочки (для некоторых людей что является дисквалификатором)
  2. .hta will st искусство, чтобы поднять линии вывода пинга, до того, что процесс завершается
  3. нажав кнопку в то время как процесс запущен будет перемежать сообщения с выходом пинга (хотя реакция чувствует вялый)

A производственной версии пришлось бы потратить гораздо больше усилий на сделку с возможными состояниями .Exec и обработкой ошибок.

Для этого запустите свой вопрос here и google для «WshScriptExec Object».

+0

Отлично! Это работает. Есть ли способ скрыть окно команд, которое –

+0

@Luca - вы можете скрыть окно консоли (см. (1) в моем ответе) –

+0

в вашем (1) ответе, что вы будете * открывать * окно оболочки. хочу избежать этого. –