Determinar quando um processo em shell termina

Quando você executa a função Shell em um procedimento do Visual Basic for Applications (VBA), ela inicia um programa executável de forma assíncrona e retorna o controle ao procedimento. Esse programa em shell continua a ser executado independentemente do procedimento até que você o feche.

Se o procedimento precisar aguardar o término do processo em shell, você poderá usar a API do Windows para pesquisar o status do aplicativo, mas isso não é muito eficiente. Este tópico explica um método mais eficiente.

A API do Windows tem uma funcionalidade integrada que permite que seu aplicativo aguarde até que um processo em shell seja concluído. Para usar essas funções, você precisa ter um identificador para o processo em shell. Para fazer isso, use a função CreateProcess em vez da função Shell para iniciar o programa em shell.

Criar o processo em shell

Para criar um processo endereçável, use a função CreateProcess para iniciar seu aplicativo em shell. A função CreateProcess fornece ao programa o identificador de processo do processo em shell por meio de um de seus parâmetros passados.

Aguarde o término do processo em shell

Depois de usar a função CreateProcess para obter um identificador de processo, você pode passar esse identificador para a função WaitForSingleObject . Isso faz com que o procedimento do VBA suspenda a execução até que o processo em shell termine.

As etapas a seguir são necessárias para criar um procedimento VBA que usa a função CreateProcess para executar o aplicativo Bloco de Notas do Windows. Este código mostra como usar as funções CreateProcess e WaitForSingleObject da API do Windows para aguardar até que um processo em shell termine antes de retomar a execução.

A sintaxe da função CreateProcess é complexa, portanto, no código de exemplo, ela é encapsulada em uma função chamada ExecCmd. O ExecCmd usa um parâmetro, a linha de comando do aplicativo a ser executado.

  1. Crie um módulo padrão e cole as seguintes linhas na seção Declarações:

    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. Cole o seguinte código no 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 testar a função, cole o seguinte código na janela Imediato e pressione Enter. O Bloco de notas inicia. Depois de alguns momentos, feche o Bloco de Notas. A caixa de mensagem será exibida quando o Bloco de notas for fechado.

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

Suporte e comentários

Tem dúvidas ou quer enviar comentários sobre o VBA para Office ou sobre esta documentação? Confira Suporte e comentários sobre o VBA para Office a fim de obter orientação sobre as maneiras pelas quais você pode receber suporte e fornecer comentários.