如果您從隱藏控制檯內運行的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