excel - macro - Espere a que el comando de shell se complete
vba excel ejecutar cmd (8)
¿Podría hacer que BATCH cree un archivo cuando termine y VBA espere hasta que se cree ese archivo? ¿O tiene que eliminar por lotes un archivo de bandera cuando haya terminado y VBA espera hasta que el archivo de bandera se haya ido?
Esta pregunta ya tiene una respuesta aquí:
Estoy ejecutando un simple comando de shell en Excel VBA que ejecuta un archivo por lotes en un directorio específico como el siguiente:
Dim strBatchName As String
strBatchName = "C:/folder/runbat.bat"
Shell strBatchName
A veces, el archivo por lotes puede tardar más en ejecutarse en alguna computadora, y hay un código de VBA que depende del archivo por lotes para terminar de ejecutarse. Sé que puedes configurar un temporizador de espera como el siguiente:
Application.Wait Now + TimeSerial(0, 0, 5)
Pero eso podría no funcionar en algunas computadoras que son muy lentas. ¿Hay una manera de decirle a Excel que continúe con el resto del código VBA hasta que el shell haya terminado de ejecutarse?
Agregue el siguiente Sub:
Sub SyncShell(ByVal Cmd As String, ByVal WindowStyle As VbAppWinStyle)
VBA.CreateObject("WScript.Shell").Run Cmd, WindowStyle, True
End Sub
Si agrega una referencia a C:/Windows/system32/wshom.ocx
también puede usar:
Sub SyncShell(ByVal Cmd As String, ByVal WindowStyle As VbAppWinStyle)
Static wsh As New WshShell
wsh.Run Cmd, WindowStyle, True
End Sub
Esta versión debería ser más eficiente.
Dim wsh como nuevo wshshell
chdir "Directorio de archivo por lotes"
wsh.run "Ruta completa del archivo por lotes", vbnormalfocus, true
Hijo hecho
Esto es lo que uso para que VB
espere a que se complete el proceso antes de continuar. No escribí esto y no tomo crédito.
Se ofreció en algún otro foro abierto y funciona muy bien para mí:
Las siguientes declaraciones son necesarias para la subrutina RunShell
:
Option Explicit
Private Declare Function OpenProcess Lib "kernel32" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Const PROCESS_QUERY_INFORMATION = &H400
Private Const STATUS_PENDING = &H103&
''then in your subroutine where you need to shell:
RunShell (path and filename or command, as quoted text)
Guarde el archivo bat en "C: / WINDOWS / system32" y use el siguiente código que funciona
Dim wsh As Object
Set wsh = VBA.CreateObject("WScript.Shell")
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 1
Dim errorCode As Integer
errorCode = wsh.Run("runbat.bat", windowStyle, waitOnReturn)
If errorCode = 0 Then
''Insert your code here
Else
MsgBox "Program exited with error code " & errorCode & "."
End If
Use el WScript.Shell en su lugar, porque tiene una opción waitOnReturn
:
Dim wsh As Object
Set wsh = VBA.CreateObject("WScript.Shell")
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 1
wsh.Run "C:/folder/runbat.bat", windowStyle, waitOnReturn
(La idea se copió de Esperar que el Shell termine, luego formatee las celdas - ejecutar un comando de manera sincrónica )
Vincule el shell a un objeto, haga que el trabajo por lotes finalice el objeto de shell (salir) y haga que el código de VBA continúe una vez que el objeto de shell = ¿Nada?
O eche un vistazo a esto: ¿ Captura el valor de salida de un comando de shell en VBA?
lo que propuso con un cambio en el paréntesis en el comando Ejecutar funcionó bien con VBA para mí
Dim wsh As Object
Set wsh = VBA.CreateObject("WScript.Shell")
Dim waitOnReturn As Boolean: waitOnReturn = True
Dim windowStyle As Integer: windowStyle = 1
Dim errorCode As Integer
wsh.Run "C:/folder/runbat.bat", windowStyle, waitOnReturn