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.
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&
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
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.