El día de hoy, hablaremos de cómo compartir información entre subrutinas de VBA al invocarlas, a través del pasaje de argumentos ByVal y ByRef.Seguramente conozcas que puedes invocar una macro a partir de otra: esto significa, durante la ejecución de una subrutina de VBA determinada, hacer el llamado a una segunda subrutina, y tras la ejecución completa de esta última, retomar la primera. Esto puede ayudarte a dividir códigos extensos en fragmentos manejables, así como reutilizar y evitar la duplicación de código que puede utilizarse para más de un propósito específico.
Sin embargo, muchos estudiantes y programadores de VBA se topan con dificultades ante la necesidad de ya no solamente llamar y ejecutar macros, sino procurar pasarles algún tipo de información que estas macros secundarias puedan utilizar, leer o transformar. Sabemos que podemos almacenar información en variables, por lo que estos "paquetes" parecen apropiados para enviar información de un lado a otro. ¿Pero cómo?
VBA nos proporciona herramientas diferenciadas para los casos en que requerimos modificar variables, o únicamente leerlas. Gestionándolo adecuadamente, esto nos permitirá regular los "permisos" que existen en cuanto al acceso a las variables, para garantizar que los cambios que se produzcan sobre las mismas sean verdaderamente buscados y no accidentales. Estas herramientas son ByVal y ByRef.
- ByRef es la forma predeterminada con la cual podemos pasar argumentos: lo que se transmite es la variable en sí, con lo cual puede ser modificada antes de ser devuelta, actualizada con su nuevo valor
- ByVal es la forma en la que se proporciona acceso de "solo lectura": se envía una copia de la variable a otra macro tal que pueda leerse su valor, pero dicha variable no verá su valor alterado luego de la ejecución de la segunda macro.
Veamos cómo utilizarlas para hacer una correcta invocación a través de un ejemplo.
En primer lugar, necesitaremos contar con dos macros. Consideremos una macro Principal, que ejecuta una serie de instrucciones sin depender de otra, y una macro secundaria, llamada en este caso CalculoMonto, que es invocada por la macro Principal y debe recibir información de ella.
El objetivo de la macro Principal será capturar una serie de datos, invocar a la macro secundaria que los procesará, y finalmente mostrar un mensaje con el resultado obtenido por la segunda macro.
Para ello, crearemos tres variables: salario, que será un valor entero cargado en una celda de la hoja de cálculo, porcentaje_bono, que será un porcentaje de aumento sobre la base de salario, y monto_total, en la cual será almacenado el resultado de sumar el bono al salario. La macro secundaria, CalculoMonto, necesitará tomar estos datos y devolver un resultado. Sin embargo, no le dará el mismo tratamiento a todas las variables: únicamente necesitará leer los valores de salario y porcentaje_bono, pero necesitará actualizar el valor de monto_total, una vez realizado el cálculo.
Sub Principal()
Dim salario As Integer
Dim porcentaje_bono As Double
Dim monto_total As Double
'Capturar información
salario = Range("A1").Value
porcentaje_bono = Range("A2").Value
monto_total = 0
' Llamado para ejecutar CalculoMonto
MsgBox "Este mes percibirás un total de $" & monto_total
End Sub
En la subrutina anterior, dejamos pendiente completar la línea de invocación a CalculoMonto. Veamos primero en qué consiste esta:
Sub CalculoMonto()
resultado = valor * (1 + porcentaje)
End Sub
Como vemos, es una macro sencilla. Para que pueda recibir las variables valor, porcentaje y resultado, deberemos indicarlo dentro de los paréntesis iniciales, del siguiente modo:
Sub CalculoMonto(ByVal valor, porcentaje, ByRef resultado)
resultado = valor * (1 + porcentaje)
End Sub
En este caso, hemos hecho uso tanto de la referencia ByVal, con lo cual CalculoMonto hará únicamente lectura de los valores de las variables valor y porcentaje, y ByRef, con lo cual tendrá la capacidad de modificar el valor de resultado y devolverlo actualizado.
valor, porcentaje, resultado reciben el nombre de parámetros: valores que se esperan al invocar un procedimiento.
Sin embargo, puede que te hayas dado cuenta de algo: los nombres de las variables utilizadas en Principal y CalculoMonto no coinciden. No es motivo de preocupación: la interpretación de cuál variable se corresponde con cuál se da por la posición, como si fuera una función de Excel. Sabremos que si invocamos la subrutina CalculoMonto, tendremos que pasar en primer lugar la variable que oficiará de valor, en segundo la de porcentaje, y tercera la de resultado. En la macro Principal, estos roles las cumplen, respectivamente:
- salario
- porcentaje_bono
- monto_total
Por lo que una invocación a CalculoMonto desde Principal, se vería del siguiente modo:Call CalculoMonto(salario, porcentaje_bono, monto_total)
En esta oportunidad, no indicamos ByVal o ByRef, ya que esto se hace únicamente en la definición de la macro CalculoMonto.
salario, porcentaje_bono, monto_total reciben el nombre de argumentos: valores que se proporcionan al invocar un procedimiento.
Con ello, la situación final de ambas macros será:
Dim salario As Integer
Dim porcentaje_bono As Double
Dim monto_total As Double
'Capturar información
salario = Range("A1").Value
porcentaje_bono = Range("A2").Value
monto_total = 0
Call CalculoMonto(salario, porcentaje_bono, monto_total)
MsgBox "Este mes percibirás un total de $" & monto_total
End Sub
Sub CalculoMonto(ByVal valor, porcentaje, ByRef resultado)
resultado = valor * (1 + porcentaje)
End Sub
Y ambas macros trabajarán juntas para lograr un objetivo. Si bien trabajamos sobre un ejemplo muy sencillo, el provecho de este método adquiere mayor significado a medida que se incrementa la complejidad del proceso, ya que dividirlo en partes nos ayuda a abarcarlo de a poco. Y piensa finalmente el beneficio de invocar la macro CalculoMonto para procesar cualquier otro tipo de valor: con solo pasarle los argumentos requeridos, podrá procesar información de cualquier origen, sin duplicar o crear nuevo código.