2011-02-07 1 views
17

Questo è un esempio di codice VBScript che mostra come catturare qualsiasi cosa un programma da riga di comando invia allo standard output. Esegue il comando xcopy /? e mostra l'output in una finestra di messaggio. Prima che venga visualizzata la finestra di messaggio, per una frazione di secondo si vede apparire la finestra della console.Codice VBscript per acquisire lo stdout, senza mostrare la finestra della console

Set objShell = WScript.CreateObject("WScript.Shell") 
Set objExec = objShell.Exec("xcopy /?") 
Do 
    line = objExec.StdOut.ReadLine() 
    s = s & line & vbcrlf 
Loop While Not objExec.Stdout.atEndOfStream 
WScript.Echo s 

Ecco un altro esempio di codice VBScript che mostra come eseguire uno script senza mostrare la finestra della console.

objShell.Run "c:\temp\mybatch.bat C:\WINDOWS\system32\cmd.exe", 0 

o

objShell.Run "c:\temp\myscript.vbs C:\WINDOWS\system32\cscript.exe", 0 

Come si può vedere che ha la forma <script><space><executor>. L'ultimo esempio utilizza objShell.Run invece di objShell.Exec

Quello che non so è come eseguire un programma a riga di comando (se necessario da un file batch), catturare lo standard output, senza mostrare la finestra della console. Qualche idea?

risposta

3

Questa prova di scrittura concetto:

' pocBTicks.vbs - poor man's version of backticks (POC) 

Option Explicit 

' Globals 

Const SW_SHOWMINNOACTIVE = 7 
Const ForReading   = 1 

Dim goFS : Set goFS = CreateObject("Scripting.FileSystemObject") 
Dim goWSH : Set goWSH = CreateObject("WScript.Shell") 

' Dispatch 
WScript.Quit demoBTicks() 

' demoBTicks - 
Function demoBTicks() 
    demoBTicks = 1 
    Dim aCmds : aCmds = Array(_ 
     "dir pocBTicks.vbs" _ 
    , "dur pocBTicks.vbs" _ 
    , "xcopy /?" _ 
) 
    Dim sCmd 
    For Each sCmd In aCmds 
     WScript.Echo "########", sCmd 
     Dim aRet : aRet = BTicks(sCmd) 
     Dim nIdx 
     For nIdx = 0 To UBound(aRet) 
      WScript.Echo "--------", nIdx 
      WScript.Echo aRet(nIdx) 
     Next 
    Next 
    demoBTicks = 0 
End Function ' demoBTicks 

' BTicks - execute sCmd via WSH.Run 
' aRet(0) : goWSH.Run() result 
' aRet(1) : StdErr/error message 
' aRet(2) : StdOut 
' aRet(3) : command to run 
Function BTicks(sCmd) 
    Dim aRet : aRet  = Array(-1, "", "", "") 
    Dim sFSpec2 : sFSpec2 = goFS.GetAbsolutePathName(".") 
    Dim sFSpec1 : sFSpec1 = goFS.BuildPath(sFSpec2, goFS.GetTempName()) 
       sFSpec2 = goFS.BuildPath(sFSpec2, goFS.GetTempName()) 

    aRet(3) = """%COMSPEC%"" /c """ + sCmd + " 1>""" + sFSpec1 + """ 2>""" + sFSpec2 + """""" 
    Dim aErr 
On Error Resume Next 
    aRet(0) = goWSH.Run(aRet(3), SW_SHOWMINNOACTIVE, True) 
    aErr  = Array(Err.Number, Err.Description, Err.Source) 
On Error GoTo 0 
    If 0 <> aErr(0) Then 
    aRet(0) = aErr(0) 
    aRet(1) = Join(Array(aErr(1), aErr(2), "(BTicks)"), vbCrLf) 
    BTicks = aRet 
    Exit Function 
    End If 

    Dim nIdx : nIdx = 1 
    Dim sFSpec 
    For Each sFSpec In Array(sFSpec2, sFSpec1) 
     If goFS.FileExists(sFSpec) Then 
     Dim oFile : Set oFile = goFS.GetFile(sFSpec) 
     If 0 < oFile.Size Then 
      aRet(nIdx) = oFile.OpenAsTextStream(ForReading).ReadAll() 
      goFS.DeleteFile sFSpec 
     End If 
     End If 
     nIdx = nIdx + 1 
    Next 
    BTicks = aRet 
End Function 

mostra come usare i file temporanei .Run e per ottenere qualcosa di simile a backticks con una console nascosta. La gestione dei file decente, la citazione in sCmd, la pulizia delle stringhe restituite e la gestione delle codifiche richiedono più lavoro. Ma forse puoi usare la strategia per realizzare qualcosa che soddisfi le tue esigenze.

+0

Una soluzione geniale. Peccato per i file temporanei. Ma soddisfa i requisiti quindi i punti sono tuoi. Grazie, Marcel. – mgr326639

5

Per reindirizzare l'output sulla console, eseguire lo script utilizzando cscript, es .: c:\cscript myscript.vbs.

cscript ha alcune opzioni da riga di comando. Il più importante (per me) è l'interruttore // NOLOGO. Se su base annua lo usano (cscript //nologo myscript.vbs) si omette Microsoft merce ...

13

io di solito uso questo:

Wscript.echo execStdOut("ping google.com") 

Function execStdOut(cmd) 
    Dim goWSH : Set goWSH = CreateObject("WScript.Shell") 
    Dim aRet: Set aRet = goWSH.exec(cmd) 
    execStdOut = aRet.StdOut.ReadAll() 
End Function 

Per i comandi più avanzati youc un impacco per ComSpec (cmd)

my res = execStdOut("%comspec%" & " /c " & """" & "dir /b c:\windows\*.exe" & """" & " && Echo. && Echo finished") 
+2

Nota che questo si bloccherà se il tuo programma emetterà troppo (circa 4KB IIRC), e non è nascosto. –

+0

@CamiloMartin Da dove viene il limite di 4KB? È una limitazione di 'StdOut.ReadAll()'. Ho appena usato 'StdOut.ReadLine()' su un file di 109KB senza problemi per http://ss64.com/vb/stdoutread.html. Sebbene io possa confermare l'osservazione "non nascosta", rendere questa soluzione non ideale per coloro che cercano una "finestra nascosta" come requisito rigoroso, secondo l'OP. – tresf

+0

@QZSupport Sinceramente non ho più il minimo indizio, ma probabilmente l'ho provato e qualcosa è stato appeso dopo 4KB, poi altre due persone sono venute a svenderlo perché c'era qualcosa per loro. Se funziona davvero è grandioso, assicurati di testare su tutte le versioni di Windows che stai supportando. (Inoltre, dovrebbe essere notato: è molto probabile che * ReadAll' leggerà tutto nella RAM, e sarebbe molto brutto da solo - direi che dovresti eseguire lo streaming di StdOut, ma ancora non lo so come; 'ReadLine' non sarebbe buono per l'output binario). –

0

Per restituire in VBA tutte le sottocartelle in G: \ OF

sub M_snb() 
    c00= createobejct("wscript.Shell").exec("cmd /c Dir G:\OF\*. /s/b").stdout.readall 
end sub 

per dividere la stringa restituita in una matrice

sub M_snb() 
    sn=split(createobejct("wscript.Shell").exec("cmd /c Dir G:\OF\*. /s/b").stdout.readall,vbCrLf) 

    for j=0 to ubound(sn) 
    msgbox sn(j) 
    next 
End Sub 
+3

-1 per: 'createobejct', manca la citazione prima di' cmd', e non si rivolge alla specifica "nascosta". –

-1

Invece di WScript.Shell, è possibile utilizzare con Win32_Process con startupInfo.ShowWindow = 0 per avviare il processo con SW_HIDE. Ho pubblicato un esempio dettagliato sotto VBS Run cmd.exe output to a variable; not text file.

+0

Parte di codice interessante. Ma in questo caso non vedo davvero il vantaggio, perché stai ancora facendo affidamento su un file temporaneo. – mgr326639

0

Se non ti dispiace di visualizzare il pulsante barra delle applicazioni, puoi spostare la finestra della console fuori dallo schermo prima di avviarla.

Se la chiave HKCU\Console\WindowPosition esiste, Windows utilizzerà il suo valore per posizionare la finestra della console. Se la chiave non esiste, otterrai una finestra posizionata nel sistema.

Quindi, salvare il valore originale di questa chiave, impostare il proprio valore per posizionarlo fuori schermo, chiamare Exec() e acquisire l'output, quindi ripristinare il valore originale della chiave.

La chiave WindowPosition prevede un valore a 32 bit. La parola alta è la coordinata X e la parola bassa è la coordinata Y (XXXXYYYY).

With CreateObject("WScript.Shell") 

    ' Save the original window position. If system-positioned, this key will not exist. 
    On Error Resume Next 
    intWindowPos = .RegRead("HKCU\Console\WindowPosition") 
    On Error GoTo 0 

    ' Set Y coordinate to something crazy... 
    .RegWrite "HKCU\Console\WindowPosition", &H1000, "REG_DWORD" 

    ' Run Exec() and capture output (already demonstrated by others)... 
    .Exec(...) 

    ' Restore window position, if previously set. Otherwise, remove key... 
    If Len(intWindowPos) > 0 Then 
     .RegWrite "HKCU\Console\WindowPosition", intWindowPos, "REG_DWORD" 
    Else 
     .RegDelete "HKCU\Console\WindowPosition" 
    End If 

End With 

Se davvero vuole fare in modo le coordinate sono Offscreen, è possibile ottenere le dimensioni dello schermo tramite VBScript utilizzando Internet Explorer o altri strumenti.