Cmd.exe пишет в stdout / stderr? - PullRequest
       17

Cmd.exe пишет в stdout / stderr?

0 голосов
/ 25 февраля 2019

Это странный вопрос, основанный на плохом поведении VBScript, который я пытаюсь обойти.Пожалуйста, потерпите меня и спасибо заранее.

В VBScript вы можете сделать следующее, чтобы запустить задачу:

Set WshShell = CreateObject("WScript.Shell")
Set WshShellExec = WshShell.Exec(strCommand)
Do While WshShellExec.Status <> WshFinished
    WScript.Sleep(1000)
Loop

Однако, есть ошибка, если, если команда /задача, запущенная вызовом WshShell.Exec, записывает> = 4kb в StdOut или StdErr, WshShellExec.Status никогда не будет равен WshFinished (1).Я предполагаю, что это связано с тем, что в буфере нет места, которое система использует для stdout / stderr, поэтому инициируемая задача зависает при следующей записи в stdout / stderr, как только записывает достаточно байтов в буфер (ы).

В зависимости от запущенной программы вы можете сделать что-то вроде следующего, чтобы обойти это:

Set wshShellExec = WshShell.Exec(cmd)
Set objStdOut = wshShellExec.StdOut
Set objStdErr = wshShellExec.StdErr

Do Until objStdOut.AtEndOfStream
    standardout = standardout & objStdOut.ReadLine & vbCrlf
Loop

Do Until objStdErr.AtEndOfStream
    errtext = errtext & objStdErr.ReadLine & vbCrlf
Loop

Однако, это не всегда работает.Если работающая программа записывает 4kb в stderr перед записью чего-либо в stdout, этот код зависает при оценке objStdOut.AtEndOfStream или objStdOut.ReadLine (обратите внимание, что вы не можете использовать objStdOut.ReadAll, потому что это также навсегда заблокирует).

Итак, я пришел к следующему решению, которое, кажется, работает:

strCommand = "c:\Windows\System32\cmd.exe /C StdOutTester.exe > " & rsltTextFile & " 2>&1 || call echo %^errorLevel% > " & rsltErrCodeFile

Set WshShellExec = WshShell.Exec(strCommand)

Do While WshShellExec.Status <> WshFinished 
    Wscript.Sleep(1000)
    secCount = secCount+1
    If secCount >= 10 Then 'kill children
        If KillTaskChildren(WshShellExec.ProcessID) <> 0 Then
            WScript.Echo "WMI Terminate Failed. Killing CMD..."
            WshShellExec.Terminate
        End If
    End If
Loop

Для этого нужно запустить текущую задачу в другом окне cmd и перенаправить оба stdout / stderr в файл (итакже код ошибки, если применимо).Поскольку я запускаю команду в другом окне cmd, stdout и stderr отделены от объекта WshShellExec.Это также позволяет мне убить запущенную задачу за время ожидания (реальное, то есть не окно cmd, а реальная задача, с помощью WMI).

Итак, мой вопрос становится таким:

Поскольку я запускаю другое окно cmd.exe, возможно, что приглашение cmd само сталкивается с той же проблемой, если записывает достаточно данных в stdout / stderr (в этом случае моя логика тайм-аута должна его убить)?Записывает ли он что-нибудь в stdout / stderr?Как насчет того, чтобы использовать параметр / Q?

...