VBA: chamar uma macro em outra macro

Setembro 2017

Para chamar uma macro a partir de outra, vamos ter que distinguir vários casos. A chamada de um Sub ou de uma função não é feita exatamente da mesma maneira. Além disso, vamos ter que estudar, separadamente, a chamada de um procedimento de evento e a chamada de um procedimento contida em outra pasta de trabalho.


Chamar um Sub a partir de um Sub

Sem configurações

Quando os dois Sub estão no mesmo módulo e não têm parâmetros. A Macro2 chama a Macro1:

Sub Macro1()
    MsgBox "Hello world!"
End Sub

Sub Macro2()
    Call Macro1
End Sub

Eventualmente, podemos fazer sem a instrução Call:

Sub Macro1()
    MsgBox "Hello world!"
End Sub

Sub Macro2()
    Macro1
End Sub

No entanto, eu não recomendo. Na verdade, esta instrução Call torna o código muito mais legível. Ao lê-lo, o programador vê, imediatamente, que se trata da chamada de um procedimento.

Quando os dois Sub estão em módulos diferentes e não têm parâmetros. Não é preciso especificar o módulo. O exemplo anterior funcionará da mesma forma, porém você deverá pensar na sua manutenção, desde a criação do seu código. O fato de especificar em que módulo fica o procedimento chamado, fará com que você não perca tempo com pesquisas inúteis durante os possíveis desbloqueios. Então, se a Macro1 estiver no Módulo1 e a Macro2 no Módulo 2:

Sub Macro1()
    MsgBox "Hello world!"
End Sub

Sub Macro2()
    Call Module1.Macro1
End Sub

Com configurações

O método é o mesmo. Basta adicionar as configurações entre parênteses. No entanto, cuidado ao digitar essas configurações, para evitar a geração de erro (do tipo 13). Se a sua função espera um parâmetro digitado em string, não envie uma Dupla dobro:

Com a instrução Call:

Sub Macro1(Nb1 As Long, Nb2 As Long)
    Range("A1") = Nb1
    Range("A2") = Nb2
End Sub

Sub Macro2()
    Call Macro1(18254, 654897)
End Sub

Sem a instrução Call:

Sub Macro1(Nb1 As Long, Nb2 As Long)
    Range("A1") = Nb1
    Range("A2") = Nb2
End Sub

Sub Macro2()
    Macro1 18254321, 654897
End Sub

Note-se aqui a ausência de parênteses.

Se as macros estiverem em diferentes módulos, mesma sanção:

Sub Macro2()
    Call Module1.Macro1(918254321, 654897)
End Sub

Chamada de uma função a partir de um Sub

O que é uma função, mesmo? O que a diferencia de um Sub? Uma função (Function) é uma instrução que depende de parâmetros e que retorna um valor. Um Sub também é uma instrução dependente de parâmetros (se houver), mas não retorna nada.

Exemplo de Function:

Function Addition(Nb1 As Double, Nb2 As Double) As Double
Addition = Nb1 + Nb2
End Function

Aqui vemos que a nossa Function é declarada como As Double (esta declaração de tipo é opcional). O valor que ela retorna será do tipo duplo (Double). Como uma função retorna um valor, você deverá, no Sub que chama, prever o armazenamento desse valor. Isso pode se dar tanto em uma célula do Excel, como em uma variável (pensar em declarar a variável no tipo certo), em um controle, etc.

Aqui vamos recebê-la em uma variável do mesmo tipo (Double):

 Sub Macro2()
  Dim Soma As Double
  Soma = Addition(1234.56, 654.32)
  MsgBox Soma
End Sub

Function Addition(Nb1 As Double, Nb2 As Double) As Double
Addition = Nb1 + Nb2
End Function 

Note-se aqui a obrigação de colocar os parâmetros entre parênteses e separados por vírgulas.

Chamada de uma Function a partir de uma Function

Exatamente o mesmo princípio.


Exemplo com armazenamento do resultado em uma variável intermediária:

 Sub Macro2()
  Dim Soma As Double
  Soma = Addition(1234.56, 654.32)
  MsgBox Soma
End Sub

Function Addition(Nb1 As Double, Nb2 As Double) As Double
  Dim VarNb As Double
  VarNb = MultiplicadoPorDois(Nb2)
  Addition = Nb1 + VarNb
End Function

Function MultiplicadoPorDois(Nb As Double) As Double
  MultiplicadoPorDois = Nb * 2
End Function

Mesmo exemplo sem variável intermediária:

 Sub Macro2()
  Dim Soma As Double
  Soma = Addition(1234.56, 654.32)
  MsgBox Soma
End Sub

Function Addition(Nb1 As Double, Nb2 As Double) As Double
  Addition = Nb1 + MultiplicadoPorDois(Nb2)
End Function

Function MultiplicadoPorDois(Nb As Double) As Double
  MultiplicadoPorDois = Nb * 2
End Function

Chamada de um procedimento de evento

Um procedimento de evento é uma declaração que se ativa automaticamente durante uma ação do usuário em um objeto. O objeto pode ser uma planilha, uma pasta de trabalho, uma prova, etc. O evento pode ser a abertura ou o fechamento de uma pasta de trabalho, a mudança de planilha, a escolha em uma lista, digitar em uma prova, etc. Os procedimentos de evento são usados para interceptar essas ações, para iniciar, automaticamente, os procedimentos que você criou.


Exemplo:
Gostaríamos que, quando houver uma alteração do valor da célula A1, apareça em B1, "Nada mal!", se A1 for superior a 10. Para isso, vá no código do Módulo da planilha em questão e clique direito na guia da planilha > Ver o Código.

Na janela de código, insira isto:

Private Sub Worksheet_Change(ByVal Target As Range)
'Se a célula da mudança não tiver o endereço A1 => fechamos
If Target.Address <> "$A$1" Then Exit Sub
'Se a célula (A1) for superior a 10 colocaremos "Nada mal!" na B1
If Target.Value > 10 Then Target.Offset(0, 1) = "Nada mal!" Else Target.Offset(0, 1) = "Insuficiente!"
End Sub

Você já pode testar o efeito, alterando o valor da célula A1 da planilha em questão.

Observação: você me dirá: "basta alterar o valor da A1 a partir da nossa macro, e isso funcionará. Sim, você tem razão. Mas isso é apenas um exemplo.

Com a instrução Call

Se o seu procedimento de chamada estiver situado no mesmo módulo que o seu procedimento de evento, basta chamá-lo, assim:

Private Sub Worksheet_Change(ByVal Target As Range)
'Se a célula da mudança não tiver o endereço A1 => fechamos
If Target.Address <> "$A$1" Then Exit Sub
'Se a célula (A1) for superior a 10 colocaremos "Nada mal!" na B1
If Target.Value > 10 Then Target.Offset(0, 1) = "Nada mal!" Else Target.Offset(0, 1) = "Insuficiente!"
End Sub

Sub MaMacro()
Dim minhaLinha As Range
Set minhaLinha = Sheets("Planilha1").Range("A1")
Call Worksheet_Change(minhaLinha)
End Sub

Em compensação, se você colocar o seu procedimento de chamada no Módulo1, por exemplo, seja lá o que você fizer, mesmo declarando como Public em vez de Private, você continuará a receber uma mensagem de erro: "Erro de compilação Sub ou Função não definida." Mais claramente, o VBA não tem acesso ao procedimento de evento. Como dar-lhe este acesso?

Como dar acesso ao VBA com a função CallByName

Sintaxe: CallByName (Objeto, NomeDoProcedimento, TypeAppel, Args());

Objeto: obrigatório. Do tipo Objeto. Designa o objeto envolvido no procedimento;

NomeDoProcedimento: obrigatório. Do tipo String. Representa o nome do processo de chamada;

TipoDeChamada: obrigatório. Do tipo CallType. Talvez Method, Set, Let ou Get;

Args(): opcional. Tabela de parâmetros a serem passados para a função de chamada.

No nosso exemplo, vamos colocar MinhaMacro no Módulo1 e tentar chamar o Sub Worksheet_Change. Antes disso, é preciso declarar o nosso procedimento de evento em outro nível. Na verdade, declarada como Private (Privada), ela só poderá ser usada no módulo da planilha.

Então, tiramos a palavra Private do módulo da planilha:

Sub Worksheet_Change(ByVal Target As Range)
'Se a célula da mudança não tiver o endereço A1 => fechamos
If Target.Address <> "$A$1" Then Exit Sub
'Se a célula (A1) for superior a 10 colocaremos "Nada mal!" na B1
If Target.Value > 10 Then Target.Offset(0, 1) = "Nada mal!" Else Target.Offset(0, 1) = "Insuficiente!"
End Sub

Agora, vamos colocar o Sub MinhaMacro no Módulo2:

 Sub MinhaMacro()
Dim minhaLinha As Range
Set minhaLinha = Sheets("Planilha1").Range("A1")
CallByName Worksheets("Planilha1"), "Worksheet_Change", VbMethod, minhaLinha
End Sub

Outro exemplo:
Ao clicar em um botão do formulário de usuário (UserForm2), eu quero acionar o evento ComboBox1_Change de uma lista suspensa situada num UserForm1:

 Private Sub CommandButton1_Click()
CallByName UserForm1, "ComboBox1_Change", VbMethod
End Sub

Sem esquecer de, antes, remover o Private do evento em questão: Sub ComboBox1_Change().

Chamada de um procedimento em outra pasta de trabalho

Neste caso, será preciso usar o método Run. Vamos especificar, principalmente, a pasta de trabalho com o procedimento de chamada e o nome do mesmo.

Caso da chamada de um Sub

Aqui, temos duas opções:


Ou o arquivo foi aberto anteriormente. Neste caso, não há necessidade de especificar o caminho de acesso:

Sub TestRun()
Application.Run "'Pasta1.xlsm'!Módulo2.Macro2"
End Sub

Ou a pasta de trabalho está fechada. De qualquer maneira, o caminho de acesso completo deve ser referenciado:

Sub TestRun()
Application.Run "'C:\Users\franck\Desktop\Pasta1.xlsm'!Módulo2.Macro2"
End Sub

Observação: note a presença obrigatória das aspas em torno do nome do arquivo.

Caso de chamada de uma Function

Como no caso da chamada de uma função a partir da mesma pasta de trabalho, você deverá pensar em um lugar de armazenamento. Neste caso, uma variável. Também vamos ter que comunicar a partir do Sub de chamada, todos os parâmetros a serem transmitidos para a função de chamada.

Retomemos a nossa Function Addition situada na ‘Pasta1.xlsm’:

Function Addition(Nb1 As Double, Nb2 As Double) As Double
Addition = Nb1 + Nb2
End Function 

Para chamá-la no nosso procedimento Principal() situada na pasta de trabalho ‘Pasta2.xlsm’, precisamos do seguinte código:

Pasta já aberta:

Sub Principal()
Dim Soma As Double
  Soma = Run("'Pasta1.xlsm'!Module2.Addition", 1234.56, 654.32)
  MsgBox Soma
End Sub

Pasta fechada:

Sub Principal ()
Dim Soma As Double
  Soma = Run("'C:\Users\franck\Desktop\Pasta1.xlsm'!Module2.Adição", 1234.56, 654.32)
  MsgBox Soma
End Sub

Observação: se a sua pasta de trabalho foi previamente fechada, ela será aberta depois da execução desta macro. Assim sendo, não se esqueça de fechá-la com um código.

Nosso último exemplo. Se adicionarmos o encerramento da pasta de trabalho, ficaria assim:

Sub TestRun()
Dim Soma As Double
  Soma = Run("'Pasta1.xlsm'!Module2.Addition", 1234.56, 654.32)
  Workbooks("Pasta1.xlsm").Close False
  MsgBox Soma
End Sub

Conclusão

Não deixe de compartilhar qualquer comentário sobre estas explicações. Qualquer dúvida, poste sua pergunta no fórum adequado.


Foto: © Microsoft.

Veja também

Artigo original publicado por pijaku. Tradução feita por pintuda. Última modificação: 2 de agosto de 2017 às 12:52 por Pedro.CCM.
Este documento, intitulado 'VBA: chamar uma macro em outra macro', está disponível sob a licença Creative Commons. Você pode copiar e/ou modificar o conteúdo desta página com base nas condições estipuladas pela licença. Não se esqueça de creditar o CCM (br.ccm.net) ao utilizar este artigo.