如果您从隐藏控制台内运行的cscript
开始执行Exec
操作,则启动的进程也将被隐藏。但是这不会发生从.hta
,Exec
方法创建一个控制台附加到执行的进程,并且没有方法隐藏它没有第三方代码。
因此,处理命令输出解析的通常方法是将输出重定向到一个文件,然后读取文件,当然会丢失写入已启动进程的StdIn
流的选项。
要一个过程的输出重定向到一个文件,第一个想法就是使用类似
>"outputFile" command
但问题是,试图执行此直接将无法正常工作。这种重定向是不是操作系统的一部分,但cmd.exe
运营商,所以,我们需要像
cmd /c" >"outputFile" command "
我们还需要一种方法来知道如果这个过程已经结束运行的东西,并没有更多的数据将可用。我们可以使用Run
方法的Wait
参数,但这会使.hta
接口冻结,并被Run
方法阻塞。
不能使用Wait
参数,我们必须启动进程,获取进程ID并等待它结束并读取其所有数据,或者定期检索输出,直到进程结束。
你有一个基本类(ProcessOutputMonitor
)在这个测试中实现了此方法.hta
<html>
<head>
<title>pingMonitor</title>
<HTA:APPLICATION
ID="pingMonitor"
APPLICATIONNAME="pingMonitorHTA"
MINIMIZEBUTTON="no"
MAXIMIZEBUTTON="no"
SINGLEINSTANCE="no"
SysMenu="no"
BORDER="thin"
/>
<script type="text/vbscript" >
Class ProcessOutputMonitor
Dim shell, fso, wmi
Dim processID, retCode, processQuery
Dim outputFile, inputFile
Private Sub Class_Initialize
Set fso = CreateObject("Scripting.FileSystemObject")
Set shell = CreateObject("WScript.Shell")
Set wmi = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set inputFile = Nothing
End Sub
Private Sub Class_Terminate
freeResources
End Sub
Public Default Function Start(ByVal commandLine)
Const SW_HIDE = 0
Const SW_NORMAL = 1
Const TemporaryFolder = 2
Dim startUp
Start = False
If Not IsEmpty(processID) Then Exit Function
outputFile = fso.BuildPath(_
fso.GetSpecialFolder(TemporaryFolder) _
, Left(CreateObject("Scriptlet.TypeLib").GUID,38) & ".tmp" _
)
' "%comspec%" /c">"outputFile" command arguments "
commandLine = Join(_
Array(_
quote(shell.ExpandEnvironmentStrings("%comspec%")) _
, "/c"">" & quote(outputFile) _
, commandLine _
, """" _
) _
, " " _
)
' https://msdn.microsoft.com/en-us/library/aa394375%28v=vs.85%29.aspx
Set startUp = wmi.Get("Win32_ProcessStartup").SpawnInstance_
startUp.ShowWindow = SW_HIDE
retCode = wmi.Get("Win32_Process").Create(commandLine , Null, startUp, processID)
If retCode <> 0 Then
freeResources
Exit Function
End If
processQuery = "SELECT ProcessID From Win32_Process WHERE ProcessID=" & processID
Start = True
End Function
Public Property Get StartReturnCode
StartReturnCode = retCode
End Property
Public Property Get WasStarted
End Property
Public Property Get PID
PID = processID
End Property
Public Property Get IsRunning()
IsRunning = False
If Not IsEmpty(processID) Then
If getWMIProcess() Is Nothing Then
processID = Empty
freeResources
Else
IsRunning = True
End If
End If
End Property
Public Property Get NextLine
NextLine = getFromInputFile("line")
End Property
Public Property Get NextData
NextData = getFromInputFile("all")
End Property
Private Function getFromInputFile(what)
Const ForReading = 1
getFromInputFile = Empty
If Not IsEmpty(processID) Then
If inputFile Is Nothing Then
If fso.FileExists(outputFile) Then
Set inputFile = fso.GetFile(outputFile).OpenAsTextStream(ForReading)
End If
End If
If Not (inputFile Is Nothing) Then
If Not inputFile.AtEndOfStream Then
Select Case what
Case "line" : getFromInputFile = inputFile.ReadLine()
Case "all" : getFromInputFile = inputFile.ReadAll()
End Select
End If
End If
End If
End Function
Private Function quote(text)
quote = """" & text & """"
End Function
Private Function getWMIProcess()
Const wbemFlagForwardOnly = 32
Dim process
Set getWMIProcess = Nothing
If Not IsEmpty(processID) Then
For Each process In wmi.ExecQuery(processQuery, "WQL", wbemFlagForwardOnly)
Set getWMIProcess = process
Next
End If
End Function
Private Sub freeResources()
Dim process
Set process = getWMIProcess()
If Not (process Is Nothing) Then
process.Terminate
End If
processID = Empty
processQuery = Empty
If Not (inputFile Is Nothing) Then
inputFile.Close
Set inputFile = Nothing
fso.DeleteFile outputFile
End If
End Sub
End Class
</script>
<SCRIPT LANGUAGE="VBScript">
Dim timerID
Dim monitorGoogle, monitorMicrosoft
Sub Window_onLoad
window.resizeTo 1024,400
Set monitorGoogle = New ProcessOutputMonitor
monitorGoogle.Start "ping -4 www.google.com"
Set monitorMicrosoft = New ProcessOutputMonitor
monitorMicrosoft.Start "ping -4 www.microsoft.com"
timerID = window.setInterval(GetRef("monitorPings"), 500)
End Sub
Sub monitorPings
Dim buffer, keepRunning
keepRunning = False
buffer = monitorGoogle.NextData
If Not IsEmpty(buffer) Then
google.innerHTML = google.innerHTML & Replace(buffer, vbCrLf, "<br>")
keepRunning = True
Else
keepRunning = CBool(keepRunning Or monitorGoogle.IsRunning)
End If
buffer = monitorMicrosoft.NextData
If Not IsEmpty(buffer) Then
microsoft.innerHTML = microsoft.innerHTML & Replace(buffer, vbCrLf, "<br>")
keepRunning = True
Else
keepRunning = CBool(keepRunning Or monitorMicrosoft.IsRunning)
End If
If Not keepRunning Then
window.clearInterval(timerID)
timerID = Empty
alert("Done")
End If
End Sub
Sub ExitProgram
If Not IsEmpty(timerID) Then window.clearInterval(timerID)
window.close()
End Sub
</SCRIPT>
</head>
<body>
<input id="checkButton" type="button" value="EXIT" name="run_button" onClick="ExitProgram" align="right">
<br><br>
<span id="CurrentTime"></span>
<br><br>
<table style="width:100%">
<tr><th style="width:50%;">microsoft</th><th style="width:50%">google</th></tr>
<tr>
<td id="microsoft" style="font-family=courier;font-size:0.6em;vertical-align:top;"></td>
<td id="google" style="font-family=courier;font-size:0.6em;vertical-align:top;"></td>
</tr>
</table>
</body>
</html>
这将简单地启动两个ping
过程,并使用window.setInterval
将检索每500毫秒这两个过程的输出,并追加它(不好的方法,只是测试代码)到输出,直到两个进程结束。
检查[此WSH VBS GUI](https://stackoverflow.com/a/47111556/2165759)解决方案和[此控制台窗口隐藏](https://stackoverflow.com/a/32302212/2165759)方法。 – omegastripes