2011-02-07 18 views
17

Este es un ejemplo de código de VBScript que muestra cómo atrapar lo que un programa de línea de comando envíe a la salida estándar. Ejecuta el comando xcopy /? y muestra el resultado en un cuadro de mensaje. Antes de que aparezca el cuadro de mensaje, por una fracción de segundo verá que aparece la ventana de la consola.Código de VBscript para capturar stdout, sin mostrar la ventana de la consola

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 

Aquí hay otro ejemplo de código de VBScript que muestra cómo ejecutar una secuencia de comandos sin mostrar la ventana de la consola.

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 

Como se puede ver que tiene la forma <script><space><executor>. El último ejemplo se utiliza en lugar de objShell.RunobjShell.Exec

Lo que no sé es cómo ejecutar un programa de línea de comandos (si es necesario desde un archivo por lotes), coger la salida estándar, sin mostrar la ventana de la consola. ¿Algunas ideas?

Respuesta

3

Esta prueba de escritura conceptual:

' 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 

muestra cómo utilizar .Llevar y archivos temporales para obtener algo así como acentos abiertos con una consola oculta. El manejo de archivos decente, las citas en sCmd, la limpieza de las cadenas devueltas y el manejo de las codificaciones requerirán más trabajo. Pero quizás puedas usar la estrategia para implementar algo que se adapte a tus necesidades.

+0

Una ingeniosa solución. Lástima de los archivos temporales. Pero cumple con los requisitos, por lo que los puntos son tuyos. Gracias, Marcel. – mgr326639

5

Para redirigir la salida a la consola, ejecute la secuencia de comandos usando cscript, ej .: c:\cscript myscript.vbs.

cscript tiene algunas opciones de línea de comandos. Lo más importante (para mí) es el interruptor // NOLOGO. Si ia lo utilizan (cscript //nologo myscript.vbs) se omitirá mercancía Microsoft ...

13

que suelen utilizar esto:

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 

Para los comandos más avanzados youc una envoltura a comspec (cmd)

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

Tenga en cuenta que esto se bloqueará si su programa genera demasiadas (aproximadamente 4 KB IIRC) y no está oculto. –

+0

@CamiloMartin ¿De dónde obtiene la limitación de 4 KB? ¿Es eso una limitación de 'StdOut.ReadAll()'. Acabo de usar 'StdOut.ReadLine()' en un archivo de 109KB sin problemas por http://ss64.com/vb/stdoutread.html. Aunque puedo confirmar la observación "no oculta", esta solución no es ideal para aquellos que buscan una "ventana oculta" como requisito estricto, según el OP. – tresf

+0

@QZSupport Sinceramente, ya no tengo la menor pista, pero probablemente lo intenté y algo se colgó después de 4 KB, luego otras dos personas vinieron y lo votaron porque algo les colgó también. Si realmente funciona, es genial, solo asegúrese de probar en todas las versiones de Windows que soporte. (Además, debe tenerse en cuenta: es * muy probable * 'ReadAll' leerá todo en la memoria RAM, y sería muy feo por sí mismo, diría que debe transmitir el StdOut en su lugar, pero una vez más, no sé cómo; 'ReadLine' no sería bueno para la salida binaria). –

0

Para devolver en VBA todas las subcarpetas en G: \ OF

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

para dividir la cadena devuelta en una matriz

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 para: 'createobejct', falta la comilla antes de' cmd', y no trata la especificación "hidden". –

-1

En lugar de WScript.Shell, considere el uso usando Win32_Process con startupInfo.ShowWindow = 0 para poner en marcha el proceso con SW_HIDE. Publiqué un ejemplo detallado debajo de VBS Run cmd.exe output to a variable; not text file.

+0

Pieza de código interesante. Pero realmente no veo la ventaja en este caso, porque aún confía en un archivo temporal. – mgr326639

0

Si no le importa que aparezca el botón barra de tareas, simplemente puede mover la ventana de la consola fuera de la pantalla antes de iniciarla.

Si existe la clave HKCU\Console\WindowPosition, Windows usará su valor para colocar la ventana de la consola. Si la clave no existe, obtendrá una ventana posicionada en el sistema.

Guarde el valor original de esta clave, establezca su propio valor para colocarlo fuera de la pantalla, llame al Exec() y capture su salida, luego restaure el valor original de la clave.

La clave WindowPosition espera un valor de 32 bits. La palabra alta es la coordenada X y la palabra baja es la coordenada 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 

Si realmente quiere asegurarse de que las coordenadas están fuera de la pantalla, puede obtener las dimensiones de la pantalla a través de VBScript mediante el uso de IE u otras herramientas.

Cuestiones relacionadas