Vba Es PDF
Vba Es PDF
Vba Es PDF
#vba
Tabla de contenido
Acerca de 1
Observaciones 2
Versiones 2
Examples 2
Depuración 6
Ventana de relojes 6
Ventana inmediata 6
Capítulo 2: Arrays 8
Examples 8
Elementos de acceso 8
Indexación de matrices 8
Índice especifico 8
Declaración dinámica 8
Arrays dinámicos 12
Arreglos Multidimensionales 16
Arreglos Multidimensionales 16
Observaciones 23
Examples 23
Utilice la función de cadena para asignar una cadena con n caracteres repetidos 23
Usa las funciones de Cadena y Espacio para asignar una cadena de n caracteres 23
Capítulo 4: Atributos 24
Sintaxis 24
Examples 24
VB_Name 24
VB_GlobalNameSpace 24
VB_Createable 24
VB_PredeclaredId 25
Declaración 25
Llamada 25
VB_Expuesto 25
VB_Descripción 26
Hacer una clase iteratable con una construcción de bucle For Each 27
Introducción 29
Sintaxis 29
Observaciones 29
Examples 29
Raspado web 33
Hacer clic 34
Principales problemas de IE 35
Observaciones 36
Examples 36
Capítulo 7: Clasificación 38
Introducción 38
Examples 38
Capítulo 8: Colecciones 41
Observaciones 41
Examples 42
Llaves 46
Artículos 47
Observaciones 49
Examples 49
Apóstrofe Comentarios 49
REM comentarios 50
Examples 51
Examples 54
Nombres de variables 54
Notación húngara 55
Nombres de procedimientos 57
Observaciones 59
Examples 59
Utilice Formato para convertir y formatear un tipo numérico como una cadena 59
Utilice StrConv para convertir una matriz de bytes de caracteres de un solo byte en una ca 59
Convertir implícitamente una matriz de bytes de caracteres de múltiples bytes en una caden 59
Examples 61
Copiando Arrays 61
Observaciones 66
Examples 66
Examples 70
Devolviendo un valor 70
Observaciones 73
Examples 73
Observaciones 75
Examples 75
Examples 76
Variables 76
Alcance 76
Variables locales 77
Variables estáticas 77
Campos 79
Campos de instancia 79
Campos de encapsulacion 80
Constantes (const) 80
Modificadores de acceso 81
Opción Módulo Privado 82
Tipo de sugerencias 82
Observaciones 87
Examples 87
Introducción 90
Examples 90
Código incorrecto 90
Código correcto 90
Otras notas 91
código incorrecto 91
Código correcto 91
Otras notas 91
código incorrecto 92
Otras notas 92
código incorrecto 93
Código correcto 93
código incorrecto 93
Código correcto 94
Otras notas 94
código incorrecto 94
Código correcto 95
Otras notas 95
Examples 96
Seleccione el caso 96
Sintaxis 98
Hacer bucle 98
Mientras bucle 99
En bucle 99
Introducción 101
Examples 101
Sintaxis 104
Observaciones 104
Examples 104
Manipuladores 104
Fuentes 106
Examples 109
La persona que llama no debe ser molestada con los controles. 110
Introducción 114
Examples 114
Capítulo 26: Lectura de 2GB + archivos en binario en VBA y File Hashes 118
Introducción 118
Observaciones 118
MÉTODOS PARA LA CLASE POR MICROSOFT 118
Examples 119
Esto tiene que estar en un módulo de clase, ejemplos más adelante referidos como "Aleatori 119
Código 126
Observaciones 129
Examples 129
Introducción 132
Observaciones 132
Examples 133
Observaciones 150
Examples 150
Notas 153
Bitwise \ Operadores lógicos 155
Examples 158
Examples 171
Introducción 178
Examples 178
Examples 180
Calendario 180
Ejemplo 180
IsDate () 182
DateDiff () 185
FechaAgregar () 185
Conversión y Creación 186
CDate () 186
DateSerial () 187
Observaciones 189
Examples 189
Usa la función de Len para determinar el número de caracteres en una cadena 189
Utilice la función LenB para determinar el número de bytes en una cadena 189
Prefiero `If Len (myString) = 0 Then` sobre` If myString = "" Then` 189
Observaciones 191
Examples 191
Sintaxis 197
Parámetros 197
Observaciones 197
Examples 198
Introducción 203
Observaciones 203
Examples 203
ByRef 204
ByVal 206
Introducción 208
Examples 208
Sintaxis 211
Parámetros 211
Observaciones 211
Examples 211
Introducción 215
Observaciones 215
Examples 215
Factoriales 215
Examples 217
Uso de FSO.BuildPath para crear una ruta completa desde la ruta de la carpeta y el nombre 221
Observaciones 222
Examples 222
Use Left o Left $ para obtener los 3 caracteres más a la izquierda en una cadena 222
Use Right o Right $ para obtener los 3 caracteres más a la derecha en una cadena 222
Use Mid o Mid $ para obtener caracteres específicos dentro de una cadena 222
Utilice Recortar para obtener una copia de la cadena sin espacios iniciales ni finales 223
Examples 224
Byte 224
Entero 225
Booleano 225
Largo 226
Soltero 226
Doble 226
Moneda 227
Fecha 227
Cuerda 228
Variante 229
LongPtr 230
Decimal 231
Observaciones 232
Examples 232
Capítulo 45: Trabajar con archivos y directorios sin usar FileSystemObject 237
Observaciones 237
Examples 237
Examples 240
Abstracción 240
Los niveles de abstracción ayudan a determinar cuándo dividir las cosas. 240
Encapsulacion 240
La encapsulación oculta los detalles de implementación del código del cliente. 241
Polimorfismo 244
Creditos 248
Acerca de
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version
from: vba
It is an unofficial and free VBA ebook created for educational purposes. All the content is extracted
from Stack Overflow Documentation, which is written by many hardworking individuals at Stack
Overflow. It is neither affiliated with Stack Overflow nor official VBA.
The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to info@zzzprojects.com
https://riptutorial.com/es/home 1
Capítulo 1: Empezando con VBA
Observaciones
Esta sección proporciona una descripción general de qué es vba y por qué un desarrollador
puede querer usarlo.
También debe mencionar cualquier tema grande dentro de vba, y vincular a los temas
relacionados. Dado que la Documentación para vba es nueva, es posible que deba crear
versiones iniciales de los temas relacionados.
Versiones
VBA para
2004, 2011 - 2016 2004-05-11
Mac
Examples
Accediendo al Editor de Visual Basic en Microsoft Office
Puede abrir el editor de VB en cualquiera de las aplicaciones de Microsoft Office presionando Alt
+ F11 o yendo a la pestaña Desarrollador y haciendo clic en el botón "Visual Basic". Si no ve la
pestaña Desarrollador en la cinta, verifique si está habilitada.
Por defecto, la pestaña Desarrollador está deshabilitada. Para habilitar la pestaña Desarrollador,
vaya a Archivo -> Opciones, seleccione Personalizar cinta en la lista de la izquierda. En la vista
de árbol derecha "Personalizar la cinta de opciones", busque el elemento del árbol Desarrollador
y configure la casilla de verificación Activar Desarrollador. Haga clic en Aceptar para cerrar el
cuadro de diálogo Opciones.
https://riptutorial.com/es/home 2
La pestaña Desarrollador ahora está visible en la cinta de opciones en la que puede hacer clic en
"Visual Basic" para abrir el Editor de Visual Basic. Alternativamente, puede hacer clic en "Ver
código" para ver directamente el panel de código del elemento activo actualmente, por ejemplo,
Hoja de trabajo, Gráfico, Forma.
https://riptutorial.com/es/home 3
https://riptutorial.com/es/home 4
https://riptutorial.com/es/home 5
en su barra de herramientas o simplemente presione la tecla F5 . ¡Felicidades! Has construido tu
primer módulo VBA propio.
Depuración
La depuración es una forma muy poderosa de observar de cerca y corregir el código que funciona
incorrectamente (o que no funciona).
Ventana de relojes
Ejecutar el código línea por línea es solo el primer paso, necesitamos conocer más detalles y una
herramienta para eso es la ventana de visualización (Ver - Ventana de visualización), aquí puede
ver los valores de las expresiones definidas. Para agregar una variable a la ventana de
visualización, ya sea:
Cuando agrega una nueva expresión, puede elegir si solo desea ver su valor, o también
interrumpir la ejecución del código cuando es verdadera o cuando cambia su valor.
https://riptutorial.com/es/home 6
Ventana inmediata
La ventana inmediata le permite ejecutar código arbitrario o imprimir elementos precediéndolos
con la palabra clave Print o con un único signo de interrogación " ? "
Algunos ejemplos:
* La obtención / configuración de valores para variables a través de la ventana Inmediata solo se puede realizar
durante el tiempo de ejecución
Si eso no ayuda, entonces comience a depurarlo; para procedimientos cortos, puede ser eficiente
simplemente ejecutarlo línea por línea, para los más largos probablemente necesite establecer
puntos de interrupción o interrupciones en las expresiones observadas, el objetivo aquí es
encontrar que la línea no funcione como se espera.
Una vez que tenga la línea que da el resultado incorrecto, pero la razón aún no está clara, intente
simplificar expresiones o reemplace las variables con constantes, que pueden ayudar a entender
si el valor de las variables es incorrecto.
https://riptutorial.com/es/home 7
Capítulo 2: Arrays
Examples
Declarando un Array en VBA
Declarar una matriz es muy similar a declarar una variable, excepto que necesita declarar la
dimensión de la Matriz justo después de su nombre:
De forma predeterminada, las matrices en VBA se indexan desde CERO , por lo tanto, el número
dentro del paréntesis no se refiere al tamaño de la matriz, sino al índice del último elemento
Elementos de acceso
El acceso a un elemento de la matriz se realiza utilizando el nombre de la matriz, seguido del
índice del elemento, entre paréntesis:
Indexación de matrices
Puede cambiar la indexación de Arrays colocando esta línea en la parte superior de un módulo:
Option Base 1
Con esta línea, todos los Arrays declarados en el módulo serán indexados desde UNO .
Índice especifico
También puede declarar cada Array con su propio índice usando la palabra clave To , y el límite
inferior y superior (= índice):
Declaración dinámica
Cuando no conoce el tamaño de su Array antes de su declaración, puede usar la declaración
dinámica y la palabra clave ReDim :
https://riptutorial.com/es/home 8
Dim myDynamicArray() As Strings 'Creates an Array of an unknown number of strings
ReDim myDynamicArray(5) 'This resets the array to 6 elements
Tenga en cuenta que el uso de la palabra clave ReDim eliminará cualquier contenido anterior de su
Array. Para evitar esto, puede usar la palabra clave Preserve después de ReDim :
Función de división
devuelve una matriz unidimensional basada en cero que contiene un número específico de
subcadenas.
Sintaxis
Parte Descripción
Ajustes
https://riptutorial.com/es/home 9
Constante Valor Descripción
Ejemplo
En este ejemplo se muestra cómo funciona la división mostrando varios estilos. Los comentarios
mostrarán el conjunto de resultados para cada una de las diferentes opciones de división
realizadas. Finalmente, se demuestra cómo recorrer la matriz de cadena devuelta.
Sub Test
https://riptutorial.com/es/home 10
de una matriz:
A For Each loop iterará todas las dimensiones de exterior a interno (el mismo orden que los
elementos están en la memoria), por lo que no hay necesidad de bucles anidados:
https://riptutorial.com/es/home 11
Next
Tenga en cuenta que los bucles For Each se utilizan mejor para iterar objetos de la Collection , si
el rendimiento es importante.
0
1
2
3
Arrays dinámicos
Agregar y reducir dinámicamente las variables en una matriz es una gran ventaja para cuando la
información que está tratando no tiene un número determinado de variables.
En el siguiente ejemplo, creamos una matriz y la aumentamos en una variable más en cada
iteración, a la vez que conservamos los valores que ya se encuentran en la matriz.
For n = 1 To 100
If IsEmpty(Dynamic_array) Then
'isempty() will check if we need to add the first value to the array or subsequent
ones
ReDim Dynamic_array(0)
'ReDim Dynamic_array(0) will resize the array to one variable only
Dynamic_array(0) = n
Else
ReDim Preserve Dynamic_array(0 To UBound(Dynamic_array) + 1)
'in the line above we resize the array from variable 0 to the UBound() = last
variable, plus one effectivelly increeasing the size of the array by one
Dynamic_array(UBound(Dynamic_array)) = n
'attribute a value to the last variable of Dynamic_array
End If
Next
https://riptutorial.com/es/home 12
Eliminar valores dinámicamente
Podemos utilizar la misma lógica para disminuir la matriz. En el ejemplo, el valor "último" se
eliminará de la matriz.
En el siguiente fragmento, construyo una matriz con los valores de 1 a 40, vacío la matriz y la
recargo con los valores de 40 a 100, todo esto se hace de forma dinámica.
For n = 1 To 100
If IsEmpty(Dynamic_array) Then
ReDim Dynamic_array(0)
Dynamic_array(0) = n
Next
https://riptutorial.com/es/home 13
internas), mientras que la matriz dentada sería como una anual Calendario con las matrices
internas que tienen un número diferente de elementos, como días en diferentes meses.
Aunque los Arreglos Jagged son bastante complicados y difíciles de usar debido a sus niveles
anidados y no tienen muchos tipos de seguridad, pero son muy flexibles, le permiten manipular
diferentes tipos de datos con bastante facilidad y no necesitan contener datos no utilizados o
elementos vacios.
Debug.Print OuterArray(0)(1)
Debug.Print OuterArray(1)(1)
'accessing elements inside the jagged by giving the coordenades of the element
https://riptutorial.com/es/home 14
Else
ReDim Preserve Headers(0 To UBound(Headers) + 1)
Headers(UBound(Headers)) = Cells(1, c).Value
End If
Next
For r = 2 To 6
'iterate through the customers/rows
For c = 1 To 4
'iterate through the values/columns
Main_Array(0) = Headers
Main_Array(1) = Customers
To better understand the way to Dynamically construct a one dimensional array please check
Dynamic Arrays (Array Resizing and Dynamic Handling) on the Arrays documentation.
El resultado del fragmento de código anterior es una matriz dentada con dos matrices, una de
esas matrices con 4 elementos, 2 niveles de sangría y la otra es otra matriz dentada que contiene
5 matrices de 4 elementos cada una y 3 niveles de sangría, vea a continuación la estructura:
https://riptutorial.com/es/home 15
Para acceder a la información, deberá tener en cuenta la estructura de la matriz irregular que
cree, en el ejemplo anterior puede ver que la Main Array contiene una matriz de Headers y una
matriz de matrices ( Customers ), por lo tanto, con diferentes formas de Accediendo a los
elementos.
Ahora leeremos la información de la Main Array e imprimiremos cada información de los clientes
como Info Type: Info .
For n = 0 To UBound(Main_Array(1))
'n to iterate from fisrt to last array in Main_Array(1)
For j = 0 To UBound(Main_Array(1)(n))
'j will iterate from first to last element in each array of Main_Array(1)
Arreglos Multidimensionales
Arreglos Multidimensionales
Como su nombre lo indica, las matrices multidimensionales son matrices que contienen más de
una dimensión, generalmente dos o tres, pero pueden tener hasta 32 dimensiones.
Una matriz múltiple funciona como una matriz con varios niveles, tome como ejemplo una
comparación entre una, dos y tres dimensiones.
*1D - Visually*
(0)
(1)
(2)
Two Dimensions se vería como una cuadrícula de Sudoku o una hoja de Excel. Al inicializar la
https://riptutorial.com/es/home 16
matriz, definiría cuántas filas y columnas tendría la matriz.
*2D - Visually*
(0,0) (0,1) (0,2)
(1,0) (1,1) (1,2)
(2,0) (2,1) (2,2)
Three Dimensions comenzaría a parecerse al Cubo de Rubik, al inicializar la matriz, definiría filas
y columnas y las capas / profundidades que tendría la matriz.
*3D - Visually*
1st layer 2nd layer 3rd layer
front middle back
(0,0,0) (0,0,1) (0,0,2) ¦ (1,0,0) (1,0,1) (1,0,2) ¦ (2,0,0) (2,0,1) (2,0,2)
(0,1,0) (0,1,1) (0,1,2) ¦ (1,1,0) (1,1,1) (1,1,2) ¦ (2,1,0) (2,1,1) (2,1,2)
(0,2,0) (0,2,1) (0,2,2) ¦ (1,2,0) (1,2,1) (1,2,2) ¦ (2,2,0) (2,2,1) (2,2,2)
Otras dimensiones podrían pensarse como la multiplicación de la 3D, por lo que una 4D (1,3,3,3)
sería dos matrices 3D de lado a lado.
El siguiente ejemplo será una compilación de una lista de empleados, cada empleado tendrá un
conjunto de información en la lista (Nombre, Apellido, Dirección, Correo electrónico, Teléfono ...),
el ejemplo esencialmente se almacenará en la matriz ( empleado, información) siendo el (0,0) es
el primer nombre del primer empleado.
Bosses = [{"Jonh","Snow","President";"Ygritte","Wild","Vice-President"}]
'initialise a 2D array directly by filling it with information, the redult wil be a array(1,2)
size 2x3 = 6 elements
https://riptutorial.com/es/home 17
the array
'needs two parameters 1st the array you which to check and 2nd the dimension, in this case 1 =
employee and 2 = information
For information_e = 0 To UBound(Employees, 2)
'for each information element/column in the array
Redimensionamiento
Cambiar el tamaño o ReDim Preserve una Multi-Array como la norma para una matriz de One-
Dimension obtendría un error, en lugar de eso, la información debe transferirse a una matriz
Temporal con el mismo tamaño que el original más el número de filas / columnas para agregar.
En el siguiente ejemplo, veremos cómo inicializar una matriz temporal, transferir la información de
la matriz original, llenar los elementos vacíos restantes y reemplazar la matriz temporal por la
matriz original.
'transfer
For emp = LBound(Employees, 1) To UBound(Employees, 1)
For info = LBound(Employees, 2) To UBound(Employees, 2)
'to transfer Employees into TempEmp we iterate both arrays and fill TempEmp with the
corresponding element value in Employees
TempEmp(emp, info) = Employees(emp, info)
Next
Next
'fill remaining
'after the transfers the Temp array still has unused elements at the end, being that it was
increased
'to fill the remaining elements iterate from the last "row" with values to the last row in the
array
'in this case the last row in Temp will be the size of the Employees array rows + 1, as the
last row of Employees array is already filled in the TempArray
Next
Next
'erase Employees, attribute Temp array to Employees and erase Temp array
Erase Employees
https://riptutorial.com/es/home 18
Employees = TempEmp
Erase TempEmp
Para cambiar / alterar los valores en un elemento determinado se puede hacer simplemente
llamando a la coordenada para cambiar y dándole un nuevo valor: Employees(0, 0) = "NewValue"
Alternativamente, iterar a través de las coordenadas usa las condiciones para hacer coincidir los
valores correspondientes a los parámetros necesarios:
Leyendo
El acceso a los elementos de la matriz se puede hacer con un bucle anidado (iterando cada
elemento), Loop y Coordenadas (iterar filas y acceder a columnas directamente), o acceder
directamente con ambas coordenadas.
'loop and coordinate, iteration through all rows and in each row accessing all columns
directly
For emp = LBound(Employees, 1) To UBound(Employees, 1)
Debug.Print Employees(emp, 0)
Debug.Print Employees(emp, 1)
Debug.Print Employees(emp, 2)
Debug.Print Employees(emp, 3)
Debug.Print Employees(emp, 4)
Debug.Print Employees(emp, 5)
Next
https://riptutorial.com/es/home 19
Para la matriz 3D, usaremos la misma premisa que la matriz 2D, con la adición de no solo
almacenar el empleado y la información, sino también la construcción en la que trabajan.
La matriz 3D tendrá los Empleados (se pueden considerar como Filas), la Información (Columnas)
y la Construcción que se pueden considerar como hojas diferentes en un documento de Excel,
tienen el mismo tamaño entre ellas, pero cada hoja tiene un Diferentes conjuntos de información
en sus celdas / elementos. La matriz 3D contendrá n número de matrices 2D.
Creando
Una matriz 3D necesita 3 coordenadas para ser inicializada Dim 3Darray(2,5,5) As Variant la
primera coordenada en la matriz será el número de Building / Sheets (diferentes conjuntos de filas
y columnas), la segunda coordenada definirá Rows y la tercera Columnas La Dim arriba dará
como resultado una matriz 3D con 108 elementos ( 3*6*6 ), que tendrá efectivamente 3 conjuntos
diferentes de matrices 2D.
Redimensionamiento
Cambiar el tamaño de una matriz 3D es similar a cambiar el tamaño de una 2D, primero cree una
matriz temporal con el mismo tamaño del original agregando una en la coordenada del parámetro
para aumentar, la primera coordenada aumentará el número de conjuntos en la matriz, la
segunda y Las terceras coordenadas aumentarán el número de filas o columnas en cada
conjunto.
El siguiente ejemplo aumenta la cantidad de Filas en cada conjunto en uno, y llena los nuevos
elementos agregados con nueva información.
https://riptutorial.com/es/home 20
'ReDim/Resize Temp array as a 3D array with size UBound(ThreeDArray)+1 = (last element in
Employees 2nd dimension) + 1,
'the other dimension remains the same as the original array. we effectively add 1 row in the
for each set of the 3D array
'transfer
For building = LBound(ThreeDArray, 1) To UBound(ThreeDArray, 1)
For emp = LBound(ThreeDArray, 2) To UBound(ThreeDArray, 2)
For info = LBound(ThreeDArray, 3) To UBound(ThreeDArray, 3)
'to transfer ThreeDArray into TempEmp by iterating all sets in the 3D array and
fill TempEmp with the corresponding element value in each set of each row
TempEmp(building, emp, info) = ThreeDArray(building, emp, info)
Next
Next
Next
'fill remaining
'to fill the remaining elements we need to iterate from the last "row" with values to the last
row in the array in each set, remember that the first empty element is the original array
Ubound() plus 1
For building = LBound(TempEmp, 1) To UBound(TempEmp, 1)
For emp = UBound(ThreeDArray, 2) + 1 To UBound(TempEmp, 2)
For info = LBound(TempEmp, 3) To UBound(TempEmp, 3)
Next
Next
Next
'erase Employees, attribute Temp array to Employees and erase Temp array
Erase ThreeDArray
ThreeDArray = TempEmp
Erase TempEmp
Do
' using Do ... While for early exit
For building = 0 To UBound(ThreeDArray, 1)
For emp = 0 To UBound(ThreeDArray, 2)
If ThreeDArray(building, emp, 0) = "Gloria" And ThreeDArray(building, emp, 1) =
"Stephan" Then
'if value found
ThreeDArray(building, emp, 1) = "Married, Last Name Change"
Exit Do
'don't iterate through all the array unless necessary
End If
Next
Next
Loop While False
https://riptutorial.com/es/home 21
For emp = LBound(ThreeDArray, 2) To UBound(ThreeDArray, 2)
For info = LBound(ThreeDArray, 3) To UBound(ThreeDArray, 3)
Debug.Print ThreeDArray(building, emp, info)
Next
Next
Next
'loop and coordinate, will iterate through all set of rows and ask for the row plus the value
we choose for the columns
For building = LBound(ThreeDArray, 1) To UBound(ThreeDArray, 1)
For emp = LBound(ThreeDArray, 2) To UBound(ThreeDArray, 2)
Debug.Print ThreeDArray(building, emp, 0)
Debug.Print ThreeDArray(building, emp, 1)
Debug.Print ThreeDArray(building, emp, 2)
Debug.Print ThreeDArray(building, emp, 3)
Debug.Print ThreeDArray(building, emp, 4)
Debug.Print ThreeDArray(building, emp, 5)
Next
Next
https://riptutorial.com/es/home 22
Capítulo 3: Asignando cadenas con
caracteres repetidos
Observaciones
Hay veces que necesita asignar una variable de cadena con un carácter específico repetido un
número específico de veces. VBA proporciona dos funciones principales para este propósito:
• String / String$
• Space / Space$ .
Examples
Utilice la función de cadena para asignar una cadena con n caracteres
repetidos
https://riptutorial.com/es/home 23
Capítulo 4: Atributos
Sintaxis
• Atributo VB_Name = "ClassOrModuleName"
• Atributo VB_GlobalNameSpace = False 'Ignored
• Atributo VB_Creatable = Falso 'Ignorado
• Atributo VB_PredeclaredId = {True | Falso}
• Atributo VB_Exposed = {True | Falso}
• Atributo variableName.VB_VarUserMemId = 0 'Cero indica que este es el miembro
predeterminado de la clase.
• Atributo variableName.VB_VarDescription = "alguna cadena" 'Agrega el texto a la
información del Examinador de objetos para esta variable.
• Atributo procName.VB_Description = "alguna cadena" 'Agrega el texto a la información del
Examinador de objetos para el procedimiento.
• Atributo procName.VB_UserMemId = {0 | -4}
○ '0: hace que la función sea el miembro predeterminado de la clase.
○ '-4: Especifica que la función devuelve un Enumerador.
Examples
VB_Name
VB_GlobalNameSpace
En VB6, crea una instancia global predeterminada de la clase (un "acceso directo") para que se
pueda acceder a los miembros de la clase sin usar el nombre de la clase. Por ejemplo, DateTime
(como en DateTime.Now ) es en realidad parte de la clase VBA.Conversion .
Debug.Print VBA.Conversion.DateTime.Now
Debug.Print DateTime.Now
VB_Createable
https://riptutorial.com/es/home 24
Este atributo se ignora. No fue portado desde VB6.
En VB6, se usó en combinación con el atributo VB_Exposed para controlar la accesibilidad de clases
fuera del proyecto actual.
VB_Exposed=True
VB_Creatable=True
Resultaría en una Public Class , a la que se podría acceder desde otros proyectos, pero esta
funcionalidad no existe en VBA.
VB_PredeclaredId
Crea una instancia global predeterminada de una clase. Se accede a la instancia predeterminada
a través del nombre de la clase.
Declaración
Llamada
Debug.Print Class1.GiveMeATwo
De alguna manera, esto simula el comportamiento de las clases estáticas en otros idiomas, pero
a diferencia de otros idiomas, aún puede crear una instancia de la clase.
VB_Expuesto
https://riptutorial.com/es/home 25
Hace que la clase sea Private . No se puede acceder fuera del proyecto actual.
Expone la clase de Public , fuera del proyecto. Sin embargo, dado que VB_Createable se ignora en
VBA, las instancias de la clase no se pueden crear directamente. Esto es equivalente a la
siguiente clase VB.Net.
Para obtener una instancia externa al proyecto, debe exponer una fábrica para crear instancias.
Una forma de hacerlo es con un módulo Public regular.
Dado que los módulos públicos son accesibles desde otros proyectos, esto nos permite crear
nuevas instancias de nuestras clases Public - Not Createable .
VB_Descripción
Agrega una descripción de texto a un miembro de clase o módulo que se hace visible en el
Explorador de objetos. Idealmente, todos los miembros públicos de una interfaz / API pública
deberían tener una descripción.
Nota: todos los miembros de acceso de una propiedad ( Get , Let , Set ) usan la misma
descripción.
https://riptutorial.com/es/home 26
una clase
Una clase de List que encapsularía una Collection desearía tener una propiedad de Item , por lo
que el código del cliente puede hacer esto:
Pero con un atributo VB_UserMemId establecido en 0 en la propiedad Item , el código del cliente
puede hacer esto:
Solo un miembro puede tener legalmente VB_UserMemId = 0 en cualquier clase dada. Para
propiedades, especifique el atributo en el Get acceso Get :
Option Explicit
Private internal As New Collection
https://riptutorial.com/es/home 27
Con el valor mágico -4 , el atributo VB_UserMemId le dice a VBA que este miembro produce un
enumerador, lo que permite que el código del cliente haga esto:
La forma más fácil de implementar este método es llamar al captador de propiedades ocultas
[_NewEnum] en una Collection interna / encapsulada; el identificador debe estar entre corchetes
debido al subrayado principal que lo convierte en un identificador de VBA ilegal:
https://riptutorial.com/es/home 28
Capítulo 5: Automatización o uso de otras
bibliotecas de aplicaciones.
Introducción
Si usa los objetos en otras aplicaciones como parte de su aplicación de Visual Basic, es posible
que desee establecer una referencia a las bibliotecas de objetos de esas aplicaciones. Esta
documentación proporciona una lista, fuentes y ejemplos de cómo usar bibliotecas de diferentes
softwares, como Windows Shell, Internet Explorer, XML HttpRequest y otros.
Sintaxis
• expression.CreateObject (ObjectName)
• expresión; Necesario. Una expresión que devuelve un objeto de aplicación.
• Nombre del objeto; Cadena requerida. El nombre de clase del objeto a crear. Para obtener
información acerca de los nombres de clase válidos, vea OLE Programmatic Identifiers.
Observaciones
• MSDN-Understanding Automation
Cuando una aplicación admite la automatización, Visual Basic puede acceder a los
objetos que la aplicación expone. Use Visual Basic para manipular estos objetos
invocando métodos en el objeto u obteniendo y configurando las propiedades del
objeto.
Si usa los objetos en otras aplicaciones como parte de su aplicación de Visual Basic,
es posible que desee establecer una referencia a las bibliotecas de objetos de esas
aplicaciones. Antes de poder hacer eso, primero debe asegurarse de que la aplicación
proporciona una biblioteca de objetos.
Le permite seleccionar los objetos de otra aplicación que desea que estén disponibles
en su código configurando una referencia a la biblioteca de objetos de esa aplicación.
• Método MSDN-CreateObject
Examples
https://riptutorial.com/es/home 29
Expresiones regulares de VBScript
Código
Puede usar estas funciones para obtener resultados RegEx, concatenar todas las coincidencias
(si son más de 1) en una cadena y mostrar el resultado en la celda de Excel.
getRegExResult = removeLeadingDelimiter(concatObjectItems(getRegExMatches(RegExObject,
SourceString, RegExPattern, isGlobalSearch, isCaseSensitive), Delimiter), Delimiter)
End Function
With RegExObj
.Global = isGlobalSearch
.IgnoreCase = Not (isCaseSensitive) 'it is more user friendly to use positive meaning
of argument, like isCaseSensitive, than to use negative IgnoreCase
.Pattern = RegExPattern
Set getRegExMatches = .Execute(SourceString)
End With
End Function
https://riptutorial.com/es/home 30
String = ";") As String
Dim ObjElement As Variant
For Each ObjElement In Obj
concatObjectItems = concatObjectItems & DelimiterCustom & ObjElement.Value
Next
End Function
Temas de MSDN-FileSystemObject : " ... explica el concepto de FileSystemObject y cómo usarlo "
. Exceltrick-FileSystemObject en VBA - Explicación
Scripting.FileSystemObject
https://riptutorial.com/es/home 31
Objeto Scripting.Dictionary
MSDN-objeto del diccionario
Objeto MSDN-InternetExplorer
Sub IEGetToKnow()
Dim IE As InternetExplorer 'Reference to Microsoft Internet Controls
Set IE = New InternetExplorer
With IE
.Visible = True 'Sets or gets a value that indicates whether the object is visible or
hidden.
'Navigation
.Navigate2 "http://www.example.com" 'Navigates the browser to a location that might
not be expressed as a URL, such as a PIDL for an entity in the Windows Shell namespace.
Debug.Print .Busy 'Gets a value that indicates whether the object is engaged in a
navigation or downloading operation.
Debug.Print .ReadyState 'Gets the ready state of the object.
.Navigate2 "http://www.example.com/2"
.GoBack 'Navigates backward one item in the history list
.GoForward 'Navigates forward one item in the history list.
.GoHome 'Navigates to the current home or start page.
.Stop 'Cancels a pending navigation or download, and stops dynamic page elements, such
as background sounds and animations.
.Refresh 'Reloads the file that is currently displayed in the object.
Debug.Print .Silent 'Sets or gets a value that indicates whether the object can
display dialog boxes.
Debug.Print .Type 'Gets the user type name of the contained document object.
Debug.Print .Top 'Sets or gets the coordinate of the top edge of the object.
Debug.Print .Left 'Sets or gets the coordinate of the left edge of the object.
Debug.Print .Height 'Sets or gets the height of the object.
Debug.Print .Width 'Sets or gets the width of the object.
End With
https://riptutorial.com/es/home 32
End Sub
Raspado web
Lo más común que se puede hacer con IE es raspar parte de la información de un sitio web, o
completar un formulario de sitio web y enviar información. Vamos a ver cómo hacerlo.
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style ... </style>
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is established to be used for illustrative examples in documents.
You may use this
domain in examples without prior coordination or asking for permission.</p>
<p><a href="http://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
Sub IEWebScrape1()
Dim IE As InternetExplorer 'Reference to Microsoft Internet Controls
Set IE = New InternetExplorer
With IE
.Visible = True
.Navigate2 "http://www.example.com"
https://riptutorial.com/es/home 33
href="http://www.iana.org/domains/example">More information...</a>"
Debug.Print .GetElementsByTagName("p")(1).innerText 'prints "More information..."
Debug.Print .GetElementsByTagName("a")(0).innerText 'prints "More information..."
'We can change the localy displayed website. Don't worry about breaking the site.
.GetElementsByTagName("title")(0).innerHtml = "Psst, scraping..."
.GetElementsByTagName("h1")(0).innerHtml = "Let me try something fishy." 'You have
just changed the local HTML of the site.
.GetElementsByTagName("p")(0).innerHtml = "Lorem ipsum........... The End"
.GetElementsByTagName("a")(0).innerText = "iana.org"
End With '.document
End Sub
Que esta pasando? El jugador clave aquí es el .Documento , que es el código fuente HTML.
Podemos aplicar algunas consultas para obtener las Colecciones u Objetos que deseamos.
Por ejemplo, el IE.Document.GetElementsByTagName("title")(0).innerHtml . GetElementsByTagName
devuelve una colección de elementos HTML, que tienen la etiqueta " título ". Sólo hay una
etiqueta de este tipo en el código fuente. La colección está basada en 0 Entonces para obtener
el primer elemento agregamos (0) . Ahora, en nuestro caso, solo queremos el innerHtml (un
String), no el Element Object en sí mismo. Por eso especificamos la propiedad que queremos.
Hacer clic
Para seguir un enlace en un sitio, podemos usar múltiples métodos:
Sub IEGoToPlaces()
Dim IE As InternetExplorer 'Reference to Microsoft Internet Controls
Set IE = New InternetExplorer
With IE
.Visible = True
.Navigate2 "http://www.example.com"
Stop 'VBE Stop. Continue line by line to see what happens.
'Click
.Document.GetElementsByTagName("a")(0).Click
Stop 'VBE Stop.
'Return Back
.GoBack
Stop 'VBE Stop.
https://riptutorial.com/es/home 34
Biblioteca de objetos HTML de Microsoft o mejor amigo de
IE
Para aprovechar al máximo el HTML que se carga en el IE, puede (o debería) usar otra
Biblioteca, es decir, la Biblioteca de Objetos HTML de Microsoft . Más sobre esto en otro ejemplo.
Principales problemas de IE
El problema principal con IE es verificar que la página haya terminado de cargarse y esté lista
para interactuar con ella. The Do While... Loop ayuda, pero no es confiable.
Además, el uso de IE solo para raspar el contenido HTML es OVERKILL. ¿Por qué? Debido a
que el navegador está diseñado para navegar, es decir, mostrar la página web con todos los
CSS, JavaScripts, imágenes, ventanas emergentes, etc. Si solo necesita los datos en bruto,
considere un enfoque diferente. Por ejemplo, utilizando XML HTTPRequest . Más sobre esto en
otro ejemplo.
https://riptutorial.com/es/home 35
Capítulo 6: Buscando dentro de las cadenas
la presencia de subcadenas.
Observaciones
Cuando necesita verificar la presencia o posición de una subcadena dentro de una cadena, VBA
ofrece las funciones InStr e InStrRev que devuelven la posición de carácter de la subcadena en la
cadena, si está presente.
Examples
Usa InStr para determinar si una cadena contiene una subcadena
https://riptutorial.com/es/home 36
https://riptutorial.com/es/vba/topic/3480/buscando-dentro-de-las-cadenas-la-presencia-de-
subcadenas-
https://riptutorial.com/es/home 37
Capítulo 7: Clasificación
Introducción
A diferencia de .NET Framework, la biblioteca de Visual Basic para aplicaciones no incluye rutinas
para ordenar matrices.
Hay dos tipos de soluciones: 1) implementar un algoritmo de clasificación desde cero, o 2) usar
rutinas de clasificación en otras bibliotecas comúnmente disponibles.
Examples
Implementación de algoritmos - Ordenación rápida en una matriz
unidimensional
tmpLow = inLow
tmpHi = inHi
Wend
End Sub
https://riptutorial.com/es/home 38
Uso de la biblioteca de Excel para ordenar una matriz unidimensional
Sub testExcelSort()
InitArray arr
ExcelSort arr
End Sub
Const size = 10
ReDim arr(size)
Dim i As Integer
End Sub
With MySort
.SortFields.Clear
.SortFields.Add rng, xlSortOnValues, xlAscending, xlSortNormal
.SetRange rng
.Header = xlNo
.Apply
End With
https://riptutorial.com/es/home 39
' Copy the results back to the array
CopyRangeToArray rng, arr
End Sub
Dim i As Long
Dim c As Range
End Sub
https://riptutorial.com/es/home 40
Capítulo 8: Colecciones
Observaciones
Una Collection es un objeto contenedor que se incluye en el tiempo de ejecución de VBA. No se
requieren referencias adicionales para usarlo. Una Collection se puede utilizar para almacenar
artículos de cualquier tipo de datos y permite la recuperación mediante el índice ordinal del
artículo o mediante el uso de una clave única opcional.
Cómo determinar si un artículo Iterar todos los Iterar todos los Iterar todos los
existe elementos elementos elementos
Eliminar todos los elementos .Remove y. .Remove Erase , ReDim .RemoveAll función
1Solo se puede cambiar el tamaño de las matrices dinámicas, y solo la última dimensión de las
matrices multidimensionales.
https://riptutorial.com/es/home 41
3 Determinado por la propiedad .CompareMode .
Examples
Agregar elementos a una colección
Sintaxis:
Parámetro Descripción
Opcional. Una String que sirve como un identificador único para recuperar
elementos de la Collection . Si la clave especificada ya existe en la Collection ,
llave
se producirá un error de tiempo de ejecución 457: "Esta clave ya está asociada
con un elemento de esta colección".
Opcional. Una clave existente (valor de String ) o índice (valor numérico) para
insertar el elemento antes en la Collection . Si se proporciona un valor, el
parámetro posterior debe estar vacío o debe aparecer un error de tiempo de
ejecución 5: "Llamada o argumento de procedimiento no válido". Si se pasa
antes de
una clave de String que no existe en la Collection , se generará un error de
tiempo de ejecución 5: "Llamada o argumento de procedimiento no válido". Si
se pasa un índice numérico que no existe en la Collection , se generará un
error de tiempo de ejecución 9: "Subíndice fuera de rango".
Opcional. Una clave existente (valor de String ) o índice (valor numérico) para
insertar el elemento después en la Collection . Si se da un valor, el parámetro
después
anterior debe estar vacío. Los errores planteados son idénticos al parámetro
anterior .
Notas:
• Las claves no distinguen entre mayúsculas y minúsculas. .Add "Bar", "Foo" y .Add "Baz",
"foo" resultará en una colisión de teclas.
https://riptutorial.com/es/home 42
Esto significa que se debe tener cuidado al realizar inserciones en bucles utilizando índices
numéricos.
Uso de la muestra:
With foo
.Add "One" 'No key. This item can only be retrieved by index.
.Add "Two", "Second" 'Key given. Can be retrieved by key or index.
.Add "Three", , 1 'Inserted at the start of the collection.
.Add "Four", , , 1 'Inserted at index 2.
End With
Sintaxis:
.Remove(index)
Parámetro Descripción
Notas:
https://riptutorial.com/es/home 43
Uso de la muestra:
With foo
.Add "One"
.Add "Two", "Second"
.Add "Three"
.Add "Four"
End With
Sintaxis:
.Count()
Uso de la muestra:
With foo
.Add "One"
.Add "Two"
.Add "Three"
.Add "Four"
End With
Sintaxis:
.Item(index)
https://riptutorial.com/es/home 44
Parámetro Descripción
Notas:
With foo
.Add "One"
.Add "Two"
.Add "Three"
.Add "Four"
End With
https://riptutorial.com/es/home 45
foo.Add values(index), keys(index)
Next
With foo
.Add "One", "Foo"
.Add "Two", "Bar"
.Add "Three", "Baz"
End With
Tenga en cuenta que la sintaxis de bang ( ! ) Está permitida porque .Item es el miembro
predeterminado y puede tomar un solo argumento de String . La utilidad de esta sintaxis es
cuestionable.
Llaves
A diferencia de un Scripting.Dictionary , una Collection no tiene un método para determinar si
existe una clave determinada o una forma de recuperar las claves que están presentes en la
Collection . El único método para determinar si una clave está presente es usar el controlador de
errores:
If .Number = 0 Then
KeyExistsInCollection = True
ElseIf .Number <> 5 Then
.Raise .Number
End If
End With
End Function
https://riptutorial.com/es/home 46
Artículos
La única manera de determinar si un artículo está contenido en una Collection es iterar sobre la
Collection hasta que se encuentre el artículo. Tenga en cuenta que debido a que una Collection
puede contener primitivos u objetos, se necesita un manejo adicional para evitar errores de
tiempo de ejecución durante las comparaciones:
La forma más fácil de eliminar todos los elementos de una Collection es simplemente
reemplazarlo con una nueva Collection y dejar que el anterior quede fuera del alcance:
With foo
.Add "One"
.Add "Two"
.Add "Three"
End With
Sin embargo, si hay varias referencias a la Collection retenida, este método solo le dará una
Collection vacía para la variable asignada .
https://riptutorial.com/es/home 47
With foo
.Add "One"
.Add "Two"
.Add "Three"
End With
En este caso, la forma más fácil de borrar el contenido es recorrer la cantidad de elementos en la
Collection y eliminar repetidamente el elemento más bajo:
https://riptutorial.com/es/home 48
Capítulo 9: Comentarios
Observaciones
Bloques de comentarios
Si necesita comentar o descomentar varias líneas a la vez, puede usar los botones de la barra de
herramientas de edición del IDE:
Descomprimir bloque : elimina el primer apóstrofe del inicio de todas las líneas
seleccionadas
Comentarios multilínea Muchos otros idiomas admiten comentarios de bloque multilínea, pero
VBA solo permite comentarios de una sola línea.
Examples
Apóstrofe Comentarios
Un comentario se marca con un apóstrofe ( ' ) y se ignora cuando se ejecuta el código. Los
comentarios ayudan a explicar su código a futuros lectores, incluido usted mismo.
Como todas las líneas que comienzan con un comentario se ignoran, también se pueden usar
para evitar que el código se ejecute (mientras se depura o refactoriza). Colocar un apóstrofe '
antes de que su código lo convierta en un comentario. (Esto se llama comentar la línea.)
Sub InlineDocumentation()
'Comments start with an "'"
'They can be place before a line of code, which prevents the line from executing
'Debug.Print "Hello World"
https://riptutorial.com/es/home 49
but this can make for hard to read code
REM comentarios
Sub RemComments()
Rem Comments start with "Rem" (VBA will change any alternate casing to "Rem")
Rem is an abbreviation of Remark, and similar to DOS syntax
Rem Is a legacy approach to adding comments, and apostrophes should be preferred
Rem Comments CANNOT appear after a statement, use the apostrophe syntax instead
Rem Unless they are preceded by the instruction separator token
Debug.Print "Hello World": Rem prints a welcome message
Debug.Print "Hello World" 'Prints a welcome message
End Sub
https://riptutorial.com/es/home 50
Capítulo 10: Compilación condicional
Examples
Cambiar el comportamiento del código en tiempo de compilación
La directiva #Const se usa para definir una constante de preprocesador personalizada. Estos
pueden ser utilizados posteriormente por #If para controlar qué bloques de código se compilan y
ejecutan.
#Const DEBUGMODE = 1
#Const Scope
La directiva #Const solo es efectiva para un archivo de código único (módulo o clase). Debe
declararse para todos y cada uno de los archivos en los que desea utilizar su constante
personalizada. Alternativamente, puede declarar un #Const globalmente para su proyecto yendo a
Herramientas >> [Nombre de su proyecto] Propiedades del proyecto. Esto abrirá el cuadro de
diálogo de propiedades del proyecto donde ingresaremos la declaración constante. En el cuadro
"Argumentos de compilación condicional", escriba [constName] = [value] . Puede ingresar más de
1 constante separándolas con dos puntos, como [constName1] = [value1] : [constName2] =
[value2] .
https://riptutorial.com/es/home 51
Constantes predefinidas
Algunas constantes de compilación ya están predefinidas. Las que existan dependerán del grado
de bit de la versión de Office en la que esté ejecutando VBA. Tenga en cuenta que Vba7 se
introdujo junto con Office 2010 para admitir versiones de Office de 64 bits.
Tenga en cuenta que Win64 / Win32 se refiere a la versión de Office, no a la versión de Windows.
Por ejemplo, Win32 = TRUE en Office de 32 bits, incluso si el sistema operativo es una versión de
Windows de 64 bits.
https://riptutorial.com/es/home 52
#If Win64 Then
Declare PtrSafe Function GetFoo64 Lib "exampleLib32" () As LongLong
#Else
Declare PtrSafe Function GetFoo Lib "exampleLib32" () As Long
#End If
#Else
' Must be Vba6, the PtrSafe keyword didn't exist back then,
' so we need to declare Win32 imports a bit differently than above.
Esto se puede simplificar un poco según las versiones de Office que necesite admitir. Por
ejemplo, no hay mucha gente que aún admita versiones de Office de 16 bits. La última versión de
16 bit office fue la versión 4.3, lanzada en 1994 , por lo que la siguiente declaración es suficiente
para casi todos los casos modernos (incluido Office 2007).
Si no tiene que admitir nada más antiguo que Office 2010, esta declaración funciona bien.
https://riptutorial.com/es/home 53
Capítulo 11: Convenciones de nombres
Examples
Nombres de variables
Las variables mantienen los datos. Nómbrelos con el nombre para el que se usan, no con su tipo
de datos o alcance, usando un nombre . Si se siente obligado a numerar sus variables (por
ejemplo thing1, thing2, thing3 ), entonces considere usar una estructura de datos apropiada en
su lugar (por ejemplo, una matriz, una Collection o un Dictionary ).
Los nombres de las variables que representan un conjunto de valores iterativo, por ejemplo, una
matriz, una Collection , un Dictionary o un Range de celdas, deben ser plurales.
camelCase
End Sub
PascalCase
Para constantes:
End Sub
Sin embargo, los nombres de PascalCase hacen que el código tenga un aspecto más PascalCase y
https://riptutorial.com/es/home 54
sean tan buenos, dado que IntelliSense usa diferentes íconos para variables y constantes:
Notación húngara
Asígnele un nombre según su uso, no después de su tipo de datos o alcance.
"La notación húngara hace que sea más fácil ver cuál es el tipo de variable"
Para lo que se usa una variable es mucho más información útil que su tipo de datos,
especialmente en un lenguaje como VBA que convierte feliz e implícitamente un tipo en otro
según sea necesario.
iFile = FreeFile
Open strFile For Input As #iFile
Input #iFile, strData
bRetVal = True
CleanExit:
Close #iFile
bReadFile = bRetVal
Exit Function
CleanFail:
bRetVal = False
Resume CleanExit
End Function
https://riptutorial.com/es/home 55
Comparar con:
CleanExit:
Close #handle
CanReadFile = result
Exit Function
CleanFail:
result = False
Resume CleanExit
End Function
strDatase pasa ByRef en el ejemplo de arriba, pero junto al hecho de que tenemos la suerte de
ver que se pasa explícitamente como tal, no hay ninguna indicación de que strData está
realmente devuelto por la función.
El ejemplo de abajo lo nombra fuera de outContent ; este prefijo de out es para lo que se inventó la
notación húngara: para ayudar a aclarar para qué se utiliza una variable , en este caso para
identificarla claramente como un parámetro "fuera".
Esto es útil, porque IntelliSense por sí mismo no muestra ByRef , incluso cuando el parámetro se
pasa explícitamente por referencia:
La notación húngara originalmente no tenía nada que ver con tipos de variables . De hecho, la
notación húngara hecha correctamente es realmente útil. Considere este pequeño ejemplo ( ByVal
y As Integer eliminado por brevedad):
Comparar con:
https://riptutorial.com/es/home 56
srcy dst son los prefijos de notación húngara aquí, y transmiten información útil que de otra
manera no se puede inferir de los nombres de parámetros o IntelliSense que nos muestra el tipo
declarado.
Por supuesto, hay una mejor manera de transmitirlo todo, mediante una abstracción adecuada y
palabras reales que se pueden pronunciar en voz alta y tiene sentido, como un ejemplo artificial:
Type Coordinate
RowIndex As Long
ColumnIndex As Long
End Type
Nombres de procedimientos
Los procedimientos hacen algo . Nómbrelos después de lo que están haciendo, usando un verbo
. Si no es posible nombrar con precisión un procedimiento, es probable que el procedimiento esté
haciendo demasiadas cosas y deba dividirse en procedimientos más pequeños y más
especializados.
PascalCase
End Sub
End Function
ObjectName_EventName
End Sub
End Sub
https://riptutorial.com/es/home 57
Miembros booleanos
Comparar con:
El prefijo Can tiene el mismo propósito que el prefijo b : identifica el valor de retorno de la función
como Boolean . Pero Can leer mejor que b :
Comparado con:
Considere el uso de prefijos como Can , Is o Has delante de los miembros que regresan a Boolean
(funciones y propiedades), pero solo cuando agrega valor. Esto cumple con las directrices
actuales de nomenclatura de Microsoft .
https://riptutorial.com/es/home 58
Capítulo 12: Convertir otros tipos a cadenas
Observaciones
VBA convertirá implícitamente algunos tipos en cadenas según sea necesario y sin ningún trabajo
adicional por parte del programador, pero VBA también proporciona una serie de funciones de
conversión de cadenas explícitas, y también puede escribir las suyas propias.
Examples
Usa CStr para convertir un tipo numérico a una cadena
Utilice Formato para convertir y formatear un tipo numérico como una cadena
'Declare an array of bytes, assign single-byte character codes, and convert to a string
Dim singleByteChars(4) As Byte
singleByteChars(0) = 72
singleByteChars(1) = 101
singleByteChars(2) = 108
singleByteChars(3) = 108
singleByteChars(4) = 111
Dim stringFromSingleByteChars As String
stringFromSingleByteChars = StrConv(singleByteChars, vbUnicode)
'stringFromSingleByteChars = "Hello"
'Declare an array of bytes, assign multi-byte character codes, and convert to a string
Dim multiByteChars(9) As Byte
multiByteChars(0) = 87
https://riptutorial.com/es/home 59
multiByteChars(1) = 0
multiByteChars(2) = 111
multiByteChars(3) = 0
multiByteChars(4) = 114
multiByteChars(5) = 0
multiByteChars(6) = 108
multiByteChars(7) = 0
multiByteChars(8) = 100
multiByteChars(9) = 0
https://riptutorial.com/es/home 60
Capítulo 13: Copiando, devolviendo y
pasando matrices.
Examples
Copiando Arrays
Puede copiar una matriz VBA en una matriz del mismo tipo utilizando el operador = . Las matrices
deben ser del mismo tipo, de lo contrario, el código arrojará un error de compilación "No se puede
asignar a la matriz".
La matriz de origen puede ser fija o dinámica, pero la matriz de destino debe ser dinámica. Si
intenta copiar en una matriz fija, se producirá un error de compilación "No se puede asignar a la
matriz". Cualquier dato preexistente en la matriz receptora se pierde y sus límites y dimensiones
se cambian al mismo que la matriz de origen.
Una vez que se realiza la copia, las dos matrices se separan en la memoria, es decir, las dos
variables no son referencias a los mismos datos subyacentes, por lo que los cambios realizados
en una matriz no aparecen en la otra.
source(0) = 3
source(1) = 1
source(2) = 4
destination = source
destination(0) = 2
https://riptutorial.com/es/home 61
Debug.Print source(0); source(1); source(2) ' outputs: 3 1 4
Debug.Print destination(0); destination(1); destination(2) ' outputs: 2 1 4
destination = source
var = source
destination = var
var = 5
destination = var ' throws runtime error
Una función en un módulo normal (pero no en un módulo de clase) puede devolver una matriz
poniendo () después del tipo de datos.
https://riptutorial.com/es/home 62
outputArray(0) = 3
outputArray(1) = 1
outputArray(2) = 4
arrayOfPiDigits = outputArray
End Function
El resultado de la función se puede colocar en una matriz dinámica del mismo tipo o una variante.
También se puede acceder directamente a los elementos utilizando un segundo conjunto de
corchetes, sin embargo, esto llamará a la función cada vez, por lo que es mejor almacenar los
resultados en una nueva matriz si planea usarlos más de una vez.
Sub arrayExample()
destination = arrayOfPiDigits()
var = arrayOfPiDigits
End Sub
Tenga en cuenta que lo que se devuelve es en realidad una copia de la matriz dentro de la
función, no una referencia. Por lo tanto, si la función devuelve el contenido de una matriz estática,
sus datos no pueden modificarse mediante el procedimiento de llamada.
Sub printPiDigits()
Dim digits(0 To 2) As Long
https://riptutorial.com/es/home 63
threePiDigits digits
Debug.Print digits(0); digits(1); digits(2) ' outputs 3 1 4
End Sub
destination(0) = 3
destination(1) = 1
destination(2) = 4
End Sub
mathConsts.threePiDigits digits
Debug.Print digits(0); digits(1); digits(2) ' outputs 3 1 4
End Sub
Las matrices se pueden pasar a los procedimientos poniendo () después del nombre de la
variable de matriz.
Las matrices deben ser pasadas por referencia. Si no se especifica ningún mecanismo de paso,
por ejemplo, myFunction(arr()) , VBA asumirá ByRef de forma predeterminada, sin embargo, es
una buena práctica de codificación para hacerlo explícito. Intentar pasar una matriz por valor, por
ejemplo, myFunction(ByVal arr()) generará un error de compilación "El argumento de la matriz
debe ser ByRef" (o un error de compilación "Error de sintaxis" si la Auto Syntax Check no está
marcada en las opciones de VBE) .
Sub testArrayPassing()
Dim source(0 To 1) As Long
source(0) = 3
source(1) = 1
https://riptutorial.com/es/home 64
Debug.Print source(0); source(1) ' outputs 6 2
End Sub
Si desea evitar cambiar la matriz original, tenga cuidado de escribir la función para que no cambie
ningún elemento.
También puede crear una copia de trabajo de la matriz y trabajar con la copia.
copyOfArr(0) = copyOfArr(0) * 2
copyOfArr(1) = copyOfArr(1) * 2
https://riptutorial.com/es/home 65
Capítulo 14: Creación de una clase
personalizada
Observaciones
Este artículo mostrará cómo crear una clase personalizada completa en VBA. Utiliza el ejemplo
de un objeto DateRange , porque las fechas de inicio y finalización a menudo se pasan juntas a las
funciones.
Examples
Agregar una propiedad a una clase
Un procedimiento de Property es una serie de sentencias que recupera o modifica una propiedad
personalizada en un módulo.
Los accesores de propiedades a menudo se definen en pares, utilizando tanto Get como Let / Set
para cada propiedad. Una propiedad con sólo una Get procedimiento sería de sólo lectura,
mientras que una propiedad con sólo una Let / Set procedimiento sería de sólo escritura.
1. StartDate ( lectura / escritura ). Valor de fecha que representa la fecha anterior en un rango.
Cada procedimiento utiliza el valor de la variable del módulo, mStartDate .
2. EndDate ( lectura / escritura ). Valor de fecha que representa la fecha posterior en un rango.
Cada procedimiento utiliza el valor de la variable del módulo, mEndDate .
3. DaysBetween ( solo lectura ). Valor entero calculado que representa el número de días entre
las dos fechas. Como solo hay un procedimiento de Get , esta propiedad no se puede
modificar directamente.
4. RangeToCopy ( solo escritura ). Un procedimiento de Set utilizado para copiar los valores de un
objeto DateRange existente.
Private mStartDate As Date ' Module variable to hold the starting date
Private mEndDate As Date ' Module variable to hold the ending date
https://riptutorial.com/es/home 66
' Set the starting date value. Note that two methods have the name StartDate
Public Property Let StartDate(ByVal NewValue As Date)
mStartDate = NewValue
End Property
' Read-only property that returns the number of days between the two dates
Public Property Get DaysBetween() As Integer
DaysBetween = DateDiff("d", mStartDate, mEndDate)
End Function
Me.StartDate = ExistingRange.StartDate
Me.EndDate = ExistingRange.EndDate
End Property
Se puede llamar a cualquier Sub , Function , o Property pública dentro de un módulo de clase
precediendo a la llamada con una referencia de objeto:
Object.Procedure
En una clase de DateRange , se puede usar un Sub para agregar un número de días a la fecha de
finalización:
Una Function podría devolver el último día del próximo fin de mes (tenga en cuenta que
GetFirstDayOfMonth no sería visible fuera de la clase porque es privada):
Los procedimientos pueden aceptar argumentos de cualquier tipo, incluidas las referencias a los
objetos de la clase que se está definiendo.
https://riptutorial.com/es/home 67
El siguiente ejemplo prueba si el objeto DateRange actual tiene una fecha de inicio y una fecha de
finalización que incluye la fecha de inicio y finalización de otro objeto DateRange .
Tenga en cuenta el uso de la notación Me como una forma de acceder al valor del objeto que
ejecuta el código.
De forma predeterminada, un nuevo módulo de clase es una clase privada, por lo que solo está
disponible para la creación de instancias y su uso dentro del VBProject en el que está definido.
Puede declarar, crear instancias y usar la clase en cualquier lugar del mismo proyecto:
Pero a menudo escribirá clases que le gustaría usar en otros proyectos sin copiar el módulo entre
proyectos. Si define una clase llamada List en ProjectA , y desea usar esa clase en ProjectB ,
entonces deberá realizar 4 acciones:
2. Cree una función pública de "fábrica" en ProjectA que cree y devuelva una instancia de una
clase de List . Normalmente, la función de fábrica incluiría argumentos para la inicialización
de la instancia de clase. La función de fábrica es necesaria porque ProjectB puede usar la
clase, pero ProjectB no puede crear directamente una instancia de la clase de ProjectA .
4. En ProjectB , declare una variable y asígnele una instancia de List usando la función de
fábrica de ProjectA
https://riptutorial.com/es/home 68
'Use the items list methods and properties
items.Add "fizz"
Debug.Print items.ToString()
'Destroy the items object
Set items = Nothing
https://riptutorial.com/es/home 69
Capítulo 15: Creando un procedimiento
Examples
Introducción a los procedimientos.
Un Sub es un procedimiento que realiza una tarea específica pero no devuelve un valor específico.
Una Function es un procedimiento que recibe datos y devuelve un valor, idealmente sin efectos
secundarios globales o de alcance de módulo.
Una Property es un procedimiento que encapsula los datos del módulo. Una propiedad puede
tener hasta 3 accesores: Get para devolver un valor o una referencia de objeto, Let asignar un
valor y / o Set para asignar una referencia de objeto.
Devolviendo un valor
Un procedimiento de Property Get Function o Property Get puede (¡y debería!) Devolver un valor a
su interlocutor. Esto se hace asignando el identificador del procedimiento:
https://riptutorial.com/es/home 70
Funcionar con ejemplos
Como se indicó anteriormente, las funciones son procedimientos más pequeños que contienen
piezas pequeñas de código que pueden ser repetitivas dentro de un procedimiento.
Similar a un procedimiento, una función puede ser declarada con o sin una lista de argumentos.
La función se declara como un tipo de retorno, ya que todas las funciones devuelven un valor. El
nombre y la variable de retorno de una función son los mismos.
La función puede ser llamada de varias maneras dentro de una función. Dado que una función
declarada con un tipo de retorno es básicamente una variable. Se usa similar a una variable.
Llamadas funcionales:
call greet() 'Similar to a Procedural call just allows the Procedure to use the
'variable greet
string_1=greet() 'The Return value of the function is used for variable
'assignment
Además, la función también se puede utilizar como condiciones para y otras declaraciones
condicionales.
for i = 1 to 10
if check_even(i) then
msgbox i & " is Even"
else
msgbox i & " is Odd"
end if
next i
Además, más funciones pueden tener modificadores como By ref y By val para sus argumentos.
https://riptutorial.com/es/home 71
procedimiento
https://riptutorial.com/es/home 72
Capítulo 16: CreateObject vs. GetObject
Observaciones
En su forma más simple, CreateObject crea una instancia de un objeto, mientras que GetObject
obtiene una instancia existente de un objeto. Determinar si un objeto se puede crear o obtener
dependerá de su propiedad de Instancing . Algunos objetos son SingleUse (por ejemplo, WMI) y
no se pueden crear si ya existen. Otros objetos (por ejemplo, Excel) son MultiUse y permiten que
varias instancias se ejecuten a la vez. Si aún no existe una instancia de un objeto e intenta
GetObject , recibirá el siguiente mensaje atrapable: Run-time error '429': ActiveX component can't
create object .
GetObject requiere que al menos uno de estos dos parámetros opcionales esté presente:
1. Nombre de ruta - Variante (cadena): la ruta completa, incluido el nombre de archivo, del
archivo que contiene el objeto. Este parámetro es opcional, pero se requiere clase si se
omite el nombre de ruta .
2. Clase - Variante (String): una cadena que representa la definición formal (Application y
ObjectType) del objeto. Se requiere clase si se omite el nombre de ruta .
1. Clase - Variante (String): una cadena que representa la definición formal (Application y
ObjectType) del objeto. La clase es un parámetro requerido.
2. Servername - Variant (String): el nombre del equipo remoto en el que se creará el objeto. Si
se omite, el objeto se creará en la máquina local.
1. Aplicación de Word.
2. Hoja de Excel
3. Scripting.FileSystemObject
Examples
Demostrando GetObject y CreateObject
Función MSDN-GetObject
https://riptutorial.com/es/home 73
Utilice la función GetObject cuando haya una instancia actual del objeto o si desea
crear el objeto con un archivo ya cargado. Si no hay una instancia actual y no desea
que el objeto comience con un archivo cargado, use la función CreateObject.
Sub CreateVSGet()
Dim ThisXLApp As Excel.Application 'An example of early binding
Dim AnotherXLApp As Object 'An example of late binding
Dim ThisNewWB As Workbook
Dim AnotherNewWB As Workbook
Dim wb As Workbook
End Sub
https://riptutorial.com/es/home 74
Capítulo 17: Cuerdas de concatenacion
Observaciones
Las cadenas se pueden concatenar, o unir, utilizando uno o más operadores de concatenación & .
Las matrices de cadenas también se pueden concatenar utilizando la función Join y proporcionar
una cadena (que puede ser de longitud cero) para ser utilizada entre cada elemento de la matriz.
Examples
Concatenar cadenas utilizando el operador &
'Concatenate with Join and separate each element with a 3-character string
concatenatedString = VBA.Strings.Join(widgetNames, " > ")
'concatenatedString = "foo > bar > fizz"
'Concatenate with Join and separate each element with a zero-width string
concatenatedString = VBA.Strings.Join(widgetNames, vbNullString)
'concatenatedString = "foobarfizz"
https://riptutorial.com/es/home 75
Capítulo 18: Declarando variables
Examples
Declaración implícita y explícita
Si un módulo de código no contiene Option Explicit en la parte superior del módulo, entonces el
compilador creará automáticamente (es decir, "implícitamente") variables cuando los use. Ellos
por defecto serán de tipo variable Variant .
someVariable = 10 '
someOtherVariable = "Hello World"
'Both of these variables are of the Variant type.
End Sub
En el código anterior, si se especifica Option Explicit , el código se interrumpirá porque faltan las
sentencias Dim requeridas para someVariable y someOtherVariable .
Option Explicit
End Sub
Se considera una buena práctica usar Option Explicit en los módulos de código, para garantizar
que declare todas las variables.
Vea VBA Best Practices cómo configurar esta opción por defecto.
Variables
Alcance
Se puede declarar una variable (en aumento del nivel de visibilidad):
https://riptutorial.com/es/home 76
un campo de amigos
• A nivel de instancia, utilizando la palabra clave Public en cualquier tipo de módulo de clase;
Un campo público .
• A nivel mundial, utilizando la palabra clave Public en un módulo estándar ; una variable
global .
Las variables siempre deben declararse con el menor alcance posible: prefiera pasar parámetros
a procedimientos, en lugar de declarar variables globales.
Variables locales
La sintaxis de VBA también admite la declaración de múltiples variables en una sola declaración:
Observe que se debe especificar [As Type] para cada variable (que no sean las de 'Variante').
Esta es una trampa relativamente común:
Variables estáticas
Las variables locales también pueden ser Static . En VBA, la palabra clave Static se usa para
hacer que una variable "recuerde" el valor que tenía, la última vez que se llamó a un
procedimiento:
https://riptutorial.com/es/home 77
values.Add "foo"
values.Add "bar"
End If
DoSomethingElse values
End Sub
Aquí la colección de values se declara como un Static local; Debido a que es una variable de
objeto , se inicializa en Nothing . La condición que sigue a la declaración verifica si la referencia
del objeto se Set antes: si es la primera vez que se ejecuta el procedimiento, la colección se
inicializa. DoSomethingElse podría estar agregando o eliminando elementos, y aún estarán en la
colección la próxima vez que se DoSomething .
Alternativa
A menudo, un local Static podría implementarse como una variable (campo) Private a nivel de
módulo; sin embargo, esto pone en tela de juicio el principio por el cual una variable debe
declararse con el menor alcance posible; confíe en sus instintos, use el que prefiera, ambos
funcionarán ... pero usar Static sin entender lo que hace podría provocar errores interesantes.
La palabra clave Dim es legal en los niveles de procedimiento y módulo; su uso a nivel de módulo
es equivalente a usar la palabra clave Private :
Option Explicit
Dim privateField1 As Long 'same as Private privateField2 as Long
Private privateField2 As Long 'same as Dim privateField2 as Long
La palabra clave Private solo es legal a nivel de módulo; esto invita a reservar Dim para variables
locales y declarar variables de módulo con Private , especialmente con la palabra clave Public
contrastante que debería usarse de todos modos para declarar un miembro público.
Alternativamente, use Dim todas partes , lo que importa es la consistencia :
"Campos privados"
https://riptutorial.com/es/home 78
• NO use Private para declarar una variable de nivel de módulo.
• EVITA declarar campos Public . *
Campos
Una variable declarada a nivel de módulo, en la sección de declaraciones en la parte superior del
cuerpo del módulo, es un campo . Un campo Public declarado en un módulo estándar es una
variable global :
Se puede acceder a una variable con un alcance global desde cualquier lugar, incluidos otros
proyectos de VBA que hagan referencia al proyecto en el que se ha declarado.
Para hacer una variable global / pública, pero solo visible desde el proyecto, use el modificador de
Friend :
Esto es especialmente útil en los complementos, donde la intención es que otros proyectos de
VBA hagan referencia al proyecto del complemento y puedan consumir la API pública.
Friend FriendField As Long 'public within the project, aka for "friend" code
Public PublicField As Long 'public within and beyond the project
Campos de instancia
Una variable declarada a nivel de módulo, en la sección de declaraciones en la parte superior del
cuerpo de un módulo de clase (incluyendo ThisWorkbook , ThisDocument , Worksheet , UserForm y
módulos de clase ), es un campo de instancia : solo existe mientras exista una instancia de la
clase alrededor
'> Class1
Option Explicit
Public PublicField As Long
'> Module1
Option Explicit
Public Sub DoSomething()
'Class1.PublicField means nothing here
With New Class1
.PublicField = 42
End With
'Class1.PublicField means nothing here
https://riptutorial.com/es/home 79
End Sub
Campos de encapsulacion
Option Explicit
Private encapsulated As Long
La clase en sí puede modificar el valor encapsulado, pero el código de llamada solo puede
acceder a los miembros Public (y miembros de Friend , si la persona que llama está en el mismo
proyecto).
Constantes (const)
Si tiene un valor que nunca cambia en su aplicación, puede definir una constante con nombre y
usarla en lugar de un valor literal.
Puede utilizar Const solo a nivel de módulo o procedimiento. Esto significa que el contexto de
declaración para una variable debe ser una clase, estructura, módulo, procedimiento o bloque, y
no puede ser un archivo de origen, espacio de nombres o interfaz.
End Sub
https://riptutorial.com/es/home 80
Public Const GLOBAL_CONSTANT = "Project Version #1.000.000.001" 'Still a string
Public Sub ExampleDeclaration()
End Sub
Tenga en cuenta que esto es específico de las Constantes y en contraste con las variables donde
no se especifica el tipo de resultado en un tipo Variant.
Si bien es posible declarar explícitamente una constante como una cadena, no es posible declarar
una constante como una cadena usando una sintaxis de cadena de ancho fijo
Modificadores de acceso
La declaración Dim debe estar reservada para las variables locales. A nivel de módulo, prefiera
modificadores de acceso explícitos:
• para campos privados, al que solo se puede acceder dentro del módulo en el que
Private
están declarados.
• Public para campos públicos y variables globales, al que se puede acceder mediante
cualquier código de llamada.
• Friend para variables públicas dentro del proyecto, pero inaccesible para otros proyectos
VBA de referencia (relevantes para complementos)
• Global también se puede usar para campos Public en módulos estándar, pero es ilegal en
módulos de clase y está obsoleto de todos modos, prefiera el modificador Public lugar. Este
modificador tampoco es legal para los procedimientos.
ModuleVariable = "This can only be done from within the same Module"
End Sub
https://riptutorial.com/es/home 81
GlobalVariable = "This can be done from any Module within this Project"
End Sub
La especificación del Option Private Module en la parte superior de un módulo estándar evita que
sus miembros se vean expuestos como macros y UDF a la aplicación host.
Tipo de sugerencias
Las sugerencias de tipo están muy desanimadas. Existen y se documentan aquí por razones
históricas y de compatibilidad con versiones anteriores. Debería usar la sintaxis As [DataType]
lugar.
Las sugerencias de tipo disminuyen significativamente la legibilidad del código y fomentan una
notación húngara heredada que también dificulta la legibilidad:
Dim strFile$
Dim iFile%
En su lugar, declare las variables más cerca de su uso y nombre las cosas por lo que usan, no
por su tipo:
Las sugerencias de tipo también se pueden usar en literales, para imponer un tipo específico. De
forma predeterminada, un literal numérico menor que 32,768 se interpretará como un literal
Integer , pero con una sugerencia de tipo puede controlar que:
https://riptutorial.com/es/home 82
Dim foo 'implicit Variant
foo = 42& ' foo is now a Long
foo = 42# ' foo is now a Double
Debug.Print TypeName(42!) ' prints "Single"
Las sugerencias de tipo generalmente no son necesarias en los literales, ya que se asignarían a
una variable declarada con un tipo explícito, o se convertirían implícitamente al tipo apropiado
cuando se pasaran como parámetros. Las conversiones implícitas se pueden evitar usando una
de las funciones explícitas de conversión de tipos:
'Calls procedure DoSomething and passes a literal 42 as a Long using a type hint
DoSomething 42&
https://riptutorial.com/es/home 83
• VBA.Strings.LeftB -> VBA.Strings.LeftB $
• VBA.Strings.LTtrim -> VBA.Strings.LTrim $
• VBA.Strings.Mid -> VBA.Strings.Mid $
• VBA.Strings.MidB -> VBA.Strings.MidB $
• VBA.Strings.Right -> VBA.Strings.Right $
• VBA.Strings.RightB -> VBA.Strings.RightB $
• VBA.Strings.RTrim -> VBA.Strings.RTrim $
• VBA.Strings.Space -> VBA.Strings.Space $
• VBA.Strings.Str -> VBA.Strings.Str $
• VBA.Strings.String -> VBA.Strings.String $
• VBA.Strings.Trim -> VBA.Strings.Trim $
• VBA.Strings.UCase -> VBA.Strings.UCase $
Tenga en cuenta que estos son alias de funciones, no son exactamente sugerencias de tipo . La
función Left corresponde a la función oculta B_Var_Left , mientras que la versión Left$
corresponde a la función oculta B_Str_Left .
En VBA, las cadenas se pueden declarar con una longitud específica; se rellenan o truncan
automáticamente para mantener esa longitud según lo declarado.
End Sub
Una variable estática declarada localmente no se destruye y no pierde su valor cuando se sale del
procedimiento Sub. Las llamadas subsiguientes al procedimiento no requieren reinicialización o
asignación, aunque es posible que desee "cero" cualquier valor (s) recordado (s).
Estos son particularmente útiles cuando se vincula tarde un objeto en un sub 'auxiliar' que se
llama repetidamente.
https://riptutorial.com/es/home 84
Fragmento 1: reutilizar un objeto Scripting.Dictionary en muchas hojas de trabajo
Option Explicit
Sub main()
Dim w As Long
For w = 1 To Worksheets.Count
processDictionary ws:=Worksheets(w)
Next w
End Sub
With ws
End With
End Sub
Fragmento 2: cree un UDF de hoja de cálculo que tarde enlaza el objeto VBScript.RegExp
Option Explicit
With rgx
.Global = True
.MultiLine = True
.Pattern = "[0-9]{1,999}"
If .Test(str) Then
https://riptutorial.com/es/home 85
Set cmat = .Execute(str)
'resize the nums array to accept the matches
ReDim nums(cmat.Count - 1)
'populate the nums array with the matches
For n = LBound(nums) To UBound(nums)
nums(n) = cmat.Item(n)
Next n
'convert the nums array to a delimited string
numbersOnly = Join(nums, delim)
Else
numbersOnly = vbNullString
End If
End With
End Function
Ejemplo de UDF con objeto estático rellenado a través de medio millón de filas
Recuerde que un UDF no se calcula una vez en la vida útil de un libro de trabajo. Incluso un UDF
no volátil se volverá a calcular siempre que los valores dentro del rango (s) a los que hace
referencia estén sujetos a cambios. Cada evento de recálculo posterior solo aumenta los
beneficios de una variable declarada estáticamente.
• Una variable estática está disponible durante la vida útil del módulo, no el procedimiento o la
función en la que se declaró y asignó.
• Las variables estáticas solo pueden ser declaradas localmente.
• La variable estática contiene muchas de las mismas propiedades de una variable de nivel
de módulo privado pero con un alcance más restringido.
https://riptutorial.com/es/home 86
Capítulo 19: Declarar y asignar cadenas
Observaciones
Las cadenas son un tipo de referencia y son fundamentales para la mayoría de las tareas de
programación. Se asigna texto a las cadenas, incluso si el texto resulta ser numérico. Las
cadenas pueden ser de longitud cero, o cualquier longitud de hasta 2GB. Las versiones modernas
de VBA almacenan cadenas internamente utilizando una matriz de bytes de bytes de conjuntos
de caracteres de múltiples bytes (una alternativa a Unicode).
Examples
Declara una cadena constante
https://riptutorial.com/es/home 87
stateCodes(0) = "TX"
stateCodes(1) = "CA"
stateCodes(2) = "NY"
VBA ofrece una función Mid para devolver subcadenas dentro de una cadena, pero también
ofrece Mid Statement que se puede usar para asignar subcadenas o caracteres individuales
dentro de una cadena.
'Output:
'Smyth
Nota: Si necesita asignar bytes individuales en una cadena en lugar de caracteres individuales
dentro de una cadena (consulte las observaciones a continuación sobre el conjunto de caracteres
de múltiples bytes), se puede usar la declaración MidB . En este caso, el segundo argumento para
la declaración MidB es la posición basada en 1 del byte donde se iniciará la sustitución, por lo que
la línea equivalente al ejemplo anterior sería MidB(surname, 5, 2) = "y" .
Las cadenas pueden asignarse directamente a matrices de bytes y viceversa. Recuerde que las
cadenas se almacenan en un conjunto de caracteres de múltiples bytes (consulte las Notas a
continuación), por lo que solo el resto del índice de la matriz resultante será la parte del carácter
que se encuentra dentro del rango ASCII.
example = "Testing."
bytes = example 'Direct assignment.
https://riptutorial.com/es/home 88
Debug.Print reverted 'Prints "Testing."
https://riptutorial.com/es/home 89
Capítulo 20: Errores en tiempo de ejecución
de VBA
Introducción
El código que se compila todavía puede tener errores, en tiempo de ejecución. Este tema
enumera los más comunes, sus causas y cómo evitarlos.
Examples
Error en tiempo de ejecución '3': Devolución sin GoSub
Código incorrecto
Sub DoSomething()
GoSub DoThis
DoThis:
Debug.Print "Hi!"
Return
End Sub
Código correcto
Sub DoSomething()
GoSub DoThis
Exit Sub
DoThis:
Debug.Print "Hi!"
Return
End Sub
Al introducir una instrucción Exit Sub antes de la DoThis línea DoThis , hemos separado la subrutina
DoThis del resto del cuerpo del procedimiento: la única forma de ejecutar la subrutina DoThis es a
través del salto GoSub .
https://riptutorial.com/es/home 90
Otras notas
GoSub/ Return está en desuso, y debe evitarse en favor de las llamadas a procedimientos reales.
Un procedimiento no debe contener subrutinas, excepto los controladores de errores.
Esto es muy similar al error en tiempo de ejecución '20': Reanudar sin error ; en ambas
situaciones, la solución es garantizar que la ruta de ejecución normal no pueda ingresar a una
subrutina (identificada por una etiqueta de línea) sin un salto explícito (asumiendo que On Error
GoTo se considera un salto explícito ).
código incorrecto
Sub DoSomething()
Dim row As Integer
For row = 1 To 100000
'do stuff
Next
End Sub
El tipo de datos Integer es un entero con signo de 16 bits con un valor máximo de 32,767;
asignarlo a algo más grande que eso desbordará el tipo y generará este error.
Código correcto
Sub DoSomething()
Dim row As Long
For row = 1 To 100000
'do stuff
Next
End Sub
Al usar un entero Long (32 bits) en su lugar, ahora podemos hacer un bucle que itere más de
32,767 veces sin desbordar el tipo de variable del contador.
Otras notas
Consulte Tipos de datos y límites para obtener más información.
https://riptutorial.com/es/home 91
código incorrecto
Sub DoSomething()
Dim foo(1 To 10)
Dim i As Long
For i = 1 To 100
foo(i) = i
Next
End Sub
foo es una matriz que contiene 10 elementos. Cuando el contador de bucle i alcanza un valor de
11, foo(i) está fuera de rango . Este error se produce siempre que se accede a una matriz o
colección con un índice que no existe en esa matriz o colección.
Código correcto
Sub DoSomething()
Dim foo(1 To 10)
Dim i As Long
For i = LBound(foo) To UBound(foo)
foo(i) = i
Next
End Sub
Use las funciones LBound y UBound para determinar los límites inferior y superior de una matriz,
respectivamente.
Otras notas
Cuando el índice es una cadena, por ejemplo, ThisWorkbook.Worksheets("I don't exist") , este
error significa que el nombre proporcionado no existe en la colección consultada.
Sub RaisesRunTimeError5()
Dim foo As New Collection
foo.Add "foo", "foo"
Debug.Print foo("bar")
End Sub
https://riptutorial.com/es/home 92
código incorrecto
VBA está realmente tratando de convertir el "42?" argumento en un valor de Date . Cuando falla, la
llamada a DoSomethingElse no se puede ejecutar, porque VBA no sabe qué fecha pasar, por lo que
aumenta el tipo de error de tiempo de ejecución 13, porque el tipo de argumento no coincide con
el tipo esperado (y puede Tampoco se convertirá implícitamente).
Código correcto
código incorrecto
Sub DoSomething()
Dim foo As Collection
With foo
.Add "ABC"
.Add "XYZ"
End With
End Sub
Las variables de objeto contienen una referencia y las referencias deben establecerse con la
https://riptutorial.com/es/home 93
palabra clave Set . Este error se produce cuando se realiza una llamada de miembro en un objeto
cuya referencia es Nothing . En este caso, foo es una referencia de Collection , pero no está
inicializada, por lo que la referencia no contiene Nothing , y no podemos llamar a .Add en Nothing .
Código correcto
Sub DoSomething()
Dim foo As Collection
Set foo = New Collection
With foo
.Add "ABC"
.Add "XYZ"
End With
End Sub
Al asignar a la variable de objeto una referencia válida utilizando la palabra clave Set , las
llamadas .Add se .Add correctamente.
Otras notas
A menudo, una función o propiedad puede devolver una referencia de objeto; un ejemplo común
es el método Range.Find de Excel, que devuelve un objeto Range :
Sin embargo, la función puede devolver Nothing (si no se encuentra el término de búsqueda), por
lo que es probable que la llamada al miembro .Row encadenado falle.
Antes de llamar a los miembros del objeto, verifique que la referencia esté establecida con una
condición If Not xxxx Is Nothing :
código incorrecto
Sub DoSomething()
On Error GoTo CleanFail
DoSomethingElse
https://riptutorial.com/es/home 94
CleanFail:
Debug.Print Err.Number
Resume Next
End Sub
Código correcto
Sub DoSomething()
On Error GoTo CleanFail
DoSomethingElse
Exit Sub
CleanFail:
Debug.Print Err.Number
Resume Next
End Sub
Al introducir una instrucción Exit Sub antes de la CleanFail línea CleanFail , hemos segregado la
subrutina de manejo de errores CleanFail del resto del cuerpo del procedimiento: la única forma
de ejecutar la subrutina de manejo de errores es a través de un salto On Error ; por lo tanto,
ninguna ruta de ejecución llega a la instrucción Resume fuera de un contexto de error, lo que evita
el error 20 en tiempo de ejecución.
Otras notas
Esto es muy similar al error en tiempo de ejecución '3': Devolución sin GoSub ; en ambas
situaciones, la solución es garantizar que la ruta de ejecución normal no pueda ingresar a una
subrutina (identificada por una etiqueta de línea) sin un salto explícito (asumiendo que On Error
GoTo se considera un salto explícito ).
https://riptutorial.com/es/home 95
Capítulo 21: Estructuras de control de flujo
Examples
Seleccione el caso
Select Case puede usarse cuando son posibles muchas condiciones diferentes. Las condiciones
se verifican de arriba a abajo y solo se ejecutará el primer caso que coincida.
Sub TestCase()
Dim MyVar As String
Select Case MyVar 'We Select the Variable MyVar to Work with
Case "Hello" 'Now we simply check the cases we want to check
MsgBox "This Case"
Case "World"
MsgBox "Important"
Case "How"
MsgBox "Stuff"
Case "Are"
MsgBox "I'm running out of ideas"
Case "You?", "Today" 'You can separate several conditions with a comma
MsgBox "Uuuhm..." 'if any is matched it will go into the case
Case Else 'If none of the other cases is hit
MsgBox "All of the other cases failed"
End Select
Dim i As Integer
Select Case i
Case Is > 2 '"Is" can be used instead of the variable in conditions.
MsgBox "i is greater than 2"
'Case 2 < Is '"Is" can only be used at the beginning of the condition.
'Case Else is optional
End Select
End Sub
La lógica del bloque Select Case se puede invertir para admitir la prueba de diferentes variables,
en este tipo de escenario también podemos usar operadores lógicos:
Dim x As Integer
Dim y As Integer
x = 2
y = 5
https://riptutorial.com/es/home 96
Case Not y = 5
MsgBox "y is not 5"
Case x = 3 Or x = 10
MsgBox "x = 3 or 10"
Case y < 10 And x < 10
MsgBox "x and y are less than 10"
Case Else
MsgBox "No match found"
End Select
Las declaraciones de casos también pueden usar operadores aritméticos. Cuando se usa un
operador aritmético contra el valor de Select Case , debe ir precedido por la palabra clave Is :
Dim x As Integer
x = 5
Select Case x
Case 1
MsgBox "x equals 1"
Case 2, 3, 4
MsgBox "x is 2, 3 or 4"
Case 7 To 10
MsgBox "x is between 7 and 10 (inclusive)"
Case Is < 2
MsgBox "x is less than one"
Case Is >= 7
MsgBox "x is greater than or equal to 7"
Case Else
MsgBox "no match found"
End Select
La construcción de bucle For Each es ideal para iterar todos los elementos de una colección.
End Sub
https://riptutorial.com/es/home 97
Evitar For Each al iterar matrices; un bucle For ofrecerá un rendimiento significativamente mejor
con las matrices. Por el contrario, un bucle For Each ofrecerá un mejor rendimiento al iterar una
Collection .
Sintaxis
For Each [item] In [collection]
[statements]
Next [item]
La palabra clave Next puede ser seguida opcionalmente por la variable iterador; Esto puede
ayudar a aclarar los bucles anidados, aunque hay mejores formas de aclarar el código anidado,
como extraer el bucle interno en su propio procedimiento.
Debug.Print book.FullName
Hacer bucle
'Equivalent to the above loop, but the condition is only checked AFTER the
'first iteration of the loop, so it will execute even at least once even
'if entry is equal to "Stop" before entering the loop (like in this case)
Do
entry = InputBox("Enter a string, Stop to end")
Debug.Print entry
Loop While entry <> "Stop"
https://riptutorial.com/es/home 98
Loop
Mientras bucle
En bucle
El bucle For se usa para repetir la sección adjunta del código un número determinado de veces. El
siguiente ejemplo simple ilustra la sintaxis básica:
El código anterior declara un entero i . El bucle For asigna cada valor entre 1 y 10 a i y luego
ejecuta Debug.Print i , es decir, el código imprime los números del 1 al 10 en la ventana
inmediata. Tenga en cuenta que la variable de bucle se incrementa con la Next instrucción, es
decir, después de que se ejecuta el código adjunto y no antes de que se ejecute.
De forma predeterminada, el contador se incrementará en 1 cada vez que se ejecute el bucle. Sin
embargo, se puede especificar un Step para cambiar la cantidad del incremento como un valor
literal o de retorno de una función. Si el valor inicial, el valor final o el valor de Step es un número
de punto flotante, se redondeará al valor entero más cercano. Step puede ser un valor positivo o
negativo.
Dim i As Integer
For i = 1 To 10 Step 2
Debug.Print i 'Prints 1, 3, 5, 7, and 9
Next
En general, un bucle For se usaría en situaciones en las que se sabe antes de que el bucle
comience cuántas veces se ejecuta el código adjunto (de lo contrario, un bucle Do o While puede
ser más apropiado). Esto se debe a que la condición de salida se corrige después de la primera
https://riptutorial.com/es/home 99
entrada en el bucle, ya que este código demuestra:
Dim i As Integer
For i = 1 To 10
If i > 5 Then
Exit For
End If
Debug.Print i 'Prints 1, 2, 3, 4, 5 before loop exits early.
Next
https://riptutorial.com/es/home 100
Capítulo 22: Estructuras de datos
Introducción
[TODO: Este tema debe ser un ejemplo de todas las estructuras de datos básicas de CS 101
junto con una explicación como una descripción general de cómo se pueden implementar las
estructuras de datos en VBA. Esta sería una buena oportunidad para vincular y reforzar los
conceptos introducidos en los temas relacionados con la Clase en la documentación de VBA.]
Examples
Lista enlazada
Este ejemplo de lista enlazada implementa operaciones de tipos de datos abstractos establecidos
.
Clase SinglyLinkedNode
Option Explicit
Clase LinkedList
Option Explicit
https://riptutorial.com/es/home 101
If node Is head Then
Set head = node.nextNode
Else
Set prev.nextNode = node.nextNode
End If
Exit Sub
End If
Set prev = node
Set node = node.nextNode
Wend
End Sub
End Function
Árbol binario
7
/ \
5 9
/ \ \
3 6 11
\
12
\
14
https://riptutorial.com/es/home 102
\
15
Clase BinaryTreeNode
Option Explicit
Clase binario
[QUE HACER]
https://riptutorial.com/es/home 103
Capítulo 23: Eventos
Sintaxis
• Módulo de origen : [Public] Event [identifier]([argument_list])
Observaciones
• Un evento solo puede ser Public . El modificador es opcional porque los miembros del
módulo de clase (incluidos los eventos) son implícitamente Public de forma predeterminada.
• Una variable WithEvents puede ser Private o Public , pero no Friend . El modificador es
obligatorio porque WithEvents no es una palabra clave que declara una variable, sino una
palabra clave modificadora que forma parte de la sintaxis de declaración de la variable. Por
lo tanto, la palabra clave Dim debe usarse si no está presente un modificador de acceso.
Examples
Fuentes y manejadores
Las API a menudo exponen objetos que generan una serie de eventos en respuesta a varios
estados. Por ejemplo, un objeto Excel.Application genera un evento cada vez que se crea, abre,
activa o cierra un nuevo libro de trabajo. O cuando se calcula una hoja de cálculo. O justo antes
de guardar un archivo. O inmediatamente después. Un botón en un formulario genera un evento
Click cuando el usuario hace clic en él, el formulario del usuario genera un evento justo después
de que se activa y otro justo antes de que se cierre.
Desde la perspectiva de la API, los eventos son puntos de extensión : el código del cliente puede
elegir implementar un código que maneje estos eventos y ejecutar código personalizado cada vez
que se activen: así es como puede ejecutar su código personalizado automáticamente cada vez
que la selección cambia en cualquier hoja de trabajo - manejando el evento que se activa cuando
la selección cambia en cualquier hoja de cálculo.
Un objeto que expone eventos es un origen de eventos . Un método que maneja un evento es un
manejador .
https://riptutorial.com/es/home 104
Manipuladores
Los módulos de documentos VBA (por ejemplo, ThisDocument , ThisWorkbook , Sheet1 , etc.) y los
módulos UserForm son módulos de clase que implementan interfaces especiales que exponen una
serie de eventos . Puede navegar por estas interfaces en el menú desplegable del lado izquierdo
en la parte superior del panel de código:
El menú desplegable del lado derecho muestra los miembros de la interfaz seleccionada en el
menú desplegable del lado izquierdo:
Cada declaración WithEvents está disponible para seleccionar desde el menú desplegable del lado
izquierdo. Cuando se selecciona un evento en el menú desplegable del lado derecho, el VBE
genera un apéndice de controlador de eventos con el nombre del objeto WithEvents y el nombre
del evento, unido con un guión bajo:
End Sub
https://riptutorial.com/es/home 105
End Sub
Solo los tipos que exponen al menos un evento pueden usarse con WithEvents , y las
declaraciones WithEvents no pueden ser asignadas una referencia en el momento con la palabra
clave New . Este código es ilegal:
La referencia del objeto se debe Set explícitamente; en un módulo de clase, un buen lugar para
hacerlo es a menudo en el controlador Class_Initialize , porque entonces la clase maneja los
eventos de ese objeto mientras exista su instancia.
Fuentes
Cualquier módulo de clase (o módulo de documento o formulario de usuario) puede ser un origen
de evento. Use la palabra clave Event para definir la firma del evento, en la sección de
declaraciones del módulo:
La firma del evento determina cómo se genera el evento y cómo se verán los controladores de
eventos.
Los eventos solo se pueden generar dentro de la clase en la que están definidos, el código del
cliente solo puede manejarlos . Los eventos se RaiseEvent con la palabra clave RaiseEvent ; Los
argumentos del evento se proporcionan en ese punto:
Sin el código que maneja el evento SomethingHappened , la ejecución del procedimiento DoSomething
aún DoSomething el evento, pero no ocurrirá nada. Suponiendo que el origen del evento es el
código anterior en una clase llamada Something , este código en ThisWorkbook mostraría un cuadro
de mensaje que dice "hola" cada vez que se realiza una test.DoSomething .
https://riptutorial.com/es/home 106
Pasar datos de nuevo al origen del evento
RaiseEvent AfterSomething
End Sub
Suponiendo que la referencia de objeto foo se asigna en algún lugar, cuando foo.DoSomething
ejecuta, un cuadro de mensaje le foo.DoSomething si desea cancelar, y un segundo cuadro de
mensaje dice "no cancelar" solo cuando se seleccionó No.
https://riptutorial.com/es/home 107
ReturnValue = encapsulated
End Property
Combinado con el tipo Variant , esto se puede usar para crear formas no obvias de devolver un
valor a la persona que llama:
RaiseEvent SomeEvent(result)
https://riptutorial.com/es/home 108
Capítulo 24: Formularios de usuario
Examples
Mejores prácticas
Al ser un módulo de clase , un formulario es, por lo tanto, un modelo para un objeto . Debido a
que un formulario puede contener el estado y los datos, es una mejor práctica trabajar con una
nueva instancia de la clase, en lugar de con la predeterminada / global:
En lugar de:
UserForm1.Show vbModal
If Not UserForm1.IsCancelled Then
'...
End If
Trabajar con la instancia predeterminada puede provocar errores sutiles cuando el formulario se
cierra con el botón rojo "X" y / o cuando se utiliza Unload Me en el código subyacente.
Escriba el código de tal manera que UserForm solo sea responsable de saber cómo mostrar y
recopilar datos: de dónde provienen los datos, o qué sucede con los datos después, no es motivo
de preocupación.
https://riptutorial.com/es/home 109
La persona que llama no debe ser molestada con los controles.
Cree un modelo bien definido para el formulario con el que trabajar, ya sea en su propio módulo
de clase dedicado o encapsulado dentro del propio código subyacente del formulario: exponga el
modelo con procedimientos de Property Get y haga que el código del cliente trabaje con estos:
esto hace que la forma una abstracción sobre los controles y sus detalles esenciales, exponiendo
solo los datos relevantes al código del cliente.
En lugar de esto:
Por lo general, los formularios tienen un botón Cerrar , y las indicaciones / diálogos tienen los
botones Aceptar y Cancelar ; el usuario puede cerrar el formulario utilizando el cuadro de control
del formulario (el botón rojo "X"), que destruye la instancia del formulario de forma
predeterminada (otra buena razón para trabajar con una nueva instancia cada vez ).
La forma más sencilla de controlar el evento QueryClose es establecer el parámetro Cancel en True
y luego ocultar el formulario en lugar de cerrarlo :
De esa manera, el botón "X" nunca destruirá la instancia, y la persona que llama puede acceder
de forma segura a todos los miembros públicos.
https://riptutorial.com/es/home 110
Ocultar, no cerrar.
El código que crea un objeto debe ser responsable de destruirlo: no es responsabilidad del
formulario descargarse y terminarse.
Evite usar Unload Me en el código subyacente de un formulario. Call Me.Hide en Me.Hide lugar, para
que el código de llamada aún pueda usar el objeto que creó cuando se cierra el formulario.
Cualquiera que sea el estilo elegido, cualquier cosa es mejor que dejar que todos los controles
tengan sus nombres predeterminados. La consistencia en el estilo de nombre también es ideal.
El evento QueryClose se QueryClose cada vez que se cierra un formulario, ya sea a través de la
acción del usuario o mediante programación. El parámetro CloseMode contiene un valor de
enumeración VbQueryClose que indica cómo se cerró el formulario:
https://riptutorial.com/es/home 111
Constante Descripción Valor
Para una mejor legibilidad, es mejor usar estas constantes en lugar de usar su valor directamente.
Option Explicit
Private Type TView
IsCancelled As Boolean
SomeOtherSetting As Boolean
'other properties skipped for brievety
End Type
Private this As TView
https://riptutorial.com/es/home 112
'...more properties...
La propiedad IsCancelled devuelve True cuando se hace clic en el botón Cancelar , o cuando el
usuario cierra el formulario utilizando el cuadro de control .
https://riptutorial.com/es/home 113
Capítulo 25: Interfaces
Introducción
Una interfaz es una forma de definir un conjunto de comportamientos que realizará una clase. La
definición de una interfaz es una lista de firmas de métodos (nombre, parámetros y tipo de
retorno). Una clase que tiene todos los métodos se dice que "implementa" esa interfaz.
En VBA, el uso de interfaces le permite al compilador verificar que un módulo implemente todos
sus métodos. Una variable o parámetro se puede definir en términos de una interfaz en lugar de
una clase específica.
Examples
Interfaz simple - Flyable
Un módulo de clase, Airplane , usa la palabra clave Implements para decirle al compilador que
genere un error a menos que tenga dos métodos: un sub Flyable_Fly() y una función
Flyable_GetAltitude() que devuelva un Long .
Implements Flyable
Implements Flyable
https://riptutorial.com/es/home 114
Flyable_GetAltitude = 30
End Function
Podemos escribir una rutina que acepte cualquier valor de Flyable , sabiendo que responderá a
un comando de Fly o GetAltitude :
Debido a que la interfaz está definida, la ventana emergente de IntelliSense mostrará Fly y
GetAltitude for F
FlyAndCheckAltitude MyDuck
FlyAndCheckAltitude MyAirplane
La salida es:
Tenga en cuenta que aunque la subrutina se llama Flyable_Fly tanto en Airplane como en Duck ,
se puede llamar como Fly cuando la variable o el parámetro se definen como Flyable . Si la
variable se define específicamente como un Duck , debería llamarse como Flyable_Fly .
Usando el ejemplo de Flyable como punto de partida, podemos agregar una segunda interfaz,
Swimmable , con el siguiente código:
Sub Swim()
' No code
End Sub
Implements Flyable
Implements Swimmable
https://riptutorial.com/es/home 115
Public Function Flyable_GetAltitude() As Long
Flyable_GetAltitude = 30
End Function
Implements Swimmable
Ahora, podemos ver que el objeto Duck se puede pasar a un Sub como un Flyable por un lado, y
un Swimmable por el otro:
Sub InterfaceTest()
FlyAndCheckAltitude MyDuck
FlyAndCheckAltitude MyAirplane
TrySwimming MyDuck
TrySwimming MyFish
End Sub
30
https://riptutorial.com/es/home 116
10000
Flotando en el agua
https://riptutorial.com/es/home 117
Capítulo 26: Lectura de 2GB + archivos en
binario en VBA y File Hashes
Introducción
Existe una forma fácil de leer archivos en binario dentro de VBA, sin embargo, tiene una
restricción de 2GB (2,147,483,647 bytes - máx del tipo de datos Long). A medida que la
tecnología evoluciona, este límite de 2 GB se viola fácilmente. Por ejemplo, una imagen ISO del
sistema operativo instala un disco DVD. Microsoft proporciona una manera de superar esto
mediante la API de Windows de bajo nivel y aquí hay una copia de seguridad de la misma.
También demuestre (lea la parte) para calcular Hashes de archivos sin un programa externo
como fciv.exe de Microsoft.
Observaciones
Nombre del
Descripción
método
Esta abierto Devuelve un valor booleano para indicar si el archivo está abierto.
OpenFile (
sFileNam e As Abre el archivo especificado por el argumento sFileName.
String)
ReadBytes (
Lee bytes ByteCount y los devuelve en una matriz de bytes Variant y
ByteCount como
mueve el puntero.
largo)
WriteBytes (
Escribe el contenido de la matriz de bytes en la posición actual en el
DataBytes () como
archivo y mueve el puntero.
byte)
https://riptutorial.com/es/home 118
Nombre del
Descripción
método
GB.
Mueve el puntero del archivo hasta +/- 2GB desde la ubicación actual.
SeekRelative ( Puede volver a escribir este método para permitir desplazamientos
Offset As Long) mayores de 2 GB convirtiendo un desplazamiento firmado de 64 bits
en dos valores de 32 bits.
Propiedad Descripción
Nombre del
El nombre del archivo abierto actualmente.
archivo
Modulo normal
Función Notas
Debe des / comentar el uFileSize como doble en consecuencia. He probado MD5 y SHA1.
Examples
Esto tiene que estar en un módulo de clase, ejemplos más adelante referidos
como "Aleatorio"
Option Explicit
https://riptutorial.com/es/home 119
Public Enum W32F_Errors
W32F_UNKNOWN_ERROR = 45600
W32F_FILE_ALREADY_OPEN
W32F_PROBLEM_OPENING_FILE
W32F_FILE_ALREADY_CLOSED
W32F_Problem_seeking
End Enum
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function FlushFileBuffers Lib "kernel32" (ByVal hFile As Long) As Long
https://riptutorial.com/es/home 120
Private hFile As Long, sFName As String, fAutoFlush As Boolean
https://riptutorial.com/es/home 121
End If
ReDim Bytes(0 To ByteCount - 1) As Byte
ReadFile hFile, Bytes(0), ByteCount, BytesRead, 0
ReadBytes = Bytes
End Function
https://riptutorial.com/es/home 122
Err.Raise W32F_FILE_ALREADY_OPEN, W32F_SOURCE, "The file '" & sExtra & "' is
already open." & Win32Text
Case W32F_PROBLEM_OPENING_FILE
Err.Raise W32F_PROBLEM_OPENING_FILE, W32F_SOURCE, "Error opening '" & sExtra &
"'." & Win32Text
Case W32F_FILE_ALREADY_CLOSED
Err.Raise W32F_FILE_ALREADY_CLOSED, W32F_SOURCE, "There is no open file."
Case W32F_Problem_seeking
Err.Raise W32F_Problem_seeking, W32F_SOURCE, "Seek Error." & vbCrLf & sExtra
Case Else
Err.Raise W32F_UNKNOWN_ERROR, W32F_SOURCE, "Unknown error." & Win32Text
End Select
End Sub
Private uFileSize As Double ' Comment out if not testing performance by FileHashes()
Sub FileHashes()
Dim tStart As Date, tFinish As Date, sHash As String, aTestFiles As Variant, oTestFile As
Variant, aBlockSizes As Variant, oBlockSize As Variant
Dim BLOCKSIZE As Double
' This performs performance testing on different file sizes and block sizes
aBlockSizes = Array("2^12-1", "2^13-1", "2^14-1", "2^15-1", "2^16-1", "2^17-1", "2^18-1",
"2^19-1", "2^20-1", "2^21-1", "2^22-1", "2^23-1", "2^24-1", "2^25-1", "2^26-1")
aTestFiles = Array("C:\ISO\clonezilla-live-2.2.2-37-amd64.iso",
"C:\ISO\HPIP201.2014_0902.29.iso",
"C:\ISO\SW_DVD5_Windows_Vista_Business_W32_32BIT_English.ISO",
"C:\ISO\Win10_1607_English_x64.iso",
"C:\ISO\SW_DVD9_Windows_Svr_Std_and_DataCtr_2012_R2_64Bit_English.ISO")
Debug.Print "Test files: " & Join(aTestFiles, " | ")
Debug.Print "BlockSizes: " & Join(aBlockSizes, " | ")
For Each oTestFile In aTestFiles
Debug.Print oTestFile
For Each oBlockSize In aBlockSizes
https://riptutorial.com/es/home 123
BLOCKSIZE = Evaluate(oBlockSize)
tStart = Now
sHash = GetFileHash(CStr(oTestFile), BLOCKSIZE, HashTypeMD5)
tFinish = Now
Debug.Print sHash, uFileSize, Format(tFinish - tStart, "hh:mm:ss"), oBlockSize & "
(" & BLOCKSIZE & ")"
Next
Next
End Sub
Application.ScreenUpdating = False
' Process the file in chunks of uBlockSize or less
If uFileSize = 0 Then
ReDim aBlock(0)
oCSP.TransformFinalBlock aBlock, 0, 0
bDone = True
Else
With oRnd
.OpenFile sFile
Do
If uBytesRead + uBlockSize < uFileSize Then
uBytesToRead = uBlockSize
Else
uBytesToRead = uFileSize - uBytesRead
bDone = True
End If
' Read in some bytes
aBytes = .ReadBytes(uBytesToRead)
aBlock = aBytes
If bDone Then
oCSP.TransformFinalBlock aBlock, 0, uBytesToRead
uBytesRead = uBytesRead + uBytesToRead
Else
uBytesRead = uBytesRead + oCSP.TransformBlock(aBlock, 0, uBytesToRead,
aBlock, 0)
End If
https://riptutorial.com/es/home 124
DoEvents
Loop Until bDone
.CloseFile
End With
End If
If bDone Then
' convert Hash byte array to an hexadecimal string
aHash = oCSP.hash
For i = 0 To UBound(aHash)
Mid$(sHash, i * 2 + (aHash(i) > 15) + 2) = Hex(aHash(i))
Next
End If
Application.ScreenUpdating = True
' Clean up
oCSP.Clear
CleanUp:
Set oFSO = Nothing
Set oRnd = Nothing
Set oCSP = Nothing
GetFileHash = sHash
End Function
Tamaño del
Nombre del archivo
archivo (bytes)
146,800,640 clonezilla-live-2.2.2-37-amd64.iso
798,210,048 HPIP201.2014_0902.29.iso
2,073,016,320 SW_DVD5_Windows_Vista_Business_W32_32BIT_English.ISO
4.380.387.328 Win10_1607_English_x64.iso
5,400,115,200 SW_DVD9_Windows_Svr_Std_and_DataCtr_2012_R2_64Bit_English.ISO
Otra variación del código anterior le brinda más rendimiento cuando desea obtener códigos hash
de todos los archivos de una carpeta raíz, incluidas todas las subcarpetas.
https://riptutorial.com/es/home 125
Código
Option Explicit
uFileCount = 0
If oRnd Is Nothing Then Set oRnd = New Random ' Class by Microsoft: Random
If oFSO Is Nothing Then Set oFSO = CreateObject("Scripting.FileSystemObject") ' Just to
get correct FileSize
If oCSP Is Nothing Then Set oCSP = CreateObject("System.Security.Cryptography." &
sHashType & "CryptoServiceProvider")
ProcessFolder oFSO.GetFolder(sRootFDR)
Application.StatusBar = False
Application.ScreenUpdating = True
oCSP.Clear
Set oCSP = Nothing
Set oRng = Nothing
Set oFSO = Nothing
Set oRnd = Nothing
https://riptutorial.com/es/home 126
Debug.Print "Total file count: " & uFileCount
End Sub
If oRnd Is Nothing Then Set oRnd = New Random ' Class by Microsoft: Random
If oFSO Is Nothing Then Set oFSO = CreateObject("Scripting.FileSystemObject") ' Just to
get correct FileSize
If oCSP Is Nothing Then Set oCSP = CreateObject("System.Security.Cryptography." &
sHashType & "CryptoServiceProvider")
https://riptutorial.com/es/home 127
uFileSize = oFSO.GetFile(sFile).Size ' FILELEN() has 2GB max
uBytesRead = 0
bDone = False
sHash = String(oCSP.HashSize / 4, "0") ' Each hexadecimal is 4 bits
https://riptutorial.com/es/home 128
Capítulo 27: Literales de cadenas - Escape,
caracteres no imprimibles y continuaciones
de línea
Observaciones
La asignación de literales de cadena en VBA está limitada por las limitaciones del IDE y la página
de códigos de la configuración de idioma del usuario actual. Los ejemplos anteriores demuestran
los casos especiales de cadenas escapadas, cadenas especiales no imprimibles y cadenas
largas literales.
Al asignar literales de cadena que contienen caracteres que son específicos de una determinada
página de códigos, es posible que deba tener en cuenta los problemas de internacionalización
asignando una cadena de un archivo de recursos Unicode separado.
Examples
Escapando al "personaje
La sintaxis de VBA requiere que aparezca una cadena literal dentro de " marcas " , de modo que
cuando su cadena deba contener comillas, deberá escapar / anteponer el " carácter con un extra
" para que VBA entienda que desea que "" sea interpretado como una " cadena.
'Output:
'The man said, "Never use air-quotes"
'The man said, "Never use air-quotes"
El editor de VBA solo permite 1023 caracteres por línea, pero generalmente solo los primeros
100-150 caracteres son visibles sin desplazamiento. Si necesita asignar literales de cadena larga,
pero desea mantener su código legible, deberá usar continuaciones de línea y concatenación
para asignar su cadena.
Debug.Print "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " & _
"Integer hendrerit maximus arcu, ut elementum odio varius " & _
"nec. Integer ipsum enim, iaculis et egestas ac, condiment" & _
"um ut tellus."
'Output:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer hendrerit maximus arcu, ut
elementum odio varius nec. Integer ipsum enim, iaculis et egestas ac, condimentum ut tellus.
https://riptutorial.com/es/home 129
VBA le permitirá usar un número limitado de continuaciones de línea (el número real varía según
la longitud de cada línea dentro del bloque continuado), por lo que si tiene cadenas muy largas,
deberá asignar y reasignar con concatenación .
Debug.Print loremIpsum
'Output:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer hendrerit maximus arcu, ut
elementum odio varius nec. Integer ipsum enim, iaculis et egestas ac, condimentum ut tellus.
VBA define una serie de constantes de cadena para caracteres especiales como:
Puede usar estas constantes con concatenación y otras funciones de cadena para construir
cadenas literales con caracteres especiales.
Usar vbNullString se considera una mejor práctica que el valor equivalente de "" debido a las
diferencias en la forma en que se compila el código. Se accede a las cadenas a través de un
puntero a un área de memoria asignada, y el compilador VBA es lo suficientemente inteligente
como para usar un puntero nulo para representar vbNullString . El literal "" se asigna a la
memoria como si fuera una variante de tipo String, lo que hace que el uso de la constante sea
https://riptutorial.com/es/home 130
mucho más eficiente:
https://riptutorial.com/es/home 131
Capítulo 28: Llamadas API
Introducción
API significa interfaz de programación de aplicaciones
Las API para VBA implican un conjunto de métodos que permiten la interacción directa con el
sistema operativo
Observaciones
Archivos comunes de la biblioteca del entorno operativo (DLL):
Biblioteca de enlace
Descripción
dinámico
https://riptutorial.com/es/home 132
Tipo ít Descripción
• Win32api32.txt para Visual Basic 5.0 (antiguas declaraciones de API, revisado por última
vez en marzo de 2005, Microsoft)
Examples
Declaración y uso de la API
Option Explicit
https://riptutorial.com/es/home 133
#If Win64 Then
Private Declare PtrSafe Sub xLib "Kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)
Private Declare Sub apiSleep Lib "Kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)
#End If
La declaración anterior le dice a VBA cómo llamar a la función "Sleep" definida en el archivo
Kernel32.dll
Constantes predefinidas
Algunas constantes de compilación ya están predefinidas. Las que existan dependerán del grado
de bit de la versión de Office en la que esté ejecutando VBA. Tenga en cuenta que Vba7 se
introdujo junto con Office 2010 para admitir versiones de Office de 64 bits.
La diferencia principal al declarar las API es entre las versiones de Office de 32 y 64 bits que
introdujeron nuevos tipos de parámetros (consulte la sección de Comentarios para más detalles)
Notas:
https://riptutorial.com/es/home 134
• Los procedimientos de DLL declarados en cualquier otro tipo de módulo son
privados para ese módulo
start = Timer
Debug.Print "Paused for " & Format(Timer - start, "#,###.000") & " seconds"
End Sub
Se recomienda crear un módulo API dedicado para proporcionar un fácil acceso a las funciones
del sistema desde los envoltorios de VBA: las subscripciones o funciones normales de VBA que
encapsulan los detalles necesarios para la llamada real del sistema, como los parámetros
utilizados en las bibliotecas y la inicialización de esos parámetros.
Declare Function publicname Lib "libname" [Alias "alias"] [([[ByVal] variable [As type]
[,[ByVal] variable [As type]]...])] As Type
Declare Sub publicname Lib "libname" [Alias "alias"] [([[ByVal] variable [As type] [,[ByVal]
variable [As type]]...])]
https://riptutorial.com/es/home 135
• !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!
Private Declare Function system Lib "libc.dylib" (ByVal command As String) As Long
Sub RunSafari()
Dim result As Long
result = system("open -a Safari --args http://www.google.com")
Debug.Print Str(result)
End Sub
Los siguientes ejemplos (API de Windows - Módulo dedicado (1 y 2)) muestran un módulo de API
que incluye declaraciones comunes para Win64 y Win32
Option Explicit
https://riptutorial.com/es/home 136
"GetCommandLineA" () As Long
Private Declare PtrSafe Function apiGetDiskFreeSpaceEx Lib "Kernel32" Alias
"GetDiskFreeSpaceExA" (ByVal lpDirectoryName As String, lpFreeBytesAvailableToCaller As
Currency, lpTotalNumberOfBytes As Currency, lpTotalNumberOfFreeBytes As Currency) As Long
Private Declare PtrSafe Function apiGetDriveType Lib "Kernel32" Alias "GetDriveTypeA"
(ByVal nDrive As String) As Long
Private Declare PtrSafe Function apiGetExitCodeProcess Lib "Kernel32" Alias
"GetExitCodeProcess" (ByVal hProcess As Long, lpExitCode As Long) As Long
Private Declare PtrSafe Function apiGetForegroundWindow Lib "User32" Alias
"GetForegroundWindow" () As Long
Private Declare PtrSafe Function apiGetFrequency Lib "Kernel32" Alias
"QueryPerformanceFrequency" (cyFrequency As Currency) As Long
Private Declare PtrSafe Function apiGetLastError Lib "Kernel32" Alias "GetLastError" () As
Integer
Private Declare PtrSafe Function apiGetParent Lib "User32" Alias "GetParent" (ByVal hWnd
As Long) As Long
Private Declare PtrSafe Function apiGetSystemMetrics Lib "User32" Alias "GetSystemMetrics"
(ByVal nIndex As Long) As Long
Private Declare PtrSafe Function apiGetSystemMetrics32 Lib "User32" Alias
"GetSystemMetrics" (ByVal nIndex As Long) As Long
Private Declare PtrSafe Function apiGetTickCount Lib "Kernel32" Alias
"QueryPerformanceCounter" (cyTickCount As Currency) As Long
Private Declare PtrSafe Function apiGetTickCountMs Lib "Kernel32" Alias "GetTickCount" ()
As Long
Private Declare PtrSafe Function apiGetUserName Lib "AdvApi32" Alias "GetUserNameA" (ByVal
lpBuffer As String, nSize As Long) As Long
Private Declare PtrSafe Function apiGetWindow Lib "User32" Alias "GetWindow" (ByVal hWnd
As Long, ByVal wCmd As Long) As Long
Private Declare PtrSafe Function apiGetWindowRect Lib "User32" Alias "GetWindowRect"
(ByVal hWnd As Long, lpRect As winRect) As Long
Private Declare PtrSafe Function apiGetWindowText Lib "User32" Alias "GetWindowTextA"
(ByVal hWnd As Long, ByVal szWindowText As String, ByVal lLength As Long) As Long
Private Declare PtrSafe Function apiGetWindowThreadProcessId Lib "User32" Alias
"GetWindowThreadProcessId" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Declare PtrSafe Function apiIsCharAlphaNumericA Lib "User32" Alias
"IsCharAlphaNumericA" (ByVal byChar As Byte) As Long
Private Declare PtrSafe Function apiIsIconic Lib "User32" Alias "IsIconic" (ByVal hWnd As
Long) As Long
Private Declare PtrSafe Function apiIsWindowVisible Lib "User32" Alias "IsWindowVisible"
(ByVal hWnd As Long) As Long
Private Declare PtrSafe Function apiIsZoomed Lib "User32" Alias "IsZoomed" (ByVal hWnd As
Long) As Long
Private Declare PtrSafe Function apiLStrCpynA Lib "Kernel32" Alias "lstrcpynA" (ByVal
pDestination As String, ByVal pSource As Long, ByVal iMaxLength As Integer) As Long
Private Declare PtrSafe Function apiMessageBox Lib "User32" Alias "MessageBoxA" (ByVal
hWnd As Long, ByVal lpText As String, ByVal lpCaption As String, ByVal wType As Long) As Long
Private Declare PtrSafe Function apiOpenIcon Lib "User32" Alias "OpenIcon" (ByVal hWnd As
Long) As Long
Private Declare PtrSafe Function apiOpenProcess Lib "Kernel32" Alias "OpenProcess" (ByVal
dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare PtrSafe Function apiPathAddBackslashByPointer Lib "ShlwApi" Alias
"PathAddBackslashW" (ByVal lpszPath As Long) As Long
Private Declare PtrSafe Function apiPathAddBackslashByString Lib "ShlwApi" Alias
"PathAddBackslashW" (ByVal lpszPath As String) As Long 'http://msdn.microsoft.com/en-
us/library/aa155716%28office.10%29.aspx
Private Declare PtrSafe Function apiPostMessage Lib "User32" Alias "PostMessageA" (ByVal
hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare PtrSafe Function apiRegQueryValue Lib "AdvApi32" Alias "RegQueryValue"
(ByVal hKey As Long, ByVal sValueName As String, ByVal dwReserved As Long, ByRef lValueType As
Long, ByVal sValue As String, ByRef lResultLen As Long) As Long
Private Declare PtrSafe Function apiSendMessage Lib "User32" Alias "SendMessageA" (ByVal
https://riptutorial.com/es/home 137
hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare PtrSafe Function apiSetActiveWindow Lib "User32" Alias "SetActiveWindow"
(ByVal hWnd As Long) As Long
Private Declare PtrSafe Function apiSetCurrentDirectoryA Lib "Kernel32" Alias
"SetCurrentDirectoryA" (ByVal lpPathName As String) As Long
Private Declare PtrSafe Function apiSetFocus Lib "User32" Alias "SetFocus" (ByVal hWnd As
Long) As Long
Private Declare PtrSafe Function apiSetForegroundWindow Lib "User32" Alias
"SetForegroundWindow" (ByVal hWnd As Long) As Long
Private Declare PtrSafe Function apiSetLocalTime Lib "Kernel32" Alias "SetLocalTime"
(lpSystem As SystemTime) As Long
Private Declare PtrSafe Function apiSetWindowPlacement Lib "User32" Alias
"SetWindowPlacement" (ByVal hWnd As Long, ByRef lpwndpl As winPlacement) As Long
Private Declare PtrSafe Function apiSetWindowPos Lib "User32" Alias "SetWindowPos" (ByVal
hWnd As Long, ByVal hWndInsertAfter As Long, ByVal X As Long, ByVal Y As Long, ByVal cx As
Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Declare PtrSafe Function apiSetWindowText Lib "User32" Alias "SetWindowTextA"
(ByVal hWnd As Long, ByVal lpString As String) As Long
Private Declare PtrSafe Function apiShellExecute Lib "Shell32" Alias "ShellExecuteA"
(ByVal hWnd As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters
As String, ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
Private Declare PtrSafe Function apiShowWindow Lib "User32" Alias "ShowWindow" (ByVal hWnd
As Long, ByVal nCmdShow As Long) As Long
Private Declare PtrSafe Function apiShowWindowAsync Lib "User32" Alias "ShowWindowAsync"
(ByVal hWnd As Long, ByVal nCmdShow As Long) As Long
Private Declare PtrSafe Function apiStrCpy Lib "Kernel32" Alias "lstrcpynA" (ByVal
pDestination As String, ByVal pSource As String, ByVal iMaxLength As Integer) As Long
Private Declare PtrSafe Function apiStringLen Lib "Kernel32" Alias "lstrlenW" (ByVal
lpString As Long) As Long
Private Declare PtrSafe Function apiStrTrimW Lib "ShlwApi" Alias "StrTrimW" () As Boolean
Private Declare PtrSafe Function apiTerminateProcess Lib "Kernel32" Alias
"TerminateProcess" (ByVal hWnd As Long, ByVal uExitCode As Long) As Long
Private Declare PtrSafe Function apiTimeGetTime Lib "Winmm" Alias "timeGetTime" () As Long
Private Declare PtrSafe Function apiVarPtrArray Lib "MsVbVm50" Alias "VarPtr" (Var() As
Any) As Long
Private Type browseInfo 'used by apiBrowseForFolder
hOwner As Long
pidlRoot As Long
pszDisplayName As String
lpszTitle As String
ulFlags As Long
lpfn As Long
lParam As Long
iImage As Long
End Type
Private Declare PtrSafe Function apiBrowseForFolder Lib "Shell32" Alias
"SHBrowseForFolderA" (lpBrowseInfo As browseInfo) As Long
Private Type CHOOSECOLOR 'used by apiChooseColor;
http://support.microsoft.com/kb/153929 and http://www.cpearson.com/Excel/Colors.aspx
lStructSize As Long
hWndOwner As Long
hInstance As Long
rgbResult As Long
lpCustColors As String
flags As Long
lCustData As Long
lpfnHook As Long
lpTemplateName As String
End Type
Private Declare PtrSafe Function apiChooseColor Lib "ComDlg32" Alias "ChooseColorA"
(pChoosecolor As CHOOSECOLOR) As Long
https://riptutorial.com/es/home 138
Private Type FindWindowParameters 'Custom structure for passing in the parameters in/out
of the hook enumeration function; could use global variables instead, but this is nicer
strTitle As String 'INPUT
hWnd As Long 'OUTPUT
End Type 'Find a specific window with dynamic caption from a
list of all open windows: http://www.everythingaccess.com/tutorials.asp?ID=Bring-an-external-
application-window-to-the-foreground
Private Declare PtrSafe Function apiEnumWindows Lib "User32" Alias "EnumWindows" (ByVal
lpEnumFunc As LongPtr, ByVal lParam As LongPtr) As Long
Private Type lastInputInfo 'used by apiGetLastInputInfo, getLastInputTime
cbSize As Long
dwTime As Long
End Type
Private Declare PtrSafe Function apiGetLastInputInfo Lib "User32" Alias "GetLastInputInfo"
(ByRef plii As lastInputInfo) As Long
'http://www.pgacon.com/visualbasic.htm#Take%20Advantage%20of%20Conditional%20Compilation
'Logical and Bitwise Operators in Visual Basic: http://msdn.microsoft.com/en-
us/library/wz3k228a(v=vs.80).aspx and http://stackoverflow.com/questions/1070863/hidden-
features-of-vba
Private Type SystemTime
wYear As Integer
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type
Private Declare PtrSafe Sub apiGetLocalTime Lib "Kernel32" Alias "GetLocalTime" (lpSystem
As SystemTime)
Private Type pointAPI 'used by apiSetWindowPlacement
X As Long
Y As Long
End Type
Private Type rectAPI 'used by apiSetWindowPlacement
Left_Renamed As Long
Top_Renamed As Long
Right_Renamed As Long
Bottom_Renamed As Long
End Type
Private Type winPlacement 'used by apiSetWindowPlacement
length As Long
flags As Long
showCmd As Long
ptMinPosition As pointAPI
ptMaxPosition As pointAPI
rcNormalPosition As rectAPI
End Type
Private Declare PtrSafe Function apiGetWindowPlacement Lib "User32" Alias
"GetWindowPlacement" (ByVal hWnd As Long, ByRef lpwndpl As winPlacement) As Long
Private Type winRect 'used by apiMoveWindow
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare PtrSafe Function apiMoveWindow Lib "User32" Alias "MoveWindow" (ByVal hWnd
As Long, xLeft As Long, ByVal yTop As Long, wWidth As Long, ByVal hHeight As Long, ByVal
repaint As Long) As Long
https://riptutorial.com/es/home 139
Private Declare PtrSafe Function apiInternetOpen Lib "WiniNet" Alias "InternetOpenA"
(ByVal sAgent As String, ByVal lAccessType As Long, ByVal sProxyName As String, ByVal
sProxyBypass As String, ByVal lFlags As Long) As Long 'Open the Internet object 'ex:
lngINet = InternetOpen(“MyFTP Control”, 1, vbNullString, vbNullString, 0)
Private Declare PtrSafe Function apiInternetConnect Lib "WiniNet" Alias "InternetConnectA"
(ByVal hInternetSession As Long, ByVal sServerName As String, ByVal nServerPort As Integer,
ByVal sUsername As String, ByVal sPassword As String, ByVal lService As Long, ByVal lFlags As
Long, ByVal lContext As Long) As Long 'Connect to the network 'ex: lngINetConn =
InternetConnect(lngINet, "ftp.microsoft.com", 0, "anonymous", "wally@wallyworld.com", 1, 0, 0)
Private Declare PtrSafe Function apiFtpGetFile Lib "WiniNet" Alias "FtpGetFileA" (ByVal
hFtpSession As Long, ByVal lpszRemoteFile As String, ByVal lpszNewFile As String, ByVal
fFailIfExists As Boolean, ByVal dwFlagsAndAttributes As Long, ByVal dwFlags As Long, ByVal
dwContext As Long) As Boolean 'Get a file 'ex: blnRC = FtpGetFile(lngINetConn,
"dirmap.txt", "c:\dirmap.txt", 0, 0, 1, 0)
Private Declare PtrSafe Function apiFtpPutFile Lib "WiniNet" Alias "FtpPutFileA" (ByVal
hFtpSession As Long, ByVal lpszLocalFile As String, ByVal lpszRemoteFile As String, ByVal
dwFlags As Long, ByVal dwContext As Long) As Boolean 'Send a file 'ex: blnRC =
FtpPutFile(lngINetConn, “c:\dirmap.txt”, “dirmap.txt”, 1, 0)
Private Declare PtrSafe Function apiFtpDeleteFile Lib "WiniNet" Alias "FtpDeleteFileA"
(ByVal hFtpSession As Long, ByVal lpszFileName As String) As Boolean 'Delete a file 'ex: blnRC
= FtpDeleteFile(lngINetConn, “test.txt”)
Private Declare PtrSafe Function apiInternetCloseHandle Lib "WiniNet" (ByVal hInet As
Long) As Integer 'Close the Internet object 'ex: InternetCloseHandle lngINetConn 'ex:
InternetCloseHandle lngINet
Private Declare PtrSafe Function apiFtpFindFirstFile Lib "WiniNet" Alias
"FtpFindFirstFileA" (ByVal hFtpSession As Long, ByVal lpszSearchFile As String, lpFindFileData
As WIN32_FIND_DATA, ByVal dwFlags As Long, ByVal dwContent As Long) As Long
Private Type FILETIME
dwLowDateTime As Long
dwHighDateTime As Long
End Type
Private Type WIN32_FIND_DATA
dwFileAttributes As Long
ftCreationTime As FILETIME
ftLastAccessTime As FILETIME
ftLastWriteTime As FILETIME
nFileSizeHigh As Long
nFileSizeLow As Long
dwReserved0 As Long
dwReserved1 As Long
cFileName As String * 1 'MAX_FTP_PATH
cAlternate As String * 14
End Type 'ex: lngHINet = FtpFindFirstFile(lngINetConn, "*.*", pData, 0, 0)
Private Declare PtrSafe Function apiInternetFindNextFile Lib "WiniNet" Alias
"InternetFindNextFileA" (ByVal hFind As Long, lpvFindData As WIN32_FIND_DATA) As Long 'ex:
blnRC = InternetFindNextFile(lngHINet, pData)
#ElseIf Win32 Then 'Win32 = True, Win16 = False
https://riptutorial.com/es/home 140
Private Declare Sub apiSetCursorPos Lib "User32" Alias "SetCursorPos" (ByVal X As Integer,
ByVal Y As Integer) 'Logical and Bitwise Operators in Visual Basic:
http://msdn.microsoft.com/en-us/library/wz3k228a(v=vs.80).aspx and
http://stackoverflow.com/questions/1070863/hidden-features-of-vba
'http://www.pgacon.com/visualbasic.htm#Take%20Advantage%20of%20Conditional%20Compilation
Private Declare Sub apiSleep Lib "Kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)
Private Declare Function apiAttachThreadInput Lib "User32" Alias "AttachThreadInput"
(ByVal idAttach As Long, ByVal idAttachTo As Long, ByVal fAttach As Long) As Long
Private Declare Function apiBringWindowToTop Lib "User32" Alias "BringWindowToTop" (ByVal
lngHWnd As Long) As Long
Private Declare Function apiCloseHandle Lib "Kernel32" (ByVal hObject As Long) As Long
Private Declare Function apiCloseWindow Lib "User32" Alias "CloseWindow" (ByVal hWnd As
Long) As Long
'Private Declare Function apiCreatePipe Lib "Kernel32" (phReadPipe As Long, phWritePipe As
Long, lpPipeAttributes As SECURITY_ATTRIBUTES, ByVal nSize As Long) As Long
'Private Declare Function apiCreateProcess Lib "Kernel32" Alias "CreateProcessA" (ByVal
lpApplicationName As Long, ByVal lpCommandLine As String, lpProcessAttributes As Any,
lpThreadAttributes As Any, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long,
lpEnvironment As Any, ByVal lpCurrentDriectory As String, lpStartupInfo As STARTUPINFO,
lpProcessInformation As PROCESS_INFORMATION) As Long
Private Declare Function apiDestroyWindow Lib "User32" Alias "DestroyWindow" (ByVal hWnd
As Long) As Boolean
Private Declare Function apiEndDialog Lib "User32" Alias "EndDialog" (ByVal hWnd As Long,
ByVal result As Long) As Boolean
Private Declare Function apiEnumChildWindows Lib "User32" Alias "EnumChildWindows" (ByVal
hWndParent As Long, ByVal pEnumProc As Long, ByVal lParam As Long) As Long
Private Declare Function apiExitWindowsEx Lib "User32" Alias "ExitWindowsEx" (ByVal uFlags
As Long, ByVal dwReserved As Long) As Long
Private Declare Function apiFindExecutable Lib "Shell32" Alias "FindExecutableA" (ByVal
lpFile As String, ByVallpDirectory As String, ByVal lpResult As String) As Long
Private Declare Function apiFindWindow Lib "User32" Alias "FindWindowA" (ByVal lpClassName
As String, ByVal lpWindowName As String) As Long
Private Declare Function apiFindWindowEx Lib "User32" Alias "FindWindowExA" (ByVal hWnd1
As Long, ByVal hWnd2 As Long, ByVal lpsz1 As String, ByVal lpsz2 As String) As Long
Private Declare Function apiGetActiveWindow Lib "User32" Alias "GetActiveWindow" () As
Long
Private Declare Function apiGetClassNameA Lib "User32" Alias "GetClassNameA" (ByVal hWnd
As Long, ByVal szClassName As String, ByVal lLength As Long) As Long
Private Declare Function apiGetCommandLine Lib "Kernel32" Alias "GetCommandLineW" () As
Long
Private Declare Function apiGetCommandLineParams Lib "Kernel32" Alias "GetCommandLineA" ()
As Long
Private Declare Function apiGetDiskFreeSpaceEx Lib "Kernel32" Alias "GetDiskFreeSpaceExA"
(ByVal lpDirectoryName As String, lpFreeBytesAvailableToCaller As Currency,
lpTotalNumberOfBytes As Currency, lpTotalNumberOfFreeBytes As Currency) As Long
Private Declare Function apiGetDriveType Lib "Kernel32" Alias "GetDriveTypeA" (ByVal
nDrive As String) As Long
Private Declare Function apiGetExitCodeProcess Lib "Kernel32" (ByVal hProcess As Long,
lpExitCode As Long) As Long
Private Declare Function apiGetFileSize Lib "Kernel32" (ByVal hFile As Long,
lpFileSizeHigh As Long) As Long
Private Declare Function apiGetForegroundWindow Lib "User32" Alias "GetForegroundWindow"
() As Long
Private Declare Function apiGetFrequency Lib "Kernel32" Alias "QueryPerformanceFrequency"
(cyFrequency As Currency) As Long
Private Declare Function apiGetLastError Lib "Kernel32" Alias "GetLastError" () As Integer
Private Declare Function apiGetParent Lib "User32" Alias "GetParent" (ByVal hWnd As Long)
As Long
Private Declare Function apiGetSystemMetrics Lib "User32" Alias "GetSystemMetrics" (ByVal
nIndex As Long) As Long
Private Declare Function apiGetTickCount Lib "Kernel32" Alias "QueryPerformanceCounter"
https://riptutorial.com/es/home 141
(cyTickCount As Currency) As Long
Private Declare Function apiGetTickCountMs Lib "Kernel32" Alias "GetTickCount" () As Long
Private Declare Function apiGetUserName Lib "AdvApi32" Alias "GetUserNameA" (ByVal
lpBuffer As String, nSize As Long) As Long
Private Declare Function apiGetWindow Lib "User32" Alias "GetWindow" (ByVal hWnd As Long,
ByVal wCmd As Long) As Long
Private Declare Function apiGetWindowRect Lib "User32" Alias "GetWindowRect" (ByVal hWnd
As Long, lpRect As winRect) As Long
Private Declare Function apiGetWindowText Lib "User32" Alias "GetWindowTextA" (ByVal hWnd
As Long, ByVal szWindowText As String, ByVal lLength As Long) As Long
Private Declare Function apiGetWindowThreadProcessId Lib "User32" Alias
"GetWindowThreadProcessId" (ByVal hWnd As Long, lpdwProcessId As Long) As Long
Private Declare Function apiIsCharAlphaNumericA Lib "User32" Alias "IsCharAlphaNumericA"
(ByVal byChar As Byte) As Long
Private Declare Function apiIsIconic Lib "User32" Alias "IsIconic" (ByVal hWnd As Long) As
Long
Private Declare Function apiIsWindowVisible Lib "User32" Alias "IsWindowVisible" (ByVal
hWnd As Long) As Long
Private Declare Function apiIsZoomed Lib "User32" Alias "IsZoomed" (ByVal hWnd As Long) As
Long
Private Declare Function apiLStrCpynA Lib "Kernel32" Alias "lstrcpynA" (ByVal pDestination
As String, ByVal pSource As Long, ByVal iMaxLength As Integer) As Long
Private Declare Function apiMessageBox Lib "User32" Alias "MessageBoxA" (ByVal hWnd As
Long, ByVal lpText As String, ByVal lpCaption As String, ByVal wType As Long) As Long
Private Declare Function apiOpenIcon Lib "User32" Alias "OpenIcon" (ByVal hWnd As Long) As
Long
Private Declare Function apiOpenProcess Lib "Kernel32" Alias "OpenProcess" (ByVal
dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Private Declare Function apiPathAddBackslashByPointer Lib "ShlwApi" Alias
"PathAddBackslashW" (ByVal lpszPath As Long) As Long
Private Declare Function apiPathAddBackslashByString Lib "ShlwApi" Alias
"PathAddBackslashW" (ByVal lpszPath As String) As Long 'http://msdn.microsoft.com/en-
us/library/aa155716%28office.10%29.aspx
Private Declare Function apiPostMessage Lib "User32" Alias "PostMessageA" (ByVal hWnd As
Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Private Declare Function apiReadFile Lib "Kernel32" (ByVal hFile As Long, lpBuffer As Any,
ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Any) As Long
Private Declare Function apiRegQueryValue Lib "AdvApi32" Alias "RegQueryValue" (ByVal hKey
As Long, ByVal sValueName As String, ByVal dwReserved As Long, ByRef lValueType As Long, ByVal
sValue As String, ByRef lResultLen As Long) As Long
Private Declare Function apiSendMessage Lib "User32" Alias "SendMessageA" (ByVal hWnd As
Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As Long
Private Declare Function apiSetActiveWindow Lib "User32" Alias "SetActiveWindow" (ByVal
hWnd As Long) As Long
Private Declare Function apiSetCurrentDirectoryA Lib "Kernel32" Alias
"SetCurrentDirectoryA" (ByVal lpPathName As String) As Long
Private Declare Function apiSetFocus Lib "User32" Alias "SetFocus" (ByVal hWnd As Long) As
Long
Private Declare Function apiSetForegroundWindow Lib "User32" Alias "SetForegroundWindow"
(ByVal hWnd As Long) As Long
Private Declare Function apiSetLocalTime Lib "Kernel32" Alias "SetLocalTime" (lpSystem As
SystemTime) As Long
Private Declare Function apiSetWindowPlacement Lib "User32" Alias "SetWindowPlacement"
(ByVal hWnd As Long, ByRef lpwndpl As winPlacement) As Long
Private Declare Function apiSetWindowPos Lib "User32" Alias "SetWindowPos" (ByVal hWnd As
Long, ByVal hWndInsertAfter As Long, ByVal X As Long, ByVal Y As Long, ByVal cx As Long, ByVal
cy As Long, ByVal wFlags As Long) As Long
Private Declare Function apiSetWindowText Lib "User32" Alias "SetWindowTextA" (ByVal hWnd
As Long, ByVal lpString As String) As Long
Private Declare Function apiShellExecute Lib "Shell32" Alias "ShellExecuteA" (ByVal hWnd
As Long, ByVal lpOperation As String, ByVal lpFile As String, ByVal lpParameters As String,
https://riptutorial.com/es/home 142
ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
Private Declare Function apiShowWindow Lib "User32" Alias "ShowWindow" (ByVal hWnd As
Long, ByVal nCmdShow As Long) As Long
Private Declare Function apiShowWindowAsync Lib "User32" Alias "ShowWindowAsync" (ByVal
hWnd As Long, ByVal nCmdShow As Long) As Long
Private Declare Function apiStrCpy Lib "Kernel32" Alias "lstrcpynA" (ByVal pDestination As
String, ByVal pSource As String, ByVal iMaxLength As Integer) As Long
Private Declare Function apiStringLen Lib "Kernel32" Alias "lstrlenW" (ByVal lpString As
Long) As Long
Private Declare Function apiStrTrimW Lib "ShlwApi" Alias "StrTrimW" () As Boolean
Private Declare Function apiTerminateProcess Lib "Kernel32" Alias "TerminateProcess"
(ByVal hWnd As Long, ByVal uExitCode As Long) As Long
Private Declare Function apiTimeGetTime Lib "Winmm" Alias "timeGetTime" () As Long
Private Declare Function apiVarPtrArray Lib "MsVbVm50" Alias "VarPtr" (Var() As Any) As
Long
Private Declare Function apiWaitForSingleObject Lib "Kernel32" (ByVal hHandle As Long,
ByVal dwMilliseconds As Long) As Long
Private Type browseInfo 'used by apiBrowseForFolder
hOwner As Long
pidlRoot As Long
pszDisplayName As String
lpszTitle As String
ulFlags As Long
lpfn As Long
lParam As Long
iImage As Long
End Type
Private Declare Function apiBrowseForFolder Lib "Shell32" Alias "SHBrowseForFolderA"
(lpBrowseInfo As browseInfo) As Long
Private Type CHOOSECOLOR 'used by apiChooseColor;
http://support.microsoft.com/kb/153929 and http://www.cpearson.com/Excel/Colors.aspx
lStructSize As Long
hWndOwner As Long
hInstance As Long
rgbResult As Long
lpCustColors As String
flags As Long
lCustData As Long
lpfnHook As Long
lpTemplateName As String
End Type
Private Declare Function apiChooseColor Lib "ComDlg32" Alias "ChooseColorA" (pChoosecolor
As CHOOSECOLOR) As Long
Private Type FindWindowParameters 'Custom structure for passing in the parameters in/out
of the hook enumeration function; could use global variables instead, but this is nicer
strTitle As String 'INPUT
hWnd As Long 'OUTPUT
End Type 'Find a specific window with dynamic caption from a
list of all open windows: http://www.everythingaccess.com/tutorials.asp?ID=Bring-an-external-
application-window-to-the-foreground
Private Declare Function apiEnumWindows Lib "User32" Alias "EnumWindows" (ByVal lpEnumFunc
As Long, ByVal lParam As Long) As Long
Private Type lastInputInfo 'used by apiGetLastInputInfo, getLastInputTime
cbSize As Long
dwTime As Long
End Type
Private Declare Function apiGetLastInputInfo Lib "User32" Alias "GetLastInputInfo" (ByRef
plii As lastInputInfo) As Long
Private Type SystemTime
wYear As Integer
wMonth As Integer
https://riptutorial.com/es/home 143
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type
Private Declare Sub apiGetLocalTime Lib "Kernel32" Alias "GetLocalTime" (lpSystem As
SystemTime)
Private Type pointAPI
X As Long
Y As Long
End Type
Private Type rectAPI
Left_Renamed As Long
Top_Renamed As Long
Right_Renamed As Long
Bottom_Renamed As Long
End Type
Private Type winPlacement
length As Long
flags As Long
showCmd As Long
ptMinPosition As pointAPI
ptMaxPosition As pointAPI
rcNormalPosition As rectAPI
End Type
Private Declare Function apiGetWindowPlacement Lib "User32" Alias "GetWindowPlacement"
(ByVal hWnd As Long, ByRef lpwndpl As winPlacement) As Long
Private Type winRect
Left As Long
Top As Long
Right As Long
Bottom As Long
End Type
Private Declare Function apiMoveWindow Lib "User32" Alias "MoveWindow" (ByVal hWnd As
Long, xLeft As Long, ByVal yTop As Long, wWidth As Long, ByVal hHeight As Long, ByVal repaint
As Long) As Long
#Else ' Win16 = True
#End If
API de Mac
Microsoft no admite oficialmente las API, pero con algunas investigaciones se pueden encontrar
más declaraciones en línea
A diferencia de otras versiones de aplicaciones de Office que admiten VBA, las aplicaciones de
Office 2016 para Mac están en un espacio aislado.
El sandboxing restringe que las aplicaciones accedan a recursos fuera del contenedor de la
aplicación. Esto afecta a los complementos o macros que involucran el acceso a archivos o la
comunicación a través de procesos. Puede minimizar los efectos del sandboxing utilizando los
nuevos comandos que se describen en la siguiente sección. Nuevos comandos VBA para Office
2016 para Mac
https://riptutorial.com/es/home 144
Los siguientes comandos de VBA son nuevos y exclusivos de Office 2016 para Mac.
Private Declare Function system Lib "libc.dylib" (ByVal command As String) As Long
Private Declare Function popen Lib "libc.dylib" (ByVal command As String, ByVal mode As
String) As Long
Private Declare Function pclose Lib "libc.dylib" (ByVal file As Long) As Long
Private Declare Function fread Lib "libc.dylib" (ByVal outStr As String, ByVal size As Long,
ByVal items As Long, ByVal stream As Long) As Long
Private Declare Function feof Lib "libc.dylib" (ByVal file As Long) As Long
Private Declare PtrSafe Function popen Lib "libc.dylib" (ByVal command As String, ByVal mode
As String) As LongPtr
Private Declare PtrSafe Function pclose Lib "libc.dylib" (ByVal file As LongPtr) As Long
Private Declare PtrSafe Function fread Lib "libc.dylib" (ByVal outStr As String, ByVal size As
LongPtr, ByVal items As LongPtr, ByVal stream As LongPtr) As Long
Private Declare PtrSafe Function feof Lib "libc.dylib" (ByVal file As LongPtr) As LongPtr
Option Explicit
'VBA Wrappers:
Public Function dllGetMonitors() As Long
Const SM_CMONITORS = 80
dllGetMonitors = GetSystemMetrics32(SM_CMONITORS)
End Function
https://riptutorial.com/es/home 145
Public Function dllGetHorizontalResolution() As Long
Const SM_CXVIRTUALSCREEN = 78
dllGetHorizontalResolution = GetSystemMetrics32(SM_CXVIRTUALSCREEN)
End Function
'Total monitors: 1
'Horizontal Resolution: 1920
'Vertical Resolution: 1080
End Sub
modFTP
Option Explicit
Option Compare Text
Option Private Module
'http://msdn.microsoft.com/en-us/library/aa384180(v=VS.85).aspx
'http://www.dailydoseofexcel.com/archives/2006/01/29/ftp-via-vba/
'http://www.15seconds.com/issue/981203.htm
'Get a file
Private Declare Function FtpGetFile Lib "wininet.dll" Alias "FtpGetFileA" ( _
https://riptutorial.com/es/home 146
ByVal hFtpSession As Long, _
ByVal lpszRemoteFile As String, _
ByVal lpszNewFile As String, _
ByVal fFailIfExists As Boolean, _
ByVal dwFlagsAndAttributes As Long, _
ByVal dwFlags As Long, _
ByVal dwContext As Long _
) As Boolean
'ex: blnRC = FtpGetFile(lngINetConn, "dirmap.txt", "c:\dirmap.txt", 0, 0, 1, 0)
'Send a file
Private Declare Function FtpPutFile Lib "wininet.dll" Alias "FtpPutFileA" _
( _
ByVal hFtpSession As Long, _
ByVal lpszLocalFile As String, _
ByVal lpszRemoteFile As String, _
ByVal dwFlags As Long, ByVal dwContext As Long _
) As Boolean
'ex: blnRC = FtpPutFile(lngINetConn, “c:\dirmap.txt”, “dirmap.txt”, 1, 0)
'Delete a file
Private Declare Function FtpDeleteFile Lib "wininet.dll" Alias "FtpDeleteFileA" _
( _
ByVal hFtpSession As Long, _
ByVal lpszFileName As String _
) As Boolean
'ex: blnRC = FtpDeleteFile(lngINetConn, “test.txt”)
https://riptutorial.com/es/home 147
Private Declare Function InternetFindNextFile Lib "wininet.dll" Alias "InternetFindNextFileA"
_
( _
ByVal hFind As Long, _
lpvFindData As WIN32_FIND_DATA _
) As Long
'ex: blnRC = InternetFindNextFile(lngHINet, pData)
Modregional:
Option Explicit
Private Declare Function GetLocaleInfo Lib "Kernel32" Alias "GetLocaleInfoA" (ByVal Locale As
Long, ByVal LCType As Long, ByVal lpLCData As String, ByVal cchData As Long) As Long
Private Declare Function SetLocaleInfo Lib "Kernel32" Alias "SetLocaleInfoA" (ByVal Locale As
Long, ByVal LCType As Long, ByVal lpLCData As String) As Boolean
Private Declare Function GetUserDefaultLCID% Lib "Kernel32" ()
https://riptutorial.com/es/home 148
Dim ListSeparator As String, iRetVal1 As Long, iRetVal2 As Long, lpLCDataVar As String,
Position As Integer, Locale As Long
Locale = GetUserDefaultLCID()
iRetVal1 = GetLocaleInfo(Locale, LOCALE_SLIST, lpLCDataVar, 0)
ListSeparator = String$(iRetVal1, 0)
iRetVal2 = GetLocaleInfo(Locale, LOCALE_SLIST, ListSeparator, iRetVal1)
Position = InStr(ListSeparator, Chr$(0))
If Position > 0 Then ListSeparator = Left$(ListSeparator, Position - 1) Else ListSeparator
= vbNullString
getListSeparator = ListSeparator
End Function
Private Sub ChangeSettingExample() 'change the setting of the character displayed as the
decimal separator.
Call SetLocalSetting(LOCALE_SDECIMAL, ",") 'to change to ","
Stop 'check your control panel to verify or use the
GetLocaleInfo API function
Call SetLocalSetting(LOCALE_SDECIMAL, ".") 'to back change to "."
End Sub
https://riptutorial.com/es/home 149
Capítulo 29: Los operadores
Observaciones
Los operadores son evaluados en el siguiente orden:
• Operadores matematicos
• Operadores bitwise
• Operadores de concatenacion
• Operadores de comparación
• Operadores logicos
Examples
Operadores matematicos
Multiplicación
*
1 Devuelve el producto de 2 operandos.
https://riptutorial.com/es/home 150
Simbólico Nombre Descripción
Operadores de Concatenacion
Si el operador & se usa con un tipo de variable que no sea una String , se convierte
implícitamente en una String antes de concatenar.
Tenga en cuenta que el operador de + concatenación es una sobrecarga del operador de suma + .
El comportamiento de + está determinado por los tipos de variables de los operandos y la
precedencia de los tipos de operadores. Si ambos operandos se escriben como una String o
Variant con un subtipo de String , se concatenan:
left = "5"
right = "5"
https://riptutorial.com/es/home 151
End Sub
Si cualquiera de los lados es un tipo numérico y el otro lado es una String que se puede convertir
en un número, la prioridad de tipo de los operadores matemáticos hace que el operador sea
tratado como el operador de suma y se agreguen los valores numéricos:
left = 5
right = "5"
Este comportamiento puede dar lugar a errores sutiles y difíciles de depurar, especialmente si se
utilizan los tipos Variant , por lo que normalmente solo se debe usar el operador & para la
concatenación.
Operadores de comparación
Mas
Devuelve True si el operando de la izquierda es mayor que el de la
> grande
derecha.
que
https://riptutorial.com/es/home 152
Simbólico Nombre Descripción
Notas
La sintaxis VBA permite "cadenas" de operadores de comparación, pero estas construcciones
generalmente deben evitarse. Las comparaciones siempre se realizan de izquierda a derecha en
solo 2 operandos a la vez, y cada comparación da como resultado un Boolean . Por ejemplo, la
expresión ...
a = 2: b = 1: c = 0
expr = a > b > c
... se puede leer en algunos contextos como una prueba de si b está entre a y c . En VBA, esto se
evalúa de la siguiente manera:
a = 2: b = 1: c = 0
expr = a > b > c
expr = (2 > 1) > 0
expr = True > 0
expr = -1 > 0 'CInt(True) = -1
expr = False
Cualquier operador de comparación que no Is use con un Object como operando se realizará en
el valor de retorno del miembro predeterminado del Object . Si el objeto no tiene un miembro
predeterminado, la comparación dará como resultado un error 438 en tiempo de ejecución: "El
objeto no admite su propiedad o método".
Si se usa el literal Nothing con cualquier operador de comparación que no sea Is , se producirá un
error de compilación: "Uso no válido del objeto".
Si el miembro predeterminado del Object es otro Object , VBA llamará continuamente al miembro
predeterminado de cada valor de retorno sucesivo hasta que se devuelva un tipo primitivo o se
genere un error. Por ejemplo, suponga que SomeClass tiene un miembro predeterminado de Value ,
que es una instancia de ChildClass con un miembro predeterminado de ChildValue . La
comparación...
https://riptutorial.com/es/home 153
Set x = New SomeClass
Debug.Print x > 42
Si cualquiera de los operandos es de tipo numérico y el otro es una String o Variant de subtipo
String , se realizará una comparación numérica. En este caso, si la String no se puede convertir a
un número, se generará un error de tiempo de ejecución 13 - "Falta de coincidencia de tipo" en la
comparación.
Si ambos operandos son una String o Variant de subtipo String , se realizará una comparación
de cadena en función de la configuración de Opción Comparación del módulo de código. Estas
comparaciones se realizan en una base de carácter por carácter. Tenga en cuenta que la
representación de caracteres de una String contiene un número no es lo mismo que una
comparación de los valores numéricos:
left = "42"
right = "5"
Debug.Print left > right 'Prints False
Debug.Print Val(left) > Val(right) 'Prints True
End Sub
Por este motivo, asegúrese de que las variables String o Variant se conviertan en números antes
de realizar comparaciones numéricas de inequidad en ellos.
Si el otro operando es una String o Variant de subtipo String que se puede convertir en una Date
utilizando la configuración regional actual, la String se convertirá en una Date . Si no se puede
convertir a una Date en la configuración regional actual, se generará un error de tiempo de
ejecución 13 - "No coincide el tipo" en la comparación.
Se debe tener cuidado al hacer comparaciones entre valores Double o Single y valores booleanos .
A diferencia de otros tipos numéricos, no se puede suponer que los valores que no son cero sean
True debido al comportamiento de VBA de promover el tipo de datos de una comparación que
implique un número de punto flotante a Double :
https://riptutorial.com/es/home 154
'True is promoted to Double - Test is not cast to Boolean
Debug.Print Test = True 'Prints False
Todos los operadores lógicos en VBA se pueden considerar como "anulaciones" de los
operadores a nivel de bits del mismo nombre. Técnicamente, siempre se tratan como operadores
bitwise. Todos los operadores de comparación en VBA devuelven un valor booleano , que
siempre tendrá ninguno de sus bits establecidos ( False ) o todos sus bits establecidos ( True ).
Pero tratará un valor con cualquier bit establecido como True . Esto significa que el resultado de
convertir el resultado a nivel de bits de una expresión a un operador Boolean (ver Operadores de
comparación) siempre será el mismo que tratarlo como una expresión lógica.
Asignar el resultado de una expresión usando uno de estos operadores dará el resultado a nivel
de bits. Tenga en cuenta que en las tablas de verdad a continuación, 0 es equivalente a False y 1
es equivalente a True .
And
0 0 0
0 1 0
1 0 0
1 1 1
Or
0 0 0
0 1 1
1 0 1
1 1 1
https://riptutorial.com/es/home 155
Not
Devuelve True si la expresión se evalúa como False y False si las evaluaciones de expresión son
True .
0 1
1 0
Not es el único operando sin un operando de la mano izquierda. El Editor de Visual Basic
simplificará automáticamente las expresiones con un argumento de la mano izquierda. Si escribe
...
Debug.Print x Not y
Debug.Print Not x
Xor
También conocido como "exclusivo o". Devuelve True si ambas expresiones evalúan resultados
diferentes.
0 0 0
0 1 1
1 0 1
1 1 0
Tenga en cuenta que aunque el operador Xor se puede usar como un operador lógico, no hay
absolutamente ninguna razón para hacerlo, ya que da el mismo resultado que el operador de
comparación <> .
Eqv
También conocido como "equivalencia". Devuelve True cuando ambas expresiones evalúan al
mismo resultado.
https://riptutorial.com/es/home 156
Operando de mano izquierda Operando de mano derecha Resultado
0 0 1
0 1 0
1 0 0
1 1 1
Tenga en cuenta que la función Eqv se usa muy raramente, ya que x Eqv y es equivalente a Not (x
Xor y) mucho más legible.
Imp
También conocido como "implicación". Devuelve True si ambos operandos son iguales o si el
segundo es True .
0 0 1
0 1 1
1 0 0
1 1 1
Tenga en cuenta que la función Imp es muy rara vez utilizada. Una buena regla general es que si
no puede explicar lo que significa, debe usar otra construcción.
https://riptutorial.com/es/home 157
Capítulo 30: Macro seguridad y firma de
proyectos / módulos VBA.
Examples
Crear un certificado autofirmado digital válido SELFCERT.EXE
Para ejecutar macros y mantener la seguridad que proporcionan las aplicaciones de Office contra
el código malicioso, es necesario firmar digitalmente el VBAProject.OTM desde el editor de VBA>
Herramientas> Firma digital .
Office viene con una utilidad para crear un certificado digital autofirmado que puede emplear en la
PC para firmar sus proyectos.
Haga clic en Certificado digital para proyectos VBA para abrir el asistente de certificados.
En el cuadro de diálogo, ingrese un nombre adecuado para el certificado y haga clic en Aceptar.
https://riptutorial.com/es/home 158
Si todo va bien verás una confirmación:
Ahora puede cerrar el asistente SELFCERT y dirigir su atención al certificado que ha creado.
https://riptutorial.com/es/home 159
Verá que el certificado no es de confianza y la razón se indica en el cuadro de diálogo.
https://riptutorial.com/es/home 160
ventana como se muestra a continuación y haga clic en 'Aceptar'.
En el menú Archivo, seleccione Agregar o quitar complemento ... Luego, en el cuadro de diálogo
que sigue, haga doble clic en Certificados y luego haga clic en Aceptar
https://riptutorial.com/es/home 161
Expanda el menú desplegable en la ventana izquierda para Certificados - Usuario actual 'y
seleccione los certificados como se muestra a continuación. El panel central mostrará los
certificados en esa ubicación, que incluirá el certificado que creó anteriormente:
https://riptutorial.com/es/home 162
Haga clic derecho en el certificado y seleccione Todas las tareas> Exportar:
https://riptutorial.com/es/home 163
Asistente de exportación
https://riptutorial.com/es/home 164
Haga clic en Siguiente
https://riptutorial.com/es/home 165
Sólo estará disponible una opción preseleccionada, por lo que haga clic en 'Siguiente'
nuevamente:
https://riptutorial.com/es/home 166
Haga clic en Siguiente nuevamente para guardar el certificado.
https://riptutorial.com/es/home 167
Botón derecho del ratón. Seleccionar todas las tareas e importar
https://riptutorial.com/es/home 168
Haga clic en siguiente y guardar en la tienda Trusted Root Certification Authorities :
https://riptutorial.com/es/home 169
Luego Siguiente> Finalizar, ahora cierra la Consola.
Si ahora usa el certificado y verifica sus propiedades, verá que es un certificado de confianza y
puede usarlo para firmar su proyecto:
https://riptutorial.com/es/home 170
Capítulo 31: Manejo de errores
Examples
Evitando condiciones de error.
Cuando se produce un error de tiempo de ejecución, un buen código debe manejarlo. La mejor
estrategia de manejo de errores es escribir código que verifique las condiciones de error y
simplemente evite ejecutar código que genere un error de tiempo de ejecución.
Un elemento clave para reducir los errores de tiempo de ejecución, es escribir pequeños
procedimientos que hacen una cosa . Cuantas menos razones tengan los procedimientos para
fallar, más fácil será la depuración del código en su totalidad.
Este error se generará cuando se utilice un objeto antes de que se asigne su referencia. Uno
podría tener un procedimiento que recibe un parámetro de objeto:
Si el target no tiene asignada una referencia, el código anterior generará un error que se evitará
fácilmente al verificar si el objeto contiene una referencia de objeto real:
Esta forma de salir temprano de un procedimiento cuando uno o más parámetros no es válido, se
denomina cláusula de guarda .
Este error se produce cuando se accede a una matriz fuera de sus límites.
https://riptutorial.com/es/home 171
Dado un índice mayor que el número de hojas de trabajo en ActiveWorkbook , el código anterior
generará un error de tiempo de ejecución. Una simple cláusula de guardia puede evitar que:
Declaración de error
Incluso con las cláusulas de guardia, no se puede dar cuenta de manera realista siempre para
todas las posibles condiciones de error que podrían ser planteadas en el cuerpo de un
procedimiento. La instrucción On Error GoTo indica a VBA que salte a una etiqueta de línea e
ingrese al "modo de manejo de errores" siempre que ocurra un error inesperado en el tiempo de
ejecución. Después de manejar un error, el código puede reanudar de nuevo en la ejecución
"normal" con el Resume de palabras clave.
Las etiquetas de línea denotan subrutinas : como las subrutinas se originan a partir del código
BASIC heredado y GoSub saltos GoTo y GoSub y declaraciones de Return para saltar a la rutina
"principal", es bastante fácil escribir código espagueti difícil de seguir si las cosas no están
estructuradas de manera rigurosa . Por esta razón, es mejor que:
Esto significa que un procedimiento que maneja sus errores, debe estar estructurado así:
CleanExit:
'cleanup code here
Exit Sub
CleanFail:
'error-handling code here
Resume CleanExit
End Sub
CleanExit:
Exit Sub
CleanFail:
Select Case Err.Number
Case 9
MsgBox "Specified number doesn't exist. Please try again.", vbExclamation
Resume
Case 91
'woah there, this shouldn't be happening.
Stop 'execution will break here
Resume 'hit F8 to jump to the line that raised the error
Case Else
MsgBox "An unexpected error has occurred:" & vbNewLine & Err.Description,
vbCritical
Resume CleanExit
End Select
End Sub
Como una guía general, considere activar el manejo de errores para una subrutina o función
completa, y manejar todos los errores que puedan ocurrir dentro de su alcance. Si solo necesita
manejar los errores en la sección pequeña del código, active y desactive el manejo de errores al
mismo nivel:
If CheckValue = 0 Then
On Error GoTo ErrorHandler ' turn error handling on
' code that may result in error
On Error GoTo 0 ' turn error handling off - same level
End If
CleanExit:
Exit Sub
ErrorHandler:
' error handling code here
' do not turn off error handling here
Resume
End Sub
Línea de números
VBA admite números de línea de estilo heredado (por ejemplo, QBASIC). La propiedad oculta de
Erl se puede usar para identificar el número de línea que generó el último error. Si no estás
usando números de línea, Erl solo devolverá 0.
https://riptutorial.com/es/home 173
Sub DoSomething()
10 On Error GoTo 50
20 Debug.Print 42 / 0
30 Exit Sub
40
50 Debug.Print "Error raised on line " & Erl ' returns 20
End Sub
Si está usando números de línea, pero no de manera consistente, entonces Erl devolverá el
último número de línea antes de la instrucción que generó el error .
Sub DoSomething()
10 On Error GoTo 50
Debug.Print 42 / 0
30 Exit Sub
Tenga en cuenta que Erl también solo tiene precisión Integer y se desbordará silenciosamente.
Esto significa que los números de línea fuera del rango de enteros darán resultados incorrectos:
Sub DoSomething()
99997 On Error GoTo 99999
99998 Debug.Print 42 / 0
99999
Debug.Print Erl 'Prints 34462
End Sub
El número de línea no es tan relevante como la declaración que causó el error, y las líneas de
numeración rápidamente se vuelven tediosas y no son fáciles de mantener.
La palabra clave Resume solo se debe utilizar dentro de una subrutina de manejo de errores,
porque si VBA encuentra Resume sin estar en un estado de error, se genera el error 20 "Reanudar
sin error".
Hay varias formas en que una subrutina de manejo de errores puede usar la palabra clave Resume
:
https://riptutorial.com/es/home 174
instrucción que causó el error. Si el error no se maneja realmente antes de hacer eso,
entonces se permite que la ejecución continúe con datos potencialmente inválidos, lo que
puede resultar en errores lógicos y un comportamiento inesperado.
• Resume [line label] continúa la ejecución en la etiqueta de línea especificada (o número
de línea, si está usando números de línea de estilo heredado). Por lo general, esto permitiría
ejecutar algún código de limpieza antes de salir del procedimiento de forma limpia, como
asegurarse de que la conexión de la base de datos se cierre antes de regresar a la persona
que llama.
La declaración On Error tiene un ámbito de procedimiento, por eso normalmente debería haber
solo una , tal como la declaración On Error en un procedimiento determinado.
Sin embargo, a veces no se puede evitar una condición de error, y saltar a una subrutina de
manejo de errores solo para Resume Next simplemente no se siente bien. En este caso específico,
lo conocido a fallar posiblemente-afirmación puede ser envuelto entre dos On Error
declaraciones:
Callee
https://riptutorial.com/es/home 175
Exit Sub
Handler:
Debug.Print "Error " & Err.Number & " in Caller."
End Sub
Exit Sub
Handler:
Debug.Print "Error " & Err.Number & " in Callee."
Resume Next
End Sub
Errores personalizados
A menudo, al escribir una clase especializada, querrá que genere sus propios errores específicos,
y querrá una forma limpia para que el usuario / código de llamada maneje estos errores
personalizados. Una buena forma de lograrlo es mediante la definición de un tipo de Enum
dedicado:
Option Explicit
Public Enum FoobarError
Err_FooWasNotBarred = vbObjectError + 1024
Err_BarNotInitialized
Err_SomethingElseHappened
End Enum
Err.Raise Err_FooWasNotBarred
El método Err.Raise también puede tomar parámetros personalizados de Description y Source ; por
esta razón, es una buena idea también definir constantes para contener la descripción de cada
error personalizado:
https://riptutorial.com/es/home 176
Private Const Msg_FooWasNotBarred As String = "The foo was not barred."
Private Const Msg_BarNotInitialized As String = "The bar was not initialized."
El código del cliente puede manejar Err_BarNotInitialized como lo haría con cualquier otro error,
dentro de su propia subrutina de manejo de errores.
Nota: la palabra clave de Error heredada también se puede usar en lugar de Err.Raise , pero está
obsoleta / obsoleta.
https://riptutorial.com/es/home 177
Capítulo 32: Manipulación de cuerdas de uso
frecuente.
Introducción
Ejemplos rápidos para las funciones de cadena MID LEFT y RIGHT utilizando INSTR FIND y
LEN.
¿Cómo encuentra el texto entre dos términos de búsqueda (por ejemplo, después de dos puntos
y antes de una coma)? ¿Cómo se obtiene el resto de una palabra (usando MID o usando
DERECHA)? ¿Cuál de estas funciones utiliza parámetros basados en cero y códigos de retorno
frente a uno basado? ¿Qué pasa cuando las cosas van mal? ¿Cómo manejan las cadenas
vacías, los resultados no encontrados y los números negativos?
Examples
Manipulación de cuerdas de uso frecuente.
Mejor MID () y otros ejemplos de extracción de cadenas, que actualmente faltan en la web. Por
favor, ayúdame a dar un buen ejemplo, o completa este aquí. Algo como esto:
strNull = NOTHING
strEmpty = ""
theText = "1234, 78910"
' -----------------
' Extract the word after the comma ", " and before "910" result: "78" ***
' -----------------
https://riptutorial.com/es/home 178
' Get remaining text after the comma-and-space using RIGHT
result = ...
Por favor, siéntase libre de editar este ejemplo y hacerlo mejor. Siempre que quede claro, y tenga
en él prácticas de uso comunes.
https://riptutorial.com/es/home 179
Capítulo 33: Manipulación de fecha y hora
Examples
Calendario
Ejemplo
Sub CalendarExample()
'Cache the current setting.
Dim Cached As Integer
Cached = Calendar
Current Calendar : 0
SampleDate = 2016-07-28
Current Calendar : 1
SampleDate = 1437-10-23
https://riptutorial.com/es/home 180
Funciones de base
Sub DateTimeExample()
' -----------------------------------------------------
' Note : EU system with default date format DD/MM/YYYY
' -----------------------------------------------------
Debug.Print Now ' prints 28/07/2016 10:16:01 (output below assumes this date and time)
Debug.Print Date ' prints 28/07/2016
Debug.Print Time ' prints 10:16:01
End Sub
Función de temporizador
La función de Timer devuelve un solo que representa el número de segundos transcurridos desde
la medianoche. La precisión es una centésima de segundo.
Sub TimerExample()
End Sub
Debido a que las funciones Now y Time son solo precisas a segundos, el Timer ofrece una manera
conveniente de aumentar la precisión de la medición del tiempo:
Sub GetBenchmark()
https://riptutorial.com/es/home 181
Dim StartTime As Single
StartTime = Timer 'Store the current Time
Dim i As Long
Dim temp As String
For i = 1 To 1000000 'See how long it takes Left$ to execute 1,000,000 times
temp = Left$("Text", 2)
Next i
End Sub
IsDate ()
IsDate () comprueba si una expresión es una fecha válida o no. Devuelve un Boolean .
Sub IsDateExamples()
anything = #9/11/2001#
anything = vbNull
End Sub
Funciones de extraccion
Estas funciones toman una Variant que se puede convertir en una Date como parámetro y
devuelven un Integer representa una parte de una fecha u hora. Si el parámetro no se puede
convertir en una Date , se producirá un error de tiempo de ejecución 13: No coincide el tipo.
Valor
Función Descripción
devuelto
Entero (100 a
Año() Devuelve la parte del año del argumento de fecha.
9999)
https://riptutorial.com/es/home 182
Valor
Función Descripción
devuelto
12)
Entero (1 a
Día() Devuelve la parte del día del argumento de fecha.
31)
Entero (0 a
Hora() Devuelve la parte de hora del argumento de fecha.
23)
Entero (0 a
Minuto() Devuelve la porción de minutos del argumento de fecha.
59)
Entero (0 a
Segundo() Devuelve la segunda parte del argumento de fecha.
59)
Ejemplos:
Sub ExtractionExamples()
End Sub
Función DatePart ()
DatePart() es también una función que devuelve una parte de una fecha, pero funciona de manera
diferente y permite más posibilidades que las funciones anteriores. Puede, por ejemplo, devolver
el trimestre del año o la semana del año.
https://riptutorial.com/es/home 183
Sintaxis:
Intervalo Descripción
"q" Trimestre (1 a 4)
Firstweekofyear es opcional. Es una constante que especifica la primera semana del año. Si no
se especifica, se supone que la primera semana es la semana en que ocurre el 1 de enero.
Ejemplos:
Sub DatePartExample()
End Sub
https://riptutorial.com/es/home 184
Funciones de calculo
DateDiff ()
DateDiff() devuelve un valor Long representa el número de intervalos de tiempo entre dos fechas
especificadas.
Sintaxis
Ejemplos
Sub DateDiffExamples()
End Sub
FechaAgregar ()
DateAdd() devuelve una Date a la que se ha agregado una fecha o un intervalo de tiempo
específico.
Sintaxis
https://riptutorial.com/es/home 185
• fecha es una Date o literal que representa la fecha a la que se agrega el intervalo
Ejemplos:
Sub DateAddExamples()
End Sub
Conversión y Creación
CDate ()
CDate() convierte algo de cualquier tipo de datos a un tipo de Date
Sub CDateExamples()
' Find the 10000th day from the epoch date of 1899-12-31
sample = CDate(10000)
Debug.Print Format$(sample, "yyyy-mm-dd") ' prints 1927-05-18
End Sub
https://riptutorial.com/es/home 186
Tenga en cuenta que VBA también tiene un CVDate() escrito de forma CVDate() que funciona de la
misma manera que la función CDate() , aparte de devolver una Variant tipo de fecha en lugar de
una Date tipo muy fuerte. La versión CDate() debe ser preferida cuando se pasa a un parámetro de
Date o se asigna a una variable de Date , y la versión CVDate() debe preferir cuando se pasa a un
parámetro de Variant o se asigna a una variable de Variant . Esto evita la conversión implícita de
tipos.
DateSerial ()
DateSerial()función DateSerial() se utiliza para crear una fecha. Devuelve una Date para un año,
mes y día especificados.
Sintaxis:
Con año, mes y día los argumentos son enteros válidos (año de 100 a 9999, mes de 1 a 12, día
de 1 a 31).
Ejemplos
Sub DateSerialExamples()
End Sub
Tenga en cuenta que DateSerial() aceptará fechas "no válidas" y calculará una fecha válida a
partir de ellas. Esto puede ser usado creativamente para bien:
Ejemplo positivo
Sub GoodDateSerialExample()
https://riptutorial.com/es/home 187
End Sub
Sin embargo, es más probable que cause dolor al intentar crear una fecha a partir de una entrada
de usuario no validada:
Ejemplo negativo
Sub BadDateSerialExample()
End Sub
https://riptutorial.com/es/home 188
Capítulo 34: Midiendo la longitud de las
cuerdas
Observaciones
La longitud de una cadena se puede medir de dos maneras: la medida de longitud más utilizada
es el número de caracteres que usan las funciones de Len , pero VBA también puede revelar el
número de bytes que usan LenB funciones de LenB . Un carácter de doble byte o Unicode tiene
más de un byte de longitud.
Examples
Usa la función de Len para determinar el número de caracteres en una cadena
charLength = Len(baseString)
'charlength = 11
byteLength = LenB(baseString)
'byteLength = 22
Cuando se comprueba si una cadena es de longitud cero, es una mejor práctica y más eficiente,
inspeccionar la longitud de la cadena en lugar de comparar la cadena con una cadena vacía.
https://riptutorial.com/es/home 189
Lea Midiendo la longitud de las cuerdas en línea:
https://riptutorial.com/es/vba/topic/3576/midiendo-la-longitud-de-las-cuerdas
https://riptutorial.com/es/home 190
Capítulo 35: Objeto Scripting.Dictionary
Observaciones
Debe agregar Microsoft Scripting Runtime al proyecto VBA a través del comando Herramientas →
Referencias de VBE para implementar el enlace anticipado del objeto Scripting Dictionary. Esta
referencia de la biblioteca se lleva con el proyecto; no es necesario volver a referenciarlo cuando
el proyecto de VBA se distribuye y ejecuta en otra computadora.
Examples
Propiedades y metodos
Un objeto del Diccionario de Scripting almacena información en pares de Clave / Elemento. Las
Claves deben ser únicas y no una matriz, pero los Elementos asociados se pueden repetir (su
singularidad se mantiene en la Clave complementaria) y puede ser de cualquier tipo de variante u
objeto.
Un diccionario puede considerarse como una base de datos de dos campos en la memoria con un
índice único primario en el primer "campo" (la clave ). Este índice único en la propiedad Claves
permite "búsquedas" muy rápidas para recuperar el valor del elemento asociado de una Clave.
Propiedades
leer
nombre tipo descripción
escribir
leer variante no
Llave Cada clave única individual en el diccionario.
escribir matricial
https://riptutorial.com/es/home 191
leer
nombre tipo descripción
escribir
la clave pasada.
Métodos
nombre descripción
Existe ( clave ) Prueba booleana para determinar si ya existe una clave en el diccionario.
Eliminar (
Elimina una clave de diccionario individual y su elemento asociado.
clave )
Código de muestra
'Populate, enumerate, locate and remove entries in a dictionary that was created
'with late binding
Sub iterateDictionaryLate()
Dim k As Variant, dict As Object
End Sub
'Populate, enumerate, locate and remove entries in a dictionary that was created
https://riptutorial.com/es/home 192
'with early binding (see Remarks)
Sub iterateDictionaryEarly()
Dim d As Long, k As Variant
Dim dict As New Scripting.Dictionary
End Sub
Los diccionarios son excelentes para administrar información donde se producen entradas
múltiples, pero solo le preocupa un valor único para cada conjunto de entradas: el primer o último
valor, el mínimo o el valor máximo, un promedio, una suma, etc.
Considere un libro de trabajo que contenga un registro de la actividad del usuario, con un script
que inserte el nombre de usuario y la fecha de edición cada vez que alguien edite el libro de
trabajo:
Hoja de Log
https://riptutorial.com/es/home 193
UNA segundo
Supongamos que desea generar la última hora de edición para cada usuario en una hoja de
cálculo llamada Summary .
Notas:
1. Se asume que los datos están en ActiveWorkbook .
2. Estamos utilizando una matriz para extraer los valores de la hoja de trabajo; esto es más eficiente que iterar sobre
cada celda.
3. El Dictionary se crea mediante el enlace temprano.
Sub LastEdit()
Dim vLog as Variant, vKey as Variant
Dim dict as New Scripting.Dictionary
Dim lastRow As Integer, lastColumn As Integer
Dim i as Long
Dim anchor As Range
With ActiveWorkbook
With .Sheets("Log")
'Pull entries in "log" into a variant array
lastRow = .Range("a" & .Rows.Count).End(xlUp).Row
vlog = .Range("a1", .Cells(lastRow, 2)).Value2
With .Sheets("Summary")
'Loop through keys
For Each vKey in dict.Keys
'Add the key and value at the next available row
Anchor = .Range("A" & .Rows.Count).End(xlUp).Offset(1,0)
Anchor = vKey
https://riptutorial.com/es/home 194
Anchor.Offset(0,1) = dict(vKey)
Next vKey
End With
End With
End Sub
UNA segundo
Si, por otro lado, desea mostrar cuántas veces ha editado el libro cada usuario, el cuerpo del
bucle For debe tener este aspecto:
UNA segundo
mover 2
Alicia 3
El Dictionary permite obtener un conjunto único de valores muy simple. Considera la siguiente
función:
https://riptutorial.com/es/home 195
Dim val As Variant
For Each val In values
dict(val) = 1 'The value doesn't matter here
Next
Unique = dict.Keys
End Function
https://riptutorial.com/es/home 196
Capítulo 36: Opción VBA Palabra clave
Sintaxis
• Opción optionName [valor]
• Opción explícita
• Opción Comparar {Texto | Binario Base de datos}
• Opción Módulo Privado
• Base de opciones {0 | 1}
Parámetros
Opción Detalle
Comparar
(Solo MS-Access) Hace que las comparaciones de cadenas del módulo
base de
funcionen como lo harían en una declaración SQL.
datos
Impide que se acceda al miembro Public del módulo desde fuera del
Módulo proyecto en el que reside el módulo, ocultando efectivamente los
privado procedimientos de la aplicación host (es decir, no está disponible para usar
como macros o funciones definidas por el usuario).
Observaciones
https://riptutorial.com/es/home 197
Es mucho más fácil controlar los límites de las matrices declarando los límites explícitamente en
lugar de dejar que el compilador retroceda en una declaración de Option Base {0|1} . Esto se
puede hacer así:
Examples
Opción explícita
Se considera la mejor práctica usar siempre Option Explicit en VBA, ya que obliga al
desarrollador a declarar todas sus variables antes de usar. Esto también tiene otros beneficios,
como el uso de mayúsculas automáticas para los nombres de variables declarados e IntelliSense.
Option Explicit
Sub OptionExplicit()
Dim a As Integer
a = 5
b = 10 '// Causes compile error as 'b' is not declared
End Sub
Esto evitará errores de codificación tontos, como errores ortográficos, y también influirá en el uso
del tipo de variable correcto en la declaración de la variable. (Algunos ejemplos más se dan en
SIEMPRE use "Opción explícita" .)
https://riptutorial.com/es/home 198
Opción Comparar {Binary | Texto | Base de datos}
Sub CompareBinary()
'// "b" (Chr 98) is NOT greater than "á" (Chr 225)
foo = "á"
bar = "b"
End Sub
(A | a) <(B | b) <(Z | z)
https://riptutorial.com/es/home 199
Option Compare Text
Sub CompareText()
End Sub
Nota: se desaconseja el uso de esta configuración a menos que el módulo se use para escribir
UDF (funciones definidas por el usuario) personalizadas de Access que deban tratar las
comparaciones de texto de la misma manera que las consultas SQL en esa base de datos.
Base de opciones {0 | 1}
Option Base se utiliza para declarar el límite inferior predeterminado de los elementos de la matriz
. Se declara a nivel de módulo y solo es válido para el módulo actual.
De forma predeterminada (y, por lo tanto, si no se especifica una Base de Opción), la Base es 0.
Lo que significa que el primer elemento de cualquier matriz declarada en el módulo tiene un
índice de 0.
Ejemplo en Base 0:
Option Base 0
https://riptutorial.com/es/home 200
Sub BaseZero()
For i = 0 To UBound(myStrings)
Debug.Print myStrings(i) ' This will print "Apple", then "Orange", then "Peach"
Next i
End Sub
Sub BaseOne()
For i = 0 To UBound(myStrings)
Next i
End Sub
El segundo ejemplo generó un Subíndice fuera de rango (Error 9) en la primera etapa del bucle
porque se realizó un intento de acceder al índice 0 de la matriz, y este índice no existe ya que el
módulo se declara con Base 1
For i = 1 To UBound(myStrings)
Debug.Print myStrings(i) ' This will print "Apple", then "Orange", then "Peach"
Next i
Debe tenerse en cuenta que la función Dividir siempre crea una matriz con un índice de elemento
https://riptutorial.com/es/home 201
basado en cero, independientemente de la configuración de Option Base . Los ejemplos sobre
cómo usar la función Split se pueden encontrar aquí.
Función de división
Devuelve una matriz unidimensional basada en cero que contiene un número específico de
subcadenas.
En Excel, las propiedades Range.Value y Range.Formula para un rango de varias celdas siempre
devuelven una matriz de Variante 2D basada en 1.
Del mismo modo, en ADO, el método Recordset.GetRows siempre devuelve una matriz 2D basada
en 1.
Una de las mejores prácticas recomendadas es usar siempre las funciones LBound y UBound
para determinar las extensiones de una matriz.
La Option Base 1 debe estar en la parte superior de cada módulo de código donde se crea una
matriz o se redimensiona para que las matrices se creen de manera consistente con un límite
inferior de 1.
https://riptutorial.com/es/home 202
Capítulo 37: Pasando Argumentos ByRef o
ByVal
Introducción
Los modificadores ByRef y ByVal son parte de la firma de un procedimiento e indican cómo se pasa
un argumento a un procedimiento. En VBA, se pasa un parámetro ByRef menos que se
especifique lo contrario (es decir, ByRef está implícito si está ausente).
Nota En muchos otros lenguajes de programación (incluido VB.NET), los parámetros se pasan
implícitamente por valor si no se especifica ningún modificador: considere la posibilidad de
especificar los modificadores ByRef explícitamente para evitar posibles confusiones.
Observaciones
Pasando matrices
Las matrices deben ser pasadas por referencia. Este código se compila, pero genera un error de
tiempo de ejecución 424 "Objeto requerido":
Examples
Pasando variables simples ByRef y ByVal
Pasar ByRef o ByVal indica si el valor real de un argumento se pasa al CalledProcedure mediante el
CallingProcedure , o si una referencia (llamada puntero en otros idiomas) se pasa al
CalledProcedure .
https://riptutorial.com/es/home 203
Si se pasa un argumento ByVal , el valor real, no una referencia a la variable, se pasa a
CalledProcedure .
Sub CallingProcedure()
Dim A As Long
Dim B As Long
A = 123
B = 456
Debug.Print "BEFORE CALL => A: " & CStr(A), "B: " & CStr(B)
''Result : BEFORE CALL => A: 123 B: 456
Debug.Print "AFTER CALL = A: " & CStr(A), "B: " & CStr(B)
''Result : AFTER CALL => A: 321 B: 456
End Sub
Otro ejemplo:
Sub Main()
Dim IntVarByVal As Integer
Dim IntVarByRef As Integer
IntVarByVal = 5
IntVarByRef = 10
ByRef
https://riptutorial.com/es/home 204
Public Sub DoSomething1(foo As Long)
End Sub
¡Cuidado! Si viene a VBA con experiencia de otros idiomas, es muy probable que este
sea el comportamiento opuesto al que está acostumbrado. En muchos otros lenguajes
de programación (incluido VB.NET), el modificador implícito / predeterminado pasa los
parámetros por valor.
Llamar a las salidas del procedimiento de Test 84. DoSomething se da foo y recibe una
referencia al valor y, por lo tanto, funciona con la misma dirección de memoria que la
persona que llama.
• Cuando se pasa una referencia ByRef , el procedimiento recibe una referencia al puntero.
https://riptutorial.com/es/home 205
Forzar ByVal en el sitio de la llamada
Al usar paréntesis en el sitio de la llamada, puede anular ByRef y forzar la aprobación de un
argumento ByVal :
bar = DoSomething(foo) 'function call, no whitespace; parens are part of args list
DoSomething (foo) 'procedure call, notice whitespace; parens are NOT part of args
list
DoSomething foo 'procedure call does not force the foo parameter to be ByVal
ByVal
• Cuando se pasa un valor ByVal , el procedimiento recibe una copia del valor.
Llamando a las salidas del procedimiento de Test 42. DoSomething se da foo y recibe una
copia del valor. La copia se multiplica por 2 y luego se desecha cuando finaliza el
procedimiento; La copia de la persona que llama nunca fue alterada.
• Cuando se pasa una referencia ByVal , el procedimiento recibe una copia del puntero.
https://riptutorial.com/es/home 206
Public Sub Test()
Dim foo As Collection
Set foo = New Collection
DoSomething foo
Debug.Print foo.Count
End Sub
Llamando a la anterior Test salidas de procedimiento 1. DoSomething es dada foo y recibe una
copia del puntero a la Collection de objetos. Debido a que la variable de objeto foo en el
alcance de Test apunta al mismo objeto, agregar un elemento en DoSomething agrega el
elemento al mismo objeto. Debido a que es una copia del puntero, establecer su referencia
en Nothing no afecta a la propia copia de la persona que llama.
https://riptutorial.com/es/home 207
Capítulo 38: Personajes no latinos
Introducción
VBA puede leer y escribir cadenas en cualquier idioma o script utilizando Unicode . Sin embargo,
existen reglas más estrictas para los identificadores de identificadores .
Examples
Texto no latino en código VBA
تَغَزَب ذِإ ِسمَشلا ِلثِمَك ِدوَخ َقلَخ فِص- ِراطعِم َءالجَن اهِب ُعيجَضلا ىظحَي
VBA proporciona las funciones AscW y ChrW para trabajar con códigos de caracteres de múltiples
bytes. También podemos usar matrices de Byte para manipular la variable de cadena
directamente:
Sub NonLatinStrings()
' Printing the entire string to the immediate window fails (all '?'s)
Debug.Print "Whole String" & vbNewLine & rng.Value
https://riptutorial.com/es/home 208
Set rng = rng.Offset(1)
Loop
End Sub
Cadena entera
??? ????? ????? ??????? ??????? ??? ??????? - ????? ???????? ???? ???????
???????
Tenga en cuenta que VBA no puede imprimir texto no latino en la ventana inmediata a pesar de
que las funciones de cadena funcionan correctamente. Esta es una limitación del IDE y no del
idioma.
Los identificadores de VBA (nombres de variables y funciones) pueden usar el script latino y
también pueden usar scripts en japonés , coreano , chino simplificado y chino tradicional .
https://riptutorial.com/es/home 209
Dim ñizol As String 'Mapudungun
Dim Vår As String 'Norwegian
Dim «brações» As String 'Portuguese
Dim d’fhàg As String 'Scottish Gaelic
Tenga en cuenta que en el IDE de VBA, un solo apóstrofe dentro de un nombre de variable no
convierte la línea en un comentario (como lo hace en Stack Overflow).
Además, los idiomas que usan dos ángulos para indicar una cita «» pueden usarlos en nombres
de variables a pesar de que las comillas de tipo "" no lo son.
https://riptutorial.com/es/home 210
Capítulo 39: Procedimiento de llamadas
Sintaxis
• IdentifierName [ argumentos ]
• Call IdentifierName [ (argumentos) ]
• [Let | Set] expresión = IdentifierName [ (argumentos) ]
• [Let | Set] IdentifierName [ (argumentos) ] = expresión
Parámetros
Parámetro Información
Nombre del
El nombre del procedimiento a llamar.
identificador
Observaciones
Las dos primeras sintaxis son para llamar a los procedimientos Sub ; Note que la primera sintaxis
no implica paréntesis.
Ver Esto es confuso. ¿Por qué no usar siempre paréntesis? para una explicación detallada de las
diferencias entre las dos primeras sintaxis.
La tercera sintaxis es para llamar a los procedimientos de Function y Function Property Get ;
Cuando hay parámetros, los paréntesis son siempre obligatorios. La palabra clave Let es opcional
cuando se asigna un valor , pero se requiere la palabra clave Set cuando se asigna una
referencia .
La cuarta sintaxis es para llamar a los procedimientos Property Let y Property Set ; la expression
en el lado derecho de la asignación se pasa al parámetro de valor de la propiedad.
Examples
Sintaxis de llamada implícita
ProcedureName
ProcedureName argument1, argument2
https://riptutorial.com/es/home 211
Caso extremo
La palabra clave de Call solo se requiere en un caso de borde:
Valores de retorno
Para recuperar el resultado de una llamada de procedimiento (por ejemplo, los procedimientos de
Function o Property Get ), coloque la llamada en el lado derecho de una asignación:
result = ProcedureName
result = ProcedureName(argument1, argument2)
Los paréntesis deben estar presentes si hay parámetros. Si el procedimiento no tiene parámetros,
los paréntesis son redundantes.
Los paréntesis se utilizan para encerrar los argumentos de las llamadas de función . Su uso para
llamadas de procedimiento puede causar problemas inesperados.
Porque pueden introducir errores, tanto en tiempo de ejecución al pasar un valor posiblemente no
deseado al procedimiento, como en tiempo de compilación simplemente por ser una sintaxis no
válida.
Tiempo de ejecución
Los paréntesis redundantes pueden introducir errores. Dado un procedimiento que toma una
referencia de objeto como parámetro ...
https://riptutorial.com/es/home 212
Esto generará un error de tiempo de ejecución "Objeto requerido" # 424. Otros errores son
posibles en otras circunstancias: aquí la referencia del objeto Application.ActiveCell Range se
evalúa y se pasa por valor, independientemente de la firma del procedimiento que especifique
que ByRef pasaría el target . El valor real pasado de ByVal a DoSomething en el fragmento anterior,
es Application.ActiveCell.Value .
Los paréntesis obligan a VBA a evaluar el valor de la expresión entre corchetes y pasar el
resultado ByVal al procedimiento llamado. Cuando el tipo del resultado evaluado no coincide con
el tipo esperado del procedimiento y no se puede convertir implícitamente, se genera un error de
tiempo de ejecución.
Tiempo de compilación
Este código no podrá compilar:
Call ProcedureName
Call ProcedureName(argument1, argument2)
La sintaxis de llamada explícita requiere la palabra clave de Call y paréntesis alrededor de la lista
de argumentos; los paréntesis son redundantes si no hay parámetros. Esta sintaxis se volvió
obsoleta cuando se agregó a VB la sintaxis de llamada implícita más moderna.
Argumentos opcionales
Por ejemplo, si la función, ProcedureName tuviera dos argumentos obligatorios ( argument1 , argument2
) y un argumento opcional, optArgument3 , podría llamarse al menos cuatro formas:
https://riptutorial.com/es/home 213
' Using named arguments (allows a different order)
result = ProcedureName(optArgument3:="C", argument1:="A", argument2:="B")
La estructura del encabezado de la función que se llama aquí sería algo así:
La palabra clave Optional indica que este argumento se puede omitir. Como se mencionó
anteriormente, todos los argumentos opcionales introducidos en el encabezado deben aparecer
al final, después de los argumentos requeridos.
En esta función, si no se proporciona el argumento para c , su valor será por defecto "C" . Si se
proporciona un valor, esto anulará el valor predeterminado.
https://riptutorial.com/es/home 214
Capítulo 40: Recursion
Introducción
Una función que se llama a sí misma se dice que es recursiva . La lógica recursiva a menudo
también se puede implementar como un bucle. La recursión debe controlarse con un parámetro,
de modo que la función sepa cuándo dejar de recurrir y profundizar la pila de llamadas. La
recursión infinita eventualmente causa un error en el tiempo de ejecución '28': "Fuera de espacio
de pila".
Ver Recursión .
Observaciones
La recursión permite llamadas repetidas y autorreferencia de un procedimiento.
Examples
Factoriales
Carpeta Recursion
Sub EnumerateFilesAndFolders( _
FolderPath As String, _
Optional MaxDepth As Long = -1, _
Optional CurrentDepth As Long = 0, _
Optional Indentation As Long = 2)
https://riptutorial.com/es/home 215
End If
https://riptutorial.com/es/home 216
Capítulo 41: Scripting.FileSystemObject
Examples
Creando un FileSystemObject
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8
Sub FsoExample()
Dim fso As Object ' declare variable
Set fso = CreateObject("Scripting.FileSystemObject") ' Set it to be a File System Object
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8
Sub ReadTextFileExample()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
myFilePath = "C:\mypath\to\myfile.txt"
Set sourceFile = fso.OpenTextFile(myFilePath, ForReading)
myFileText = sourceFile.ReadAll ' myFileText now contains the content of the text file
sourceFile.Close ' close the file
' do whatever you might need to do with the text
https://riptutorial.com/es/home 217
Creando un archivo de texto con FileSystemObject
Sub CreateTextFileExample()
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
myFilePath = "C:\mypath\to\myfile.txt"
Set targetFile = fso.CreateTextFile(myFilePath, True) ' this will overwrite any existing
file
targetFile.Write "This is some new text"
targetFile.Write " And this text will appear right after the first bit of text."
targetFile.WriteLine "This bit of text includes a newline character to ensure each write
takes its own line."
targetFile.Close ' close the file
End Sub
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8
Sub WriteTextFileExample()
Dim oFso
Set oFso = CreateObject("Scripting.FileSystemObject")
myFilePath = "C:\mypath\to\myfile.txt"
' First check if the file exists
If oFso.FileExists(myFilePath) Then
' this will overwrite any existing filecontent with whatever you send the file
' to append data to the end of an existing file, use ForAppending instead
Set oFile = oFso.OpenTextFile(myFilePath, ForWriting)
Else
' create the file instead
Set oFile = oFso.CreateTextFile(myFilePath) ' skipping the optional boolean for
overwrite if exists as we already checked that the file doesn't exist.
End If
oFile.Write "This is some new text"
oFile.Write " And this text will appear right after the first bit of text."
oFile.WriteLine "This bit of text includes a newline character to ensure each write takes
its own line."
oFile.Close ' close the file
End Sub
https://riptutorial.com/es/home 218
Public Sub EnumerateDirectory()
Dim fso As Scripting.FileSystemObject
Set fso = New Scripting.FileSystemObject
Límite tardío:
Sub EnumerateFilesAndFolders( _
FolderPath As String, _
Optional MaxDepth As Long = -1, _
Optional CurrentDepth As Long = 0, _
Optional Indentation As Long = 2)
https://riptutorial.com/es/home 219
End If
Next subFldr
C:\Test
Documents
Personal
Budget.xls
Recipes.doc
Work
Planning.doc
Downloads
FooBar.exe
ReadMe.txt
C:\Test
Documents
Downloads
ReadMe.txt
C:\Test
Documents
Personal
Work
Downloads
FooBar.exe
ReadMe.txt
Imprime MyFile.something
https://riptutorial.com/es/home 220
Dim fso As New Scripting.FileSystemObject
Debug.Print fso.GetExtensionName("MyFile.something.txt")
Imprime txt Tenga en cuenta que el método GetExtensionName() ya maneja múltiples períodos en
un nombre de archivo.
El método GetParentFolderName devuelve la carpeta principal para cualquier ruta. Si bien esto
también se puede usar con carpetas, podría decirse que es más útil para extraer la ruta de una
ruta de archivo absoluta:
Si está aceptando la entrada del usuario para las rutas de las carpetas, es posible que deba
verificar si hay barras diagonales ( \ ) antes de crear una ruta de archivo. El método FSO.BuildPath
hace esto más simple:
Salida:
C:\Temp\Results.txt
C:\Temp\Results.txt
https://riptutorial.com/es/home 221
Capítulo 42: Subcadenas
Observaciones
VBA tiene funciones incorporadas para extraer partes específicas de cadenas, que incluyen:
• Left / Left$
• Right / Right$
• Mid / Mid$
• Trim / Trim$
Para evitar la conversión de tipo implícita en la cabecera (y, por lo tanto, para un mejor
rendimiento), use la versión con el sufijo $ de la función cuando se pasa una variable de cadena a
la función, y / o si el resultado de la función se asigna a una variable de cadena.
Pasar un valor de parámetro Null a una función $ -suffixed generará un error de tiempo de
ejecución ("uso no válido de nulo"), esto es especialmente relevante para el código que involucra
una base de datos.
Examples
Use Left o Left $ para obtener los 3 caracteres más a la izquierda en una
cadena
Use Right o Right $ para obtener los 3 caracteres más a la derecha en una
cadena
Use Mid o Mid $ para obtener caracteres específicos dentro de una cadena
https://riptutorial.com/es/home 222
Utilice Recortar para obtener una copia de la cadena sin espacios iniciales ni
finales
https://riptutorial.com/es/home 223
Capítulo 43: Tipos de datos y límites
Examples
Byte
Un byte es un tipo de datos de 8 bits sin firmar. Puede representar números enteros entre 0 y 255
y tratar de almacenar un valor fuera de ese rango dará como resultado un error de tiempo de
ejecución 6: Overflow . Byte es el único tipo sin signo intrínseco disponible en VBA.
La función de conversión para convertir a un byte es CByte() . Para las conversiones de tipos de
punto flotante, el resultado se redondea al valor entero más cercano con .5 redondeo hacia arriba.
Las cadenas y las matrices de bytes se pueden sustituir entre sí mediante una asignación simple
(no se requieren funciones de conversión).
Por ejemplo:
Sub ByteToStringAndBack()
End Sub
Para poder codificar caracteres Unicode , cada carácter de la cadena ocupa dos bytes en la
matriz, con el byte menos significativo primero. Por ejemplo:
Sub UnicodeExample()
https://riptutorial.com/es/home 224
End Sub
Entero
Un entero es un tipo de datos firmado de 16 bits. Puede almacenar números enteros en el rango
de -32,768 a 32,767 y tratar de almacenar un valor fuera de ese rango resultará en un error de
tiempo de ejecución 6: Desbordamiento.
Los enteros se almacenan en la memoria como valores little-endian con negativos representados
como un complemento de dos .
Tenga en cuenta que, en general, es una mejor práctica utilizar un tipo Long en lugar de un
Integer, a menos que el tipo más pequeño sea miembro de un Tipo o sea requerido (ya sea por
una convención de llamada de API o por alguna otra razón) para que sea de 2 bytes. En la
mayoría de los casos, VBA trata a los enteros como 32 bits internamente, por lo que
generalmente no hay ninguna ventaja al usar el tipo más pequeño. Además, hay una penalización
en el rendimiento en la que se incurre cada vez que se usa un tipo Integer, ya que se lanza
silenciosamente como un Long.
La función de conversión para convertir a un entero es CInt() . Para las conversiones de tipos de
punto flotante, el resultado se redondea al valor entero más cercano con .5 redondeo hacia arriba.
Booleano
Un booleano se utiliza para almacenar valores que pueden representarse como Verdadero o
Falso. Internamente, el tipo de datos se almacena como un valor de 16 bits con 0 que representa
Falso y cualquier otro valor que representa Verdadero.
Se debe tener en cuenta que cuando un valor booleano se convierte en un tipo numérico, todos
los bits se establecen en 1. Esto da como resultado una representación interna de -1 para los
tipos con signo y el valor máximo para un tipo sin signo (Byte).
https://riptutorial.com/es/home 225
Example = CBool(2 ^ 17)
Debug.Print CInt(Example) 'Prints -1
Debug.Print CByte(Example) 'Prints 255
Largo
A Long es un tipo de datos firmado de 32 bits. Puede almacenar números enteros en el rango de -
2,147,483,648 a 2,147,483,647 y tratar de almacenar un valor fuera de ese rango resultará en un
error de tiempo de ejecución 6: Desbordamiento.
Los largos se almacenan en la memoria como valores little-endian con negativos representados
como un complemento de dos .
Tenga en cuenta que dado que un Largo coincide con el ancho de un puntero en un sistema
operativo de 32 bits, los Largos se usan comúnmente para almacenar y pasar punteros hacia y
desde las funciones API.
La función de conversión para convertir a un largo es CLng() . Para las conversiones de tipos de
punto flotante, el resultado se redondea al valor entero más cercano con .5 redondeo hacia arriba.
Soltero
Al igual que con todos los números de punto flotante, se debe tener cuidado al hacer
comparaciones de igualdad. La mejor práctica es incluir un valor delta apropiado para la precisión
requerida.
Doble
https://riptutorial.com/es/home 226
Un doble es un tipo de datos de punto flotante de 64 bits firmado. Al igual que el Single , se
almacena internamente utilizando un diseño de memoria IEEE 754 little-endian y se deben tomar
las mismas precauciones con respecto a la precisión. Un Double puede almacenar valores
enteros en el rango de -9,007,199,254,740,992 a 9,007,199,254,740,992 sin pérdida de
precisión. La precisión de los números de punto flotante depende del exponente.
Moneda
Una moneda es un tipo de datos de punto flotante con signo de 64 bits similar a un doble , pero
escalado en 10,000 para dar una mayor precisión a los 4 dígitos a la derecha del punto decimal.
Una variable de moneda puede almacenar valores desde -922,337,203,685,477.5808 hasta
922,337,203,685,477.5807, lo que le otorga la mayor capacidad de cualquier tipo intrínseco en
una aplicación de 32 bits. Como lo indica el nombre del tipo de datos, se considera la mejor
práctica usar este tipo de datos cuando se representan cálculos monetarios, ya que la escala
ayuda a evitar errores de redondeo.
Fecha
Un tipo de fecha se representa internamente como un tipo de datos de coma flotante de 64 bits
con signo con el valor a la izquierda del punto decimal que representa el número de días desde la
fecha de época de 30 de diciembre de 1899 (aunque véase la nota a continuación). El valor a la
derecha del decimal representa la hora como un día fraccionario. Por lo tanto, una fecha entera
tendría un componente de hora de 12:00:00 AM y x.5 tendría un componente de hora de 12:00:00
PM.
Los valores válidos para fechas están entre el 1 de enero de 100 y 31 de diciembre de 9999. Desde
una doble tiene un alcance más amplio, es posible desbordamiento de una fecha mediante la
asignación de valores fuera de ese rango.
Como tal, se puede usar indistintamente con los cálculos de Doble para la fecha:
https://riptutorial.com/es/home 227
La función de conversión para convertir a una Fecha es CDate() , que acepta cualquier tipo de
representación numérica de fecha / hora de cadena. Es importante tener en cuenta que las
representaciones de cadena de las fechas se convertirán en función de la configuración regional
actual en uso, por lo que se deben evitar los lanzamientos directos si se pretende que el código
sea portátil.
Cuerda
Longitud variable
Una cadena de longitud variable permite agregar y truncar y se almacena en la memoria como un
COM BSTR . Consiste en un entero sin signo de 4 bytes que almacena la longitud de la cadena
en bytes seguidos por los propios datos de cadena como caracteres anchos (2 bytes por carácter)
y terminados con 2 bytes nulos. Por lo tanto, la longitud máxima de la cadena que puede ser
manejada por VBA es 2,147,483,647 caracteres.
Debido a que la longitud puede cambiar, VBA reasigna la memoria para una Cadena cada vez
que se asigna la variable , lo que puede imponer penalizaciones de rendimiento para los
procedimientos que las alteran repetidamente.
Longitud fija
Dim Value As String * 1024 'Declares a fixed length string of 1024 characters.
Las cadenas de longitud fija se asignan a 2 bytes para cada carácter y se almacenan en la
memoria como una simple matriz de bytes. Una vez asignada, la longitud de la Cadena es
inmutable. No están terminación nula en la memoria, por lo que una cadena que se llena la
memoria asignada con caracteres que no son nulos no es adecuado para pasar a funciones API
esperan una cadena terminada en nulo.
Las cadenas de longitud fija superan una limitación del índice de 16 bits heredado, por lo que solo
pueden tener hasta 65.535 caracteres de longitud. El intento de asignar un valor más largo que el
espacio de memoria disponible no generará un error de tiempo de ejecución; en su lugar, el valor
resultante simplemente se truncará:
https://riptutorial.com/es/home 228
Debug.Print Foobar 'Prints "Fooba"
Largo largo
El tipo de datos LongLong se introdujo como parte del soporte del sistema operativo de 64 bits de
VBA. En aplicaciones de 64 bits, este valor se puede utilizar para almacenar y pasar punteros a
API de 64 bits.
Variante
Una variante es un tipo de datos COM que se utiliza para almacenar e intercambiar valores de
tipos arbitrarios, y cualquier otro tipo en VBA se puede asignar a una variante. Las variables
declaradas sin un tipo explícito especificado por As [Type] defecto a Variant.
Las variantes se almacenan en la memoria como una estructura VARIANTE que consta de un
descriptor de tipo de byte ( VARTYPE ) seguido de 6 bytes reservados y luego un área de datos
de 8 bytes. Para los tipos numéricos (incluidos Date y Boolean), el valor subyacente se almacena
en la propia Variant. Para todos los demás tipos, el área de datos contiene un puntero al valor
subyacente.
El tipo subyacente de una Variante se puede determinar con la función VarType() que devuelve el
valor numérico almacenado en el descriptor de tipo, o la función TypeName() que devuelve la
representación de la cadena:
https://riptutorial.com/es/home 229
Dim Example As Variant
Example = 42
Debug.Print VarType(Example) 'Prints 2 (VT_I2)
Debug.Print TypeName(Example) 'Prints "Integer"
Example = "Some text"
Debug.Print VarType(Example) 'Prints 8 (VT_BSTR)
Debug.Print TypeName(Example) 'Prints "String"
Debido a que las Variantes pueden almacenar valores de cualquier tipo, las asignaciones de
literales sin sugerencias de tipo se convertirán implícitamente a una Variante del tipo apropiado
de acuerdo con la siguiente tabla. Los literales con sugerencias de tipo se convertirán a una
Variante del tipo indicado.
Nota: A menos que haya una razón específica para usar una Variante (es decir, un iterador en un
bucle For Each o un requisito de API), el tipo generalmente se debe evitar para las tareas de
rutina por las siguientes razones:
• No son de tipo seguro, lo que aumenta la posibilidad de errores de tiempo de ejecución. Por
ejemplo, una Variante que contiene un valor Integer se convertirá silenciosamente en un
Largo en lugar de desbordarse.
• Introducen la sobrecarga de procesamiento al requerir al menos una desreferencia de
puntero adicional.
• El requisito de memoria para una Variante es siempre al menos 8 bytes más alto que el
necesario para almacenar el tipo subyacente.
LongPtr
Su uso principal es proporcionar una forma portátil para almacenar y pasar punteros en ambas
arquitecturas (consulte Cambiar el comportamiento del código en tiempo de compilación .
https://riptutorial.com/es/home 230
Aunque el sistema operativo lo trata como una dirección de memoria cuando se usa en llamadas
a la API, se debe tener en cuenta que VBA lo trata como un tipo firmado (y, por lo tanto, está
sujeto a desbordamiento firmado y no firmado). Por esta razón, cualquier aritmética de punteros
realizada con LongPtrs no debe usar comparaciones > o < . Esta "peculiaridad" también hace
posible que agregar desplazamientos simples que apuntan a direcciones válidas en la memoria
puede causar errores de desbordamiento, por lo que se debe tener cuidado al trabajar con
punteros en VBA.
Decimal
El tipo de datos Decimal solo está disponible como subtipo de Variant , por lo que debe declarar
cualquier variable que deba contener un Decimal como Variant y luego asignar un valor Decimal
mediante la función CDec . La palabra clave Decimal es una palabra reservada (lo que sugiere que
VBA eventualmente agregará soporte de primera clase para el tipo), por lo que el Decimal no se
puede usar como una variable o nombre de procedimiento.
El tipo Decimal requiere 14 bytes de memoria (además de los bytes requeridos por la variante
principal) y puede almacenar números con hasta 28 decimales. Para los números sin ningún lugar
decimal, el rango de valores permitidos es de -79,228,162,514,264,337,593,550,335 a
+79,228,162,514,264,337,593,543,950,335 inclusive. Para los números con el máximo de 28
decimales, el rango de valores permitidos es de -7.9228162514264337593543950335 a
+7.9228162514264337593543950335 inclusive.
https://riptutorial.com/es/home 231
Capítulo 44: Trabajando con ADO
Observaciones
Los ejemplos que se muestran en este tema utilizan el enlace inicial para mayor claridad y
requieren una referencia a la biblioteca Microsoft ActiveX Data Object xx. Se pueden convertir a
enlace tardío reemplazando las referencias fuertemente tipadas con Object y reemplazando la
creación de objetos usando New con CreateObject cuando sea apropiado.
Examples
Haciendo una conexión a una fuente de datos
El primer paso para acceder a una fuente de datos a través de ADO es crear un objeto de
Connection ADO. Normalmente, esto se hace usando una cadena de conexión para especificar los
parámetros de la fuente de datos, aunque también es posible abrir una conexión DSN pasando el
DSN, el ID de usuario y la contraseña al método .Open .
Tenga en cuenta que no se requiere un DSN para conectarse a una fuente de datos a través de
ADO: cualquier fuente de datos que tenga un proveedor ODBC puede conectarse con la cadena
de conexión apropiada. Si bien las cadenas de conexión específicas para diferentes proveedores
están fuera del alcance de este tema, ConnectionStrings.com es una excelente referencia para
encontrar la cadena adecuada para su proveedor.
With database
.ConnectionString = ConnString
.ConnectionTimeout = 10 'Value is given in seconds.
.Open
End With
OpenDatabaseConnection = database
Exit Function
Handler:
Debug.Print "Database connection failed. Check your connection string."
https://riptutorial.com/es/home 232
End Function
Las consultas se pueden realizar de dos formas, ambas de las cuales devuelven un objeto
Recordset ADO que es una colección de filas devueltas. Tenga en cuenta que los dos ejemplos a
continuación utilizan la función OpenDatabaseConnection del ejemplo de Conexión a un origen de
datos con el propósito de ser breves. Recuerde que la sintaxis del SQL pasado al origen de datos
es específica del proveedor.
El segundo método es crear un objeto de Command ADO para la consulta que desea ejecutar. Esto
requiere un poco más de código, pero es necesario para usar consultas parametrizadas:
https://riptutorial.com/es/home 233
If Not database Is Nothing Then
Dim query As ADODB.Command
Set query = New ADODB.Command
'Build the command to pass to the data source.
With query
.ActiveConnection = database
.CommandText = "SELECT DISTINCT Item FROM Table"
.CommandType = adCmdText
End With
Dim records As ADODB.Recordset
'Execute the command to retrieve the recordset.
Set records = query.Execute()
Tenga en cuenta que los comandos enviados al origen de datos son vulnerables a la inyección
de SQL , ya sea intencional o no intencional. En general, las consultas no deben crearse
concatenando entradas de usuario de ningún tipo. En su lugar, deben estar parametrizados (ver
Crear comandos parametrizados ).
Las conexiones ADO se pueden usar para realizar prácticamente cualquier función de base de
datos que el proveedor admita a través de SQL. En este caso, no siempre es necesario usar el
Recordset devuelto por la función Execute , aunque puede ser útil para obtener asignaciones de
claves después de las instrucciones INSERT con @@ Identity o comandos SQL similares. Tenga
en cuenta que el siguiente ejemplo utiliza la función OpenDatabaseConnection del ejemplo de
Conexión a un origen de datos con el propósito de brevedad.
https://riptutorial.com/es/home 234
.Execute 'We don't need the return from the DB, so ignore it.
End With
End If
CleanExit:
If Not database Is Nothing And database.State = adStateOpen Then
database.Close
End If
Exit Sub
Handler:
Debug.Print "Error " & Err.Number & ": " & Err.Description
Resume CleanExit
End Sub
Tenga en cuenta que los comandos enviados al origen de datos son vulnerables a la inyección
de SQL , ya sea intencional o no intencional. En general, las sentencias de SQL no deben
crearse concatenando entradas de usuario de ningún tipo. En su lugar, deben estar
parametrizados (ver Crear comandos parametrizados ).
Cada vez que el SQL ejecutado a través de una conexión ADO debe contener información del
usuario, se considera la mejor práctica para parametrizarlo a fin de minimizar la posibilidad de
inyección de SQL. Este método también es más legible que las concatenaciones largas y facilita
un código más robusto y mantenible (es decir, mediante el uso de una función que devuelve una
matriz de Parameter ).
https://riptutorial.com/es/home 235
'Add the parameters to the Command
.Parameters.Append fooValue
.Parameters.Append condition
.Execute
End With
End If
CleanExit:
If Not database Is Nothing And database.State = adStateOpen Then
database.Close
End If
Exit Sub
Handler:
Debug.Print "Error " & Err.Number & ": " & Err.Description
Resume CleanExit
End Sub
Nota: el ejemplo anterior muestra una instrucción UPDATE parametrizada, pero a cualquier
instrucción SQL se le pueden dar parámetros.
https://riptutorial.com/es/home 236
Capítulo 45: Trabajar con archivos y
directorios sin usar FileSystemObject
Observaciones
El Scripting.FileSystemObject es mucho más robusto que los métodos heredados en este tema.
Se debe preferir en casi todos los casos.
Examples
Determinar si existen carpetas y archivos
Archivos:
Para determinar si existe un archivo, simplemente pase el nombre de archivo a la función Dir$ y
compruebe si devuelve un resultado. Tenga en cuenta que Dir$ admite comodines, por lo que
para probar un archivo específico , el nombre de pathName pasado se debe probar para asegurarse
de que no los contiene. La muestra a continuación genera un error: si este no es el
comportamiento deseado, la función se puede cambiar para que simplemente devuelva False .
La función Dir$() también se puede usar para determinar si existe una carpeta al especificar
vbDirectory para el parámetro de attributes opcional. En este caso, el pasado pathName valor debe
terminar con un separador de ruta ( \ ), como búsqueda de nombres de archivos hará que los
falsos positivos. Tenga en cuenta que los comodines solo se permiten después del último
separador de ruta, por lo que la siguiente función de ejemplo arrojará un error de tiempo de
ejecución 52 - "Nombre o número de archivo incorrecto" si la entrada contiene un comodín. Si
este no es el comportamiento deseado, elimine el comentario On Error Resume Next en la parte
superior de la función. También recuerde que Dir$ admite rutas de archivo relativas (es decir,
..\Foo\Bar ), por lo que se garantiza que los resultados solo serán válidos siempre que no se
cambie el directorio de trabajo actual.
https://riptutorial.com/es/home 237
If pathName = vbNullString Or Right$(pathName, 1) <> "\" Then
Exit Function
End If
FolderExists = Dir$(pathName, vbDirectory) <> vbNullString
End Function
La instrucción ChDir también se puede utilizar para probar si existe una carpeta. Tenga en cuenta
que este método cambiará temporalmente el entorno en el que se está ejecutando VBA, por lo
que si eso es una consideración, se debe usar el método Dir$ su lugar. Tiene la ventaja de ser
mucho menos tolerante con su parámetro. Este método también admite rutas de archivo relativas,
por lo que tiene la misma advertencia que el método Dir$ .
NOTA: para mayor brevedad, los siguientes ejemplos utilizan la función FolderExists del ejemplo
de Determinación de si existen carpetas y archivos en este tema.
La declaración MkDir se puede utilizar para crear una nueva carpeta. Acepta rutas que contienen
letras de unidad ( C:\Foo ), nombres UNC ( \\Server\Foo ), rutas relativas ( ..\Foo ) o el directorio
de trabajo actual ( Foo ).
Si se omite la unidad o el nombre UNC (es decir, \Foo ), la carpeta se crea en la unidad actual.
Este puede o no ser el mismo disco que el directorio de trabajo actual.
La instrucción RmDir se puede utilizar para eliminar carpetas existentes. Acepta rutas en las
mismas formas que MkDir y usa la misma relación con el directorio y la unidad de trabajo actuales.
Tenga en cuenta que la instrucción es similar al comando de Windows rd shell, por lo que arrojará
https://riptutorial.com/es/home 238
un error de tiempo de ejecución 75: "Error de acceso a la ruta / archivo" si el directorio de destino
no está vacío.
https://riptutorial.com/es/home 239
Capítulo 46: VBA orientado a objetos
Examples
Abstracción
El procedimiento DoSomething tiene un alto nivel de abstracción : podemos decir que está
mostrando un formulario y creando algún modelo, y pasar ese objeto a algún procedimiento
ProcessUserData que sabe qué hacer con él; cómo se crea el modelo es el trabajo de otro
procedimiento:
Aquí, el procedimiento es leer los valores disponibles de un rango con nombre en una hoja de
cálculo DataSheet . Igualmente, podría ser leerlos desde una base de datos, o los valores podrían
estar codificados: es un detalle de la implementación que no es motivo de preocupación para
ninguno de los niveles de abstracción más altos.
Encapsulacion
https://riptutorial.com/es/home 240
La encapsulación oculta los detalles de implementación del código del
cliente.
'...
Y cuando el código del cliente quiere leer ese valor, no necesita preocuparse por una casilla de
verificación; en su lugar, simplemente utiliza la propiedad SomeOtherSetting :
Vayamos un paso más allá encapsulando el modelo del formulario en un módulo de clase
dedicado. Pero si hiciéramos una Public Property para el nombre de UserName y la Timestamp ,
tendríamos que exponer los accesores de Property Let , haciendo que las propiedades sean
mutables, y no queremos que el código del cliente tenga la capacidad de cambiar estos valores
una vez que estén establecidos.
Option Explicit
https://riptutorial.com/es/home 241
Public Property Get Timestamp() As Date
End Property
Observe que las propiedades de Timestamp y nombre de UserName solo exponen una Property Get
acceso. Ahora la clase SomeModel puede implementar esa interfaz:
Option Explicit
Implements ISomeModel
https://riptutorial.com/es/home 242
this.SomeSetting = value
End Property
Los miembros de la interfaz son todos Private , y todos los miembros de la interfaz deben
implementarse para que el código se compile. Los miembros Public no forman parte de la interfaz
y, por lo tanto, no están expuestos a código escrito contra la interfaz de ISomeModel .
Usando un atributo VB_PredeclaredId , podemos hacer que la clase SomeModel tenga una instancia
https://riptutorial.com/es/home 243
predeterminada y escribir una función que funcione como un miembro de nivel de tipo ( Shared en
VB.NET, static en C #) al que el código de cliente pueda llamar sin necesidad de crear primero
Una instancia, como hicimos aquí:
Este método de fábrica asigna los valores de propiedad que son de solo lectura cuando se
accede desde la interfaz de ISomeModel , aquí Timestamp y UserName :
Y ahora podemos codificar en contra de la ISomeModel interfaz, que expone Timestamp y UserName
como propiedades de sólo lectura que no se pueden reasignar (siempre y cuando el código está
escrito en contra de la interfaz).
Polimorfismo
Option Explicit
https://riptutorial.com/es/home 244
El código subyacente del formulario podría verse así:
Option Explicit
Implements ISomeView
Pero entonces, nada prohíbe la creación de otro módulo de clase que implemente la interfaz
ISomeView sin ser un formulario de usuario ; esto podría ser una clase SomeViewMock :
Option Explicit
Implements ISomeView
https://riptutorial.com/es/home 245
End Type
Private this As TView
Y ahora podemos cambiar el código que funciona con un UserForm y hacerlo funcionar fuera de la
interfaz ISomeView , por ejemplo, dándole el formulario como un parámetro en lugar de crear una
instancia de él:
Debido a que el DoSomething método depende de una interfaz (es decir, una abstracción) y no una
clase concreta (por ejemplo, un determinado UserForm ), podemos escribir una prueba unitaria
automatizado que asegura que ProcessUserData no se ejecuta cuando view.IsCancelled es True ,
haciendo que nuestra prueba crear una instancia de SomeViewMock , establecer su propiedad
IsCancelled en True y pasarla a DoSomething .
Se pueden hacer pruebas unitarias de escritura en VBA, hay complementos que incluso se
integran en el IDE. Pero cuando el código se combina estrechamente con una hoja de trabajo,
una base de datos, un formulario o el sistema de archivos, entonces la prueba de la unidad
comienza a requerir una hoja de trabajo, una base de datos, un formulario o un sistema de
archivos reales, y estas dependencias son nuevas fallas fuera de control puntos que el código
https://riptutorial.com/es/home 246
comprobable debe aislar, por lo que las pruebas unitarias no requieren una hoja de trabajo, base
de datos, formulario o sistema de archivos real.
Al escribir código contra interfaces, de una manera que permite que el código de prueba inyecte
implementaciones de código auxiliar / simulacro (como el ejemplo anterior de SomeViewMock ),
puede escribir pruebas en un "entorno controlado", y simular lo que sucede cuando cada uno de
los 42 posibles permutaciones de las interacciones del usuario en los datos del formulario, sin
siquiera mostrar una vez el formulario y hacer clic manualmente en un control de formulario.
https://riptutorial.com/es/home 247
Creditos
S.
Capítulos Contributors
No
Automatización o uso de
5 otras bibliotecas de Branislav Kollár
aplicaciones.
8 Colecciones Comintern
Copiando, devolviendo y
13 Mark.R
pasando matrices.
Creación de una clase Branislav Kollár, Macro Man, Mat's Mug, Neil Mussett,
14
personalizada ThunderFrame
https://riptutorial.com/es/home 248
CreateObject vs.
16 Branislav Kollár, Dave, Tim
GetObject
Declarar y asignar
19 Comintern, ThunderFrame
cadenas
Errores en tiempo de
20 Branislav Kollár, Macro Man, Mat's Mug
ejecución de VBA
Literales de cadenas -
Escape, caracteres no
27 Comintern, ThunderFrame
imprimibles y
continuaciones de línea
Manipulación de cuerdas
32 pashute
de uso frecuente.
https://riptutorial.com/es/home 249
Manipulación de fecha y
33 Comintern, FreeMan, Thomas G
hora
Procedimiento de
39 Macro Man, Mat's Mug, Neil Mussett, Sam Johnson
llamadas
https://riptutorial.com/es/home 250