wscript visual vbnormalfocus vbhide retval ejecutar desde completo comandos shell vba

visual - ¿Capturar el valor de salida de un comando de shell en VBA?



vbnormalfocus (6)

Basándome en la respuesta de bburns.km , agregué información de paso (usando StdInput) al ejecutable durante la llamada. Por si acaso alguien se topa con esto y tiene la misma necesidad.

'''''' <summary> '''''' Executes the given executable in a shell instance and returns the output produced '''''' by it. If iStdInput is given, it is passed to the executable during execution. '''''' Note: You must make sure to correctly enclose the executable path or any given '''''' arguments in quotes (") if they contain spaces. '''''' </summary> '''''' <param name="iExecutablePath"> '''''' The full path to the executable (and its parameters). This string is passed to the '''''' shell unaltered, so be sure to enclose it in quotes if it contains spaces. '''''' </param> '''''' <param name="iStdInput"> '''''' The (optional) input to pass to the executable. Default: Null '''''' </param> Public Function ExecuteAndReturnStdOutput(ByVal iExecutablePath As String, _ Optional ByVal iStdInput As String = vbNullString) _ As String Dim strResult As String Dim oShell As WshShell Set oShell = New WshShell Dim oExec As WshExec Set oExec = oShell.Exec(iExecutablePath) If iStdInput <> vbNullString Then oExec.StdIn.Write iStdInput oExec.StdIn.Close '' Close input stream to prevent deadlock End If strResult = oExec.StdOut.ReadAll oExec.Terminate ExecuteAndReturnStdOutput = strResult End Function

Nota: Deberá agregar una referencia al Windows Script Host Object Model para que se WshShell los tipos WshShell y WshExec .
(Para hacer esto, vaya a Extras -> Referencias en la barra de menú del IDE de VBA).

Encontré esta función http://www.cpearson.com/excel/ShellAndWait.aspx

Pero también tendría que capturar la salida de la salida de shell. ¿Alguna sugerencia de código?


De acuerdo con la respuesta de Andrew Lessard, aquí hay una función para ejecutar un comando y devolver la salida como una cadena:

Public Function ShellRun(sCmd As String) As String ''Run a shell command, returning the output as a string Dim oShell As Object Set oShell = CreateObject("WScript.Shell") ''run command Dim oExec As Object Dim oOutput As Object Set oExec = oShell.Exec(sCmd) Set oOutput = oExec.StdOut ''handle the results as they are written to and read from the StdOut object Dim s As String Dim sLine As String While Not oOutput.AtEndOfStream sLine = oOutput.ReadLine If sLine <> "" Then s = s & sLine & vbCrLf Wend ShellRun = s End Function

Uso:

MsgBox ShellRun("dir c:/")


Esta función proporciona una forma rápida de ejecutar un comando de línea de comandos, utilizando el objeto del portapapeles:

Captura de salida de línea de comandos:

Function getCmdlineOutput(cmd As String) CreateObject("WScript.Shell").Run "cmd /c """ & cmd & "|clip""", 0, True ''output>clipbrd With CreateObject("New:{1C3B4210-F441-11CE-B9EA-00AA006B1A69}") ''latebound clipbrd obj .GetFromClipboard ''get cmdline output from clipboard getCmdlineOutput = .GetText(1) ''return clipboard contents End With End Function

Ejemplo de uso:

Sub Demo1() MsgBox getCmdlineOutput("w32tm /tz") ''returns the system Time Zone information End Sub

Utiliza el comando WShell Run porque opcionalmente permite la ejecución asíncrona, lo que significa que esperará a que el comando termine de ejecutarse antes de que continúe VBA, lo cual es importante cuando se trata del portapapeles.

También utiliza una utilidad de línea de comandos incorporada pero a menudo olvidada llamada clip.exe , en este caso como un destino para la salida de línea de datos del canal .

La manipulación del portapapeles requiere una referencia a la biblioteca de Microsoft Forms 2.0 , que en este caso creé con una referencia de enlace tardío (que se ve diferente ya que MS Forms, también fm20.dll como fm20.dll ) es una biblioteca de Windows, no VBA.

Preservando los datos existentes del portapapeles:

En mi caso, fue un problema que la función anterior borra los datos existentes del portapapeles, por lo que la siguiente función se modifica para conservar y reemplazar el texto existente en el portapapeles.

Si hay algo más que texto en el portapapeles, se le avisará de que se perderá. Algunos códigos pesados ​​podrían permitir que se devuelva otro / cualquier tipo de datos del portapapeles ... pero la manipulación avanzada del portapapeles es mucho más compleja de lo que la mayoría de los usuarios se dan cuenta, y francamente no tengo la necesidad o el deseo de hacerlo. Más información here .

Tenga en cuenta que, en este método, MS Forms es Early-Bound pero podría cambiarse si lo desea. (Pero recuerde que como regla general, la vinculación tardía generalmente duplica el tiempo de procesamiento).

Function getCmdlineOutput2(cmd As String) ''requires Reference: C:/Windows/System32/FM20.DLL (MS Forms 2.0) [Early Bound] Dim objClipboard As DataObject, strOrigClipbrd As Variant Set objClipboard = New MSForms.DataObject ''create clipboard object objClipboard.GetFromClipboard ''save existing clipboard text If Not objClipboard.GetFormat(1) Then MsgBox "Something other than text is on the clipboard.", 64, "Clipboard to be lost!" Else strOrigClipbrd = objClipboard.GetText(1) End If ''shell to hidden commandline window, pipe output to clipboard, wait for finish CreateObject("WScript.Shell").Run "cmd /c """ & cmd & "|clip""", 0, True objClipboard.GetFromClipboard ''get cmdline output from clipboard getCmdlineOutput2 = objClipboard.GetText(1) ''return clipboard contents objClipboard.SetText strOrigClipbrd, 1 ''Restore original clipboard text objClipboard.PutInClipboard End Function

Ejemplo de uso:

Sub Demo2() MsgBox getCmdlineOutput2("dir c:/") ''returns directory listing of C:/ End Sub


Siempre puede redirigir la salida de shell a un archivo y luego leer la salida del archivo.


Puede StdOut y StdOut la aplicación redirigiendo su StdOut a una canalización, y luego leer esa tubería directamente; http://pastebin.com/CszKUpNS

dim resp as string resp = redirect("cmd","/c dir") resp = redirect("ipconfig","")


Sub StdOutTest() Dim objShell As Object Dim objWshScriptExec As Object Dim objStdOut As Object Dim rline As String Dim strline As String Set objShell = CreateObject("WScript.Shell") Set objWshScriptExec = objShell.Exec("c:/temp/batfile.bat") Set objStdOut = objWshScriptExec.StdOut While Not objStdOut.AtEndOfStream rline = objStdOut.ReadLine If rline <> "" Then strline = strline & vbCrLf & CStr(Now) & ":" & Chr(9) & rline '' you can handle the results as they are written to and subsequently read from the StdOut object Wend MsgBox strline ''batfile.bat ''ping 1.1.1.1 -n 1 -w 2000 > nul ''echo 2 ''ping 1.1.1.1 -n 1 -w 2000 > nul ''echo 4 ''ping 1.1.1.1 -n 1 -w 2000 > nul ''echo 6 ''ping 1.1.1.1 -n 1 -w 2000 > nul ''echo 8 End Sub