Share via


Determinar cuándo termina un proceso ejecutado desde el Shell

Cuando se ejecuta la función Shell en un procedimiento de Visual Basic para Aplicaciones (VBA), se inicia un programa ejecutable de forma asincrónica y se devuelve el control al procedimiento. Este programa continúa ejecutándose de manera independiente del procedimiento hasta que se cierra.

Si el procedimiento necesita esperar a que termine el proceso ejecutable, puede utilizar la API de Windows para sondear el estado de la aplicación, aunque este método no es muy eficaz. En este tema se explica el uso de un método más eficaz.

La API de Windows dispone de funciones incorporadas que permiten que la aplicación espere hasta que el proceso ejecutable haya terminado de ejecutarse. Para utilizar estas funciones es necesario tener un identificador del proceso ejecutable. Para obtenerlo, se debe comenzar el programa ejecutable con la función CreateProcess en lugar de la función Shell.

Creación del proceso shelled

Para crear un proceso direccionable, use la función CreateProcess para iniciar la aplicación ejecutable. La función CreateProcess ofrece al programa el identificador del proceso ejecutable mediante uno de los parámetros que se han pasado.

Esperar a que finalice el proceso shelled

Una vez que haya utilizado la función CreateProcess para obtener el identificador de proceso, puede pasar dicho identificador a la función WaitForSingleObject. Esto hará que el procedimiento de VBA suspenda la ejecución hasta que termine el proceso ejecutable.

Los pasos siguientes son necesarios para compilar un procedimiento VBA que use la función CreateProcess para ejecutar la aplicación Del Bloc de notas de Windows. Este código muestra cómo utilizar las funciones CreateProcess y WaitForSingleObject de la API de Windows para esperar hasta que termine un proceso ejecutable antes de reanudar la ejecución.

La sintaxis de la función CreateProcess es compleja, por lo que en el código de ejemplo se encapsula en una función denominada ExecCmd. ExecCmd toma un parámetro, la línea de comandos de la aplicación que se va a ejecutar.

  1. Cree un módulo estándar y pegue las líneas siguientes en la sección Declaraciones:

    Option Explicit 
    
    Private Type STARTUPINFO 
    cb As Long 
    lpReserved As String 
    lpDesktop As String 
    lpTitle As String 
    dwX As Long 
    dwY As Long 
    dwXSize As Long 
    dwYSize As Long 
    dwXCountChars As Long 
    dwYCountChars As Long 
    dwFillAttribute As Long 
    dwFlags As Long 
    wShowWindow As Integer 
    cbReserved2 As Integer 
    lpReserved2 As Long 
    hStdInput As Long 
    hStdOutput As Long 
    hStdError As Long 
    End Type 
    
    Private Type PROCESS_INFORMATION 
    hProcess As Long 
    hThread As Long 
    dwProcessID As Long 
    dwThreadID As Long 
    End Type 
    
    Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal _ 
    hHandle As Long, ByVal dwMilliseconds As Long) As Long 
    
    Private Declare Function CreateProcessA Lib "kernel32" (ByVal _ 
    lpApplicationName As Long, ByVal lpCommandLine As String, ByVal _ 
    lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _ 
    ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _ 
    ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As Long, _ 
    lpStartupInfo As STARTUPINFO, lpProcessInformation As _ 
    PROCESS_INFORMATION) As Long 
    
    Private Declare Function CloseHandle Lib "kernel32" (ByVal _ 
    hObject As Long) As Long 
    
    Private Const NORMAL_PRIORITY_CLASS = &H20& 
    Private Const INFINITE = -1& 
    
    
  2. Pegue el código siguiente en el módulo:

    Public Sub ExecCmd(cmdline As String) 
    Dim proc As PROCESS_INFORMATION 
    Dim start As STARTUPINFO 
    Dim ReturnValue As Integer 
    
    ' Initialize the STARTUPINFO structure: 
    start.cb = Len(start) 
    
    ' Start the shelled application: 
    ReturnValue = CreateProcessA(0&, cmdline$, 0&, 0&, 1&, _ 
    NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc) 
    
    ' Wait for the shelled application to finish: 
    Do 
    ReturnValue = WaitForSingleObject(proc.hProcess, 0) 
    DoEvents 
    Loop Until ReturnValue <> 258 
    
    ReturnValue = CloseHandle(proc.hProcess) 
    End Sub
    
  3. Para probar la función, pegue el código siguiente en la ventana Inmediato y presione Entrar. Se inicia el Bloc de notas. Después de un momento, cierre el Bloc de notas. El cuadro de mensaje aparece cuando se cierra el Bloc de notas.

    ExecCmd "NOTEPAD.EXE": MsgBox "Process Finished" 
    

Soporte técnico y comentarios

¿Tiene preguntas o comentarios sobre VBA para Office o esta documentación? Vea Soporte técnico y comentarios sobre VBA para Office para obtener ayuda sobre las formas en las que puede recibir soporte técnico y enviar comentarios.