Espere a que finalice Shell, luego formatee las celdas: ejecute un comando sincrónicamente

Resuelto Alaa Elwany asked hace 12 años • 8 respuestas

Tengo un ejecutable al que llamo usando el comando de shell:

Shell (ThisWorkbook.Path & "\ProcessData.exe")

El ejecutable realiza algunos cálculos y luego exporta los resultados a Excel. Quiero poder cambiar el formato de los resultados DESPUÉS de exportarlos.

En otras palabras, primero necesito el comando Shell para ESPERAR hasta que el ejecutable finalice su tarea, exporte los datos y LUEGO realice los siguientes comandos para formatear.

Probé el Shellandwait(), pero sin mucha suerte.

Tuve:

Sub Test()

ShellandWait (ThisWorkbook.Path & "\ProcessData.exe")

'Additional lines to format cells as needed

End Sub

Desafortunadamente, aún así, el formateo se realiza antes de que finalice el ejecutable.

Sólo como referencia, aquí estaba mi código completo usando ShellandWait

' Start the indicated program and wait for it
' to finish, hiding while we wait.


Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
Private Declare Function WaitForSingleObject Lib "kernel32.dll" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
Private Declare Function OpenProcess Lib "kernel32.dll" (ByVal dwDesiredAccessas As Long, ByVal bInheritHandle As Long, ByVal dwProcId As Long) As Long
Private Const INFINITE = &HFFFF


Private Sub ShellAndWait(ByVal program_name As String)
Dim process_id As Long
Dim process_handle As Long

' Start the program.
On Error GoTo ShellError
process_id = Shell(program_name)
On Error GoTo 0

' Wait for the program to finish.
' Get the process handle.
process_handle = OpenProcess(SYNCHRONIZE, 0, process_id)
If process_handle <> 0 Then
WaitForSingleObject process_handle, INFINITE
CloseHandle process_handle
End If

Exit Sub

ShellError:
MsgBox "Error starting task " & _
txtProgram.Text & vbCrLf & _
Err.Description, vbOKOnly Or vbExclamation, _
"Error"

End Sub

Sub ProcessData()

  ShellAndWait (ThisWorkbook.Path & "\Datacleanup.exe")

  Range("A2").Select
    Range(Selection, Selection.End(xlToRight)).Select
    Range(Selection, Selection.End(xlDown)).Select
    With Selection
        .HorizontalAlignment = xlLeft
        .VerticalAlignment = xlTop
        .WrapText = True
        .Orientation = 0
        .AddIndent = False
        .IndentLevel = 0
        .ShrinkToFit = False
        .ReadingOrder = xlContext
        .MergeCells = False
    End With
    Selection.Borders(xlDiagonalDown).LineStyle = xlNone
    Selection.Borders(xlDiagonalUp).LineStyle = xlNone
End Sub
Alaa Elwany avatar Jan 18 '12 04:01 Alaa Elwany
Aceptado

Pruebe el objeto WshShell en lugar de la función nativa Shell.

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 Long

errorCode = wsh.Run("notepad.exe", windowStyle, waitOnReturn)

If errorCode = 0 Then
    MsgBox "Done! No error to report."
Else
    MsgBox "Program exited with error code " & errorCode & "."
End If    

Aunque tenga en cuenta que:

Si bWaitOnReturnse establece en falso (el valor predeterminado), el método Ejecutar regresa inmediatamente después de iniciar el programa, devolviendo automáticamente 0 (no debe interpretarse como un código de error).

Entonces, para detectar si el programa se ejecutó exitosamente, debe waitOnReturnconfigurarlo en Verdadero como en mi ejemplo anterior. De lo contrario, simplemente devolverá cero pase lo que pase.

Para el enlace anticipado (da acceso a Autocompletado), establezca una referencia a "Modelo de objetos de Windows Script Host" (Herramientas > Referencia > establecer marca de verificación) y declare así:

Dim wsh As WshShell 
Set wsh = New WshShell

Ahora, para ejecutar su proceso en lugar del Bloc de notas... Espero que su sistema se oponga a las rutas que contienen caracteres de espacio ( ...\My Documents\...,, ...\Program Files\...etc.), por lo que debe encerrar la ruta entre "comillas ":

Dim pth as String
pth = """" & ThisWorkbook.Path & "\ProcessData.exe" & """"
errorCode = wsh.Run(pth , windowStyle, waitOnReturn)
Jean-François Corbett avatar Jan 18 '2012 08:01 Jean-François Corbett

Lo que tienes funcionará una vez que agregues

Private Const SYNCHRONIZE = &H100000

que te falta. (El significado 0se transmite como cuyo derecho de acceso OpenProcessno es válido)

Hacer Option Explicitla línea superior de todos sus módulos habría generado un error en este caso

Alex K. avatar Jan 18 '2012 12:01 Alex K.