Está en la página 1de 223

6/1/2021 Intitulado

Página 1

VBA

#vba
https://translate.googleusercontent.com/translate_f 1/223
6/1/2021 Intitulado
Página 2

Tabla de contenido
Acerca de 1

Capítulo 1: Empezando con VBA 2

Observaciones 2

Versiones 2

Ejemplos 2

Accediendo al Editor de Visual Basic en Microsoft Office 2

Primer módulo y Hola mundo 4

Depuración 5

Ejecute el código paso a paso 5

Ventana de relojes 5

Ventana inmediata 5

Mejores prácticas de depuración 6

Capítulo 2: Llamadas a la API 7

Introducción 7

Observaciones 7

Ejemplos 8

Declaración y uso de API 8

API de Windows: módulo dedicado (1 de 2) 11

API de Windows: módulo dedicado (2 de 2) 15

API de Mac 19

Obtenga monitores totales y resolución de pantalla 20

FTP y API regionales 21

Capítulo 3: Matrices 25

Ejemplos 25

Declarar una matriz en VBA 25

Acceso a elementos 25

Indexación de matrices 25

Índice específico 25

Declaración dinámica 25

Uso de Split para crear una matriz a partir de una cadena 26

Página 3

Iterando elementos de una matriz 27

Para ... Siguiente 27

Para cada uno ... Siguiente 28

Matrices dinámicas (cambio de tamaño de matriz y manejo dinámico) 29

Matrices dinámicas 29

https://translate.googleusercontent.com/translate_f 2/223
6/1/2021 Intitulado
Agregar valores dinámicamente 29

Eliminar valores dinámicamente 29

Restablecimiento de una matriz y reutilización dinámica 30

Matrices irregulares (matrices de matrices) 30

Matrices irregulares NO matrices multidimensionales 30

Crear una matriz irregular 31

Creación y lectura dinámica de matrices irregulares 31

Matrices multidimensionales 33

Matrices multidimensionales 33

Matriz de dos dimensiones 34

Matriz de tres dimensiones 36

Capítulo 4: Asignar cadenas con caracteres repetidos 40

Observaciones 40

Ejemplos 40

Utilice la función Cadena para asignar una cadena con n caracteres repetidos 40

Utilice las funciones String y Space para asignar una cadena de n caracteres 40

Capítulo 5: Atributos 41

Sintaxis 41

Ejemplos 41

VB_Name 41

VB_GlobalNameSpace 41

VB_Createable 41

VB_PredeclaredId 42

Declaración 42

Llamada 42

VB_Exposed 42

VB_Description 43

Página 4

VB_ [Var] UserMemId 43

Especificar el miembro predeterminado de una clase 43

Hacer una clase iterable con una construcción de bucle For Each 44

Capítulo 6: Automatización o uso de otras bibliotecas de aplicaciones 46

Introducción 46

Sintaxis 46

Observaciones 46

Ejemplos 46

Expresiones regulares de VBScript 46

Código 47

https://translate.googleusercontent.com/translate_f 3/223
6/1/2021 Intitulado
Objeto de sistema de archivos de secuencias de comandos 48
Objeto Diccionario de secuencias de comandos 48

Objeto de Internet Explorer 49

Miembros básicos de Internet Explorer Objec 49

Raspado web 49

Hacer clic 51

Biblioteca de objetos HTML de Microsoft o Mejor amigo de IE 51

IE Principales problemas 52

Capítulo 7: Colecciones 53

Observaciones 53

Comparación de funciones con matrices y diccionarios 53

Ejemplos 53

Agregar elementos a una colección 53

Eliminar elementos de una colección 55

Obtener el recuento de elementos de una colección 56

Recuperar elementos de una colección 56

Determinar si existe una clave o un elemento en una colección 58

Llaves 58

Artículos 58

Borrar todos los elementos de una colección 59

Capítulo 8: Comentarios 61

Página 5

Observaciones 61

Ejemplos 61

Comentarios del apóstrofe 61

Comentarios REM 62

Capítulo 9: Concatenar cadenas 63

Observaciones 63

Ejemplos 63

Concatenar cadenas usando el operador & 63

Concatenar una matriz de cadenas usando la función Unir 63

Capítulo 10: Compilación condicional 64

Ejemplos 64

Cambiar el comportamiento del código en tiempo de compilación 64

Uso de Declare Importaciones que funcionan en todas las versiones de Office sesenta y cinco

Capítulo 11: Conversión de otros tipos a cadenas 67

Observaciones 67

Ejemplos 67

https://translate.googleusercontent.com/translate_f 4/223
6/1/2021 Intitulado
Utilice CStr para convertir un tipo numérico en una cadena 67

Utilice Formato para convertir y formatear un tipo numérico como una cadena 67

Utilice StrConv para convertir una matriz de bytes de caracteres de un solo byte en una cadena 67

Convierta implícitamente una matriz de bytes de caracteres de varios bytes en una cadena 67

Capítulo 12: Copiar, devolver y pasar matrices 69

Ejemplos 69

Copiar matrices 69

Copiar matrices de objetos 70

Variantes que contienen una matriz 70

Devolución de matrices de funciones 70

Salida de una matriz a través de un argumento de salida 71

Salida a una matriz fija 71

Salida de una matriz desde un método de clase 72

Pasar matrices a procedimientos 72

Capítulo 13: CreateObject frente a GetObject 74

Página 6

Observaciones 74

Ejemplos 74

Demostrar GetObject y CreateObject 74

Capítulo 14: Creación de una clase personalizada 76

Observaciones 76

Ejemplos 76

Agregar una propiedad a una clase 76

Agregar funcionalidad a una clase 77

Alcance, instanciación y reutilización del módulo de clase 78

Capítulo 15: Creación de un procedimiento 80

Ejemplos 80

Introducción a los procedimientos 80

Devolviendo un valor 80

Función con ejemplos 81

Capítulo 16: Estructuras de datos 82

Introducción 82

Ejemplos 82

Lista enlazada 82

Árbol binario 83

Capítulo 17: Tipos de datos y límites 85

Ejemplos 85

Byte 85

https://translate.googleusercontent.com/translate_f 5/223
6/1/2021 Intitulado
Entero 86

Booleano 86

Largo 87

Soltero 87

Doble 87

Moneda 88

Fecha 88

Cuerda 88

Longitud variable 89

Longitud fija 89

Página 7

Largo largo 89

Variante 90

LongPtr 91

Decimal 91

Capítulo 18: Manipulación de fecha y hora 93

Ejemplos 93

Calendario 93

Ejemplo 93

Funciones base 94

Recuperar fecha y hora del sistema 94

Función de temporizador 94

IsDate () 95

Funciones de extracción 95

Función DatePart () 96

Funciones de cálculo 97

DateDiff () 98

DateAdd () 98

Conversión y creación 99

CDate () 99

DateSerial () 100

Capítulo 19: Declaración y asignación de cadenas 102

Observaciones 102

Ejemplos 102

Declarar una constante de cadena 102

Declarar una variable de cadena de ancho variable 102

Declarar y asignar una cadena de ancho fijo 102

Declarar y asignar una matriz de cadenas 102

Asignar caracteres específicos dentro de una cadena usando la declaración Mid 103

https://translate.googleusercontent.com/translate_f 6/223
6/1/2021 Intitulado
Asignación hacia y desde una matriz de bytes 103

Capítulo 20: Declaración de variables 104

Ejemplos 104

Declaración implícita y explícita 104

Página 8

Variables 104

Alcance 104

Variables locales 105

Variables estáticas 105

Campos 106

Campos de instancia 107

Encapsular campos 107

Constantes (Const) 108

Modificadores de acceso 109

Opción Módulo Privado 109

Sugerencias de tipo 110

Funciones integradas de retorno de cadenas 110

Declarar cadenas de longitud fija 112

Cuándo usar una variable estática 112

Capítulo 21: Manejo de errores 115

Ejemplos 115

Evitando condiciones de error 115

En declaración de error 116

Estrategias de manejo de errores 116

Línea de números 117

Reanudar palabra clave 118

En caso de error, reanudar siguiente 118

Errores personalizados 120

Generando sus propios errores en tiempo de ejecución 120

Capítulo 22: Eventos 122

Sintaxis 122

Observaciones 122

Ejemplos 122

Fuentes y controladores 122

¿Qué son los eventos? 122

Manipuladores 122

https://translate.googleusercontent.com/translate_f 7/223
6/1/2021 Intitulado
Página 9

Fuentes 124

Pasar datos a la fuente del evento 124

Usando parámetros pasados por referencia 124

Usando objetos mutables 125

Capítulo 23: Estructuras de control de flujo 127

Ejemplos 127

Seleccione el caso 127

Para cada bucle 128

Sintaxis 129

Hacer bucle 129

Mientras bucle 130

En bucle 130

Capítulo 24: Manipulación de cuerdas de uso frecuente 132

Introducción 132

Ejemplos 132

Manipulación de cadenas ejemplos de uso frecuente 132

Capítulo 25: Interfaces 134

Introducción 134

Ejemplos 134

Interfaz simple - Volable 134

Múltiples interfaces en una clase: se puede volar y se puede nadar 135

Capítulo 26: Seguridad de macros y firma de proyectos / módulos VBA 138

Ejemplos 138

Cree un certificado autofirmado digital válido SELFCERT.EXE 138

Capítulo 27: Medición de la longitud de cuerdas 151

Observaciones 151

Ejemplos 151

Use la función Len para determinar el número de caracteres en una cadena 151

Utilice la función LenB para determinar el número de bytes en una cadena 151

Prefiera `If Len (myString) = 0 Then` sobre` If myString = "" Then` 151

Capítulo 28: Convenciones de nomenclatura 152

Página 10

Ejemplos 152

Nombres de variables 152

Notación húngara 153

Nombres de procedimientos 155

https://translate.googleusercontent.com/translate_f 8/223
6/1/2021 Intitulado
Capítulo 29: Caracteres no latinos 157
Introducción 157

Ejemplos 157

Texto no latino en código VBA 157

Identificadores no latinos y cobertura de idiomas 158

Capítulo 30: VBA orientado a objetos 160

Ejemplos 160

Abstracción 160

Los niveles de abstracción ayudan a determinar cuándo dividir las cosas. 160

Encapsulamiento 160

La encapsulación oculta los detalles de implementación del código del cliente. 160

Usar interfaces para imponer la inmutabilidad 161

Usando un método de fábrica para simular un constructor 163

Polimorfismo 164

El polimorfismo es la capacidad de presentar la misma interfaz para diferentes impleme subyacentes 164

El código comprobable depende de abstracciones 166

Capítulo 31: Operadores 167

Observaciones 167

Ejemplos 167

Operadores matemáticos 167

Operadores de concatenación 168

Operadores de comparación 169

Notas 169

Operadores bit a bit \ lógicos 171

Capítulo 32: Pasando argumentos ByRef o ByVal 175

Introducción 175

Observaciones 175

Pasando matrices 175

Página 11

Ejemplos 175

Pasar variables simples ByRef y ByVal 175

ByRef 176

Modificador predeterminado 176

Pasando por referencia 177

Forzar ByVal en el sitio de la llamada 177

ByVal 178

Pasando por valor 178

Capítulo 33: Llamadas a procedimientos 180

Sintaxis 180

https://translate.googleusercontent.com/translate_f 9/223
6/1/2021 Intitulado
Parámetros 180

Observaciones 180

Ejemplos 180

Sintaxis de llamada implícita 180

Caso extremo 180

Valores devueltos 181

Esto es confuso. ¿Por qué no usar siempre paréntesis? 181

Tiempo de ejecución 181

Tiempo de compilación 182

Sintaxis de llamada explícita 182

Argumentos opcionales 182

Capítulo 34: Lectura de archivos de 2GB + en binario en VBA y File Hashes 184

Introducción 184

Observaciones 184

MÉTODOS PARA LA CLASE DE MICROSOFT 184

PROPIEDADES DE LA CLASE POR MICROSOFT 185

MÓDULO NORMAL 185

Ejemplos 185

Esto tiene que estar en un módulo de clase, los ejemplos más adelante se denominarán "aleatorios" 185

Código para calcular el hash de archivo en un módulo estándar 189

Calcular todos los archivos hash desde una carpeta raíz 191

Pagina 12

Ejemplo de hoja de trabajo: 191

Código 191

Capítulo 35: Recurrencia 195

Introducción 195

Observaciones 195

Ejemplos 195

Factoriales 195

Recurrencia de carpeta 195

Capítulo 36: Scripting Objeto Diccionario 197

Observaciones 197

Ejemplos 197

Propiedades y métodos 197

Agregando datos con Scripting.Dictionary (Máximo, Recuento) 199

Obteniendo valores únicos con Scripting. 201

Capítulo 37: Scripting.FileSystemObject 203

Ejemplos 203

https://translate.googleusercontent.com/translate_f 10/223
6/1/2021 Intitulado

Creando un FileSystemObject 203

Leer un archivo de texto usando un FileSystemObject 203

Creando un archivo de texto con FileSystemObject 204

Escribir en un archivo existente con FileSystemObject 204

Enumerar archivos en un directorio usando FileSystemObject 204

Enumere carpetas y archivos de forma recursiva 205

Quitar la extensión de archivo de un nombre de archivo 206

Recuperar solo la extensión de un nombre de archivo 206

Recuperar solo la ruta de una ruta de archivo 207

Usando FSO.BuildPath para construir una ruta completa a partir de la ruta de la carpeta y el nombre del archivo 207

Capítulo 38: Búsqueda dentro de cadenas de la presencia de subcadenas 208

Observaciones 208

Ejemplos 208

Use InStr para determinar si una cadena contiene una subcadena 208

Use InStr para encontrar la posición de la primera instancia de una subcadena 208

Utilice InStrRev para encontrar la posición de la última instancia de una subcadena 208

Página 13

Capítulo 39: Clasificación 209

Introducción 209

Ejemplos 209

Implementación de algoritmos: clasificación rápida en una matriz unidimensional 209

Uso de la biblioteca de Excel para ordenar una matriz unidimensional 210

Capítulo 40: Literales de cadena: caracteres de escape, no imprimibles y continuaciones de línea 212

Observaciones 212

Ejemplos 212

Escapando del "personaje 212

Asignar literales de cadena larga 212

Usando constantes de cadena de VBA 213

Capítulo 41: Subcadenas 215

Observaciones 215

Ejemplos 215

Use Left o Left $ para obtener los 3 caracteres más a la izquierda en una cadena 215

Use Right o Right $ para obtener los 3 caracteres más a la derecha en una cadena 215

Use Mid o Mid $ para obtener caracteres específicos dentro de una cadena 215

Utilice Recortar para obtener una copia de la cadena sin espacios iniciales o finales 215

Capítulo 42: Formularios de usuario 217

Ejemplos 217

Mejores prácticas 217

Trabaje con una nueva instancia cada vez. 217

https://translate.googleusercontent.com/translate_f 11/223
6/1/2021 Intitulado

Implemente la lógica en otro lugar. 217

La persona que llama no debe preocuparse por los controles. 218

Maneja el evento QueryClose. 218

Escóndete, no cierres. 219

Nombra cosas. 219

Manejo de QueryClose 219

Un formulario de usuario cancelable 220

Capítulo 43: Palabra clave de opción de VBA 222

Sintaxis 222

Parámetros 222

Página 14

Observaciones 222

Ejemplos 223

Opción explícita 223

Opción Comparar {Binario | Texto | Base de datos} 223

Opción Comparar binario 223

Opción Comparar texto 224

Opción Comparar base de datos 225

Base de opciones {0 | 1} 225

Ejemplo en Base 0: 225

Mismo ejemplo con Base 1 226

El código correcto con Base 1 es: 226

Capítulo 44: Errores en tiempo de ejecución de VBA 228

Introducción 228

Ejemplos 228

Error en tiempo de ejecución '3': retorno sin GoSub 228

Código incorrecto 228

¿Por qué no funciona esto? 228

Código correcto 228

¿Por qué funciona esto? 228

Otras notas 228

Error en tiempo de ejecución '6': desbordamiento 229

código incorrecto 229

¿Por qué no funciona esto? 229

Código correcto 229

¿Por qué funciona esto? 229

Otras notas 229

Error en tiempo de ejecución '9': subíndice fuera de rango 229

https://translate.googleusercontent.com/translate_f 12/223
6/1/2021 Intitulado
código incorrecto 229
¿Por qué no funciona esto? 230

Código correcto 230

¿Por qué funciona esto? 230

Otras notas 230

Página 15

Error en tiempo de ejecución '13': no coinciden los tipos 230

código incorrecto 230

¿Por qué no funciona esto? 231

Código correcto 231

¿Por qué funciona esto? 231

Error en tiempo de ejecución '91': variable de objeto o con variable de bloque no establecida 231

código incorrecto 231

¿Por qué no funciona esto? 231

Código correcto 231

¿Por qué funciona esto? 232

Otras notas 232

Error en tiempo de ejecución '20': reanudar sin error 232

código incorrecto 232

¿Por qué no funciona esto? 232

Código correcto 233

¿Por qué funciona esto? 233

Otras notas 233

Capítulo 45: Trabajar con ADO 234

Observaciones 234

Ejemplos 234

Hacer una conexión a una fuente de datos 234

Recuperar registros con una consulta 235

Ejecutando funciones no escalares 236

Crear comandos parametrizados 237

Capítulo 46: Trabajar con archivos y directorios sin usar FileSystemObject 239

Observaciones 239

Ejemplos 239

Determinar si existen carpetas y archivos 239

Crear y eliminar carpetas de archivos 240

Créditos 242

https://translate.googleusercontent.com/translate_f 13/223
6/1/2021 Intitulado

Página 16

Acerca de
Puede compartir este PDF con cualquier persona que crea que podría beneficiarse de él, descargue la última versión
desde: vba

Es un libro electrónico de VBA no oficial y gratuito creado con fines educativos. Se extrae todo el contenido
desde Stack Overflow Documentation , que está escrita por muchas personas trabajadoras en Stack
Desbordamiento. No está afiliado a Stack Overflow ni a VBA oficial.

El contenido se publica bajo Creative Commons BY-SA, y la lista de contribuyentes de cada


se proporcionan en la sección de créditos al final de este libro. Las imágenes pueden ser propiedad de
sus respectivos dueños a menos que se especifique lo contrario. Todas las marcas comerciales y marcas comerciales registradas son
propiedad de sus respectivos dueños de empresas.

Utilice el contenido presentado en este libro bajo su propio riesgo; no se garantiza que sea correcto ni
precisa, envíe sus comentarios y correcciones a info@zzzprojects.com

https://riptutorial.com/ 1

Página 17

Capítulo 1: Empezando con VBA


Observaciones
https://translate.googleusercontent.com/translate_f 14/223
6/1/2021 Intitulado

Esta sección proporciona una descripción general de qué es vba y por qué un desarrollador podría querer usarlo.

También debe mencionar cualquier tema importante dentro de vba y vincular a los temas relacionados. Desde el
La documentación para vba es nueva, es posible que deba crear versiones iniciales de esos temas relacionados.

Versiones

Versión Versiones de Office Fecha de publicación Notas Fecha de publicación

Vba6 ? - 2007 [Algún tiempo después] [1] 1992-06-30

Vba7 2010 - 2016 [blog.techkit.com] [2] 2010-04-15

VBA para Mac 2004, 2011-2016 2004-05-11

Ejemplos

Accediendo al Editor de Visual Basic en Microsoft Office

Puede abrir el editor 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, compruebe si está habilitado.

De forma predeterminada, la pestaña Desarrollador está desactivada. Para habilitar la pestaña Desarrollador, vaya a Archivo -> Opciones, seleccione
Personalice la cinta en la lista de la izquierda. En la vista de árbol "Personalizar la cinta" de la derecha, busque
Elemento del árbol del desarrollador y marque la casilla de verificación de Desarrollador. Haga clic en Aceptar para cerrar
el cuadro de diálogo Opciones.

https://riptutorial.com/ 2

Página 18

https://translate.googleusercontent.com/translate_f 15/223
6/1/2021 Intitulado

La pestaña Desarrollador ahora está visible en la cinta 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/ 3

Página 19

https://translate.googleusercontent.com/translate_f 16/223
6/1/2021 Intitulado

https://riptutorial.com/ 4

Página 20

llave. ¡Felicidades! Ha creado su primer módulo VBA propio.

Depuración

La depuración es una forma muy poderosa de observar más de cerca y corregir el funcionamiento incorrecto (o no
código de trabajo).

Ejecute el código paso a paso


Lo primero que debe hacer durante la depuración es detener el código en ubicaciones específicas y luego ejecutarlo
línea por línea para ver si eso sucede lo que se espera.

• Breakpoint ( F9 , Debug - Toggle breakpoint): puede agregar un punto de interrupción a cualquier línea ejecutada
(por ejemplo, no a declaraciones), cuando la ejecución llega a ese punto, se detiene y da control a
usuario.
• También puede agregar la palabra clave Stop a una línea en blanco para que el código se detenga en esa ubicación en
tiempo de ejecución. Esto es útil si, por ejemplo, antes de las líneas de declaración a las que no puede agregar una
punto de interrupción con F9
• Step into ( F8 , Debug - Step into): ejecuta solo una línea de código, si es una llamada de un usuario
sub / función definida, entonces se ejecuta línea por línea.
• Pasar por encima ( Shift + F8 , Depurar - Pasar por encima): ejecuta una línea de código, no ingresa al usuario
subs / funciones definidas.
• Salir ( Ctrl + Shift + F8 , Depurar - Salir): Salir de la subfunción / función actual (ejecutar el código hasta
fin).
• Ejecutar al cursor ( Ctrl + F8 , Depurar - Ejecutar al cursor): ejecuta el código hasta llegar a la línea con el
cursor.
• Puede utilizar Debug.Print para imprimir líneas en la ventana Inmediato en tiempo de ejecución. También puede
utilizar Debug.? como un atajo para Debug.Print

https://translate.googleusercontent.com/translate_f 17/223
6/1/2021 Intitulado

Ventana de relojes
Ejecutar 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 observación (Ver - Ventana de observación), aquí puede ver los valores de las expresiones definidas. A
agregue una variable a la ventana de inspección, ya sea:

• Haz clic derecho sobre él y luego selecciona "Agregar reloj".


• Haga clic con el botón derecho en la ventana de inspección y seleccione "Agregar vigilancia".
• Vaya a Depurar - Agregar reloj.

Cuando agrega una nueva expresión, puede elegir si solo desea ver su valor o también
romper la ejecución del código cuando es verdadero o cuando cambia su valor.

Ventana inmediata

https://riptutorial.com/ 5

Página 21

La ventana inmediata le permite ejecutar código arbitrario o imprimir elementos precediéndolos


con la palabra clave Imprimir o un solo signo de interrogación " ? "

Algunos ejemplos:

• ? ActiveSheet.Name :
devuelve el nombre de la hoja activa
• Print ActiveSheet.Name :
devuelve el nombre de la hoja activa
• ? foo - devuelve el valor de foo *
• x = 10 conjuntos x a 10 *

* Obtener / configurar valores para variables a través de la ventana inmediata solo se puede realizar durante el tiempo de ejecución

Mejores prácticas de depuración


Siempre que su código no funcione como se esperaba, lo primero que debe hacer es leerlo nuevamente
con cuidado, buscando errores.

Si eso no ayuda, 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 la visualización
expresiones, el objetivo aquí es encontrar la línea que no funciona como se esperaba.

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 reemplazar variables con constantes, que pueden ayudar a comprender si
el valor de las variables es incorrecto.

Si aún no puede resolverlo y pida ayuda:

• Incluya la menor parte posible de su código para comprender su problema


• Si el problema no está relacionado con el valor de las variables, reemplácelas por constantes. (entonces,
en lugar de Hojas (a * b * c + d ^ 2) .Range (addressOfRange) escribe Hojas (4) .Range ("A2") )
• Describe qué línea da el comportamiento incorrecto y cuál es (error, resultado incorrecto ...)

Lea Comenzando con VBA en línea: https://riptutorial.com/vba/topic/802/getting-started-with-vba

https://translate.googleusercontent.com/translate_f 18/223
6/1/2021 Intitulado

https://riptutorial.com/ 6

Página 22

Capítulo 2: Llamadas a la 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

Las llamadas al sistema se pueden realizar ejecutando procedimientos definidos en archivos DLL

Observaciones
Archivos de biblioteca de entornos operativos comunes (DLL):

Enlace dinámico
Descripción
Biblioteca

Biblioteca de servicios avanzados para API que incluyen muchas funciones de seguridad y
Advapi32.dll
Llamadas de registro

Comdlg32.dll Biblioteca de API de diálogo común

Gdi32.dll Biblioteca de API de interfaz de dispositivo gráfico

Kernel32.dll Compatibilidad con API base de Windows de 32 bits

Lz32.dll Rutinas de compresión de 32 bits

Mpr.dll Biblioteca de enrutadores de proveedores múltiples

Netapi32.dll Biblioteca de API de red de 32 bits

Shell32.dll Biblioteca de API de Shell de 32 bits

User32.dll Biblioteca para rutinas de interfaz de usuario

Version.dll Biblioteca de versiones

Winmm.dll Biblioteca multimedia de Windows

Winspool.drv Interfaz de cola de impresión que contiene las llamadas a la API de cola de impresión

Nuevos argumentos utilizados para el sistema 64:

Tipo Articulo Descripción

Calificatorio PtrSafe Indica que la declaración Declare es compatible con 64 bits.

https://translate.googleusercontent.com/translate_f 19/223
6/1/2021 Intitulado
https://riptutorial.com/ 7

Página 23

Tipo Articulo Descripción

Este atributo es obligatorio en sistemas de 64 bits.

Un tipo de datos variable que es un tipo de datos de 4 bytes en versiones de 32 bits


y un tipo de datos de 8 bytes en las versiones de 64 bits de Office 2010. Esto es
la forma recomendada de declarar un puntero o un identificador para nuevos
Tipo de datos LongPtr código sino también para el código heredado si tiene que ejecutarse en la versión de 64 bits de
Office 2010. Solo se admite en el tiempo de ejecución de VBA 7 en 32 bits y
64 bits. Tenga en cuenta que puede asignarle valores numéricos pero no
tipos numéricos

Este es un tipo de datos de 8 bytes que solo está disponible en versiones de 64 bits
Tipo de datos Largo largo de Office 2010. Puede asignar valores numéricos pero no numéricos
tipos (para evitar el truncamiento)

Operador de conversión CLngPtr Convierte una expresión simple en un tipo de datos LongPtr

Operador de conversión CLngLng Convierte una expresión simple en un tipo de datos LongLong

Convertidor de variantes. Devuelve un LongPtr en versiones de 64 bits y un


Función VarPtr
Largo en 32 bits (4 bytes)

Convertidor de objetos. Devuelve un LongPtr en versiones de 64 bits y un Long


Función ObjPtr
en 32 bits (4 bytes)

Convertidor de cadenas. Devuelve un LongPtr en versiones de 64 bits y un Long


Función StrPtr
en 32 bits (4 bytes)

Referencia completa de firmas de llamada:

• Win32api32.txt para Visual Basic 5.0 (declaraciones de API antiguas, última revisión en marzo de 2005, Microsoft)

• Win32API_PtrSafe con soporte de 64 bits (Office 2010, Microsoft)

Ejemplos

Declaración y uso de API

Declarar un procedimiento de DLL para trabajar con diferentes versiones de VBA:

Opción explícita

#Si Win64 Entonces

Privado Declare PtrSafe Sub xLib "Kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)

#ElseIf Win32 Entonces

Private Declare Sub apiSleep Lib "Kernel32" Alias "Sleep" (ByVal dwMilliseconds As Long)

https://riptutorial.com/ 8

Página 24

#Terminara si

La declaración anterior le dice a VBA cómo llamar a la función "Sleep" definida en el archivo Kernel32.dll

https://translate.googleusercontent.com/translate_f 20/223
6/1/2021 Intitulado

Win64 y Win32 son constantes predefinidas que se utilizan para compilación condicional

Constantes predefinidas

Algunas constantes de compilación ya están predefinidas. Cuales existen dependerán del bitness
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 64 bits de Office.

Constante de 16 bits 32 bits 64 bits

Vba6 Falso Si Vba6 Falso

Vba7 Falso si Vba7 es verdadero

Win16 Cierto Falso Falso

Win32 Falso verdadero Cierto

Win64 Falso falso Cierto

Mac Falso si Mac Si Mac

Estas constantes se refieren 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.

La principal diferencia al declarar API es entre las versiones de Office de 32 bits y 64 bits que
introdujo nuevos tipos de parámetros (consulte la sección Comentarios para obtener más detalles)

Notas:

• Las declaraciones se colocan en la parte superior del módulo y fuera de cualquier Subs o
Funciones
• Los procedimientos declarados en módulos estándar son públicos por defecto
• Para declarar un procedimiento privado a un módulo, preceda la declaración con el
Palabra clave privada
• Los procedimientos DLL declarados en cualquier otro tipo de módulo son privados para ese módulo

Ejemplo simple para la llamada a la API de sueño:

Pausa de prueba secundaria pública ()

Comienzo tenue como doble

https://riptutorial.com/ 9

Página 25

start = temporizador

Sleep 9000 'Pausa la ejecución durante 9 segundos

Debug.Print "Paused for" & Format (Timer - start, "#, ###. 000") & "seconds"

'Resultado inmediato de la ventana: pausado durante 9.000 segundos

End Sub

Se recomienda crear un módulo API dedicado para proporcionar un fácil acceso al sistema.
funciones de envoltorios de VBA: subs o funciones de VBA normales que encapsulan los detalles
necesarios para la llamada al sistema real, como los parámetros utilizados en las bibliotecas y la inicialización de esos

https://translate.googleusercontent.com/translate_f 21/223
6/1/2021 Intitulado
parámetros

El módulo puede contener todas las declaraciones y dependencias:

• Firmas de métodos y estructuras de datos requeridas


• Contenedores que realizan la validación de entrada y garantizan que todos los parámetros se pasen como se esperaba

Para declarar un procedimiento de DLL, agregue una instrucción Declare a la sección Declaraciones del código
ventana.

Si el procedimiento devuelve un valor, declárelo como una función :

Declarar función publicname Lib "libname" [Alias "alias"] [([[ByVal] variable [Como tipo]
[, [ByVal] variable [Como tipo]] ...])] Como tipo

Si un procedimiento no devuelve un valor, declararlo como Sub :

Declare Sub publicname Lib "libname" [Alias "alias"] [([[ByVal] variable [As type] [, [ByVal]
variable [Como tipo]] ...])]

• !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!

También es de destacar que la mayoría de las llamadas no válidas a las API bloquearán Excel y posiblemente
archivos de datos corruptos

• !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!!!!!!!!!!!!!

Office 2011 para Mac

Sistema privado Declare Function Lib "libc.dylib" (comando ByVal como cadena) As Long

Sub RunSafari ()
Resultado tenue tan largo
resultado = sistema ("abrir -a Safari --args http://www.google.com")
Debug.Print Str (resultado)

https://riptutorial.com/ 10

Página 26

End Sub

Los ejemplos siguientes (API de Windows - Módulo dedicado (1 y 2)) muestran un módulo API que
incluye declaraciones comunes para Win64 y Win32

API de Windows: módulo dedicado (1 de 2)

Opción explícita

#Si Win64, entonces 'Win64 = True, Win32 = False, Win16 = False


Privada Declare PtrSafe Sub apiCopyMemory Lib "Kernel32" Alias "RtlMoveMemory" (MyDest As
Any, MySource como Any, ByVal MySize siempre que)
Private Declare PtrSafe Sub apiSalirProcess Lib "Kernel32" Alias "ExitProcess" (ByVal
uExitCode tan largo)
Privado Declare PtrSafe Sub apiSetCursorPos Lib "User32" Alias "SetCursorPos" (ByVal X As
Entero, ByVal Y como entero)
Privada Declare PtrSafe Sub apiSleep Lib "Kernel32" Alias "Sleep" (ByVal dwMilliseconds As
Largo)
Función privada Declare PtrSafe apiAttachThreadInput Lib "User32" Alias
"AttachThreadInput" (ByVal idAttach como largo, ByVal idAttachTo como largo, ByVal fAttach como largo)
Tanto tiempo
Función privada Declare PtrSafe apiBringWindowToTop Lib "User32" Alias "BringWindowToTop"
(ByVal lngHWnd Tan largo) Tan largo
Función privada Declare PtrSafe apiCloseWindow Lib "User32" Alias "CloseWindow" (ByVal
hWnd As Long) Siempre que

https://translate.googleusercontent.com/translate_f 22/223
6/1/2021 Intitulado
Función privada Declare PtrSafe apiDestroyWindow Lib "User32" Alias "DestroyWindow"
(ByVal hWnd tan largo) como booleano
Función privada Declare PtrSafe apiEndDialog Lib "User32" Alias "EndDialog" (ByVal hWnd
As Long, ByVal result As Long) As Boolean
Función privada Declare PtrSafe apiEnumChildWindows Lib "User32" Alias "EnumChildWindows"
(ByVal hWndParent tan largo, ByVal pEnumProc tan largo, ByVal lParam tan largo)
Función privada Declare PtrSafe apiSalirWindowsEx Lib "User32" Alias "ExitWindowsEx"
(ByVal uFlags tan largo, ByVal dwReserved tan largo)
Función privada Declare PtrSafe apiFindExecutable Lib "Shell32" Alias "FindExecutableA"
(ByVal lpFile como cadena, ByVallpDirectory como cadena, ByVal lpResult como cadena) Tan largo
Función privada Declare PtrSafe apiFindWindow Lib "User32" Alias "FindWindowA" (ByVal
lpClassName como cadena, ByVal lpWindowName como cadena) Tan largo
Función privada Declare PtrSafe apiFindWindowEx Lib "User32" Alias "FindWindowExA" (ByVal
hWnd1 tan largo, ByVal hWnd2 tan largo, ByVal lpsz1 como cadena, ByVal lpsz2 como cadena) Tan largo
Función privada Declare PtrSafe apiGetActiveWindow Lib "User32" Alias "GetActiveWindow"
() Siempre que
Función privada Declare PtrSafe apiGetClassNameA Lib "User32" Alias "GetClassNameA"
(ByVal hWnd tan largo, ByVal szClassName como cadena, ByVal lLength tan largo)
Función privada Declare PtrSafe apiGetCommandLine Lib "Kernel32" Alias "GetCommandLineW"
() Siempre que
Función privada Declare PtrSafe apiGetCommandLineParams Lib "Kernel32" Alias
"GetCommandLineA" () siempre que
Función privada Declare PtrSafe apiGetDiskFreeSpaceEx Lib "Kernel32" Alias
"GetDiskFreeSpaceExA" (ByVal lpDirectoryName como cadena, lpFreeBytesAvailableToCaller como
Moneda, lpTotalNumberOfBytes como moneda, lpTotalNumberOfFreeBytes como moneda) As Long
Función privada Declare PtrSafe apiGetDriveType Lib "Kernel32" Alias "GetDriveTypeA"
(ByVal nDrive como cadena) Tan largo
Función privada Declare PtrSafe apiGetSalirCodeProcess Lib "Kernel32" Alias
"GetSalirCodeProcess" (ByVal hProcess tan largo, lpSalirCode tan largo)
Función privada Declare PtrSafe apiGetForegroundWindow Lib "User32" Alias
"GetForegroundWindow" () tan largo
Función privada Declare PtrSafe apiGetFrequency Lib "Kernel32" Alias
"QueryPerformanceFrequency" (cyFrequency como moneda) siempre que

https://riptutorial.com/ 11

Página 27

Función privada Declare PtrSafe apiGetLastError Lib "Kernel32" Alias "GetLastError" () como
Entero
Función privada Declare PtrSafe apiGetParent Lib "User32" Alias "GetParent" (ByVal hWnd
Siempre que)
Función privada Declare PtrSafe apiGetSystemMetrics Lib "User32" Alias "GetSystemMetrics"
(ByVal nIndex As Long) As Long
Función privada Declare PtrSafe apiGetSystemMetrics32 Lib "User32" Alias
"GetSystemMetrics" (ByVal nIndex As Long) As Long
Función privada Declare PtrSafe apiGetTickCount Lib "Kernel32" Alias
"QueryPerformanceCounter" (cyTickCount como moneda) siempre que
Función privada Declare PtrSafe apiGetTickCountMs Lib "Kernel32" Alias "GetTickCount" ()
Tanto tiempo
Función privada Declare PtrSafe apiGetUserName Lib "AdvApi32" Alias "GetUserNameA" (ByVal
lpBuffer As String, nSize As Long) As Long
Función privada Declare PtrSafe apiGetWindow Lib "User32" Alias "GetWindow" (ByVal hWnd
Tan largo, ByVal wCmd Tan largo) Tan largo
Función privada Declare PtrSafe apiGetWindowRect Lib "User32" Alias "GetWindowRect"
(ByVal hWnd Tan largo, lpRect como winRect) Tan largo
Función privada Declare PtrSafe apiGetWindowText Lib "User32" Alias "GetWindowTextA"
(ByVal hWnd tan largo, ByVal szWindowText como cadena, ByVal lLength tan largo)
Función privada Declare PtrSafe apiGetWindowThreadProcessId Lib "User32" Alias
"GetWindowThreadProcessId" (ByVal hWnd tan largo, lpdwProcessId tan largo)
Función privada Declare PtrSafe apiIsCharAlphaNumericA Lib "User32" Alias
"IsCharAlphaNumericA" (ByVal byChar As Byte) Tan largo
Función privada Declare PtrSafe apiIsIconic Lib "User32" Alias "IsIconic" (ByVal hWnd As
Long) Tan largo
Función privada Declare PtrSafe apiIsWindowVisible Lib "User32" Alias "IsWindowVisible"
(ByVal hWnd As Long) Siempre que
Función privada Declare PtrSafe apiIsZoomed Lib "User32" Alias "IsZoomed" (ByVal hWnd As
Long) Tan largo
Función privada Declare PtrSafe apiLStrCpynA Lib "Kernel32" Alias "lstrcpynA" (ByVal
pDestination como cadena, ByVal pSource tan largo, ByVal iMaxLength como entero) Tan largo
Función privada Declare PtrSafe apiMessageBox Lib "User32" Alias "MessageBoxA" (ByVal
hWnd tan largo, ByVal lpText como cadena, ByVal lpCaption como cadena, ByVal wType tan largo)
Función privada Declare PtrSafe apiOpenIcon Lib "User32" Alias "OpenIcon" (ByVal hWnd As
Long) Tan largo
Función privada Declare PtrSafe apiOpenProcess Lib "Kernel32" Alias "OpenProcess" (ByVal
dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long
Función privada Declare PtrSafe apiPathAddBackslashByPointer Lib "ShlwApi" Alias
"PathAddBackslashW" (ByVal lpszPath As Long) As Long

https://translate.googleusercontent.com/translate_f 23/223
6/1/2021 Intitulado
Función privada Declare PtrSafe apiPathAddBackslashByString Lib "ShlwApi" Alias
"PathAddBackslashW" (ByVal lpszPath como cadena) As Long 'http://msdn.microsoft.com/en-
us / library / aa155716% 28office.10% 29.aspx
Función privada Declare PtrSafe apiPostMessage Lib "User32" Alias "PostMessageA" (ByVal
hWnd tan largo, ByVal wMsg tan largo, ByVal wParam tan largo, ByVal lParam tan largo)
Función privada Declare PtrSafe apiRegQueryValue Lib "AdvApi32" Alias "RegQueryValue"
(ByVal hKey tan largo, ByVal sValueName como cadena, ByVal dwReserved tan largo, ByRef lValueType como
Long, ByVal sValue As String, ByRef lResultLen As Long) As Long
Función privada Declare PtrSafe apiSendMessage Lib "User32" Alias "SendMessageA" (ByVal
hWnd As Long, ByVal wMsg As Long, ByVal wParam Tan Long, lParam As Any) As Long
Función privada Declare PtrSafe apiSetActiveWindow Lib "User32" Alias "SetActiveWindow"
(ByVal hWnd As Long) Siempre que
Función privada Declare PtrSafe apiSetCurrentDirectoryA Lib "Kernel32" Alias
"SetCurrentDirectoryA" (ByVal lpPathName como cadena) Tan largo
Función privada Declare PtrSafe apiSetFocus Lib "User32" Alias "SetFocus" (ByVal hWnd As
Long) Tan largo
Función privada Declare PtrSafe apiSetForegroundWindow Lib "User32" Alias
"SetForegroundWindow" (ByVal hWnd As Long) As Long
Función privada Declare PtrSafe apiSetLocalTime Lib "Kernel32" Alias "SetLocalTime"
(lpSystem como SystemTime) Siempre que
Función privada Declare PtrSafe apiSetWindowPlacement Lib "User32" Alias

https://riptutorial.com/ 12

Página 28

"SetWindowPlacement" (ByVal hWnd As Long, ByRef lpwndpl As winPlacement) As Long


Función privada Declare PtrSafe apiSetWindowPos Lib "User32" Alias "SetWindowPos" (ByVal
hWnd As Long, ByVal hWndInsertAfter Tan Long, ByVal X As Long, ByVal Y Tan Long, ByVal cx As
Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Función privada Declare PtrSafe apiSetWindowText Lib "User32" Alias "SetWindowTextA"
(ByVal hWnd tan largo, ByVal lpString como cadena) Tan largo
Función privada Declare PtrSafe apiShellExecute Lib "Shell32" Alias "ShellExecuteA"
(ByVal hWnd tan largo, ByVal lpOperation como cadena, ByVal lpFile como cadena, ByVal lpParameters
Como cadena, ByVal lpDirectory como cadena, ByVal nShowCmd tan largo)
Función privada Declare PtrSafe apiShowWindow Lib "User32" Alias "ShowWindow" (ByVal hWnd
As Long, ByVal nCmdShow As Long) As Long
Función privada Declare PtrSafe apiShowWindowAsync Lib "User32" Alias "ShowWindowAsync"
(ByVal hWnd As Long, ByVal nCmdShow As Long) Tan largo
Función privada Declare PtrSafe apiStrCpy Lib "Kernel32" Alias "lstrcpynA" (ByVal
pDestination como cadena, ByVal pSource como cadena, ByVal iMaxLength como entero) As Long
Función privada Declare PtrSafe apiStringLen Lib "Kernel32" Alias "lstrlenW" (ByVal
lpString tan largo) tan largo
Función privada Declare PtrSafe apiStrTrimW Lib "ShlwApi" Alias "StrTrimW" () como booleano
Función privada Declare PtrSafe apiTerminateProcess Lib "Kernel32" Alias
"TerminateProcess" (ByVal hWnd As Long, ByVal uSalirCode Tan Long)
Función privada Declare PtrSafe apiTimeGetTime Lib "Winmm" Alias "timeGetTime" () As Long
Función privada Declare PtrSafe apiVarPtrArray Lib "MsVbVm50" Alias "VarPtr" (Var () As
Cualquiera) Siempre que
Tipo privado browseInfo 'utilizado por apiBrowseForFolder
hOwner As Long
pidlRoot tan largo
pszDisplayName como cadena
lpszTitle como cadena
ulFlags tan largo
lpfn siempre que
lParam tan largo
iImage tan larga
Tipo final
Función privada Declare PtrSafe apiBrowseForFolder Lib "Shell32" Alias
"SHBrowseForFolderA" (lpBrowseInfo como browseInfo) Tan largo
Tipo privado CHOOSECOLOR 'utilizado por apiChooseColor;
http://support.microsoft.com/kb/153929 y http://www.cpearson.com/Excel/Colors.aspx
lStructSize siempre que
hWndOwner siempre que
hInstance tan largo
rgbResult As Long
lpCustColors como cadena
banderas tan largas
lCustData siempre que
lpfnHook tan largo
lpTemplateName como cadena
Tipo final
Función privada Declare PtrSafe apiChooseColor Lib "ComDlg32" Alias "ChooseColorA"
(pElegir color como CHOOSECOLOR) Siempre que
Estructura personalizada de FindWindowParameters de tipo privado para pasar los parámetros de entrada / salida
de la función de enumeración de ganchos; podría usar variables globales en su lugar, pero esto es mejor

https://translate.googleusercontent.com/translate_f 24/223
6/1/2021 Intitulado
strTitle As String 'INPUT
hWnd tan largo 'SALIDA
Tipo final 'Encuentra una ventana específica con subtítulos dinámicos de un
lista de todas las ventanas abiertas: http://www.everythingaccess.com/tutorials.asp?ID=Bring-an-external-
ventana de la aplicación al primer plano
Función privada Declare PtrSafe apiEnumWindows Lib "User32" Alias "EnumWindows" (ByVal
lpEnumFunc As LongPtr, ByVal lParam As LongPtr) As Long
Private Type lastInputInfo 'utilizado por apiGetLastInputInfo, getLastInputTime
cbSize As Long
dwTime As Long

https://riptutorial.com/ 13

Página 29

Tipo final
Función privada Declare PtrSafe apiGetLastInputInfo Lib "User32" Alias "GetLastInputInfo"
(ByRef plii como lastInputInfo) Tan largo
'http://www.pgacon.com/visualbasic.htm#Take%20Advantage%20of%20Conditional%20Compilation
'Operadores lógicos y bit a bit en Visual Basic: http://msdn.microsoft.com/en-
us / library / wz3k228a (v = frente a 80) .aspx y http://stackoverflow.com/questions/1070863/hidden-
características-de-vba
Tipo privado SystemTime
wYear Como entero
wMonth Como entero
wDayOfWeek como entero
wDía Como entero
wHour Como entero
wMinuto Como entero
wSecond Como entero
wMilliseconds como entero
Tipo final
Privada Declare PtrSafe Sub apiGetLocalTime Lib "Kernel32" Alias "GetLocalTime" (lpSystem
Como SystemTime)
Private Type pointAPI 'utilizado por apiSetWindowPlacement
X tanto tiempo
Y siempre que
Tipo final
Private Type rectAPI 'utilizado por apiSetWindowPlacement
Left_Renamed As Long
Top_Renamed As Long
Right_Renamed As Long
Bottom_Renamed As Long
Tipo final
WinPlacement de tipo privado 'utilizado por apiSetWindowPlacement
longitud tan larga
banderas tan largas
showCmd tan largo
ptMinPosition como pointAPI
ptMaxPosition como pointAPI
rcNormalPosition como rectAPI
Tipo final
Función privada Declare PtrSafe apiGetWindowPlacement Lib "User32" Alias
"GetWindowPlacement" (ByVal hWnd As Long, ByRef lpwndpl As winPlacement) As Long
Tipo privado winRect 'utilizado por apiMoveWindow
Dejó tanto tiempo
Arriba siempre que
Tanto tiempo
Fondo tan largo
Tipo final
Función privada Declare PtrSafe apiMoveWindow Lib "User32" Alias "MoveWindow" (ByVal hWnd
Tan largo, xIzquierdo tan largo, ByVal yTop tan largo, wWidth tan largo, ByVal hHeight tan largo, ByVal
repintar siempre que)

Función privada Declare PtrSafe apiInternetOpen Lib "WiniNet" Alias "InternetOpenA"


(ByVal sAgent como cadena, ByVal lAccessType tan largo, ByVal sProxyName como cadena, ByVal
sProxyBypass As String, ByVal lFlags As Long) As Long 'Abrir el objeto de Internet' por ejemplo:
lngINet = InternetOpen ("Control MyFTP", 1, vbNullString, vbNullString, 0)
Función privada Declare PtrSafe apiInternetConnect Lib "WiniNet" Alias "InternetConnectA"
(ByVal hInternetSession como largo, ByVal sServerName como cadena, ByVal nServerPort como entero,
ByVal sUsername como cadena, ByVal sPassword como cadena, ByVal lService tan largo, ByVal lFlags como
Long, ByVal lContext As Long) Siempre que 'Connect to the network' ex: lngINetConn =
InternetConnect (lngINet, "ftp.microsoft.com", 0, "anónimo", "wally@wallyworld.com", 1, 0, 0)
Función privada Declare PtrSafe apiFtpGetFile Lib "WiniNet" Alias "FtpGetFileA" (ByVal
hFtpSession como larga, ByVal lpszRemoteFile como cadena, ByVal lpszNewFile como cadena, ByVal
fFailIfExists como booleano, ByVal dwFlagsAndAttributes como largo, ByVal dwFlags como largo, ByVal

https://translate.googleusercontent.com/translate_f 25/223
6/1/2021 Intitulado

https://riptutorial.com/ 14

Página 30

dwContext tan largo) como booleano 'Obtener un archivo', por ejemplo: blnRC = FtpGetFile (lngINetConn,
"dirmap.txt", "c: \ dirmap.txt", 0, 0, 1, 0)
Función privada Declare PtrSafe apiFtpPutFile Lib "WiniNet" Alias "FtpPutFileA" (ByVal
hFtpSession como larga, ByVal lpszLocalFile como cadena, ByVal lpszRemoteFile como cadena, ByVal
dwFlags As Long, ByVal dwContext As Long) Como booleano 'Enviar un archivo' ej: blnRC =
FtpPutFile (lngINetConn, "c: \ dirmap.txt", "dirmap.txt", 1, 0)
Función privada Declare PtrSafe apiFtpDeleteFile Lib "WiniNet" Alias "FtpDeleteFileA"
(ByVal hFtpSession tan largo, ByVal lpszFileName como cadena) Como booleano 'Eliminar un archivo' ex: blnRC
= FtpDeleteFile (lngINetConn, "test.txt")
Función privada Declare PtrSafe apiInternetCloseHandle Lib "WiniNet" (ByVal hInet As
Long) Como entero 'Cerrar el objeto de Internet' ex: InternetCloseHandle lngINetConn 'ex:
InternetCloseHandle lngINet
Función privada Declare PtrSafe apiFtpFindFirstFile Lib "WiniNet" Alias
"FtpFindFirstFileA" (ByVal hFtpSession tan largo, ByVal lpszSearchFile como cadena, lpFindFileData
Como WIN32_FIND_DATA, ByVal dwFlags tan largo, ByVal dwContent tan largo)
Tipo privado FILETIME
dwLowDateTime tan largo
dwHighDateTime tan largo
Tipo final
Tipo privado WIN32_FIND_DATA
dwFileAttributes tan largo
ftCreationTime como FILETIME
ftLastAccessTime como FILETIME
ftLastWriteTime como FILETIME
nFileSizeHigh tan largo
nFileSizeLow tanto tiempo
dwReserved0 siempre que
dwReserved1 siempre que
cFileName como cadena * 1 'MAX_FTP_PATH
cAlternate como cadena * 14
Tipo de finalización 'ex: lngHINet = FtpFindFirstFile (lngINetConn, "*. *", PData, 0, 0)
Función privada Declare PtrSafe 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

(continúa en el segundo ejemplo)

API de Windows: módulo dedicado (2 de 2)

#ElseIf Win32 Then 'Win32 = True, Win16 = False


Private Declare Sub apiCopyMemory Lib "Kernel32" Alias "RtlMoveMemory" (MyDest As Any,
MySource como cualquiera, ByVal MySize siempre que)
Private Declare Sub apiExitProcess Lib "Kernel32" Alias "ExitProcess" (ByVal uSalirCode As
Largo)
'Private Declare Sub apiGetStartupInfo Lib "Kernel32" Alias "GetStartupInfoA"
(lpStartupInfo como STARTUPINFO)
Private Declare Sub apiSetCursorPos Lib "User32" Alias "SetCursorPos" (ByVal X As Integer,
ByVal Y As Integer) 'Operadores lógicos y bit a bit en Visual Basic:
http://msdn.microsoft.com/en-us/library/wz3k228a(v=vs.80).aspx y
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)
Función de declaración privada apiAttachThreadInput Lib "User32" Alias "AttachThreadInput"
(ByVal idAttach tan largo, ByVal idAttachTo tan largo, ByVal fAttach tan largo)
Función de declaración privada apiBringWindowToTop Lib "User32" Alias "BringWindowToTop" (ByVal
lngHWnd tan largo) tan largo
Función de declaración privada apiCloseHandle Lib "Kernel32" (ByVal hObject As Long) As Long
Función de declaración privada apiCloseWindow Lib "User32" Alias "CloseWindow" (ByVal hWnd As

https://riptutorial.com/ 15

Página 31

Long) Tan largo


'Función de declaración privada apiCreatePipe Lib "Kernel32" (phReadPipe As Long, phWritePipe As
Long, lpPipeAttributes como SECURITY_ATTRIBUTES, ByVal nSize As Long) As Long
'Función de declaración privada apiCreateProcess Lib "Kernel32" Alias "CreateProcessA" (ByVal

https://translate.googleusercontent.com/translate_f 26/223
6/1/2021 Intitulado
lpApplicationName tan largo, ByVal lpCommandLine como cadena, lpProcessAttributes como cualquiera,
lpThreadAttributes As Any, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long,
lpEnvironment como cualquiera, ByVal lpCurrentDriectory como cadena, lpStartupInfo como STARTUPINFO,
lpProcessInformation como PROCESS_INFORMATION) Siempre que
Función de declaración privada apiDestroyWindow Lib "User32" Alias "DestroyWindow" (ByVal hWnd
Tan largo) como booleano
Función de declaración privada apiEndDialog Lib "User32" Alias "EndDialog" (ByVal hWnd As Long,
ByVal result As Long) As Boolean
Función de declaración privada apiEnumChildWindows Lib "User32" Alias "EnumChildWindows" (ByVal
hWndParent tan largo, ByVal pEnumProc tan largo, ByVal lParam tan largo)
Función de declaración privada apiSalirWindowsEx Lib "User32" Alias "ExitWindowsEx" (ByVal uFlags
Siempre que, ByVal dwReservado Siempre que)
Función de declaración privada apiFindExecutable Lib "Shell32" Alias "FindExecutableA" (ByVal
lpFile como cadena, ByVallpDirectory como cadena, ByVal lpResult como cadena) Tan largo
Función de declaración privada apiFindWindow Lib "User32" Alias "FindWindowA" (ByVal lpClassName
Como cadena, ByVal lpWindowName como cadena) tan largo
Función de declaración privada apiFindWindowEx Lib "User32" Alias "FindWindowExA" (ByVal hWnd1
Tan largo, ByVal hWnd2 tan largo, ByVal lpsz1 como cadena, ByVal lpsz2 como cadena) Tan largo
Función de declaración privada apiGetActiveWindow Lib "User32" Alias "GetActiveWindow" () como
Largo
Función de declaración privada apiGetClassNameA Lib "User32" Alias "GetClassNameA" (ByVal hWnd
As Long, ByVal szClassName As String, ByVal lLength As Long) As Long
Función de declaración privada apiGetCommandLine Lib "Kernel32" Alias "GetCommandLineW" () como
Largo
Función de declaración privada apiGetCommandLineParams Lib "Kernel32" Alias "GetCommandLineA" ()
Tanto tiempo
Función de declaración privada apiGetDiskFreeSpaceEx Lib "Kernel32" Alias "GetDiskFreeSpaceExA"
(ByVal lpDirectoryName como cadena, lpFreeBytesAvailableToCaller como moneda,
lpTotalNumberOfBytes como moneda, lpTotalNumberOfFreeBytes como moneda) siempre que
Función de declaración privada apiGetDriveType Lib "Kernel32" Alias "GetDriveTypeA" (ByVal
nDrive As String) Tan largo
Función de declaración privada apiGetSalirCodeProcess Lib "Kernel32" (ByVal hProcess As Long,
lpSalirCode tan largo)
Función de declaración privada apiGetFileSize Lib "Kernel32" (ByVal hFile As Long,
lpFileSizeHigh siempre que)
Función de declaración privada apiGetForegroundWindow Lib "User32" Alias "GetForegroundWindow"
() Siempre que
Función de declaración privada apiGetFrequency Lib "Kernel32" Alias "QueryPerformanceFrequency"
(Cifrecuencia como moneda) Siempre que
Función de declaración privada apiGetLastError Lib "Kernel32" Alias "GetLastError" () como entero
Función de declaración privada apiGetParent Lib "User32" Alias "GetParent" (ByVal hWnd As Long)
Tanto tiempo
Función de declaración privada apiGetSystemMetrics Lib "User32" Alias "GetSystemMetrics" (ByVal
nIndex As Long) Siempre que
Función de declaración privada apiGetTickCount Lib "Kernel32" Alias "QueryPerformanceCounter"
(cyTickCount como moneda) Siempre que
Función de declaración privada apiGetTickCountMs Lib "Kernel32" Alias "GetTickCount" () As Long
Función de declaración privada apiGetUserName Lib "AdvApi32" Alias "GetUserNameA" (ByVal
lpBuffer As String, nSize As Long) As Long
Función de declaración privada apiGetWindow Lib "User32" Alias "GetWindow" (ByVal hWnd As Long,
ByVal wCmd As Long) Siempre que
Función de declaración privada apiGetWindowRect Lib "User32" Alias "GetWindowRect" (ByVal hWnd
Siempre que, lpRect como winRect) Siempre que
Función de declaración privada apiGetWindowText Lib "User32" Alias "GetWindowTextA" (ByVal hWnd
As Long, ByVal szWindowText como cadena, ByVal lLength As Long) As Long
Función de declaración privada apiGetWindowThreadProcessId Lib "User32" Alias
"GetWindowThreadProcessId" (ByVal hWnd tan largo, lpdwProcessId tan largo)

https://riptutorial.com/ dieciséis

Página 32

Función de declaración privada apiIsCharAlphaNumericA Lib "User32" Alias "IsCharAlphaNumericA"


(ByVal byChar As Byte) Siempre que
Función de declaración privada apiIsIconic Lib "User32" Alias "IsIconic" (ByVal hWnd siempre que)
Largo
Función de declaración privada apiIsWindowVisible Lib "User32" Alias "IsWindowVisible" (ByVal
hWnd As Long) Siempre que
Función de declaración privada apiIsZoomed Lib "User32" Alias "IsZoomed" (ByVal hWnd siempre que)
Largo
Función de declaración privada apiLStrCpynA Lib "Kernel32" Alias "lstrcpynA" (ByVal pDestination
Como cadena, ByVal pSource tan largo, ByVal iMaxLength como entero) Tan largo
Función de declaración privada apiMessageBox Lib "User32" Alias "MessageBoxA" (ByVal hWnd As
Long, ByVal lpText como cadena, ByVal lpCaption como cadena, ByVal wType tan largo)
Función de declaración privada apiOpenIcon Lib "User32" Alias "OpenIcon" (ByVal hWnd siempre que)
Largo
Función de declaración privada apiOpenProcess Lib "Kernel32" Alias "OpenProcess" (ByVal
dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal dwProcessId As Long) As Long

https://translate.googleusercontent.com/translate_f 27/223
6/1/2021 Intitulado
Función de declaración privada apiPathAddBackslashByPointer Lib "ShlwApi" Alias
"PathAddBackslashW" (ByVal lpszPath As Long) As Long
Función de declaración privada apiPathAddBackslashByString Lib "ShlwApi" Alias
"PathAddBackslashW" (ByVal lpszPath como cadena) As Long 'http://msdn.microsoft.com/en-
us / library / aa155716% 28office.10% 29.aspx
Función de declaración privada apiPostMessage Lib "User32" Alias "PostMessageA" (ByVal hWnd As
Long, ByVal wMsg tan largo, ByVal wParam tan largo, ByVal lParam tan largo)
Función de declaración privada apiReadFile Lib "Kernel32" (ByVal hFile As Long, lpBuffer As Any,
ByVal nNumberOfBytesToRead As Long, lpNumberOfBytesRead As Long, lpOverlapped As Any) As Long
Función de declaración privada 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
Función de declaración privada apiSendMessage Lib "User32" Alias "SendMessageA" (ByVal hWnd As
Long, ByVal wMsg Tan largo, ByVal wParam Tan largo, lParam Como cualquiera) Tan largo
Función de declaración privada apiSetActiveWindow Lib "User32" Alias "SetActiveWindow" (ByVal
hWnd As Long) Siempre que
Función de declaración privada apiSetCurrentDirectoryA Lib "Kernel32" Alias
"SetCurrentDirectoryA" (ByVal lpPathName como cadena) Tan largo
Función de declaración privada apiSetFocus Lib "User32" Alias "SetFocus" (ByVal hWnd As Long)
Largo
Función de declaración privada apiSetForegroundWindow Lib "User32" Alias "SetForegroundWindow"
(ByVal hWnd As Long) Siempre que
Función de declaración privada apiSetLocalTime Lib "Kernel32" Alias "SetLocalTime" (lpSystem As
SystemTime) siempre que
Función de declaración privada apiSetWindowPlacement Lib "User32" Alias "SetWindowPlacement"
(ByVal hWnd As Long, ByRef lpwndpl As winPlacement) As Long
Función de declaración privada apiSetWindowPos Lib "User32" Alias "SetWindowPos" (ByVal hWnd As
Long, ByVal hWndInsertAfter tan largo, ByVal X tan largo, ByVal Y tan largo, ByVal cx tan largo, ByVal
cy As Long, ByVal wFlags As Long) As Long
Función de declaración privada apiSetWindowText Lib "User32" Alias "SetWindowTextA" (ByVal hWnd
Tan largo, ByVal lpString como cadena) Tan largo
Función de declaración privada apiShellExecute Lib "Shell32" Alias "ShellExecuteA" (ByVal hWnd
As Long, ByVal lpOperation como cadena, ByVal lpFile como cadena, ByVal lpParameters como cadena,
ByVal lpDirectory As String, ByVal nShowCmd As Long) As Long
Función de declaración privada apiShowWindow Lib "User32" Alias "ShowWindow" (ByVal hWnd As
Long, ByVal nCmdShow As Long) As Long
Función de declaración privada apiShowWindowAsync Lib "User32" Alias "ShowWindowAsync" (ByVal
hWnd As Long, ByVal nCmdShow As Long) As Long
Función de declaración privada apiStrCpy Lib "Kernel32" Alias "lstrcpynA" (ByVal pDestination As
String, ByVal pSource como cadena, ByVal iMaxLength como entero) Tan largo
Función de declaración privada apiStringLen Lib "Kernel32" Alias "lstrlenW" (ByVal lpString As
Long) Tan largo
Función de declaración privada apiStrTrimW Lib "ShlwApi" Alias "StrTrimW" () como booleano
Función de declaración privada apiTerminateProcess Lib "Kernel32" Alias "TerminateProcess"
(ByVal hWnd tan largo, ByVal uSalirCode tan largo)

https://riptutorial.com/ 17

Página 33

Función de declaración privada apiTimeGetTime Lib "Winmm" Alias "timeGetTime" () As Long


Función de declaración privada apiVarPtrArray Lib "MsVbVm50" Alias "VarPtr" (Var () As Any) As
Largo
Función de declaración privada apiWaitForSingleObject Lib "Kernel32" (ByVal hHandle As Long,
ByVal dwMilliseconds As Long) As Long
Tipo privado browseInfo 'utilizado por apiBrowseForFolder
hOwner As Long
pidlRoot tan largo
pszDisplayName como cadena
lpszTitle como cadena
ulFlags tan largo
lpfn siempre que
lParam tan largo
iImage tan larga
Tipo final
Función de declaración privada apiBrowseForFolder Lib "Shell32" Alias "SHBrowseForFolderA"
(lpBrowseInfo como browseInfo) Tan largo
Tipo privado CHOOSECOLOR 'utilizado por apiChooseColor;
http://support.microsoft.com/kb/153929 y http://www.cpearson.com/Excel/Colors.aspx
lStructSize siempre que
hWndOwner siempre que
hInstance tan largo
rgbResult As Long
lpCustColors como cadena
banderas tan largas
lCustData siempre que
lpfnHook tan largo

https://translate.googleusercontent.com/translate_f 28/223
6/1/2021 Intitulado
lpTemplateName como cadena
Tipo final
Función de declaración privada apiChooseColor Lib "ComDlg32" Alias "ChooseColorA" (pChoosecolor
Como CHOOSECOLOR) siempre que
Estructura personalizada de FindWindowParameters de tipo privado para pasar los parámetros de entrada / salida
de la función de enumeración de ganchos; podría usar variables globales en su lugar, pero esto es mejor
strTitle As String 'INPUT
hWnd tan largo 'SALIDA
Tipo final 'Encuentra una ventana específica con subtítulos dinámicos de un
lista de todas las ventanas abiertas: http://www.everythingaccess.com/tutorials.asp?ID=Bring-an-external-
ventana de la aplicación al primer plano
Función de declaración privada apiEnumWindows Lib "User32" Alias "EnumWindows" (ByVal lpEnumFunc
As Long, ByVal lParam As Long) As Long
Private Type lastInputInfo 'utilizado por apiGetLastInputInfo, getLastInputTime
cbSize As Long
dwTime As Long
Tipo final
Función de declaración privada apiGetLastInputInfo Lib "User32" Alias "GetLastInputInfo" (ByRef
plii As lastInputInfo) Tan largo
Tipo privado SystemTime
wYear Como entero
wMonth Como entero
wDayOfWeek como entero
wDía Como entero
wHour Como entero
wMinuto Como entero
wSecond Como entero
wMilliseconds como entero
Tipo final
Private Declare Sub apiGetLocalTime Lib "Kernel32" Alias "GetLocalTime" (lpSystem As
Hora del sistema)
Punto de tipo privado API
X tanto tiempo
Y siempre que

https://riptutorial.com/ 18

Página 34

Tipo final
Tipo privado rectAPI
Left_Renamed As Long
Top_Renamed As Long
Right_Renamed As Long
Bottom_Renamed As Long
Tipo final
Tipo privado winPlacement
longitud tan larga
banderas tan largas
showCmd tan largo
ptMinPosition como pointAPI
ptMaxPosition como pointAPI
rcNormalPosition como rectAPI
Tipo final
Función de declaración privada apiGetWindowPlacement Lib "User32" Alias "GetWindowPlacement"
(ByVal hWnd As Long, ByRef lpwndpl As winPlacement) As Long
Tipo privado winRect
Dejó tanto tiempo
Arriba siempre que
Tanto tiempo
Fondo tan largo
Tipo final
Función de declaración privada apiMoveWindow Lib "User32" Alias "MoveWindow" (ByVal hWnd As
Long, xLeft tan largo, ByVal yTop tan largo, wWidth tan largo, ByVal hHeight tan largo, ByVal repintado
Siempre que)
#Else 'Win16 = Verdadero
#Terminara si

API de Mac

Microsoft no admite oficialmente las API, pero con un poco de investigación se pueden encontrar más declaraciones
en línea

Office 2016 para Mac tiene espacio aislado

https://translate.googleusercontent.com/translate_f 29/223
6/1/2021 Intitulado
A diferencia de otras versiones de las aplicaciones de Office que admiten VBA, las aplicaciones de Office 2016 para Mac son de espacio aislado.

La zona de pruebas impide que las aplicaciones accedan a recursos fuera del contenedor de aplicaciones. Esto afecta
cualquier complemento o macros que implique el acceso a archivos o la comunicación entre procesos. Usted puede
Minimice los efectos del sandboxing utilizando los nuevos comandos descritos en la siguiente sección.
Nuevos comandos de VBA para Office 2016 para Mac

Los siguientes comandos de VBA son nuevos y exclusivos de Office 2016 para Mac.

Mando Utilizar para

GrantAccessToMultipleFiles Solicita el permiso de un usuario para acceder a varios archivos a la vez

AppleScriptTask Llamar a scripts externos de AppleScript desde VB

MAC_OFFICE_VERSION IFDEF entre diferentes versiones de Mac Office en tiempo de compilación

Office 2011 para Mac

https://riptutorial.com/ 19

Página 35

Sistema privado Declare Function Lib "libc.dylib" (comando ByVal como cadena) As Long
Función de declaración privada popen Lib "libc.dylib" (comando ByVal como cadena, modo ByVal como
String) tan largo
Función de declaración privada pclose Lib "libc.dylib" (archivo ByVal siempre que sea largo)
Función de declaración privada fread Lib "libc.dylib" (ByVal outStr As String, ByVal size As Long,
Elementos ByVal As Long, ByVal stream As Long) As Long
Función de declaración privada feof Lib "libc.dylib" (archivo ByVal siempre que sea largo)

Office 2016 para Mac

Función privada Declare PtrSafe popen Lib "libc.dylib" (comando ByVal como cadena, modo ByVal
Como cadena) Como LongPtr
Función privada Declare PtrSafe pclose Lib "libc.dylib" (archivo ByVal como LongPtr) As Long
Función privada Declare PtrSafe fread Lib "libc.dylib" (ByVal outStr As String, ByVal size As
Elementos LongPtr, ByVal As LongPtr, ByVal stream As LongPtr) As Long
Función privada Declare PtrSafe feof Lib "libc.dylib" (archivo ByVal como LongPtr) como LongPtr

Obtenga monitores totales y resolución de pantalla

Opción explícita

Información de GetSystemMetrics32: http://msdn.microsoft.com/en-us/library/ms724385(VS.85).aspx


#Si Win64 Entonces
Función privada Declare PtrSafe GetSystemMetrics32 Lib "User32" Alias "GetSystemMetrics"
(ByVal nIndex As Long) As Long
#ElseIf Win32 Entonces
Función de declaración privada GetSystemMetrics32 Lib "User32" Alias "GetSystemMetrics" (ByVal
nIndex As Long) Siempre que
#Terminara si

'Envoltorios de VBA:
Función pública dllGetMonitors () tan largo
Const SM_CMONITORS = 80
dllGetMonitors = GetSystemMetrics32 (SM_CMONITORS)
Función final

Función pública dllGetHorizontalResolution () As Long


Const SM_CXVIRTUALSCREEN = 78
dllGetHorizontalResolution = GetSystemMetrics32 (SM_CXVIRTUALSCREEN)
Función final

Función pública dllGetVerticalResolution () As Long


Const SM_CYVIRTUALSCREEN = 79
dllGetVerticalResolution = GetSystemMetrics32 (SM_CYVIRTUALSCREEN)

https://translate.googleusercontent.com/translate_f 30/223
6/1/2021 Intitulado
Función final

Public Sub ShowDisplayInfo ()


Debug.Print "Monitores totales:" & vbTab & vbTab & dllGetMonitors
Debug.Print "Resolución horizontal:" & vbTab & dllGetHorizontalResolution
Debug.Print "Resolución vertical:" & vbTab & dllGetVerticalResolution

'Monitores totales: 1
'Resolución horizontal: 1920
'Resolución vertical: 1080
End Sub

https://riptutorial.com/ 20

Página 36

FTP y API regionales

modFTP

Opción explícita
Opción Comparar texto
Opción Módulo Privado

'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

'Abra el objeto de Internet


Función de declaración privada InternetOpen Lib "wininet.dll" Alias "InternetOpenA" (_
ByVal sAgent como cadena, _
ByVal lAccessType As Long, _
ByVal sProxyName como cadena, _
ByVal sProxyBypass como cadena, _
ByVal lFlags As Long _
) Tanto tiempo
'ex: lngINet = InternetOpen ("Control MyFTP", 1, vbNullString, vbNullString, 0)

'Conéctese a la red
Función de declaración privada InternetConnect Lib "wininet.dll" Alias "InternetConnectA" (_
ByVal hInternetSession siempre que, _
ByVal sServerName como cadena, _
ByVal nServerPort como entero, _
ByVal sUsername como cadena, _
ByVal sPassword como cadena, _
ByVal lService siempre que, _
ByVal lFlags As Long, _
ByVal lContext tan largo _
) Tanto tiempo
'ej: lngINetConn = InternetConnect (lngINet, "ftp.microsoft.com", 0, "anónimo",
"wally@wallyworld.com", 1, 0, 0)

'Obtener un archivo
Función de declaración privada FtpGetFile Lib "wininet.dll" Alias "FtpGetFileA" (_
ByVal hFtpSession siempre que, _
ByVal lpszRemoteFile como cadena, _
ByVal lpszNewFile como cadena, _
ByVal fFailIfExists como booleano, _
ByVal dwFlagsAndAttributes As Long, _
ByVal dwFlags As Long, _
ByVal dwContext siempre que _
) Como booleano
'ex: blnRC = FtpGetFile (lngINetConn, "dirmap.txt", "c: \ dirmap.txt", 0, 0, 1, 0)

'Enviar un archivo
Función de declaración privada FtpPutFile Lib "wininet.dll" Alias "FtpPutFileA" _
(_
ByVal hFtpSession siempre que, _
ByVal lpszLocalFile como cadena, _
ByVal lpszRemoteFile como cadena, _
ByVal dwFlags tan largo, ByVal dwContext tan largo _
) Como booleano
'ex: blnRC = FtpPutFile (lngINetConn, "c: \ dirmap.txt", "dirmap.txt", 1, 0)

'Eliminar un archivo
Función de declaración privada FtpDeleteFile Lib "wininet.dll" Alias "FtpDeleteFileA" _

https://translate.googleusercontent.com/translate_f 31/223
6/1/2021 Intitulado

https://riptutorial.com/ 21

Página 37

(_
ByVal hFtpSession siempre que, _
ByVal lpszFileName como cadena _
) Como booleano
'ex: blnRC = FtpDeleteFile (lngINetConn, "test.txt")

'Cerrar el objeto de Internet


Función de declaración privada InternetCloseHandle Lib "wininet.dll" (ByVal hInet siempre que)
Entero
por ejemplo: InternetCloseHandle lngINetConn
por ejemplo: InternetCloseHandle lngINet

Función de declaración privada FtpFindFirstFile Lib "wininet.dll" Alias "FtpFindFirstFileA" _


(_
ByVal hFtpSession siempre que, _
ByVal lpszSearchFile como cadena, _
lpFindFileData como WIN32_FIND_DATA, _
ByVal dwFlags As Long, _
ByVal dwContent tan largo _
) Tanto tiempo
Tipo privado FILETIME
dwLowDateTime tan largo
dwHighDateTime tan largo
Tipo final
Tipo privado WIN32_FIND_DATA
dwFileAttributes tan largo
ftCreationTime como FILETIME
ftLastAccessTime como FILETIME
ftLastWriteTime como FILETIME
nFileSizeHigh tan largo
nFileSizeLow tanto tiempo
dwReserved0 siempre que
dwReserved1 siempre que
cFileName como cadena * MAX_FTP_PATH
cAlternate como cadena * 14
Tipo final
'por ejemplo: lngHINet = FtpFindFirstFile (lngINetConn, "*. *", pData, 0, 0)

Función de declaración privada InternetFindNextFile Lib "wininet.dll" Alias "InternetFindNextFileA"


_
(_
ByVal hFind As Long, _
lpvFindData como WIN32_FIND_DATA _
) Tanto tiempo
'por ejemplo: blnRC = InternetFindNextFile (lngHINet, pData)

Public Sub showLatestFTPVersion ()


Dim ftpSuccess como booleano, msg como cadena, lngFindFirst como largo
Dim lngINet tan largo, lngINetConn tan largo
Atenuar pData como WIN32_FIND_DATA
'init el búfer de nombre de archivo
pData.cFileName = Cadena (260, 0)

msg = "Error de FTP"


lngINet = InternetOpen ("Control MyFTP", 1, vbNullString, vbNullString, 0)
Si lngINet> 0 entonces
lngINetConn = InternetConnect (lngINet, FTP_SERVER_NAME, FTP_SERVER_PORT,
FTP_USER_NAME, FTP_PASSWORD, 1, 0, 0)

https://riptutorial.com/ 22

Página 38

Si lngINetConn> 0, entonces
FtpPutFile lngINetConn, "C: \ Tmp \ ftp.cls", "ftp.cls", FTP_TRANSFER_BINARY, 0
'lngFindFirst = FtpFindFirstFile (lngINetConn, "ExcelDiff.xlsm", pData, 0, 0)

https://translate.googleusercontent.com/translate_f 32/223
6/1/2021 Intitulado
Si lngINet = 0 entonces
msg = "Error de DLL:" & Err.LastDllError & ", Número de error:" & Err.Number & ",
Error Desc: "& Err.Description
Más
msg = left (pData.cFileName, InStr (1, pData.cFileName, String (1, 0),
vbBinaryCompare) - 1)
Terminara si
InternetCloseHandle lngINetConn
Terminara si
InternetCloseHandle lngINet
Terminara si
MsgBox msg
End Sub

modRegional:

Opción explícita

Const privada LOCALE_SDECIMAL = & HE


Const privada LOCALE_SLIST = & HC

Función de declaración privada GetLocaleInfo Lib "Kernel32" Alias "GetLocaleInfoA" (ByVal Locale As
Long, ByVal LCType tan largo, ByVal lpLCData como cadena, ByVal cchData tan largo)
Función de declaración privada SetLocaleInfo Lib "Kernel32" Alias "SetLocaleInfoA" (ByVal Locale As
Long, ByVal LCType tan largo, ByVal lpLCData como cadena) como booleano
Función de declaración privada GetUserDefaultLCID% Lib "Kernel32" ()

Función pública getTimeSeparator () como cadena


getTimeSeparator = Application.International (xlTimeSeparator)
Función final
Función pública getDateSeparator () como cadena
getDateSeparator = Application.International (xlDateSeparator)
Función final
Función pública getListSeparator () como cadena
Dim ListSeparator como cadena, iRetVal1 tan largo, iRetVal2 tan largo, lpLCDataVar como cadena,
Posición como entero, configuración regional tan larga
Locale = GetUserDefaultLCID ()
iRetVal1 = GetLocaleInfo (Locale, LOCALE_SLIST, lpLCDataVar, 0)
ListSeparator = String $ (iRetVal1, 0)
iRetVal2 = GetLocaleInfo (Locale, LOCALE_SLIST, ListSeparator, iRetVal1)
Posición = InStr (ListSeparator, Chr $ (0))
Si Posición> 0, entonces ListSeparator = Left $ (ListSeparator, Position - 1) Else ListSeparator
= vbNullString
getListSeparator = ListSeparator
Función final

Private Sub ChangeSettingExample () 'cambia la configuración del carácter mostrado como


separador decimal.
Llame a SetLocalSetting (LOCALE_SDECIMAL, ",") 'para cambiar a ","
Detener 'revise su panel de control para verificar o usar el
Función API GetLocaleInfo
Llame a SetLocalSetting (LOCALE_SDECIMAL, ".") 'Para volver a cambiar a "."
End Sub

Función privada SetLocalSetting (LC_CONST tan largo, configuración como cadena) como booleano
Llamar a SetLocaleInfo (GetUserDefaultLCID (), LC_CONST, Configuración)

https://riptutorial.com/ 23

Página 39

Función final

Leer API Calls en línea: https://riptutorial.com/vba/topic/10569/api-calls

https://translate.googleusercontent.com/translate_f 33/223
6/1/2021 Intitulado

https://riptutorial.com/ 24

Página 40

Capítulo 3: Matrices
Ejemplos

Declarar una matriz en VBA

Declarar una matriz es muy similar a declarar una variable, excepto que debe declarar la
dimensión de la matriz justo después de su nombre:

Dim myArray (9) As String 'Declarando una matriz que contendrá hasta 10 cadenas

De forma predeterminada, las matrices en VBA están indexadas 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

Acceso a elementos
El acceso a un elemento de la matriz se realiza mediante el nombre de la matriz, seguido del índice

https://translate.googleusercontent.com/translate_f 34/223
6/1/2021 Intitulado
del elemento, entre paréntesis:

myArray (0) = "primer elemento"


myArray (5) = "sexto elemento"
myArray (9) = "último elemento"

Indexación de matrices
Puede cambiar la indexación de matrices colocando esta línea en la parte superior de un módulo:

Opción Base 1

Con esta línea, todas las matrices declaradas en el módulo se indexarán desde ONE .

Índice específico
También puede declarar cada Array con su propio índice utilizando la palabra clave To , y la menor y
límite superior (= índice):

Dim mySecondArray (1 To 12) As String 'Matriz de 12 cadenas indexadas de 1 a 12


Dim myThirdArray (13 To 24) As String 'Array de 12 cadenas indexadas de 13 a 24

Declaración dinámica
Cuando no conoce el tamaño de su Array antes de su declaración, puede usar la dinámica
declaración y la palabra clave ReDim :

https://riptutorial.com/ 25

Página 41

Dim myDynamicArray () As Strings 'Crea una matriz de un número desconocido de cadenas


ReDim myDynamicArray (5) 'Esto restablece la matriz a 6 elementos

Tenga en cuenta que el uso de la palabra clave ReDim eliminará cualquier contenido anterior de su matriz. Para prevenir esto,
puede usar la palabra clave Preserve después de ReDim :

Dim myDynamicArray (5) como cadena


myDynamicArray (0) = "Algo que quiero conservar"

ReDim Preserve myDynamicArray (8) 'Expande el tamaño hasta 9 cadenas


Debug.Print myDynamicArray (0) 'todavía imprime el elemento

Uso de Split para crear una matriz a partir de una cadena

Función dividida

devuelve una matriz unidimensional de base cero que contiene un número específico de subcadenas.

Sintaxis

Dividir (expresión [, delimitador [, límite [, comparar ]]] )

Parte Descripción

Necesario. Expresión de cadena que contiene subcadenas y delimitadores. Si expresión


es una cadena de longitud cero ("" o vbNullString), Split devuelve una matriz vacía
expresión
que no contiene elementos ni datos. En este caso, la matriz devuelta tendrá un
LBound de 0 y UBound de -1.

Opcional. Carácter de cadena utilizado para identificar límites de subcadena. Si se omite, el espacio

https://translate.googleusercontent.com/translate_f 35/223
6/1/2021 Intitulado

delimitador Se supone que el carácter ("") es el delimitador. Si el delimitador es de longitud cero


cadena, una matriz de un solo elemento que contiene la cadena de expresión completa es
regresó.

Opcional. Número de subcadenas que se devolverán; -1 indica que todas las subcadenas
límite
se devuelven.

Opcional. Valor numérico que indica el tipo de comparación que se utilizará cuando
comparar
evaluar subcadenas. Consulte la sección Configuración para conocer los valores.

Configuraciones

El argumento de comparación puede tener los siguientes valores:

Constante Descripción del valor

Realiza una comparación usando la configuración de la Opción


Descripción -1
Compare declaración.

https://riptutorial.com/ 26

Página 42

Constante Descripción del valor

vbBinaryCompare 0 Realiza una comparación binaria.

vbTextCompare 1 Realiza una comparación textual.

Solo Microsoft Access. Realiza una comparación basada en


vbDatabaseCompare 2
información en su base de datos.

Ejemplo

En este ejemplo se demuestra cómo funciona Split mostrando varios estilos. Los comentarios
muestra el conjunto de resultados para cada una de las diferentes opciones de división realizadas. Finalmente se demuestra como
para recorrer la matriz de cadenas devuelta.

Subprueba

Dim textArray () como cadena

textArray = Split ("Tecnología en la red")


'Resultado: {"Tech", "on", "the", "Net"}

textArray = Dividir ("172.23.56.4", ".")


'Resultado: {"172", "23", "56", "4"}

textArray = Dividir ("A; B; C; D", ";")


'Resultado: {"A", "B", "C", "D"}

textArray = Dividir ("A; B; C; D", ";", 1)


'Resultado: {"A; B; C; D"}

textArray = Dividir ("A; B; C; D", ";", 2)


'Resultado: {"A", "B; C; D"}

textArray = Dividir ("A; B; C; D", ";", 3)


'Resultado: {"A", "B", "C; D"}

textArray = Dividir ("A; B; C; D", ";", 4)


'Resultado: {"A", "B", "C", "D"}

'Puede iterar sobre la matriz creada


Contador de atenuación siempre que

Para contador = LBound (textArray) a UBound (textArray)


Debug.Print textArray (contador)

https://translate.googleusercontent.com/translate_f 36/223
6/1/2021 Intitulado
próximo
End Sub

Iterando elementos de una matriz

Para ... Siguiente


El uso de la variable de iterador como número de índice es la forma más rápida de iterar los elementos de un
formación:

https://riptutorial.com/ 27

Página 43

Atenuar elementos como variante


elementos = Matriz (0, 1, 2, 3)

Dim index como entero


Para index = LBound (elementos) a UBound (elementos)
'asume que el valor se puede convertir implícitamente en una cadena:
Debug.Print elementos (índice)
próximo

Los bucles anidados se pueden utilizar para iterar matrices multidimensionales:

Atenuar elementos (0 a 1, 0 a 1) como entero


elementos (0, 0) = 0
elementos (0, 1) = 1
elementos (1, 0) = 2
elementos (1, 1) = 3

Atenuar exterior como entero


Dim interior como entero
Para exterior = LBound (elementos, 1) A UBound (elementos, 1)
Para inner = LBound (elementos, 2) A UBound (elementos, 2)
'asume que el valor se puede convertir implícitamente en una cadena:
Debug.Print elementos (exterior, interior)
próximo
próximo

Para cada uno ... Siguiente


Un bucle For Each ... Next también se puede utilizar para iterar matrices, si el rendimiento no importa:

Atenuar elementos como variante


elementos = Matriz (0, 1, 2, 3)

Atenuar el elemento como variante 'debe ser una variante


Para cada artículo en artículos
'asume que el valor se puede convertir implícitamente en una cadena:
Debug.Print elemento
próximo

Un bucle For Each iterará todas las dimensiones de exterior a interior (el mismo orden en que se muestran los elementos
establecidos en la memoria), por lo que no hay necesidad de bucles anidados:

Atenuar elementos (0 a 1, 0 a 1) como entero


elementos (0, 0) = 0
elementos (1, 0) = 1
elementos (0, 1) = 2
elementos (1, 1) = 3

Atenuar elemento como variante 'debe ser variante


Para cada artículo en artículos
'asume que el valor se puede convertir implícitamente en una cadena:
Debug.Print elemento
próximo

https://translate.googleusercontent.com/translate_f 37/223
6/1/2021 Intitulado

https://riptutorial.com/ 28

Página 44

Tenga en cuenta que los bucles For Each se utilizan mejor para iterar objetos de colección , si el rendimiento es importante.

Los 4 fragmentos anteriores producen el mismo resultado:

0
1
2
3

Matrices dinámicas (cambio de tamaño de matriz y manejo dinámico)

Matrices dinámicas
Agregar y reducir variables en una matriz de forma dinámica es una gran ventaja para cuando
la información que está tratando no tiene un número determinado de variables.

Agregar valores dinámicamente


Simplemente puede cambiar el tamaño de la matriz con la declaración ReDim , esto cambiará el tamaño de la matriz, pero si
cuál para retener la información ya almacenada en la matriz necesitará la parte Preserve .

En el siguiente ejemplo, creamos una matriz y la aumentamos en una variable más en cada iteración.
conservando los valores que ya están en la matriz.

Dim Dynamic_array como variante


'primero establecemos Dynamic_array como variante

Para n = 1 a 100

Si está vacío (matriz_dinámica), entonces


'isempty () verificará si necesitamos agregar el primer valor a la matriz o el siguiente
unos

ReDim Dynamic_array (0)


'ReDim Dynamic_array (0) cambiará el tamaño de la matriz a una sola variable
Matriz_dinámica (0) = n

Más
ReDim Preserve Dynamic_array (0 a UBound (Dynamic_array) + 1)
'en la línea de arriba cambiamos el tamaño de la matriz de la variable 0 al UBound () = last
variable, más uno que aumenta efectivamente el tamaño de la matriz en uno
Matriz_dinámica (UBound (Matriz_dinámica)) = n
'atribuir un valor a la última variable de Dynamic_array
Terminara si

próximo

Eliminar valores dinámicamente


Podemos utilizar la misma lógica para disminuir la matriz. En el ejemplo, el valor "último" será

https://riptutorial.com/ 29

Página 45

eliminado de la matriz.

https://translate.googleusercontent.com/translate_f 38/223
6/1/2021 Intitulado

Dim Dynamic_array como variante


Dynamic_array = Array ("primero", "medio", "último")

ReDim Preserve Dynamic_array (0 a UBound (Dynamic_array) - 1)


'Cambiar el tamaño de la reserva mientras se suelta el último valor

Restablecimiento de una matriz y reutilización dinámica


También podemos reutilizar las matrices que creamos para no tener muchas en la memoria, lo que haría
el tiempo de ejecución más lento. Esto es útil para matrices de varios tamaños. Un fragmento que podría utilizar para volver
utilizar la matriz es ReDim la matriz de nuevo a (0) , atribuir una variable a la matriz y libremente
aumente la matriz de nuevo.

En el fragmento de abajo, construyo una matriz con los valores de 1 a 40, vacío la matriz y vuelvo a llenar el
matriz con valores de 40 a 100, todo esto realizado de forma dinámica.

Dim Dynamic_array como variante

Para n = 1 a 100

Si está vacío (matriz_dinámica), entonces


ReDim Dynamic_array (0)
Matriz_dinámica (0) = n

ElseIf Dynamic_array (0) = "" Entonces


'si la primera variante está vacía (= "") entonces dale el valor de n
Matriz_dinámica (0) = n
Más
ReDim Preserve Dynamic_array (0 a UBound (Dynamic_array) + 1)
Matriz_dinámica (UBound (Matriz_dinámica)) = n
Terminara si
Si n = 40 Entonces
ReDim Dynamic_array (0)
'Cambiar el tamaño de la matriz a una variable sin preservar,
'dejando el primer valor de la matriz vacío
Terminara si

próximo

Matrices irregulares (matrices de matrices)

Matrices irregulares NO matrices multidimensionales


Las matrices de matrices (matrices irregulares) no son lo mismo que matrices multidimensionales si piensa en
ellos visualmente las matrices multidimensionales se verían como matrices (rectangulares) con un número definido
de elementos en sus dimensiones (matrices internas), mientras que la matriz dentada sería como un calendario anual
con las matrices internas que tienen un número diferente de elementos, como días en meses diferentes.

Aunque las matrices irregulares son bastante complicadas y difíciles de usar debido a sus niveles anidados y no
tienen mucha seguridad de tipos, pero son muy flexibles, le permiten manipular diferentes tipos de datos

https://riptutorial.com/ 30

Página 46

con bastante facilidad y no es necesario que contenga elementos vacíos o no utilizados.

Crear una matriz irregular


En el siguiente ejemplo, inicializaremos una matriz dentada que contiene dos matrices, una para Nombres y
otro para Números, y luego acceder a un elemento de cada

Dim OuterArray () como variante


Atenuar nombres () como variante
Atenuar números () como variante
'las matrices se declaran como variantes para que podamos acceder a los atributos de cualquier tipo de datos a sus elementos

https://translate.googleusercontent.com/translate_f 39/223
6/1/2021 Intitulado

Nombres = Matriz ("Persona1", "Persona2", "Persona3")


Números = Matriz ("001", "002", "003")

OuterArray = Array (nombres, números)


'Dar directamente a OuterArray una matriz que contiene matrices de Nombres y Números dentro

Debug.Print OuterArray (0) (1)


Debug.Print OuterArray (1) (1)
'acceder a elementos dentro del dentado dando las coordenadas del elemento

Creación y lectura dinámica de matrices irregulares


También podemos ser más dinámicos en nuestro aproximado para construir las matrices, imagina que tenemos un
hoja de datos del cliente en Excel y queremos construir una matriz para generar los detalles del cliente.

Nombre - Teléfono - Correo electrónico - Número de cliente


Persona1 - 153486231 - 1 @ STACK - 001
Persona2 - 153486242 - 2 @ STACK - 002
Persona3 - 153486253 - 3 @ STACK - 003
Persona4 - 153486264 - 4 @ STACK - 004
Persona5 - 153486275 - 5 @ STACK - 005

Construiremos dinámicamente una matriz de encabezado y una matriz de clientes, el encabezado contendrá el
los títulos de las columnas y la matriz Clientes contendrán la información de cada cliente / fila como matrices.

Atenuar encabezados como variante


'matriz de encabezados con la sección superior de la hoja de datos del cliente
Para c = 1 a 4
Si está vacío (encabezados), entonces
Encabezados ReDim (0)
Encabezados (0) = Celdas (1, c) .Valor
Más
ReDim Preserve encabezados (0 a UBound (encabezados) + 1)
Encabezados (UBound (Encabezados)) = Celdas (1, c) .Value
Terminara si
próximo

Atenuar a los clientes como variante


'La matriz de clientes contendrá matrices de valores de cliente
Atenuar Customer_Values como variante
'Customer_Values será una matriz del cliente en sus elementos (Nombre-Teléfono-Correo electrónico-CustNum)

https://riptutorial.com/ 31

Página 47

Para r = 2 a 6
'iterar a través de los clientes / filas
Para c = 1 a 4
'iterar a través de los valores / columnas

'construir una matriz que contenga los valores del cliente


Si está vacío (Customer_Values), entonces
ReDim Customer_Values (0)
Customer_Values (0) = Celdas (r, c) .Value
ElseIf Customer_Values (0) = "" Entonces
Customer_Values (0) = Celdas (r, c) .Value
Más
ReDim Preserve Customer_Values (0 a UBound (Customer_Values) + 1)
Customer_Values (UBound (Customer_Values)) = Celdas (r, c) .Value
Terminara si
próximo

'agregar la matriz customer_values a la matriz de clientes


Si está vacío (clientes), entonces
Clientes ReDim (0)
Clientes (0) = Customer_Values
Más
ReDim Preserve Clientes (0 a UBound (Clientes) + 1)
Clientes (UBound (Clientes)) = Customer_Values
Terminara si

https://translate.googleusercontent.com/translate_f 40/223
6/1/2021 Intitulado

'restablecer Custumer_Values para reconstruir una nueva matriz si es necesario


ReDim Customer_Values (0)
próximo

Dim Main_Array (0 a 1) como variante


La matriz principal contendrá tanto los encabezados como los clientes.

Main_Array (0) = Encabezados


Main_Array (1) = Clientes

Para comprender mejor la forma de construir dinámicamente una matriz unidimensional, consulte
Matrices dinámicas (cambio de tamaño de matriz y manejo dinámico) en la documentación de matrices.

El resultado del fragmento anterior es una matriz dentada con dos matrices, una de esas matrices con 4
elementos, 2 niveles de sangría, y el otro es en sí mismo otra matriz dentada que contiene 5 matrices de
4 elementos cada uno y 3 niveles de sangría, consulte la estructura a continuación:

Main_Array (0) - Encabezados - Matriz ("Nombre", "Teléfono", "Correo electrónico", "Número de cliente")
(1) - Clientes (0) - Matriz ("Persona1", 153486231, "1 @ STACK", 001)
Clientes (1) - Array ("Person2", 153486242, "2 @ STACK", 002)
...
Clientes (4) - Array ("Person5", 153486275, "5 @ STACK", 005)

Para acceder a la información tendrás que tener en cuenta la estructura del Jagged Array que creas,
En el ejemplo anterior, puede ver que la matriz principal contiene una matriz de encabezados y una matriz de
Matrices ( Clientes ) por lo tanto con diferentes formas de acceder a los elementos.

Ahora leeremos la información del Main Array e imprimiremos la información de cada uno de los Clientes.
como tipo de información: Info .

https://riptutorial.com/ 32

Página 48

Para n = 0 a UBound (Main_Array (1))


'n para iterar de la primera a la última matriz en Main_Array (1)

Para j = 0 a UBound (Main_Array (1) (n))


'j iterará del primero al último elemento en cada matriz de Main_Array (1)

Debug.Print Main_Array (0) (j) & ":" & Main_Array (1) (n) (j)
'print Main_Array (0) (j) que es el encabezado y Main_Array (0) (n) (j) que es el
elemento en la matriz de clientes
'podemos llamar al encabezado con j ya que la matriz de encabezado tiene la misma estructura que el
matriz de clientes
próximo
próximo

RECUERDE realizar un seguimiento de la estructura de su Jagged Array, en el ejemplo anterior para acceder
el Nombre de un cliente es accediendo a Main_Array -> Clientes -> CustomerNumber -> Name which
tiene tres niveles, para devolver "Person4" necesitará la ubicación de los clientes en Main_Array, luego
la Ubicación del cliente cuatro en la matriz de Clientes irregulares y, por último, la ubicación del
elemento que necesita, en este caso Main_Array (1) (3) (0) que es
Main_Array (Clientes) (CustomerNumber) (Nombre) .

Matrices multidimensionales

Matrices multidimensionales
Como su nombre lo indica, las matrices multidimensionales son matrices que contienen más de una dimensión,
generalmente dos o tres pero puede tener hasta 32 dimensiones.

https://translate.googleusercontent.com/translate_f 41/223
6/1/2021 Intitulado
Una matriz múltiple funciona como una matriz con varios niveles, tome en ejemplo una comparación entre uno,
dos y tres dimensiones.

One Dimension es su matriz típica, parece una lista de elementos.

Dim 1D (3) como variante

* 1D: visualmente *
(0)
(1)
(2)

Dos dimensiones se verían como una cuadrícula de Sudoku o una hoja de Excel, al inicializar la matriz
definiría cuántas filas y columnas tendría la matriz.

Dim 2D (3,3) como variante


'esto resultaría en una cuadrícula de 3x3

* 2D: visualmente *
(0,0) (0,1) (0,2)
(1,0) (1,1) (1,2)
(2,0) (2,1) (2,2)

https://riptutorial.com/ 33

Página 49

Three Dimensions comenzaría a parecerse al cubo de Rubik, al inicializar la matriz


definir filas y columnas y capas / profundidades que tendría la matriz.

Dim 3D (3,3,2) como variante


'esto resultaría en una cuadrícula de 3x3x3

* 3D: visualmente *
1ra capa Segunda capa Tercera capa
frente medio espalda
(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 del 3D, por lo que un 4D (1,3,3,3) sería dos
matrices 3D en paralelo.

Matriz de dos dimensiones


Creando

El siguiente ejemplo será una compilación de una lista de empleados, cada empleado tendrá un conjunto de
información de 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) el primer empleado
primer nombre.

Dim Bosses como variante


'establece jefes como Variante, para que podamos ingresar cualquier tipo de datos que queramos

Jefes = [{"Jonh", "Snow", "Presidente"; "Ygritte", "Wild", "Vicepresidente"}]


'inicialice una matriz 2D directamente llenándola con información, el resultado será una matriz (1,2)
tamaño 2x3 = 6 elementos

Atenuar empleados como variante


'inicializa tu matriz de empleados como variante
'inicialice y ReDim la matriz de empleados para que sea una matriz dinámica en lugar de una estática,
por lo tanto, tratado de manera diferente por el compilador de VBA
Empleados de ReDim (100, 5)
'declarando una matriz 2D que puede almacenar 100 empleados con 6 elementos de información cada uno, pero
comienza vacío
'el tamaño de la matriz es 101 x 6 y contiene 606 elementos

https://translate.googleusercontent.com/translate_f 42/223
6/1/2021 Intitulado
Para empleado = 0 a UBound (empleados, 1)
'para cada empleado / fila en la matriz, UBound para matrices 2D, que obtendrá el último elemento en
la matriz
'necesita dos parámetros, primero la matriz que verificar y segundo la dimensión, en este caso 1 =
empleado y 2 = información
Para información_e = 0 a UBound (empleados, 2)
'para cada elemento / columna de información de la matriz

Empleados (empleado, información_e) = InformationNeeded 'InformationNeeded sería


los datos para llenar la matriz
'iterar la matriz completa permitirá la atribución directa de información en el
coordenadas del elemento
próximo

https://riptutorial.com/ 34

Página 50

próximo

Cambiar el tamaño

Cambiar el tamaño o ReDim Preservar una matriz múltiple como la norma para una matriz de una dimensión obtendría un
error, en cambio, la información debe transferirse a una matriz temporal con el mismo tamaño
como el original más el número de filas / columnas para agregar. En el ejemplo siguiente veremos cómo
inicializar una matriz temporal, transferir la información desde la matriz original, llenar el resto
elementos vacíos y reemplace la matriz temporal por la matriz original.

Dim TempEmp como variante


'inicializa tu matriz temporal como variante
ReDim TempEmp (UBound (empleados, 1) + 1, UBound (empleados, 2))
'ReDim / Resize Temp matriz como una matriz 2D con tamaño UBound (Empleados) +1 = (último elemento en
Empleados 1a dimensión) + 1,
'la segunda dimensión sigue siendo la misma que la matriz original. efectivamente agregamos 1 fila en el
Matriz de empleados

'transferir
Para emp = LBound (empleados, 1) a UBound (empleados, 1)
Para información = LBound (Empleados, 2) A UBound (Empleados, 2)
'para transferir empleados a TempEmp iteramos ambas matrices y llenamos TempEmp con el
valor del elemento correspondiente en Empleados
TempEmp (emp, info) = Empleados (emp, info)

próximo
próximo

'llenar restante
'después de las transferencias, la matriz Temp todavía tiene elementos no utilizados al final, ya que fue
aumentado
'para llenar los elementos restantes, iterar desde la última "fila" con valores hasta la última fila en el
formación
'en este caso, la última fila en Temp será el tamaño de las filas de la matriz Empleados + 1, ya que
La última fila de la matriz de empleados ya está llena en TempArray

Para emp = UBound (Empleados, 1) + 1 a UBound (TempEmp, 1)


Para información = LBound (TempEmp, 2) To UBound (TempEmp, 2)

TempEmp (emp, info) = InformationNeeded & "NewRow"

próximo
próximo

'borrar Empleados, atribuir la matriz Temp a Empleados y borrar la matriz Temp


Borrar empleados
Empleados = TempEmp
Borrar TempEmp

Cambiar los valores de los elementos

Para cambiar / alterar los valores en un determinado elemento se puede hacer simplemente llamando a la coordenada a
cambiar y darle un nuevo valor: Empleados (0, 0) = "NewValue"

https://translate.googleusercontent.com/translate_f 43/223
6/1/2021 Intitulado
Alternativamente, iterar a través de las condiciones de uso de coordenadas para hacer coincidir los valores correspondientes al
parámetros necesarios:

https://riptutorial.com/ 35

Página 51

Para emp = 0 a UBound (empleados)


Si Empleados (emp, 0) = "Gloria" Y Empleados (emp, 1) = "Stephan" Entonces
'si se encuentra el valor
Empleados (emp, 1) = "Casado, cambio de apellido"
Salir para
'no iterar a través de una matriz completa a menos que sea necesario
Terminara si
próximo

Leyendo

El acceso a los elementos de la matriz se puede hacer con un bucle anidado (iterando cada elemento),
Loop and Coordinate (iterar filas y acceder a columnas directamente), o acceder directamente con
ambas coordenadas.

'bucle anidado, iterará a través de todos los elementos


Para emp = LBound (empleados, 1) a UBound (empleados, 1)
Para información = LBound (Empleados, 2) A UBound (Empleados, 2)
Debug.Print empleados (emp, info)
próximo
próximo

'bucle y coordina, iteración a través de todas las filas y en cada fila accediendo a todas las columnas
directamente
Para emp = LBound (empleados, 1) a UBound (empleados, 1)
Debug.Print empleados (emp, 0)
Debug.Print empleados (emp, 1)
Debug.Print empleados (emp, 2)
Debug.Print empleados (emp, 3)
Empleados de Debug.Print (emp, 4)
Debug.Print empleados (emp, 5)
próximo

'acceder directamente al elemento con coordenadas


Empleados de Debug.Print (5, 5)

Recuerde , siempre es útil mantener un mapa de matriz cuando se utilizan matrices multidimensionales, pueden
convertirse fácilmente en confusión.

Matriz de tres dimensiones


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, pero también el Edificio en el que trabajan.

La matriz 3D tendrá los Empleados (se puede considerar como Filas), la Información (Columnas),
y edificios que se pueden considerar como hojas diferentes en un documento de Excel, tienen el mismo
tamaño entre ellos, pero cada hoja tiene un conjunto diferente de información en sus celdas / elementos. El 3D
matriz contendrá n número de matrices 2D.

Creando

https://riptutorial.com/ 36

Página 52

https://translate.googleusercontent.com/translate_f 44/223
6/1/2021 Intitulado
Una matriz 3D necesita 3 coordenadas para ser inicializada Dim 3Darray (2,5,5) Como Variante la primera coordenada
en la matriz estará el número de Edificios / Hojas (diferentes conjuntos de filas y columnas), segundo
La coordenada definirá Filas y terceras Columnas. La atenuación anterior dará como resultado una matriz 3D con 108
elementos ( 3 * 6 * 6 ), que efectivamente tienen 3 conjuntos diferentes de matrices 2D.

Dim ThreeDArray como variante


'inicializa tu matriz ThreeDArray como variante
ReDim ThreeDArray (1, 50, 5)
'declarando una matriz 3D que puede almacenar dos conjuntos de 51 empleados con 6 elementos de información
cada uno, pero comienza vacío
'el tamaño de la matriz es 2 x 51 x 6 y contiene 612 elementos

Para la construcción = 0 a UBound (ThreeDArray, 1)


'para cada edificio / conjunto de la matriz
Para empleado = 0 a UBound (ThreeDArray, 2)
'para cada empleado / fila en la matriz
Para información_e = 0 a UBound (ThreeDArray, 3)
'para cada elemento / columna de información de la matriz

ThreeDArray (edificio, empleado, información_e) = Información necesaria '


La información necesaria serían los datos para llenar la matriz
'iterar la matriz completa permitirá la atribución directa de información en el
coordenadas del elemento
próximo
próximo
próximo

Cambiar el tamaño

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 de
el original agregando uno en la coordenada del parámetro a aumentar, la primera coordenada será
aumentar el número de conjuntos en la matriz, la segunda y tercera coordenadas aumentarán el
número de filas o columnas en cada conjunto.

El siguiente ejemplo aumenta el número de Filas en cada conjunto en uno y llena las que se encuentran recientemente.
elementos agregados con nueva información.

Dim TempEmp como variante


'inicializa tu matriz temporal como variante
ReDim TempEmp (UBound (ThreeDArray, 1), UBound (ThreeDArray, 2) + 1, UBound (ThreeDArray, 3))
'ReDim / Resize Temp matriz como una matriz 3D con tamaño UBound (ThreeDArray) +1 = (último elemento en
Empleados 2da dimensión) + 1,
'la otra dimensión sigue siendo la misma que la matriz original. efectivamente agregamos 1 fila en el
para cada conjunto de la matriz 3D

'transferir
Para construir = LBound (ThreeDArray, 1) To UBound (ThreeDArray, 1)
Para emp = LBound (ThreeDArray, 2) To UBound (ThreeDArray, 2)
Para información = LBound (ThreeDArray, 3) To UBound (ThreeDArray, 3)
'para transferir ThreeDArray a TempEmp iterando todos los conjuntos en la matriz 3D y
llene TempEmp con el valor del elemento correspondiente en cada conjunto de cada fila
TempEmp (edificio, emp, información) = ThreeDArray (edificio, emp, información)

próximo
próximo

https://riptutorial.com/ 37

Página 53

próximo

'llenar restante
'para llenar los elementos restantes, necesitamos iterar desde la última "fila" con valores hasta la última
fila en la matriz en cada conjunto, recuerde que el primer elemento vacío es la matriz original
Hacia arriba () más 1
Para la construcción = LBound (TempEmp, 1) To UBound (TempEmp, 1)
Para emp = UBound (ThreeDArray, 2) + 1 To UBound (TempEmp, 2)
Para información = LBound (TempEmp, 3) a UBound (TempEmp, 3)

TempEmp (edificio, emp, info) = InformationNeeded & "NewRow"

https://translate.googleusercontent.com/translate_f 45/223
6/1/2021 Intitulado
próximo
próximo
próximo

'borrar Empleados, atribuir la matriz Temp a Empleados y borrar la matriz Temp


Borrar ThreeDArray
ThreeDArray = TempEmp
Borrar TempEmp

Cambio de valores y lectura de elementos

Leer y cambiar los elementos en la matriz 3D se puede hacer de manera similar a como lo hacemos
Matriz 2D, solo ajuste el nivel extra en los bucles y coordenadas.

Hacer
'usando Do ... While para salida anticipada
Para la construcción = 0 a UBound (ThreeDArray, 1)
Para emp = 0 a UBound (ThreeDArray, 2)
Si ThreeDArray (edificio, emp, 0) = "Gloria" y ThreeDArray (edificio, emp, 1) =
"Stephan" Entonces
'si se encuentra el valor
ThreeDArray (building, emp, 1) = "Casado, cambio de apellido"
Salir Hacer
'no iterar a través de toda la matriz a menos que sea necesario
Terminara si
próximo
próximo
Bucle en falso

'bucle anidado, iterará a través de todos los elementos


Para construir = LBound (ThreeDArray, 1) To UBound (ThreeDArray, 1)
Para emp = LBound (ThreeDArray, 2) To UBound (ThreeDArray, 2)
Para información = LBound (ThreeDArray, 3) To UBound (ThreeDArray, 3)
Debug.Print ThreeDArray (construcción, emp, información)
próximo
próximo
próximo

'bucle y coordenada, iterará a través de todo el conjunto de filas y pedirá la fila más el valor
elegimos para las columnas
Para construir = LBound (ThreeDArray, 1) To UBound (ThreeDArray, 1)
Para emp = LBound (ThreeDArray, 2) To UBound (ThreeDArray, 2)
Debug.Print ThreeDArray (edificio, emp, 0)
Debug.Print ThreeDArray (edificio, emp, 1)
Debug.Print ThreeDArray (edificio, emp, 2)
Debug.Print ThreeDArray (edificio, emp, 3)
Debug.Print ThreeDArray (edificio, emp, 4)

https://riptutorial.com/ 38

Página 54

Debug.Print ThreeDArray (edificio, emp, 5)


próximo
próximo

'acceder directamente al elemento con coordenadas


Empleados de Debug.Print (0, 5, 5)

Leer matrices en línea: https://riptutorial.com/vba/topic/3064/arrays

https://translate.googleusercontent.com/translate_f 46/223
6/1/2021 Intitulado

https://riptutorial.com/ 39

Página 55

Capítulo 4: Asignar cadenas con repetidas


caracteres
Observaciones
A veces es necesario asignar una variable de cadena con un carácter específico que se repite en un
numero de veces. VBA proporciona dos funciones principales para este propósito:

• Cadena / Cadena $

• Espacio / Espacio $ .

Ejemplos

Utilice la función Cadena para asignar una cadena con n caracteres repetidos

Dim lineOfHyphens como cadena


'Asignar una cadena con 80 guiones repetidos
lineOfHyphens = String $ (80, "-")

Utilice las funciones String y Space para asignar una cadena de n caracteres

Dim stringOfSpaces como cadena

'Asignar una cadena con 255 espacios repetidos usando Space $

https://translate.googleusercontent.com/translate_f 47/223
6/1/2021 Intitulado
stringOfSpaces = Espacio $ (255)

'Asignar una cadena con 255 espacios repetidos usando String $


stringOfSpaces = String $ (255, "")

Lea Asignar cadenas con caracteres repetidos en línea:


https://riptutorial.com/vba/topic/3581/assigning-strings-with-repeated-characters

https://riptutorial.com/ 40

Página 56

Capítulo 5: Atributos
Sintaxis
• Atributo VB_Name = "ClassOrModuleName"
• Atributo VB_GlobalNameSpace = False 'Ignorado
• Atributo VB_Creatable = Falso 'Ignorado
• Atributo VB_PredeclaredId = {Verdadero | Falso}
• Atributo VB_Exposed = {Verdadero | Falso}
• Atributo variableName.VB_VarUserMemId = 0 'Cero indica que este es el valor predeterminado
miembro de la clase.
• Attribute variableName.VB_VarDescription = "alguna cadena" 'Agrega el texto al objeto
Información del navegador para esta variable.
• Atributo procName.VB_Description = "alguna cadena" 'Agrega el texto al buscador de objetos
información 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.


Ejemplos

VB_Name

VB_Name especifica la clase o el nombre del módulo.

Atributo VB_Name = "Class1"

Se crearía una nueva instancia de esta clase con

Atenuar myClass como Class1


myClass = nueva Class1

VB_GlobalNameSpace
https://translate.googleusercontent.com/translate_f 48/223
6/1/2021 Intitulado

En VBA, este atributo se ignora. No se transfirió desde VB6.

En VB6, crea una instancia global predeterminada de la clase (un "atajo") para que los miembros de la clase puedan
ser accedido 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/ 41

Página 57

Este atributo se ignora. No se transfirió desde VB6.

En VB6, se utilizó en combinación con el atributo VB_Exposed para controlar la accesibilidad de las clases.
fuera del proyecto actual.

VB_Exposed = Verdadero
VB_Creatable = Verdadero

Daría como resultado una clase pública , a la que se podría acceder desde otros proyectos, pero esta funcionalidad
no existe en VBA.

VB_PredeclaredId

Crea una instancia predeterminada global de una clase. Se accede a la instancia predeterminada a través del nombre del
clase.

Declaración

VERSIÓN 1.0 CLASE


EMPEZAR
MultiUse = -1 'Verdadero
FIN
Atributo VB_Name = "Class1"
Atributo VB_GlobalNameSpace = Falso
Atributo VB_Creatable = Falso
Atributo VB_PredeclaredId = True
Atributo VB_Exposed = False
Opción explícita

Función pública GiveMeATwo () como entero


GiveMeATwo = 2
Función final

Llamada

Debug.Print Class1.GiveMeATwo

De alguna manera, esto simula el comportamiento de clases estáticas en otros lenguajes, pero a diferencia de otros
idiomas, aún puede crear una instancia de la clase.

Dim cls como Class1


Establecer cls = New Class1
Debug.Print cls.GiveMeATwo

VB_Exposed

https://translate.googleusercontent.com/translate_f 49/223
6/1/2021 Intitulado
Controla las características de creación de instancias de una clase.

Atributo VB_Exposed = False

https://riptutorial.com/ 42

Página 58

Hace que la clase sea privada . No se puede acceder fuera del proyecto actual.

Atributo VB_Exposed = True

Expone la clase Pública Ly, 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 VB.Net
clase.

Clase pública Foo


Friend Sub New ()
End Sub
Clase final

Para obtener una instancia desde fuera del proyecto, debe exponer una fábrica para crear instancias.
Una forma de hacerlo es con un módulo público normal .

Función pública CreateFoo () como Foo


CreateFoo = Nuevo Foo
Función final

Dado que los módulos públicos son accesibles desde otros proyectos, esto nos permite crear nuevas instancias de
nuestras clases públicas - no creables .

VB_Description

Agrega una descripción de texto a un miembro de clase o módulo que se vuelve visible en el Explorador de objetos.
Idealmente, todos los miembros públicos de una interfaz / API pública deberían tener una descripción.

Función pública GiveMeATwo () como entero


Attribute GiveMeATwo.VB_Description = "¡Devuelve un dos!"
GiveMeATwo = 2
Propiedad final

Nota: todos los miembros de acceso de una propiedad ( Get , Let , Set ) usan la misma descripción.

VB_ [Var] UserMemId

Se utilizan los atributos VB_VarUserMemId (para


variables de ámbito de módulo) y VB_UserMemId (para procedimientos)
en VBA principalmente por dos cosas.

Especificar el miembro predeterminado de una clase


Una clase List que encapsularía una colección querría tener una propiedad Item , por lo que el cliente

https://riptutorial.com/ 43

Página 59

https://translate.googleusercontent.com/translate_f 50/223
6/1/2021 Intitulado

el código puede hacer esto:

For i = 1 To myList.Count 'Los objetos de colección de VBA están basados en 1


Debug.Print myList.Item (i)
próximo

Pero con un atributo VB_UserMemId establecido en 0 en la propiedad Item , el código del cliente puede hacer esto:

For i = 1 To myList.Count 'Los objetos de colección de VBA están basados en 1


Debug.Print myList (i)
próximo

Solo un miembro puede tener legalmente VB_UserMemId = 0 en una clase determinada. Para propiedades, especifique el
atributo en el descriptor de acceso Get :

Opción explícita
Privado interno como nueva colección

Propiedad pública Obtener recuento () siempre que


Recuento = recuento interno
Propiedad final

Objeto de obtención de propiedad pública (índice ByVal tan largo) como variante
Attribute Item.VB_Description = "Obtiene o establece el elemento en el índice especificado".
Elemento de atributo.VB_UserMemId = 0
'Obtiene el elemento en el índice especificado.
Elemento = interno (índice)
Propiedad final

Propiedad pública Let Item (ByVal index As Long, ByVal value As Variant)
'Establece el elemento en el índice especificado.
Con interno
Si index = .Count + 1 Entonces
.Añadir elemento: = valor
ElseIf index = .Count Then
.Eliminar índice
.Añadir elemento: = valor
ElseIf index <.Count Then
.Eliminar índice
.Añadir elemento: = valor, antes: = índice
Terminara si
Terminar con
Propiedad final

Hacer una clase iterable con un bucle For Each

construir
Con el valor mágico -4 , el atributo VB_UserMemId le dice a VBA que este miembro produce un
enumerador, que permite que el código del cliente haga esto:

Atenuar elemento como variante

https://riptutorial.com/ 44

Página 60

Para cada elemento de myList


Debug.Print elemento
próximo

La forma más sencilla de implementar este método es llamando al getter de propiedad oculto [_NewEnum] en un
interna / encapsulada ; el identificador debe incluirse entre corchetes porque
Colección

del subrayado inicial que lo convierte en un identificador de VBA ilegal:

Propiedad pública Obtener NewEnum () como IUnknown

https://translate.googleusercontent.com/translate_f 51/223
6/1/2021 Intitulado
Attribute NewEnum.VB_Description = "Obtiene un enumerador que recorre la lista en iteración".
Atributo NewEnum.VB_UserMemId = -4
El atributo NewEnum.VB_MemberFlags = "40" 'ocultaría el miembro en VB6. no es compatible con VBA.
'Obtiene un enumerador que recorre la Lista.
Establecer NewEnum = internal. [_ NewEnum]
Propiedad final

Leer atributos en línea: https://riptutorial.com/vba/topic/5321/attributes

https://riptutorial.com/ 45

Página 61

Capítulo 6: Automatización o uso de otros


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
para 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 Aplicación.
https://translate.googleusercontent.com/translate_f 52/223
6/1/2021 Intitulado
• Nombre del objeto; Cadena requerida. El nombre de clase del objeto que se va a crear. Para obtener información sobre
nombres de clases válidos, consulte Identificadores de programación OLE.

Observaciones
• Automatización de comprensión de MSDN

Cuando una aplicación admite Automatización, los objetos que expone la aplicación pueden ser
accedido por Visual Basic. Utilice Visual Basic para manipular estos objetos invocando
métodos en el objeto o obteniendo y estableciendo las propiedades del objeto.

• MSDN-Check o agregar una referencia de biblioteca de objetos

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
Puede hacerlo, primero debe asegurarse de que la aplicación proporcione una biblioteca de objetos.

• Cuadro de diálogo de referencias de MSDN

Le permite seleccionar los objetos de otra aplicación que desea que estén disponibles en su código
estableciendo una referencia a la biblioteca de objetos de esa aplicación.

• Método MSDN-CreateObject

Crea un objeto de Automatización de la clase especificada. Si la aplicación ya está


en ejecución, CreateObject creará una nueva instancia.

Ejemplos

Expresiones regulares de VBScript

https://riptutorial.com/ 46

Página 62

Establecer createVBScriptRegExObject = CreateObject ("vbscript.RegExp")

Herramientas> Referencias> Expresiones regulares de Microsoft VBScript #. #


DLL asociado: VBScript.dll
Fuente: Internet Explorer 1.0 y 5.5

• MSDN-Microsoft refuerza VBScript con expresiones regulares


• Sintaxis de expresión regular de MSDN (secuencias de comandos)
• expertos-exchange: uso de expresiones regulares en Visual Basic para aplicaciones y Visua l
Básico 6
• Cómo usar expresiones regulares (Regex) en Microsoft Excel tanto en la celda como en bucles en SO.
• regular-expressions.info/vbscript
• regular-expressions.info/vbscriptexample
• WIKI-Expresión regular

Código
Puede utilizar estas funciones para obtener resultados RegEx, concatenar todas las coincidencias (si hay más de 1) en 1
cadena y muestra el resultado en la celda de Excel.

Función pública getRegExResult (ByVal SourceString As String, Opcional ByVal RegExPattern As


Cadena = "\ d +", _
ByVal opcional isGlobalSearch como booleano = True, ByVal opcional isCaseSensitive como booleano
= Falso, delimitador ByVal opcional como cadena = ";") como cadena

RegExObject estático como objeto


Si RegExObject no es nada, entonces

https://translate.googleusercontent.com/translate_f 53/223
6/1/2021 Intitulado
Establecer RegExObject = createVBScriptRegExObject
Terminara si

getRegExResult = removeLeadingDelimiter (concatObjectItems (getRegExMatches (RegExObject,


SourceString, RegExPattern, isGlobalSearch, isCaseSensitive), Delimiter), Delimiter)

Función final

Función privada getRegExMatches (ByRef RegExObj como objeto, _


ByVal SourceString como cadena, ByVal RegExPattern como cadena, ByVal isGlobalSearch como
Booleano, ByVal isCaseSensitive como booleano) como objeto

Con RegExObj
.Global = isGlobalSearch
.IgnoreCase = Not (isCaseSensitive) 'es más fácil de usar usar un significado positivo
de argumento, como isCaseSensitive, que usar IgnoreCase negativo
.Patrón = RegExPattern
Establecer getRegExMatches = .Execute (SourceString)
Terminar con

Función final

Función privada concatObjectItems (ByRef Obj como objeto, ByVal DelimiterCustom opcional como
String = ";") como cadena
Atenuar objeto como variante
Para cada objeto en el objeto
concatObjectItems = concatObjectItems & DelimiterCustom & ObjElement.Value

https://riptutorial.com/ 47

Página 63

próximo
Función final

Función pública removeLeadingDelimiter (ByVal SourceString como cadena, ByVal Delimiter como
String) como cadena
If Left $ (SourceString, Len (Delimiter)) = Delimiter Then
removeLeadingDelimiter = Mid $ (SourceString, Len (Delimitador) + 1)
Terminara si
Función final

Función privada createVBScriptRegExObject () como objeto


Establecer createVBScriptRegExObject = CreateObject ("vbscript.RegExp") 'ej .:
createVBScriptRegExObject.Pattern
Función final

Objeto de sistema de archivos de secuencias de comandos

Establecer createScriptingFileSystemObject = CreateObject ("Scripting.FileSystemObject")

Herramientas> Referencias> Microsoft Scripting Runtime


DLL asociado: ScrRun.dll
Fuente: sistema operativo Windows

Acceso a archivos de MSDN con FileSystemObject

El modelo de objetos del sistema de archivos (FSO) proporciona una herramienta basada en objetos para trabajar con
carpetas y archivos. Le permite utilizar la sintaxis conocida de object.method con un rico conjunto de
propiedades, métodos y eventos para procesar carpetas y archivos. También puede emplear el
instrucciones y comandos tradicionales de Visual Basic.

El modelo FSO le brinda a su aplicación la capacidad de crear, modificar, mover y eliminar


carpetas, o para determinar si existen carpetas particulares y dónde existen. También le permite obtener
información sobre carpetas, como sus nombres y la fecha en que fueron creadas o por última vez
modificado.

Temas de MSDN-FileSystemObject : " ... explicar el concepto de FileSystemObject y cómo usarlo.


" exceltrick-FileSystemObject en VBA - Explicado
Scripting.FileSystemObject

https://translate.googleusercontent.com/translate_f 54/223
6/1/2021 Intitulado

Objeto Diccionario de secuencias de comandos

Establecer dict = CreateObject ("Scripting.Dictionary")

Herramientas> Referencias> Microsoft Scripting Runtime


DLL asociado: ScrRun.dll
Fuente: sistema operativo Windows

Objeto de scripting.Dictionary
Objeto MSDN-Dictionary

https://riptutorial.com/ 48

Página 64

Objeto de Internet Explorer

Establecer createInternetExplorerObject = CreateObject ("InternetExplorer.Application")

Herramientas> Referencias> Controles de Internet de Microsoft


DLL asociado: ieframe.dll
Fuente: navegador Internet Explorer

Objeto MSDN-InternetExplorer

Controla una instancia de Windows Internet Explorer mediante la automatización.

Miembros básicos de Internet Explorer Objec


El siguiente código debería presentar cómo funciona el objeto IE y cómo manipularlo a través de VBA. yo
recomiendo recorrerlo, de lo contrario, podría producirse un error durante varias navegaciones.

Sub IEGetToKnow ()
Atenuar IE como referencia de InternetExplorer a los controles de Internet de Microsoft
Establecer IE = New InternetExplorer

Con IE
.Visible = True 'Establece u obtiene un valor que indica si el objeto es visible o
oculto.

'Navegación
.Navigate2 "http://www.example.com" 'Navega el navegador a una ubicación que
no puede expresarse como una URL, como un PIDL para una entidad en el espacio de nombres de Windows Shell.
Debug.Print .Busy 'Obtiene un valor que indica si el objeto está involucrado en un
operación de navegación o descarga.
Debug.Print .ReadyState 'Obtiene el estado listo del objeto.
.Navigate2 "http://www.example.com/2"
.GoBack 'Navega hacia atrás un elemento en la lista del historial
.GoForward 'Avanza un elemento en la lista del historial.
.GoHome 'Navega a la página de inicio o de inicio actual.
.Stop 'Cancela una navegación o descarga pendiente y detiene los elementos dinámicos de la página, como
como sonidos de fondo y animaciones.
.Refresh 'Vuelve a cargar el archivo que se muestra actualmente en el objeto.

Debug.Print .Silent 'Establece u obtiene un valor que indica si el objeto puede


mostrar cuadros de diálogo.
Debug.Print .Type 'Obtiene el nombre del tipo de usuario del objeto de documento contenido.

Debug.Print .Top 'Establece u obtiene las coordenadas del borde superior del objeto.
Debug.Print .Left 'Establece u obtiene las coordenadas del borde izquierdo del objeto.
Debug.Print .Height 'Establece u obtiene la altura del objeto.
Debug.Print .Width 'Establece u obtiene el ancho del objeto.
Terminar con

IE.Quit 'cierra la ventana de la aplicación


End Sub

https://translate.googleusercontent.com/translate_f 55/223
6/1/2021 Intitulado

Raspado web

https://riptutorial.com/ 49

Página 65

Lo más común que se puede hacer con IE es extraer información de un sitio web o completar un
formulario del sitio web y enviar información. Veremos cómo hacerlo.

Dejenos considerar código fuente de example.com :

<! doctype html>


<html>
<cabeza>
<title> Dominio de ejemplo </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" />
<estilo ... </style>
</head>

<cuerpo>
<div>
<h1> Dominio de ejemplo </h1>
<p> Este dominio está establecido para ser utilizado para ejemplos ilustrativos en documentos.
Puedes usar esto
dominio en ejemplos sin coordinación previa o sin pedir permiso. </p>
<p> <a href="http://www.iana.org/domains/example"> Más información ... </a> </p>
</div>
</body>
</html>

Podemos usar código como el siguiente para obtener y configurar información:

Sub IEWebScrape1 ()
Atenuar IE como referencia de InternetExplorer a los controles de Internet de Microsoft
Establecer IE = New InternetExplorer

Con IE
.Visible = Verdadero
.Navigate2 "http://www.example.com"

'agregamos un bucle para asegurarnos de que el sitio web esté cargado y listo.
'No funciona de manera consistente. No se puede confiar en él.
Hacer mientras .Busy = True O .ReadyState <> READYSTATE_COMPLETE 'Equivalente = .ReadyState
<> 4
'DoEvents - vale la pena considerarlo. Conozca las implicaciones antes de usarlo.
Application.Wait (Now + TimeValue ("00:00:01")) 'Espere 1 segundo y vuelva a verificar.
Lazo

'Imprimir información en la ventana inmediata


Con .Document 'el código fuente HTML "debajo" de la página mostrada.
Detener 'VBE Stop. Continúe línea por línea para ver qué sucede.
Debug.Print .GetElementsByTagName ("título") (0) .innerHtml 'imprime "Dominio de ejemplo"
Debug.Print .GetElementsByTagName ("h1") (0) .innerHtml 'imprime "Dominio de ejemplo"
Debug.Print .GetElementsByTagName ("p") (0) .innerHtml 'imprime "Este dominio es
establecido..."
Debug.Print .GetElementsByTagName ("p") (1) .innerHtml 'imprime "<a
href = "http://www.iana.org/domains/example"> Más información ... </a> "
Debug.Print .GetElementsByTagName ("p") (1) .innerText 'imprime "Más información ..."
Debug.Print .GetElementsByTagName ("a") (0) .innerText 'imprime "Más información ..."

Podemos cambiar el sitio web que se muestra localmente. No se preocupe por romper el sitio.
.GetElementsByTagName ("título") (0) .innerHtml = "Psst, raspado ..."
.GetElementsByTagName ("h1") (0) .innerHtml = "Déjame probar algo sospechoso". 'Tienes

https://riptutorial.com/ 50

Página 66

https://translate.googleusercontent.com/translate_f 56/223
6/1/2021 Intitulado

acaba de cambiar el HTML local del sitio.


.GetElementsByTagName ("p") (0) .innerHtml = "Lorem ipsum ........... El fin"
.GetElementsByTagName ("a") (0) .innerText = "iana.org"
Terminar con '.document

.Quit 'cerrar la ventana de la aplicación


Terminar con 'ie

End Sub

Que esta pasando? El jugador clave aquí es el .Document , que es el código fuente HTML. Podemos
aplicamos algunas consultas para obtener las Colecciones o el Objeto que queremos.
Por ejemplo, IE.Document.GetElementsByTagName ("título") (0) .innerHtml . GetElementsByTagName
devuelve una colección de elementos HTML, que tienen la etiqueta " título ". Solo 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 (una cadena), no el objeto elemento en sí. Entonces especificamos la propiedad que
desear.

Hacer clic
Para seguir un enlace en un sitio, podemos utilizar varios métodos:

Sub IEGoToPlaces ()
Atenuar IE como referencia de InternetExplorer a los controles de Internet de Microsoft
Establecer IE = New InternetExplorer

Con IE
.Visible = Verdadero
.Navigate2 "http://www.example.com"
Detener 'VBE Stop. Continúe línea por línea para ver qué sucede.

'Hacer clic
.Document.GetElementsByTagName ("a") (0) .Haga clic en
Detener 'VBE Stop.

'Devolver
.Regresa
Detener 'VBE Stop.

'Navegue utilizando el atributo href en la etiqueta <a> o "enlace"


.Navigate2 .Document.GetElementsByTagName ("a") (0) .href
Detener 'VBE Stop.

.Quit 'cerrar la ventana de la aplicación


Terminar con
End Sub

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 otro
Biblioteca, es decir, biblioteca de objetos HTML de Microsoft . Más sobre esto en otro ejemplo.

https://riptutorial.com/ 51

Página 67

IE Principales problemas
El problema principal con IE es verificar que la página haya terminado de cargarse y esté lista para interactuar con ella.
El bucle Do While ... ayuda, pero no es confiable.

Además, usar IE solo para raspar contenido HTML es OVERKILL. ¿Por qué? Porque el navegador está diseñado para
navegación, es decir, mostrar la página web con todos los CSS, JavaScripts, imágenes, ventanas emergentes, etc.

https://translate.googleusercontent.com/translate_f 57/223
6/1/2021 Intitulado
Solo necesita los datos brutos, considere un enfoque diferente. Por ejemplo, usandoXML HTTPRequest . Más sobre
esto en otro ejemplo.

Lea la automatización o el uso de otras bibliotecas de aplicaciones en línea:


https://riptutorial.com/vba/topic/8916/automation-or-using-other-applications-libraries

https://riptutorial.com/ 52

Página 68

Capítulo 7: Colecciones
Observaciones
Una colección es un objeto contenedor que se incluye en el tiempo de ejecución de VBA. No hay referencias adicionales
necesario para poder utilizarlo. Una colección se puede utilizar para almacenar elementos de cualquier tipo de datos y permite
recuperación mediante el índice ordinal del elemento o mediante el uso de una clave única opcional.

Comparación de funciones con matrices y diccionarios

Colección Formación Diccionario

Se puede cambiar de tamaño si A veces 1 si


https://translate.googleusercontent.com/translate_f 58/223
6/1/2021 Intitulado

Los artículos están ordenados si si Sí 2

Los elementos están fuertemente mecanografiados


No si No

Los elementos se pueden recuperar por ordinalsi si No

Se pueden insertar nuevos elementos en


si No No
ordinal

Iterar todo
Cómo determinar si existe un artículo Iterar todos los elementos Iterar todos los elementos
artículos

Los artículos se pueden recuperar con una llavesi No si

Las claves distinguen entre mayúsculas y minúsculas


No N/A Opcional 3

Cómo determinar si existe una clave Controlador de errores N/A .Existe función

.Eliminar todo
Iterar y
Quitar todos los elementos Borrar , ReDim
.Eliminar función

1 Solo se puede cambiar el tamaño de las matrices dinámicas y solo la última dimensión de las matrices multidimensionales.

2 Se ordenan las .Keys y .Items subyacentes .

3 Determinado por la propiedad .CompareMode .

Ejemplos

Agregar elementos a una colección

https://riptutorial.com/ 53

Página 69

Los elementos se agregan a una colección llamando a su método .Add :

Sintaxis:

.Añadir (elemento, [clave], [antes, después])

Descripción de parámetros

El artículo para almacenar en la Colección . Esto puede ser esencialmente cualquier valor que
articulo se puede asignar una variable, incluidos tipos primitivos, matrices, objetos y
Nada .

Opcional. Una cadena que sirve como identificador único para recuperar elementos del
Colección .
Si la clave especificada ya existe en la colección , resultará en una
llave
Error 457 en tiempo de ejecución: "Esta clave ya está asociada con un elemento de este
colección".

Opcional. Una clave existente ( valor de cadena ) o índice (valor numérico) para insertar el
artículo antes en la Colección . Si se da un valor, el parámetro after debe ser
vacío o un error en tiempo de ejecución 5: se producirá un "argumento o llamada de procedimiento no válida". Si un
antes de Se pasa una clave de cadena que no existe en la colección , un error de tiempo de ejecución 5:
Se producirá un "argumento o llamada de procedimiento no válida". Si se pasa un índice numérico que
no existe en la colección , un error en tiempo de ejecución 9: "Subíndice fuera de rango"
resultará.

https://translate.googleusercontent.com/translate_f 59/223
6/1/2021 Intitulado
Opcional. Una clave existente ( valor de cadena ) o índice (valor numérico) para insertar el
después artículo después en la colección . Si se da un valor, el parámetro before debe ser
vacío. Los errores generados son idénticos al parámetro anterior .

Notas:

• Las claves no distinguen entre mayúsculas y minúsculas. .Añadir "Bar", "Foo" y .Añadir "Baz", "foo" dará como resultado una clave
colisión.

• Si no se proporciona ninguno de los parámetros opcionales antes o después , el elemento se agregará después del
último elemento de la colección .

• Las inserciones realizadas especificando un parámetro antes o después alterarán los índices numéricos de
miembros existentes para que coincidan con su nueva posición. Esto significa que se debe tener cuidado cuando
haciendo inserciones en bucles utilizando índices numéricos.

Uso de muestra:

Subejemplo público ()
Dim foo como nueva colección

Con foo
.Agrega uno" 'No hay llave. Este elemento solo se puede recuperar por índice.

https://riptutorial.com/ 54

Página 70

.Añadir "Dos", "Segunda" 'Clave dada. Puede recuperarse por clave o índice.
.Añadir "Tres", 1 'Insertado al inicio de la colección.
.Añadir "Cuatro",,, 1 'Insertado en el índice 2.
Terminar con

Miembro atenuado como variante


Para cada miembro en foo
Debug.Print miembro 'Imprime "Tres, Cuatro, Uno, Dos"
próximo
End Sub

Eliminar elementos de una colección

Los elementos se eliminan de una colección llamando a su método .Remove :

Sintaxis:

.Remove (índice)

Descripción de parámetros

El elemento que se eliminará de la colección . Si el valor pasado es de tipo numérico o


Variante con
subtipo numérico, se interpretará como índice numérico. Si el
El valor pasado es una Cadena o Variante que contiene una cadena, se interpretará como
índice la clave. Si se pasa una clave de cadena que no existe en la colección , un Run-
error de tiempo 5: se producirá un "argumento o llamada de procedimiento no válida". Si un índice numérico es
pasado que no existe en la colección , un error de tiempo de ejecución 9: "Subíndice
fuera de rango "resultará.

Notas:

• Eliminar un elemento de una colección cambiará los índices numéricos de todos los elementos posteriores
en la colección . Para los bucles que usan índices numéricos y eliminan elementos, deben ejecutarse
hacia atrás ( Paso -1 ) para evitar excepciones de subíndices y elementos omitidos.
• Los elementos generalmente no deben eliminarse de una colección desde el interior de un bucle For Each, ya que

https://translate.googleusercontent.com/translate_f 60/223
6/1/2021 Intitulado
puede dar resultados impredecibles.

Uso de muestra:

Subejemplo público ()
Dim foo como nueva colección

Con foo
.Agrega uno"
.Añadir "Dos", "Segundo"
.Añadir "Tres"
.Añadir "Cuatro"
Terminar con

foo Quitar 1 'Elimina el primer elemento.

https://riptutorial.com/ 55

Página 71

foo.Remove "Second" 'Elimina el elemento con la tecla "Second".


foo.Remove foo.Count 'Elimina el último elemento.

Miembro atenuado como variante


Para cada miembro en foo
Debug.Print miembro 'imprime "tres"
próximo
End Sub

Obtener el recuento de elementos de una colección

El número de elementos de una colección se puede obtener llamando a su función .Count :

Sintaxis:

.Contar()

Uso de muestra:

Subejemplo público ()
Dim foo como nueva colección

Con foo
.Agrega uno"
.Añadir "Dos"
.Añadir "Tres"
.Añadir "Cuatro"
Terminar con

Debug.Print foo.Count 'Impresiones 4


End Sub

Recuperar elementos de una colección

Los elementos se pueden recuperar de una colección llamando a la función .Item .

Sintaxis:

.Artículo (índice)

Descripción de parámetros

El elemento a recuperar de la colección . Si el valor pasado es de tipo numérico o


Variante con
subtipo numérico, se interpretará como índice numérico. Si el
El valor pasado es una Cadena o Variante que contiene una cadena, se interpretará como
índice la clave. Si se pasa una clave de cadena que no existe en la colección , un Run-
https://translate.googleusercontent.com/translate_f 61/223
6/1/2021 Intitulado
error de tiempo 5: se producirá un "argumento o llamada de procedimiento no válida". Si un índice numérico es
pasado que no existe en la colección , un error de tiempo de ejecución 9: "Subíndice
fuera de rango "resultará.

https://riptutorial.com/ 56

Página 72

Notas:

• .Item es
el miembro predeterminado de Collection . Esto permite flexibilidad en la sintaxis como se demuestra en
el uso de muestra a continuación.
• Los índices numéricos están basados en 1.
• Las claves no distinguen entre mayúsculas y minúsculas. .Item ("Foo") y .Item ("foo") se refieren a la misma clave.
• El parámetro de índice no se convierte implícitamente en un número de una cadena o viceversa. Es
Es totalmente posible que .Item (1) y .Item ("1") se refieran a diferentes elementos de la Colección .

Uso de muestra (índices):

Subejemplo público ()
Dim foo como nueva colección

Con foo
.Agrega uno"
.Añadir "Dos"
.Añadir "Tres"
.Añadir "Cuatro"
Terminar con

Dim index tan largo


Para índice = 1 Para foo.Count
Debug.Print foo.Item (index) 'Imprime uno, dos, tres, cuatro
próximo
End Sub

Uso de la muestra (claves):

Subejemplo público ()
Dim keys () como cadena
keys = Split ("Foo, Bar, Baz", ",")
Dim valores () como cadena
valores = Dividir ("Uno, Dos, Tres", ",")

Dim foo como nueva colección


Dim index tan largo
Para index = LBound (valores) To UBound (valores)
foo.Añadir valores (índice), claves (índice)
próximo

Debug.Print foo.Item ("Bar") 'Imprime "Dos"


End Sub

Ejemplo de uso (sintaxis alternativa):

Subejemplo público ()
Dim foo como nueva colección

Con foo
.Añadir "Uno", "Foo".
.Añadir "Dos", "Barra"
.Añadir "Tres", "Baz"

https://riptutorial.com/ 57

https://translate.googleusercontent.com/translate_f 62/223
6/1/2021 Intitulado
Página 73

Terminar con

'Todas las líneas de abajo imprimen "Dos"


Debug.Print foo.Item ("Bar") 'Sintaxis de llamada explícita.
Debug.Print foo ("Barra") 'Sintaxis de llamada de miembro predeterminada.
Debug.Print foo! Bar 'Bang sintaxis.
End Sub

Tenga en cuenta que la sintaxis bang ( ! ) Está permitida porque .Item es el miembro predeterminado y puede tomar un solo
Argumento de cadena . La utilidad de esta sintaxis es cuestionable.

Determinar si existe una clave o un elemento en una colección

Llaves
A diferencia de un Scripting.Dictionary , una colección no tiene un método para determinar si una clave dada
existe o una forma de recuperar claves que están presentes en la Colección . El único método para determinar si
una clave está presente es usar el controlador de errores:

Función pública KeyExistsInCollection (clave ByVal como cadena, _


ByRef contenedor como colección) como booleano
Con err
Si el contenedor no es nada, entonces. Levante 91
En caso de error, reanudar siguiente
Dim temp como variante
temp = container.Item (clave)
En caso de error, vaya a 0

Si .Number = 0 Entonces
KeyExistsInCollection = True
ElseIf .Number <> 5 Entonces
.Raise .Number
Terminara si
Terminar con
Función final

Artículos
La única forma de determinar si un elemento está contenido en una colección es iterar sobre la colección
hasta que se localice el artículo. Tenga en cuenta que debido a que una colección puede contener primitivas u objetos,
se necesita un manejo adicional para evitar errores en tiempo de ejecución durante las comparaciones:

Función pública ItemExistsInCollection (destino ByRef como variante, _


ByRef contenedor como colección) como booleano
Candidato tenue como variante
Dim encontrado como booleano

Para cada candidato en contenedor


Seleccionar caso verdadero
Caso IsObject (candidato) e IsObject (destino)
encontrado = candidato es objetivo
Case IsObject (candidato), IsObject (destino)

https://riptutorial.com/ 58

Página 74

encontrado = Falso
Caso otro
encontrado = (candidato = objetivo)
Finalizar Seleccionar
Si se encuentra entonces
ItemExistsInCollection = True
Función de salida
Terminara si
próximo

https://translate.googleusercontent.com/translate_f 63/223
6/1/2021 Intitulado
Función final

Borrar todos los elementos de una colección

La forma más sencilla de eliminar todos los elementos de una colección es simplemente reemplazarla por una nueva.
Recolección y deje que el anterior salga de alcance:

Subejemplo público ()
Dim foo como nueva colección

Con foo
.Agrega uno"
.Añadir "Dos"
.Añadir "Tres"
Terminar con

Debug.Print foo.Count 'Impresiones 3


Set foo = Nueva colección
Debug.Print foo.Count 'Imprime 0
End Sub

Sin embargo, si hay varias referencias a la Colección que se tiene, este método solo le dará una
Colección vacía para la variable asignada .

Subejemplo público ()
Dim foo como nueva colección
Dim bar como colección

Con foo
.Agrega uno"
.Añadir "Dos"
.Añadir "Tres"
Terminar con

Establecer barra = foo


Set foo = Nueva colección

Debug.Print foo.Count 'Imprime 0


Debug.Print bar.Count 'Impresiones 3
End Sub

En este caso, la forma más fácil de borrar el contenido es recorrer el número de elementos en el
Recolectar y eliminar repetidamente el elemento más bajo:

Public Sub ClearCollection (contenedor ByRef como colección)


Dim index tan largo

https://riptutorial.com/ 59

Página 75

Para índice = 1 Al contenedor.


contenedor Quitar 1
próximo
End Sub

Leer colecciones en línea: https://riptutorial.com/vba/topic/5838/collections

https://translate.googleusercontent.com/translate_f 64/223
6/1/2021 Intitulado

https://riptutorial.com/ 60

Página 76

Capítulo 8: Comentarios
Observaciones
Bloques de comentarios

Si necesita comentar o descomentar varias líneas a la vez, puede usar la barra de herramientas de edición del IDE
botones:

Bloque de comentarios : agrega un solo apóstrofe al comienzo de todas las líneas seleccionadas

Bloque de eliminación de comentarios : elimina el primer apóstrofo del inicio de todas las líneas seleccionadas

Comentarios de varias líneas Muchos otros idiomas admiten comentarios de bloques de varias líneas, pero solo VBA
permite comentarios de una sola línea.

Ejemplos

https://translate.googleusercontent.com/translate_f 65/223
6/1/2021 Intitulado
Comentarios del apóstrofe
Un comentario se marca con un apóstrofo ( ' ) y se ignora cuando se ejecuta el código. Ayuda de comentarios
Explique su código a futuros lectores, incluido usted mismo.

Dado que todas las líneas que comienzan con un comentario se ignoran, también se pueden usar para evitar que el código
ejecutando (mientras 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).

Documentación en línea secundaria ()


'Los comentarios comienzan con "'"

'Se pueden colocar antes de una línea de código, lo que evita que la línea se ejecute
'Debug.Print "Hola mundo"

'También se pueden colocar después de una declaración


'La declaración todavía se ejecuta, hasta que el compilador llega al comentario
Debug.Print "Hello World" 'Imprime un mensaje de bienvenida

Los comentarios pueden tener 0 sangría ...


'... o tanto como sea necesario

'' '' Los comentarios pueden contener varios apóstrofos '' ''

'Los comentarios pueden abarcar líneas (utilizando continuaciones de línea) _


pero esto puede dificultar la lectura del código

'Si necesita tener comentarios de varias líneas, a menudo es más fácil

https://riptutorial.com/ 61

Página 77

'usa un apóstrofe en cada línea

'La sintaxis de instrucción continua (:) se trata como parte del comentario, por lo que
'no es posible colocar una declaración ejecutable después de un comentario
'Esto no se ejecutará: Debug.Print "Hello World"
End Sub

Los comentarios pueden aparecer dentro o fuera de un procedimiento

Comentarios REM

Sub RemComments ()
Los comentarios rem comienzan con "Rem" (VBA cambiará cualquier carcasa alternativa a "Rem")
Rem es una abreviatura de Remark y similar a la sintaxis de DOS
Rem es un enfoque heredado para agregar comentarios, y se deben preferir los apóstrofos

Los comentarios rem NO PUEDEN aparecer después de una declaración, use la sintaxis de apóstrofo en su lugar
Rem A menos que estén precedidos por el token separador de instrucciones
Debug.Print "Hello World": Rem imprime un mensaje de bienvenida
Debug.Print "Hello World" 'Imprime un mensaje de bienvenida

'Rem no puede ser seguido inmediatamente por los siguientes caracteres "!, @, #, $,%, &"
Mientras que la sintaxis del apóstrofo puede ir seguida de cualquier carácter imprimible.

End Sub

Los comentarios rem pueden aparecer dentro o fuera de un procedimiento

Leer comentarios en línea: https://riptutorial.com/vba/topic/2059/comments

https://translate.googleusercontent.com/translate_f 66/223
6/1/2021 Intitulado

https://riptutorial.com/ 62

Página 78

Capítulo 9: Concatenar cadenas


Observaciones
Las cadenas se pueden concatenar o unir mediante uno o más operadores de concatenación & .

Las matrices de cadenas también se pueden concatenar mediante la función Unir y proporcionar una cadena (que puede
ser de longitud cero) que se utilizará entre cada elemento de la matriz.

Ejemplos

Concatenar cadenas usando el operador &

Const string1 como String = "foo"


Const string2 As String = "bar"
Const string3 As String = "fizz"
Dim concatenatedString como cadena

'Concatenar dos cadenas


concatenatedString = cadena1 y cadena2
'concatenatedString = "foobar"

'Concatenar tres cadenas


concatenatedString = cadena1 y cadena2 y cadena3
'concatenatedString = "foobarfizz"

Concatenar una matriz de cadenas usando la función Unir

'Declarar y asignar una matriz de cadenas


Dim widgetNames (2) como cadena
widgetNames (0) = "foo"
widgetNames (1) = "barra"
widgetNames (2) = "efervescencia"

'Concatenar con Join y separar cada elemento con una cadena de 3 caracteres
concatenatedString = VBA.Strings.Join (widgetNames, ">")
'concatenatedString = "foo> bar> fizz"

'Concatenar con Join y separar cada elemento con una cadena de ancho cero
concatenatedString = VBA.Strings.Join (widgetNames, vbNullString)
'concatenatedString = "foobarfizz"

Leer Concatenación de cadenas en línea: https://riptutorial.com/vba/topic/3580/concatenating-strings

https://translate.googleusercontent.com/translate_f 67/223
6/1/2021 Intitulado

https://riptutorial.com/ 63

Página 79

Capítulo 10: Compilación condicional


Ejemplos

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
#Si controlar qué bloques de código se compilan y ejecutan.

#Const DEBUGMODE = 1

#Si DEBUGMODE Entonces


Const filepath As String = "C: \ Users \ UserName \ Path \ To \ File.txt"
#Más
Ruta de archivo constante como cadena = "\\ servidor \ recurso compartido \ ruta \ a \ archivo.txt"
#Terminara si

Esto da como resultado que el valor de la ruta de archivo se establezca en "C: \ Users \ UserName \ Path \ To \ File.txt" . Eliminando
la línea #Const , o cambiarla a #Const DEBUGMODE = 0 daría como resultado que la ruta del archivo se establezca en
"\\ servidor \ recurso compartido \ ruta \ a \ archivo.txt" .

#Const alcance

La directiva #Const solo es efectiva para un solo archivo de código (módulo o clase). Debe ser declarado 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. Esta
Aparecerá el cuadro de diálogo de propiedades del proyecto donde ingresaremos la declaración constante. En el
En el cuadro “Argumentos de compilación condicional”, escriba [constName] = [value] . Puede ingresar más de
1 constante separándolos con dos puntos, como [constName1] = [value1]: [constName2] = [value2]
.

https://riptutorial.com/ 64

https://translate.googleusercontent.com/translate_f 68/223
6/1/2021 Intitulado

Página 80

Constantes predefinidas

Algunas constantes de compilación ya están predefinidas. Cuales existen dependerán del bitness
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 64 bits de Office.

Constante de 16 bits 32 bits 64 bits

Vba6 Falso Si Vba6 Falso

Vba7 Falso si Vba7 es verdadero

Win16 Cierto Falso Falso

Win32 Falso verdadero Cierto

Win64 Falso falso Cierto

Mac Falso si Mac Si Mac

Tenga en cuenta que Win64 / Win32 se refiere a la versión de Office, no a la versión de Windows. Por ejemplo Win32 =
VERDADERO en Office de 32 bits, incluso si el sistema operativo es una versión de Windows de 64 bits.

Uso de Declare Importaciones que funcionan en todas las versiones de Office

#Si Vba7 Entonces


'Es importante verificar primero Win64,
'porque Win32 también devolverá verdadero cuando Win64 lo haga.

#Si Win64 Entonces

https://riptutorial.com/ sesenta y cinco

Página 81

Declare la función PtrSafe GetFoo64 Lib "exampleLib32" () como LongLong


#Más
Declare la función PtrSafe GetFoo Lib "exampleLib32" () As Long
#Terminara si
#Más
'Debe ser Vba6, la palabra clave PtrSafe no existía en ese entonces,
', por lo que debemos declarar las importaciones de Win32 de manera un poco diferente a la anterior.

https://translate.googleusercontent.com/translate_f 69/223
6/1/2021 Intitulado

#Si Win32 entonces


Declarar función GetFoo Lib "exampleLib32" () As Long
#Más
Declare la función GetFoo Lib "exampleLib" () como entero
#Terminara si
#Terminara si

Esto se puede simplificar un poco según las versiones de Office que necesite admitir. por
Por ejemplo, todavía no hay mucha gente compatible con las versiones de Office de 16 bits. La última versión de 16 bi t
office fue la versión 4.3, lanzada en 1994 , por lo que la siguiente declaración es suficiente para casi todos
casos modernos (incluido Office 2007).

#Si Vba7 Entonces


'Es importante verificar primero Win64,
'porque Win32 también devolverá verdadero cuando Win64 lo haga.

#Si Win64 Entonces


Declare la función PtrSafe GetFoo64 Lib "exampleLib32" () como LongLong
#Más
Declare la función PtrSafe GetFoo Lib "exampleLib32" () As Long
#Terminara si
#Más
'Debe ser Vba6. No admitimos Office de 16 bits, por lo que debe ser Win32.

Declarar función GetFoo Lib "exampleLib32" () As Long


#Terminara si

Si no tiene que admitir nada anterior a Office 2010, esta declaración funciona bien.

'Solo tenemos instalaciones de 2010, por lo que ya sabemos que tenemos Vba7.

#Si Win64 Entonces


Declare la función PtrSafe GetFoo64 Lib "exampleLib32" () como LongLong
#Más
Declare la función PtrSafe GetFoo Lib "exampleLib32" () As Long
#Terminara si

Lea la compilación condicional en línea: https://riptutorial.com/vba/topic/3364/conditional-compilation

https://riptutorial.com/ 66

Página 82

Capítulo 11: Conversión de otros tipos a cadenas


Observaciones
VBA convertirá implícitamente algunos tipos en cadenas según sea necesario y sin ningún trabajo adicional en el
parte del programador, pero VBA también proporciona una serie de funciones explícitas de conversión de cadenas,
y también puedes escribir el tuyo propio.

Tres de las funciones más utilizadas son CStr , Format y StrConv .

Ejemplos

https://translate.googleusercontent.com/translate_f 70/223
6/1/2021 Intitulado
Utilice CStr para convertir un tipo numérico en una cadena
Const zipCode As Long = 10012
Dim zipCodeText como cadena
'Convierta el número zipCode en una cadena de caracteres de dígitos
zipCodeText = CStr (código postal)
'zipCodeText = "10012"

Utilice Formato para convertir y formatear un tipo numérico como una cadena

Const zipCode Siempre que = 10012


Dim zeroPaddedNumber como cadena
zeroPaddedZipCode = Formato (zipCode, "00000000")
'zeroPaddedNumber = "00010012"

Utilice StrConv para convertir una matriz de bytes de caracteres de un solo byte en una cadena

'Declare una matriz de bytes, asigne códigos de caracteres de un solo byte y convierta a una cadena
Dim singleByteChars (4) Como Byte
singleByteChars (0) = 72
singleByteChars (1) = 101
singleByteChars (2) = 108
singleByteChars (3) = 108
singleByteChars (4) = 111
Dim stringFromSingleByteChars como cadena
stringFromSingleByteChars = StrConv (singleByteChars, vbUnicode)
'stringFromSingleByteChars = "Hola"

Convierta implícitamente una matriz de bytes de caracteres de varios bytes en una cadena

'Declare una matriz de bytes, asigne códigos de caracteres multibyte y convierta a una cadena
Dim multiByteChars (9) como byte
multiByteChars (0) = 87
multiByteChars (1) = 0
multiByteChars (2) = 111
multiByteChars (3) = 0

https://riptutorial.com/ 67

Página 83

multiByteChars (4) = 114


multiByteChars (5) = 0
multiByteChars (6) = 108
multiByteChars (7) = 0
multiByteChars (8) = 100
multiByteChars (9) = 0

Dim stringFromMultiByteChars como cadena


stringFromMultiByteChars = multiByteChars
'stringFromMultiByteChars = "Mundo"

Leer Conversión de otros tipos a cadenas en línea: https://riptutorial.com/vba/topic/3467/converting-


otros-tipos-a-cadenas

https://translate.googleusercontent.com/translate_f 71/223
6/1/2021 Intitulado

https://riptutorial.com/ 68

Página 84

Capítulo 12: Copiar, devolver y pasar


matrices
Ejemplos

Copiar matrices

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

Fuente de atenuación (0 a 2) siempre que


Destino atenuadoLong () Tan Long
Destino atenuado Doble () como doble

destinationLong = source 'copia el contenido de la fuente en destinationLong


destinationDouble = source 'no se compila

La matriz de origen puede ser fija o dinámica, pero la matriz de destino debe ser dinámica. Tratando de
copiar a una matriz fija arrojará 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 a los mismos que los de la fuente
formación.

Fuente atenuada () siempre que


Fuente ReDim (0 a 2)

Dim fijo (0 a 2) siempre que


Dim dynamic () tan largo

fijo = fuente 'no se compila


dynamic = source 'se compila

Dim dynamic2 () tan largo


ReDim dynamic2 (0 a 6, 3 a 99)

https://translate.googleusercontent.com/translate_f 72/223
6/1/2021 Intitulado

dynamic2 = source 'dynamic2 ahora tiene dimensión (0 a 2)

Una vez que se realiza la copia, las dos matrices se separan en la memoria, es decir, las dos variables no se
referencias a los mismos datos subyacentes, por lo que los cambios realizados en una matriz no aparecen en la otra.

Fuente atenuada (0 a 2) siempre que


Destino atenuado () tan largo

fuente (0) = 3
fuente (1) = 1
fuente (2) = 4

destino = fuente
destino (0) = 2

Fuente de Debug.Print (0); fuente (1); fuente (2) 'salidas: 3 1 4

https://riptutorial.com/ 69

Página 85

Debug.Print destino (0); destino (1); destino (2) 'salidas: 2 1 4

Copiar matrices de objetos


Con matrices de objetos , se copian las referencias a esos objetos, no los objetos en sí. Si un
se realiza un cambio en un objeto en una matriz, también parecerá que se ha cambiado en la otra matriz;
ambos hacen referencia al mismo objeto. Sin embargo, configurar un elemento en un objeto diferente en una
array no lo establecerá en ese objeto el otro array.

Fuente atenuada (0 a 2) como rango


Destino atenuado () como rango

Establecer fuente (0) = Rango ("A1"): fuente (0) .Valor = 3


Establecer fuente (1) = Rango ("A2"): fuente (1) .Valor = 1
Establecer fuente (2) = Rango ("A3"): fuente (2) .Valor = 4

destino = fuente

Establecer destino (0) = La referencia de rango ("A4") 'cambió en el destino pero no en la fuente

destino (0) .Value = 2 'afecta a un objeto solo en destino


destino (1) .Valor = 5 'afecta a un objeto tanto en origen como en destino

Fuente de Debug.Print (0); fuente (1); fuente (2) 'salidas 3 5 4


Debug.Print destino (0); destino (1); destino (2) 'salidas 2 5 4

Variantes que contienen una matriz


También puede copiar una matriz en y desde una variable variante. Al copiar de una variante, debe
contener una matriz del mismo tipo que la matriz receptora, de lo contrario arrojará una "Falta de coincidencia de tipos"
Error de tiempo de ejecución.

Dim var como variante


Fuente atenuada (0 a 2) como rango
Destino atenuado () como rango

var = fuente
destino = var

var = 5
destino = var 'arroja un error de tiempo de ejecución

Devolución de matrices de funciones

https://translate.googleusercontent.com/translate_f 73/223
6/1/2021 Intitulado
Una función en un módulo normal (pero no un módulo de clase) puede devolver una matriz poniendo () después de la
tipo de datos.

Función arrayOfPiDigits () As Long ()


Dim outputArray (0 a 2) tan largo

outputArray (0) = 3

https://riptutorial.com/ 70

Página 86

outputArray (1) = 1
outputArray (2) = 4

arrayOfPiDigits = outputArray
Función final

El resultado de la función se puede colocar en una matriz dinámica del mismo tipo o variante. los
También se puede acceder directamente a los elementos utilizando un segundo conjunto de corchetes, sin embargo, esto llamará
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 ()

Destino atenuado () tan largo


Dim var como variante

destino = arrayOfPiDigits ()
var = arrayOfPiDigits

Destino de debug.Print (0) 'salidas 3


Debug.Print var (1) 'salidas 1
Debug.Print arrayOfPiDigits () (2) 'salidas 4

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. Así que si
la función devuelve el contenido de una matriz estática, sus datos no pueden ser cambiados por la llamada
procedimiento.

Salida de una matriz a través de un argumento de salida


Normalmente es una buena práctica de codificación que los argumentos de un procedimiento sean entradas y salidas a través del
valor de retorno. Sin embargo, las limitaciones de VBA a veces hacen necesario que un procedimiento
datos de salida a través de un argumento ByRef .

Salida a una matriz fija

Sub threePiDigits (destino ByRef () tan largo)


destino (0) = 3
destino (1) = 1
destino (2) = 4
End Sub

Sub printPiDigits ()
Dim dígitos (0 a 2) tan largos

dígitos de threePiDigits
Debug.Print dígitos (0); dígitos (1); dígitos (2) 'salidas 3 1 4
End Sub

https://riptutorial.com/ 71

https://translate.googleusercontent.com/translate_f 74/223
6/1/2021 Intitulado

Página 87

Salida de una matriz desde un método de clase


Un argumento de salida también se puede usar para generar una matriz de un método / procedimiento en una clase
módulo

'Módulo de clase' MathConstants '


Sub threePiDigits (destino ByRef () tan largo)
Destino ReDim (0 a 2)

destino (0) = 3
destino (1) = 1
destino (2) = 4
End Sub

'Módulo de código estándar


Sub printPiDigits ()
Dim dígitos () tan largos
Dim mathConsts como nuevas MathConstants

mathConsts.threePiDigits dígitos
Debug.Print dígitos (0); dígitos (1); dígitos (2) 'salidas 3 1 4
End Sub

Pasar matrices a procedimientos

Las matrices se pueden pasar a los procedimientos poniendo () después del nombre de la variable de matriz.

Función countElements (ByRef arr () As Double) As Long


countElements = UBound (arr) - LBound (arr) + 1
Función final

Las matrices deben pasarse por referencia. Si no se especifica ningún mecanismo de paso, por ejemplo, myFunction (arr ()) ,
entonces VBA asumirá ByRef de forma predeterminada, sin embargo, es una buena práctica de codificación hacerlo explícito.
Intentar pasar una matriz por valor, por ejemplo, myFunction (ByVal arr ()) resultará en un "argumento de matriz
debe ser un error de compilación ByRef "(o un error de compilación" Error de sintaxis "si la comprobación automática de sintaxis no está
marcado en las opciones de VBE).

Pasar por referencia significa que cualquier cambio en la matriz se conservará en la llamada
proceder.

Sub testArrayPassing ()
Fuente de atenuación (0 a 1) siempre que
fuente (0) = 3
fuente (1) = 1

Debug.Print doubleAndSum (fuente) 'salidas 8


Fuente de Debug.Print (0); fuente (1) 'salidas 6 2
End Sub

Función doubleAndSum (ByRef arr () As Long)


arr (0) = arr (0) * 2
arr (1) = arr (1) * 2
doubleAndSum = arr (0) + arr (1)

https://riptutorial.com/ 72

Página 88

Función final

Si desea evitar cambiar la matriz original, tenga cuidado de escribir la función para que
no cambia ningún elemento.

https://translate.googleusercontent.com/translate_f 75/223
6/1/2021 Intitulado
Función doubleAndSum (ByRef arr () As Long)
doubleAndSum = arr (0) * 2 + arr (1) * 2
Función final

Alternativamente, cree una copia de trabajo de la matriz y trabaje con la copia.

Función doubleAndSum (ByRef arr () As Long)


Dim copyOfArr () tan largo
copyOfArr = arr

copyOfArr (0) = copyOfArr (0) * 2


copyOfArr (1) = copyOfArr (1) * 2

doubleAndSum = copyOfArr (0) + copyOfArr (1)


Función final

Lea Copiar, devolver y pasar matrices en línea: https://riptutorial.com/vba/topic/9069/copying--


matrices de retorno y paso

https://riptutorial.com/ 73

Página 89

Capítulo 13: CreateObject frente a GetObject


Observaciones
En su forma más simple, CreateObject crea una instancia de un objeto mientras que GetObject obtiene una existente
instancia de un objeto. Determinar si un objeto se puede crear u obtener dependerá de su
Propiedad de instancia . Algunos objetos son SingleUse (por ejemplo, WMI) y no se pueden crear si ya
existe. Otros objetos (por ejemplo, Excel) son MultiUse y permiten que se ejecuten varias instancias a la vez. Si una
instancia de un objeto aún no existe e intenta GetObject , recibirá el
siguiente mensaje capturable: Error en tiempo de ejecución '429': el componente ActiveX no puede crear el objeto .

GetObject requiere que esté presente al menos uno de estos dos parámetros opcionales:
https://translate.googleusercontent.com/translate_f 76/223
6/1/2021 Intitulado

1. Pathname - Variant (String): La ruta completa, incluido el nombre de archivo, del archivo que contiene el
objeto. Este parámetro es opcional, pero se requiere Class si se omite Pathname .
2. Clase - Variante (Cadena): Una cadena que representa la definición formal (Aplicación y
ObjectType) del objeto. Se requiere la clase si se omite Pathname .

CreateObject tiene un parámetro obligatorio y un parámetro opcional:

1. Clase - Variante (Cadena): Una cadena que representa la definición formal (Aplicación y
ObjectType) del objeto. La clase es un parámetro obligatorio.
2. Servername - Variant (String): El nombre de la computadora remota en la que se ubicará el objeto.
creado. Si se omite, el objeto se creará en la máquina local.

La clase siempre consta de dos partes en forma de Application.ObjectType :

1. Aplicación : el nombre de la aplicación de la que forma parte el objeto. |


2. Tipo de objeto : el tipo de objeto que se está creando. |

Algunas clases de ejemplo son:

1. Word.Application
2. Hoja de Excel
3. Scripting.FileSystemObject

Ejemplos

Demostrar GetObject y CreateObject

Función MSDN-GetObject

Devuelve una referencia a un objeto proporcionado por un componente ActiveX.

Utilice la función GetObject cuando haya una instancia actual del objeto o si lo desea

https://riptutorial.com/ 74

Página 90

para crear el objeto con un archivo ya cargado. Si no hay una instancia actual y usted
no quiere que el objeto comience con un archivo cargado, use la función CreateObject.

Sub CreateVSGet ()
Dim ThisXLApp As Excel.Application 'Un ejemplo de enlace anticipado
Dim AnotherXLApp As Object 'Un ejemplo de enlace tardío
Atenuar ThisNewWB como libro de trabajo
Atenuar otroNuevoWB como libro de trabajo
Dim wb como libro de trabajo

'Obtener esta instancia de Excel


Establecer ThisXLApp = GetObject (ThisWorkbook.Name) .Application
'Crea otra instancia de Excel
Establecer AnotherXLApp = CreateObject ("Excel.Application")
'Hacer visible la segunda instancia
AnotherXLApp.Visible = True
'Agregar un libro de trabajo a la segunda instancia
Establecer AnotherNewWB = AnotherXLApp.Workbooks.Add
'Agregar una hoja a la segunda instancia
AnotherNewWB.Sheets.Add

'Ahora debería tener 2 instancias de Excel abiertas


'La primera instancia tiene 1 libro de trabajo: Libro1
'La segunda instancia tiene 1 libro de trabajo: Libro2

'Vamos a agregar otro libro de trabajo a nuestra primera instancia


Establecer ThisNewWB = ThisXLApp.Workbooks.Add
'Ahora recorra los libros de trabajo y muestre sus nombres

https://translate.googleusercontent.com/translate_f 77/223
6/1/2021 Intitulado
Para cada wb en ThisXLApp.Workbooks
Debug.Print wb.Name
próximo
'Ahora la primera instancia tiene 2 libros de trabajo: Libro1 y Libro3
'Si cierra la primera instancia de Excel,
'Book1 y Book3 se cerrarán, pero book2 seguirá abierto

End Sub

Lea CreateObject frente a GetObject en línea: https://riptutorial.com/vba/topic/7729/createobject-vs--


getobject

https://riptutorial.com/ 75

Página 91

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
DateRange , porque las fechas de inicio y finalización a menudo se pasan juntas a las funciones.

Ejemplos

Agregar una propiedad a una clase

Un procedimiento de propiedad es una serie de instrucciones que recupera o modifica una propiedad personalizada en un
módulo.

Hay tres tipos de accesores de propiedad:

1. Un procedimiento Get que devuelve el valor de una propiedad.


2. Un procedimiento Let que asigna un valor (no objeto ) a un objeto.
3. Un procedimiento de conjunto que asigna una referencia de objeto .

Los descriptores de acceso a las propiedades a menudo se definen en pares, utilizando tanto Get como Let / Set para cada propiedad. UN
la propiedad con solo un procedimiento Get sería de solo lectura, mientras que una propiedad con solo un Let / Set
El procedimiento sería de solo escritura.

En el siguiente ejemplo, se definen cuatro descriptores de acceso a la propiedad para la clase DateRange :

1. StartDate (
lectura / escritura ). Valor de fecha que representa la fecha anterior en un rango. Cada procedimiento
usa 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 .
https://translate.googleusercontent.com/translate_f 78/223
6/1/2021 Intitulado
3. DaysBetween (
solo lectura ). Valor entero calculado que representa el número de días entre
las dos fechas. Debido a que solo hay un procedimiento Get , esta propiedad no se puede modificar
directamente.
4. RangeToCopy ( solo escritura ). Un procedimiento Set utilizado para copiar los valores de un DateRange existente
objeto.

Privado mStartDate como fecha 'Variable del módulo para contener la fecha de inicio
Privado mEndDate como fecha 'Variable de módulo para contener la fecha de finalización

'Devuelve el valor actual de la fecha de inicio


Propiedad pública Get StartDate () como fecha
StartDate = mStartDate
Propiedad final

'Establezca el valor de la fecha de inicio. Tenga en cuenta que dos métodos tienen el nombre StartDate
Propiedad pública Let StartDate (ByVal NewValue As Date)
mStartDate = NewValue
Propiedad final

https://riptutorial.com/ 76

Página 92

Lo mismo, pero para la fecha de finalización


Propiedad pública Obtener EndDate () como fecha
EndDate = mEndDate
Propiedad final

Propiedad pública Let EndDate (ByVal NewValue como fecha)


mEndDate = NewValue
Propiedad final

'Propiedad de solo lectura que devuelve el número de días entre las dos fechas
Propiedad pública Obtener DaysBetween () como entero
DaysBetween = DateDiff ("d", mStartDate, mEndDate)
Función final

'Propiedad de solo escritura que pasa una referencia de objeto de un rango para clonar
Conjunto de propiedades públicas RangeToCopy (ByRef ExistingRange como DateRange)

Me.StartDate = ExistingRange.StartDate
Me.EndDate = ExistingRange.EndDate

Propiedad final

Agregar funcionalidad a una clase

Cualquier sub , función o propiedad pública dentro de un módulo de clase se puede llamar antes de la llamada con
una referencia de objeto:

Objeto.Procedimiento

En una clase DateRange , un Sub podría usarse para agregar un número de días a la fecha de finalización:

Public Sub AddDays (ByVal NoDays como entero)


mEndDate = mEndDate + NoDays
End Sub

Una función podría devolver el último día del próximo fin de mes (tenga en cuenta que GetFirstDayOfMonth no
ser visible fuera de la clase porque es privado):

Función pública GetNextMonthEndDate () como fecha


GetNextMonthEndDate = DateAdd ("m", 1, GetFirstDayOfMonth ())
Función final

Función privada GetFirstDayOfMonth () como fecha


GetFirstDayOfMonth = DateAdd ("d", -DatePart ("d", mEndDate), mEndDate)
Función final

https://translate.googleusercontent.com/translate_f 79/223
6/1/2021 Intitulado

Los procedimientos pueden aceptar argumentos de cualquier tipo, incluidas referencias a objetos de la clase que se
definido.

El siguiente ejemplo prueba si el objeto DateRange actual tiene una fecha de inicio y una finalización
fecha que incluye la fecha de inicio y finalización de otro objeto DateRange .

https://riptutorial.com/ 77

Página 93

Función pública ContainsRange (ByRef TheRange como DateRange) como booleano


ContainsRange = TheRange.StartDate> = Me.StartDate y TheRange.EndDate <= Me.EndDate
Función final

Tenga en cuenta el uso de la notación Me como una forma de acceder al valor del objeto que ejecuta el código.

Alcance, instanciación y reutilización del módulo de clase

De forma predeterminada, un nuevo módulo de clase es una clase privada, por lo que solo está disponible para instanciar y usar
dentro del VBProject en el que está definido. Puede declarar, instanciar y usar la clase
en cualquier lugar del mismo proyecto:

'Class List tiene Instanciación establecida en Privada


En cualquier otro módulo del proyecto SAME, puede utilizar:

Atenuar elementos como lista


Establecer elementos = Nueva lista

Pero a menudo escribirás clases que te gustaría usar en otros proyectos sin copiar el módulo
entre proyectos. Si define una clase llamada Lista en ProjectA y desea usar esa clase en
ProjectB , entonces deberá realizar 4 acciones:

1. Cambie la propiedad de instancia de la clase List en ProjectA en la ventana Propiedades, desde


De privado a público No se puede crear

2. Cree una función de "fábrica" pública en ProjectA que cree y devuelva una instancia de una lista
clase. Normalmente, la función de fábrica incluiría argumentos para la inicialización de la clase
ejemplo. La función de fábrica es necesaria porque ProjectB puede utilizar la clase, pero
ProjectB no puede crear directamente una instancia de la clase de ProjectA .

Función pública CreateList (valores de ParamArray () como variante) como lista


Dim tempList como lista
Elemento tenue Contador tan largo
Establecer tempList = Nueva lista
Para itemCounter = LBound (valores) a UBound (valores)
tempList.Add valores (itemCounter)
Elemento siguiente Contador
Establecer CreateList = tempList
Función final

3. En ProjectB agregue una referencia a ProjectA usando el menú Tools..References ...

4. En ProjectB , declare una variable y asígnele una instancia de List usando la función de fábrica
de ProjectA

Atenuar elementos como ProjectA.List


Establecer elementos = ProjectA.CreateList ("foo", "bar")

'Utilice los métodos y propiedades de la lista de elementos


artículos.Añadir "fizz"
Debug.Print items.ToString ()
'Destruye el objeto de elementos

https://translate.googleusercontent.com/translate_f 80/223
6/1/2021 Intitulado
https://riptutorial.com/ 78

Página 94

Establecer elementos = Nada

Lea Crear una clase personalizada en línea: https://riptutorial.com/vba/topic/4464/creating-a-custom-


clase

https://riptutorial.com/ 79

Página 95

Capítulo 15: Creación de un procedimiento

https://translate.googleusercontent.com/translate_f 81/223
6/1/2021 Intitulado

Ejemplos
Introducción a los procedimientos

Un Sub es un procedimiento que realiza una tarea específica pero no devuelve un valor específico.

Nombre de procedimiento secundario ([lista_argumentos])


[declaraciones]
End Sub

Si no se especifica ningún modificador de acceso, un procedimiento es público de forma predeterminada.

Una función es un procedimiento que recibe datos y devuelve un valor, idealmente sin global o módulo
efectos secundarios del alcance.

NombreProcedimiento de función ([lista_argumentos]) [como tipo de retorno]


[declaraciones]
Función final

Una propiedad es un procedimiento que encapsula los datos del módulo. Una propiedad puede tener hasta 3 accesos:
Obtener para devolver un valor o referencia de objeto, Dejar para asignar un valor y / o Establecer para asignar un objeto
referencia.

Property Get | Let | Set PropertyName ([lista_argumentos]) [As ReturnType]


[declaraciones]
Propiedad final

Las propiedades se usan generalmente en módulos de clase (aunque están permitidas en módulos estándar como
bien), exponiendo al autor de acceso a datos que de otro modo serían inaccesibles para el código de llamada. Una propiedad que
solo expone que un descriptor de acceso Get es "de solo lectura"; una propiedad que solo expondría un Let y / o Set
El descriptor de acceso es de "solo escritura". Las propiedades de solo escritura no se consideran una buena práctica de programación, si
el código del cliente puede escribir un valor, debería poder leerlo . Considere implementar un Sub
procedimiento en lugar de hacer una propiedad de solo escritura.

Devolviendo un valor
Un procedimiento de obtención de función o propiedad puede (¡y debería!) Devolver un valor a su llamador. Esto es hecho por
asignando el identificador del trámite:

Propiedad Obtener Foo () como entero


Foo = 42
Propiedad final

https://riptutorial.com/ 80

Página 96

Función con ejemplos

Como se indicó anteriormente, las funciones son procedimientos más pequeños que contienen pequeños fragmentos de código que pueden
repetitivo dentro de un procedimiento.

Las funciones se utilizan para reducir la redundancia en el código.

Similar a un procedimiento, una función puede declararse 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 el regreso
Las variables de una función son iguales.

1. Función con parámetro:

https://translate.googleusercontent.com/translate_f 82/223
6/1/2021 Intitulado

Función check_even (i como entero) como booleano


si (i mod 2) = 0 entonces
check_even = Verdadero
más
check_even = Falso
terminara si
función final

2. Función sin parámetro:

Función saludar () como cadena


saludar = "¡Hola programador!"
función final

La función se puede llamar de varias formas dentro de una función. Dado que una función declarada con un
el tipo de retorno es básicamente una variable. se usa de manera similar a una variable.

Llamadas funcionales:

call greet () 'Similar a una llamada de procedimiento solo permite que el procedimiento use el
saludo variable
string_1 = greet () 'El valor de retorno de la función se usa para la variable
'asignación

Además, la función también se puede utilizar como condiciones para if y otras declaraciones condicionales.

para i = 1 a 10
si check_even (i) entonces
msgbox i & "es par"
más
msgbox i & "es impar"
terminara si
siguiente yo

Además, más funciones pueden tener modificadores como By ref y By val para sus argumentos.

Lea Creación de un procedimiento en línea: https://riptutorial.com/vba/topic/1474/creating-a-procedure

https://riptutorial.com/ 81

Página 97

Capítulo 16: 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 algunas
explicación como una descripción general de cómo se pueden implementar las estructuras de datos en VBA. Esto sería un
buena oportunidad para vincular y reforzar conceptos introducidos en temas relacionados con la clase en VBA
documentación.]

Ejemplos

Lista enlazada

Este ejemplo de lista enlazada implementa Establecer operaciones de tipo de datos abstractos .

Clase SinglyLinkedNode

Opción explícita

Valor privado como variante

https://translate.googleusercontent.com/translate_f 83/223
6/1/2021 Intitulado
NextNode privado como SinglyLinkedNode '"Siguiente" es una palabra clave en VBA y, por lo tanto, no es válida
nombre de la variable

Clase LinkedList

Opción explícita

Jefe privado As SinglyLinkedNode

'Establecer operaciones de tipo

Subadición pública (valor como variante)


Atenuar nodo como SinglyLinkedNode

Establecer nodo = Nuevo SinglyLinkedNode


node.value = valor
Establecer node.nextNode = head

Establecer cabeza = nodo


End Sub

Public Sub Remove (valor como variante)


Atenuar nodo como SinglyLinkedNode
Atenuar prev como SinglyLinkedNode

Establecer nodo = cabeza

Mientras que el nodo no es nada


Si node.value = value Entonces
'eliminar nodo
Si el nodo es la cabeza, entonces
Establecer head = node.nextNode

https://riptutorial.com/ 82

Página 98

Más
Establezca prev.nextNode = node.nextNode
Terminara si
Salir de Sub
Terminara si
Establecer prev = nodo
Establecer nodo = nodo.nextNode
Encaminarse a

End Sub

La función pública existe (valor como variante) como booleano


Atenuar nodo como SinglyLinkedNode

Establecer nodo = cabeza


Mientras que el nodo no es nada
Si node.value = value Entonces
Existe = Verdadero
Función de salida
Terminara si
Establecer nodo = nodo.nextNode
Encaminarse a
Función final

Recuento de funciones públicas () tan largo


Atenuar nodo como SinglyLinkedNode

Establecer nodo = cabeza

Mientras que el nodo no es nada


Cuenta = Cuenta + 1
Establecer nodo = nodo.nextNode
Encaminarse a

Función final

Árbol binario

https://translate.googleusercontent.com/translate_f 84/223
6/1/2021 Intitulado
Este es un ejemplo de un desequilibrio árbol de búsqueda binaria . Un árbol binario está estructurado conceptualmente
como una jerarquía de nodos que descienden de una raíz común, donde cada nodo tiene dos
niños: izquierda y derecha. Por ejemplo, suponga que los números 7, 5, 9, 3, 11, 6, 12, 14 y 15 son
insertado en un BinaryTree. La estructura sería la siguiente. Tenga en cuenta que este árbol binario no es
equilibrado , que puede ser una característica deseable para garantizar el rendimiento de las búsquedas -
ver Árboles AVL para un ejemplo de árbol de búsqueda binaria autoequilibrado.

7
/\
59
/\\
3 6 11
\
12
\
14
\
15

https://riptutorial.com/ 83

Página 99

Clase BinaryTreeNode

Opción explícita

Público dejado como BinaryTreeNode


Derecho público como BinaryTreeNode
Clave pública como variante
Valor público como variante

Clase BinaryTree

[QUE HACER]

Leer estructuras de datos en línea: https://riptutorial.com/vba/topic/8628/data-structures

https://translate.googleusercontent.com/translate_f 85/223
6/1/2021 Intitulado

https://riptutorial.com/ 84

Página 100

Capítulo 17: Tipos de datos y límites


Ejemplos

Byte

Valor de atenuación como byte

Un byte es un tipo de datos de 8 bits sin firmar. Puede representar números enteros entre 0 y 255 y
intentar almacenar un valor fuera de ese rango resultará en error de tiempo de ejecución 6: desbordamiento . Byte es el
único tipo intrínseco sin firmar 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 es
redondeado al valor entero más cercano con .5 redondeando hacia arriba.

Cadenas y matrices de bytes

Las cadenas y las matrices de bytes se pueden sustituir entre sí mediante una asignación simple (no
funciones de conversión necesarias).

Por ejemplo:

Sub ByteToStringAndBack ()

Dim str como cadena


str = "¡Hola, mundo!"

Dim byt () como byte


byt = str

Debug.Print byt (0) '72

Dim str2 como cadena


str2 = byt

Debug.Print str2 '¡Hola, mundo!

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 ()

Dim str como cadena


str = ChrW (& H2123) & "." 'Carácter de la versión y un punto

Dim byt () como byte


byt = str

Debug.Print byt (0), byt (1), byt (2), byt (3) 'Imprime: 35,33,46,0

https://translate.googleusercontent.com/translate_f 86/223
6/1/2021 Intitulado

https://riptutorial.com/ 85

Página 101

End Sub

Entero

Valor de atenuación como entero

Un entero es un tipo de datos de 16 bits con signo. Puede almacenar números enteros en el rango de -32,768 a
32,767 e intentar 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 undos' s
complemento .

Tenga en cuenta que, en general, es una mejor práctica utilizar un Largo en lugar de un entero a menos que el más pequeño
type es un miembro de un Type o es requerido (ya sea por una convención de llamada a la API o alguna otra
razón) para ser 2 bytes. En la mayoría de los casos, VBA trata a los enteros como de 32 bits internamente, por lo que generalmente no hay
ventaja de utilizar el tipo más pequeño. Además, existe una penalización de desempeño incurrida cada
vez que se usa un tipo Integer, ya que se convierte silenciosamente como Long.

La función de conversión para convertir a un entero es CInt () . Para moldes de tipos de punto flotante, el
el resultado se redondea al valor entero más cercano con 0,5 redondeando hacia arriba.

Booleano

Valor de atenuación como booleano

Un booleano se usa para almacenar valores que se pueden representar como Verdadero o Falso. Internamente, el
El tipo de datos se almacena como un valor de 16 bits, donde 0 representa Falso y cualquier otro valor representa
Cierto.

Cabe señalar que cuando un booleano se convierte en un tipo numérico, todos los bits se establecen en 1. Este
da como resultado una representación interna de -1 para tipos firmados y el valor máximo para un sin firmar
tipo (Byte).

Ejemplo de atenuación como booleano


Ejemplo = Verdadero
Debug.Print CInt (ejemplo) 'Imprime -1
Debug.Print CBool (42) 'Prints True
Debug.Print CByte (True) 'Imprime 255

La función de conversión para convertir a booleano es CBool () . Aunque se representa internamente como
un número de 16 bits, la conversión a un booleano desde valores fuera de ese rango está a salvo del desbordamiento,
aunque establece los 16 bits en 1:

Ejemplo de atenuación como booleano


Ejemplo = CBool (2 ^ 17)
Debug.Print CInt (ejemplo) 'Imprime -1
Debug.Print CByte (ejemplo) 'Imprime 255

https://riptutorial.com/ 86

Página 102

Largo

Valor de atenuación siempre que

https://translate.googleusercontent.com/translate_f 87/223
6/1/2021 Intitulado

Un Long es un tipo de datos de 32 bits con signo. Puede almacenar números enteros en el rango de -2,147,483,648 a
2,147,483,647 e intentar 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 undos' s
complemento .

Tenga en cuenta que dado que Long coincide con el ancho de un puntero en un sistema operativo de 32 bits, Longs son
de uso común para almacenar y pasar punteros hacia y desde funciones API.

La función de conversión para convertir a Long es CLng () . Para las conversiones de tipos de punto flotante, el resultado es
redondeado al valor entero más cercano con .5 redondeando hacia arriba.

Soltero

Valor de atenuación como único

Un Single es un tipo de datos de coma flotante de 32 bits con signo. Se almacena internamente mediante unIEEE little-endian
754 diseño de memoria. Como tal, no existe un rango fijo de valores que pueda ser representado por el
tipo de datos: lo que está limitado es la precisión del valor almacenado. Un solo puede almacenar un valor entero
valores en el rango de -16.777.216 a 16.777.216 sin pérdida de precisión. La precisión de
los números de coma flotante dependen del exponente.

Un Single se desbordará si se le asigna un valor superior a aproximadamente 2 128 . No se desbordará con


exponentes negativos, aunque la precisión utilizable será cuestionable antes de que el límite superior sea
alcanzado.

Al igual que con todos los números de coma flotante, se debe tener cuidado al hacer comparaciones de igualdad. Mejor
La práctica consiste en incluir un valor delta apropiado para la precisión requerida.

La función de conversión para convertir a Single es CSng () .

Doble

Valor de atenuación como doble

Un Double es un tipo de datos de coma flotante de 64 bits con signo. Como elÚnico , se almacena internamente mediante un
diseño de memoria Little-Endian IEEE 754 y se deben tomar las mismas precauciones con respecto a la precisión.
tomado. 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 coma flotante
depende del exponente.

Un Double se desbordará si se le asigna un valor superior a aproximadamente 2 1024 . No se desbordará con

https://riptutorial.com/ 87

Página 103

exponentes negativos, aunque la precisión utilizable será cuestionable antes de que el límite superior sea
alcanzado.

La función de conversión para convertir a Double es CDbl () .

Moneda

Valor atenuado como moneda

Una moneda es un tipo de datos de coma flotante de 64 bits con signo similar a un Doble , pero escalado de 10,000 a
dar mayor precisión a los 4 dígitos a la derecha del punto decimal. Una variable de moneda puede almacenar
valores de -922,337,203,685,477.5808 a 922,337,203,685,477.5807, lo que le da el mayor
https://translate.googleusercontent.com/translate_f 88/223
6/1/2021 Intitulado

capacidad de cualquier tipo intrínseco en una aplicación de 32 bits. Como implica el nombre del tipo de datos, es
consideró la mejor práctica para utilizar este tipo de datos al representar cálculos monetarios como el
el escalado ayuda a evitar errores de redondeo.

La función de conversión para convertir a una moneda es CCur () .

Fecha

Dim Valor como fecha

Un tipo de fecha se representa internamente como un tipo de datos de coma flotante de 64 bits firmado con el valor
la izquierda del punto decimal que representa el número de días desde la fecha época diciembre de 30 º ,
1899 (aunque vea la nota a continuación). El valor a la derecha del decimal representa el tiempo 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
tener un componente de tiempo de 12:00:00 PM.

Los valores válidos para fechas son entre enero 1 st 100 y 31 de diciembre st 9999. Desde una doble tiene
un rango más grande, es posible desbordar una fecha asignando valores fuera de ese rango.

Como tal, se puede usar indistintamente con un Doble para cálculos de fecha:

Atenuar MyDate como doble


MyDate = 0 'Época.
Debug.Print Format $ (MyDate, "aaaa-mm-dd") 'Imprime 1899-12-30.
MyDate = MyDate + 365
Debug.Print Format $ (MyDate, "aaaa-mm-dd") 'Imprime 1900-12-30.

La función de conversión para convertir a una fecha es CDate () , que acepta cualquier cadena de tipo numérico
representación de fecha / hora. Es importante tener en cuenta que las representaciones de cadenas de fechas
convertido en base a la configuración regional actual en uso, por lo que se deben evitar las conversiones directas si el código
está destinado a ser portátil.

Cuerda

Una cadena representa una secuencia de caracteres y viene en dos sabores:

https://riptutorial.com/ 88

Página 104

Longitud variable

Valor de atenuación como cadena

Una cadena de longitud variable permite anexar y truncamiento y se almacena en la memoria como COM
BSTR . Consiste en un entero sin signo de 4 bytes que almacena la longitud de la cadena en bytes
seguido por los datos de la cadena en sí 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 manejar VBA es 2,147,483,647
caracteres.

El puntero interno a la estructura (recuperable por la función StrPtr () ) apunta a la memoria


ubicación de los datos , no el prefijo de longitud. Esto significa que una cadena VBA se puede pasar directamente a la API
funciones que requieren un puntero a una matriz de caracteres.

Debido a que la longitud puede cambiar, VBA reasigna memoria para una Cadena cada vez que la variable es
asignados , lo que puede imponer sanciones de desempeño por procedimientos que los modifiquen repetidamente.

Longitud fija

https://translate.googleusercontent.com/translate_f 89/223
6/1/2021 Intitulado
Dim Value As String * 1024 'Declara una cadena de longitud fija de 1024 caracteres.

A las cadenas de longitud fija se les asignan 2 bytes para cada carácter y se almacenan en la memoria como un simple
matriz de bytes. Una vez asignada, la longitud de la Cadena es inmutable. Están no terminada en nulo en
memoria, por lo que una cadena que llena la memoria asignada con caracteres no nulos no es adecuada para
pasando a funciones de API esperando una cadena terminada en nulo.

Las cadenas de longitud fija tienen una limitación de índice de 16 bits heredada, por lo que solo pueden tener hasta 65.535
caracteres de longitud. Intentar asignar un valor mayor que el espacio de memoria disponible no
dará como resultado un error de tiempo de ejecución; en su lugar, el valor resultante simplemente se truncará:

Dim Foobar como cadena * 5


Foobar = "Foo" y "bar"
Debug.Print Foobar Imprime "Fooba"

La función de conversión para convertir a una cadena de cualquier tipo es CStr () .

Largo largo

Valor de atenuación como LongLong

Un LongLong es un tipo de datos firmado de 64 bits y solo está disponible en aplicaciones de 64 bits. Es no
disponible en aplicaciones de 32 bits que se ejecutan en sistemas operativos de 64 bits. Puede almacenar valores enteros en
el rango de -9,223,372,036,854,775,808 a 9,223,372,036,854,775,807 e intentar almacenar un
el valor fuera de ese rango dará como resultado un error de tiempo de ejecución 6: desbordamiento.

LongLongs se almacenan en la memoria como valores little-endian con negativos representados como undos' s

https://riptutorial.com/ 89

Página 105

complemento .

El tipo de datos LongLong se introdujo como parte del soporte del sistema operativo de 64 bits de VBA. En 64
aplicaciones de bits, este valor se puede utilizar para almacenar y pasar punteros a API de 64 bits.

La función de conversión para convertir a LongLong es CLngLng () . Para moldes de tipos de punto flotante, el
el resultado se redondea al valor entero más cercano con 0,5 redondeando hacia arriba.

Variante

Valor de atenuación como variante 'explícita


Valor de atenuación 'Implícito

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. Variables declaradas sin un tipo explícito
especificado por Como [Tipo] predeterminado en Variante.

Las variantes se almacenan en la memoria como Estructura VARIANT 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 tipos numéricos (incluidos
Date y booleano), el valor subyacente se almacena en la propia Variant. Para todos los demás tipos, los datos
El área 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 cadena
representación:

Ejemplo de atenuación como variante

https://translate.googleusercontent.com/translate_f 90/223
6/1/2021 Intitulado
Ejemplo = 42
Debug.Print VarType (Ejemplo) 'Imprime 2 (VT_I2)
Debug.Print TypeName (Ejemplo) 'Imprime "Entero"
Example = "Algún texto"
Debug.Print VarType (Ejemplo) 'Imprime 8 (VT_BSTR)
Debug.Print TypeName (Ejemplo) 'Imprime "Cadena"

Dado que las variantes pueden almacenar valores de cualquier tipo, las asignaciones de literales sin las sugerencias de tipo serán
conversión implícita a una variante del tipo apropiado de acuerdo con la tabla siguiente. Literales con tipo
las sugerencias se convertirán en una variante del tipo insinuado.

Valor Tipo resultante

Valores de cadena Cuerda

Números de coma no flotante en el rango de enteros Entero

Números de coma no flotante en rango largo Largo

Números de coma no flotante fuera de Long range Double

https://riptutorial.com/ 90

Página 106

Valor Tipo resultante

Todos los números de coma flotante Doble

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 debe evitarse para tareas de rutina por las siguientes razones:

• No son seguros para los tipos, lo que aumenta la posibilidad de errores en tiempo de ejecución. Por ejemplo, una variante
mantener un valor Integer se convertirá silenciosamente en un Long en lugar de desbordarse.
• Introducen una 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 de lo necesario para almacenar
el tipo subyacente.

La función de conversión para convertir a una variante es CVar () .

LongPtr

Valor de atenuación como LongPtr

LongPtr se introdujo en VBA para admitir plataformas de 64 bits. En un sistema de 32 bits, es


tratado como un Long y en sistemas de 64 bits se trata comoLongLong .

Su uso principal es proporcionar una forma portátil de almacenar y pasar punteros en ambas arquitecturas.
(Ver Cambiar el comportamiento del código en tiempo de compilación .

Aunque el sistema operativo lo trata como una dirección de memoria cuando se usa en llamadas a la API,
Debe tenerse en cuenta que VBA lo trata como un tipo firmado (y, por lo tanto, sujeto a unsigned to firmado
Desbordamiento). Por esta razón, cualquier aritmética de puntero realizada con LongPtrs no debe usar > o <
comparaciones. Esta "peculiaridad" también hace posible que la adición de compensaciones simples que apunten a
direcciones en la memoria pueden causar errores de desbordamiento, por lo que se debe tener cuidado al trabajar con
punteros en VBA.

La función de conversión para convertir a LongPtr es CLngPtr () . Para moldes de tipos de punto flotante, el
El resultado se redondea al valor entero más cercano con .5 redondeando hacia arriba (aunque como suele ser un
dirección de memoria, usarlo como destino de asignación para un cálculo de punto flotante es peligroso en
mejor).

Decimal

https://translate.googleusercontent.com/translate_f 91/223
6/1/2021 Intitulado
Valor de atenuación como variante
Valor = CDec (1.234)

'Establecer valor en el valor decimal más pequeño posible


Valor = CDec ("0.0000000000000000000000000001")

El tipo de datos Decimal solo está disponible como un subtipo de Variant , por lo que debe declarar cualquier variable
que debe contener un decimal como variante y luego asignar un valor decimal usando el CDec
función. La palabra clave Decimal es una palabra reservada (lo que sugiere que VBA finalmente se

https://riptutorial.com/ 91

Página 107

para agregar soporte de primera clase para el tipo), por lo que Decimal no se puede usar como una variable o procedimiento
nombre.

El tipo decimal requiere 14 bytes de memoria (además de los bytes requeridos por el padre
Variant) y puede almacenar números con hasta 28 decimales. Para números sin decimal
lugares, el rango de valores permitidos es -79,228,162,514,264,337,593,543,950,335 a
+79,228,162,514,264,337,593,543,950,335 inclusive. Para números con un máximo de 28 decimal
lugares, el rango de valores permitidos es -7,9228162514264337593543950335 a
+7.9228162514264337593543950335 inclusive.

Lea Tipos de datos y límites en línea: https://riptutorial.com/vba/topic/3418/data-types-and-limits

https://translate.googleusercontent.com/translate_f 92/223
6/1/2021 Intitulado

https://riptutorial.com/ 92

Página 108

Capítulo 18: Manipulación de fecha y hora


Ejemplos

Calendario

VBA admite 2 calendarios: Gregoriano yHijri

La propiedad Calendario se utiliza para modificar o mostrar el calendario actual.

Los 2 valores del Calendario son:

Valor constante Descripción

0 vbCalGreg Calendario gregoriano (predeterminado)

1 vbCalHijri Hijri calendario

Ejemplo

Sub CalendarExample ()
'Almacene en caché la configuración actual.
Dim en caché como entero
Cached = Calendario

'Fechas en el calendario gregoriano


Calendario = vbCalGreg
Dim muestra como fecha
'Crear fecha de muestra de 2016-07-28
Muestra = DateSerial (2016, 7, 28)

Debug.Print "Calendario actual:" & Calendario


Debug.Print "SampleDate =" & Format $ (Muestra, "aaaa-mm-dd")

'Fecha en el calendario Hijri


Calendario = vbCalHijri
Debug.Print "Calendario actual:" & Calendario
Debug.Print "SampleDate =" & Format $ (Muestra, "aaaa-mm-dd")

'Restablece VBA al valor en caché.


Cached = Calendario
End Sub

Este Sub imprime lo siguiente;

Calendario actual: 0
SampleDate = 2016-07-28
Calendario actual: 1
SampleDate = 1437-10-23

https://riptutorial.com/ 93

Página 109

Funciones base

https://translate.googleusercontent.com/translate_f 93/223
6/1/2021 Intitulado

Recuperar fecha y hora del sistema


VBA admite 3 funciones integradas para recuperar la fecha y / o la hora del reloj del sistema.

Función Tipo de retorno Valor de retorno

Ahora Fecha Devuelve la fecha y hora actuales

Fecha Fecha Devuelve la parte de la fecha de la fecha y hora actuales

Hora Fecha Devuelve la parte de tiempo de la fecha y hora actuales.

Sub DateTimeExample ()

'------------------------------------------------- ----
'Nota: sistema de la UE con formato de fecha predeterminado DD / MM / AAAA
'------------------------------------------------- ----

Debug.Print Now 'imprime 28/07/2016 10:16:01 (el resultado a continuación asume esta fecha y hora)
Debug.Print Date 'imprime 28/07/2016
Debug.Print Time 'imprime 10:16:01

'Aplicar un formato personalizado a la fecha u hora actual


Debug.Print Format $ (Now, "dd mmmm aaaa hh: nn") 'imprime el 28 de julio de 2016 10:16
Formato de depuración $ (fecha, "aaaa-mm-dd") 'impresiones 2016-07-28
Debug.Print Format $ (Time, "hh") & "hour" & _
Formato $ (Hora, "nn") & "min" & _
Formato $ (Time, "ss") & "sec" 'imprime 10 horas 16 min 01 seg

End Sub

Función de temporizador
La función Timer devuelve un Single que representa el número de segundos transcurridos desde la medianoche.
La precisión es una centésima de segundo.

Sub TimerExample ()

Debug.Print Time 'imprime 10:36:31 (tiempo de ejecución)


Debug.Print Timer 'imprime 38191,13 (segundos desde la medianoche)

End Sub

Debido a que las funciones Ahora y Hora solo son precisas en segundos, el temporizador ofrece una manera conveniente de
aumentar la precisión de la medición del tiempo:

Sub GetBenchmark ()

https://riptutorial.com/ 94

Página 110

Dim StartTime como single


StartTime = Timer 'Almacena la hora actual

Dim i tan largo


Dim temp como cadena
Para i = 1 To 1000000 'Vea cuánto tiempo le toma a Left $ ejecutar 1,000,000 veces
temp = Left $ ("Texto", 2)
Siguiente yo

Atenuar transcurrido como único


Transcurrido = Temporizador - Hora de inicio
Debug.Print "Código completado en" & CInt (Transcurrido * 1000) & "ms"

End Sub

https://translate.googleusercontent.com/translate_f 94/223
6/1/2021 Intitulado

IsDate ()
IsDate () prueba si una expresión es una fecha válida o no. Devuelve un booleano .

Sub IsDateExamples ()

Atenuar cualquier cosa como variante

cualquier cosa = "11 de septiembre de 2001"

Debug.Print IsDate (cualquier cosa) 'Prints True

cualquier cosa = # 11/9/2001 #

Debug.Print IsDate (cualquier cosa) 'Prints True

cualquier cosa = "solo una cadena"

Debug.Print IsDate (cualquier cosa) 'Imprime falso

cualquier cosa = vbNull

Debug.Print IsDate (cualquier cosa) 'Imprime falso

End Sub

Funciones de extracción

Estas funciones toman una variante que se puede convertir a una fecha como parámetro y devuelven un entero
que representa una parte de una fecha u hora. Si el parámetro no se puede convertir a una fecha , resultará en una
Error 13 en tiempo de ejecución: no coinciden los tipos.

Devuelto
Función Descripción
valor

Entero (100 a
Año() Devuelve la parte del año del argumento de fecha.
9999)

Mes() Devuelve la parte del mes del argumento de fecha. Entero (1 a

https://riptutorial.com/ 95

Página 111

Devuelto
Función Descripción
valor

12)

Entero (1 a
Día() Devuelve la parte del día del argumento de fecha.
31)

Devuelve el día de la semana del argumento de fecha. Acepta un


Día laborable() Entero (1 a 7)
segundo argumento opcional que define el primer día de la semana

Entero (0 a
Hora() Devuelve la parte de la hora del argumento de fecha.
23)

Entero (0 a
Minuto() Devuelve la parte de los minutos del argumento de fecha.
59)

Entero (0 a
Segundo() Devuelve la segunda parte del argumento de fecha.
59)

Ejemplos:
https://translate.googleusercontent.com/translate_f 95/223
6/1/2021 Intitulado

Ejemplos de extracción secundaria ()

Atenuar MyDate como fecha

MyDate = DateSerial (2016, 7, 28) + TimeSerial (12, 34, 56)

Debug.Print Format $ (MyDate, "aaaa-mm-dd hh: nn: ss") 'imprime 2016-07-28 12:34:56

Año de impresión de depuración (MyDate) 'impresiones 2016


Mes de Debug.Print (MyDate) 'impresiones 7
Debug.Print Day (MyDate) 'imprime 28
Hora de Debug.Print (MyDate) 'impresiones 12
Debug.Print Minute (MyDate) 'impresiones 34
Debug.Print Second (MyDate) 'impresiones 56

Debug.Print Weekday (MyDate) 'impresiones 5


'Varía según la ubicación, es decir, se imprimirá 4 en la UE y 5 en los EE. UU.
Debug.Print Weekday (MyDate, vbUseSystemDayOfWeek)
Debug.Print Weekday (MyDate, vbMonday) 'impresiones 4
Debug.Print Weekday (MyDate, vbSunday) 'impresiones 5

End Sub

Función DatePart ()
DatePart () también
es una función que devuelve una parte de una fecha, pero funciona de manera diferente y permite más
posibilidades que las funciones anteriores. Por ejemplo, puede devolver el trimestre del año o el
Semana del año.

Sintaxis:

https://riptutorial.com/ 96

Página 112

DatePart (intervalo, fecha [, primer día de la semana] [, primera semana del año])

El argumento de intervalo puede ser:

Descripción del intervalo

"yyyy" Año (100 a 9999)

"y" Día del año (1 a 366)

"metro" Mes (1 a 12)

"q" Cuarto (1 a 4)

"ww" Semana (1 a 53)

"w" Día de la semana (1 a 7)

"re" Día del mes (1 al 31)

"h" Hora (0 a 23)

"norte" Minuto (0 a 59)

"s" Segundo (0 a 59)

firstdayofweek es opcional. es una constante que especifica el primer día de la semana. Si no se especifica,
Se asume vbSunday .

firstweekofyear es opcional. es una constante que especifica la primera semana del año. Si no se especifica,

https://translate.googleusercontent.com/translate_f 96/223
6/1/2021 Intitulado
se supone que la primera semana es la semana en la que ocurre el 1 de enero.

Ejemplos:

Sub DatePartExample ()

Atenuar MyDate como fecha

MyDate = DateSerial (2016, 7, 28) + TimeSerial (12, 34, 56)

Debug.Print Format $ (MyDate, "aaaa-mm-dd hh: nn: ss") 'imprime 2016-07-28 12:34:56

Debug.Print DatePart ("yyyy", MyDate) 'impresiones 2016


Debug.Print DatePart ("y", MyDate) 'imprime 210
Debug.Print DatePart ("h", MyDate) 'impresiones 12
Debug.Print DatePart ("Q", MyDate) 'impresiones 3
Debug.Print DatePart ("w", MyDate) 'impresiones 5
Debug.Print DatePart ("ww", MyDate) 'impresiones 31

End Sub

Funciones de cálculo

https://riptutorial.com/ 97

Página 113

DateDiff ()
DateDiff () devuelve un Long que representa el número de intervalos de tiempo entre dos fechas especificadas.

Sintaxis

DateDiff (intervalo, fecha1, fecha2 [, primer día de la semana] [, primera semana del año])

• intervalo puede ser cualquiera de los intervalos definidos en elDatePart () función


• date1 y date2 son las dos fechas que desea utilizar en el cálculo
• primerdíadelasemana y firstweekofyear son opcionales. Referirse aFunción DatePart () para explicaciones

Ejemplos

Sub DateDiffExamples ()

'Compruebe si 2016 es un año bisiesto.


Dim NumberOfDays tan largo
NumberOfDays = DateDiff ("d", # 1/1/2016 #, # 1/1/2017 #)

Si NumberOfDays = 366 entonces


Debug.Print "2016 es un año bisiesto". 'Esto saldrá.
Terminara si

'Número de segundos en un día


Atenuar StartTime como fecha
Atenuar EndTime como fecha
StartTime = TimeSerial (0, 0, 0)
EndTime = TimeSerial (24, 0, 0)
Debug.Print DateDiff ("s", StartTime, EndTime) 'imprime 86400

End Sub

DateAdd ()
DateAdd () devuelve una fecha a la que se ha agregado una fecha o intervalo de tiempo específico.

Sintaxis

DateAdd (intervalo, número, fecha)

https://translate.googleusercontent.com/translate_f 97/223
6/1/2021 Intitulado

• intervalo puede ser cualquiera de los intervalos definidos en elDatePart () función


• número Expresión numérica que es el número de intervalos que desea agregar. Puede ser
positivo (para obtener fechas en el futuro) o negativo (para obtener fechas en el pasado).
• fecha es una fecha o literal que representa la fecha a la que se agrega el intervalo

Ejemplos:

Sub DateAddExamples ()

https://riptutorial.com/ 98

Página 114

Dim muestra como fecha


'Crear muestra de fecha y hora de 2016-07-28 12:34:56
Muestra = DateSerial (2016, 7, 28) + TimeSerial (12, 34, 56)

'Fecha 5 meses antes (impresiones 2016-02-28):


Debug.Print Format $ (DateAdd ("m", -5, Sample), "aaaa-mm-dd")

'Fecha 10 meses antes (impresiones 2015-09-28):


Debug.Print Format $ (DateAdd ("m", -10, Sample), "aaaa-mm-dd")

'Fecha en 8 meses (impresiones 2017-03-28):


Debug.Print Format $ (DateAdd ("m", 8, Sample), "aaaa-mm-dd")

'Fecha / Hora 18 horas antes (impresiones 2016-07-27 18:34:56):


Debug.Print Format $ (DateAdd ("h", -18, Sample), "aaaa-mm-dd hh: nn: ss")

'Fecha / Hora en 36 horas (impresiones 2016-07-30 00:34:56):


Debug.Print Format $ (DateAdd ("h", 36, Sample), "aaaa-mm-dd hh: nn: ss")

End Sub

Conversión y creación

CDate ()
CDate () convierte algo de cualquier tipo de datos a un tipo de datos de fecha

Sub CDateExamples ()

Dim muestra como fecha

'Convierte una cadena que representa una fecha y hora en una fecha
sample = CDate ("11 de septiembre de 2001 12:34")
Debug.Print Format $ (sample, "aaaa-mm-dd hh: nn: ss") 'imprime 2001-09-11 12:34:00

'Convierte una cadena que contiene una fecha en una fecha


sample = CDate ("11 de septiembre de 2001")
Debug.Print Format $ (sample, "aaaa-mm-dd hh: nn: ss") 'imprime 2001-09-11 00:00:00

'Convierte una cadena que contiene una hora en una fecha


sample = CDate ("12:34:56")
Hora de Debug.Print (muestra) 'impresiones 12
Debug.Print Minute (muestra) 'impresiones 34
Debug.Print Second (muestra) 'impresiones 56

'Encuentra el día número 10000 desde la fecha de la época del 31-12-1899


muestra = CDate (10000)
Debug.Print Format $ (sample, "aaaa-mm-dd") 'imprime 1927-05-18

End Sub

Tenga en cuenta que VBA también tiene un CVDate () escrito libremente que funciona de la misma manera que CDate ()
función que no sea devolver una Variante de fecha escrita en lugar de una Fecha fuertemente escrita . El CDate ()
la versión debe ser preferida cuando se pasa a un parámetro de fecha o se asigna a una variable de fecha , y
la versión CVDate () debe ser preferida cuando se pasa a un parámetro Variant o se asigna
https://translate.googleusercontent.com/translate_f 98/223
6/1/2021 Intitulado
a una variable Variant . Esto evita la conversión de tipos implícita.

https://riptutorial.com/ 99

Página 115

DateSerial ()

La función DateSerial () se utiliza para crear una fecha. Devuelve una fecha para un año, mes y
día.

Sintaxis:

DateSerial (año, mes, día)

Con argumentos de año, mes y día válidos. Enteros (año de 100 a 9999, mes de 1 a
12, Día del 1 al 31).

Ejemplos

Sub DateSerialExamples ()

'Crea una fecha específica


Dim muestra como fecha
muestra = DateSerial (2001, 9, 11)
Debug.Print Format $ (ejemplo, "aaaa-mm-dd") 'impresiones 2001-09-11

'Encuentra el primer día del mes para una fecha.


sample = DateSerial (Año (muestra), Mes (muestra), 1)
Debug.Print Format $ (ejemplo, "aaaa-mm-dd") 'impresiones 2001-09-11

'Encuentra el último día del mes anterior.


sample = DateSerial (Año (muestra), Mes (muestra), 1) - 1
Debug.Print Format $ (ejemplo, "aaaa-mm-dd") 'impresiones 2001-09-11

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
utilizado creativamente para siempre:

Ejemplo positivo

Sub GoodDateSerialExample ()

'Calcule 45 días a partir de hoy


Atenuar hoy como fecha
hoy = DateSerial (2001, 9, 11)
Dim futureDate As Date
futureDate = DateSerial (Año (hoy), Mes (hoy), Día (hoy) + 45)
Debug.Print Format $ (futureDate, "aaaa-mm-dd") 'impresiones 2009-10-26

End Sub

Sin embargo, es más probable que cause molestias al intentar crear una fecha de un usuario no validado.
entrada:

Ejemplo negativo

Sub BadDateSerialExample ()

https://riptutorial.com/ 100

Página 116

'Permitir al usuario ingresar información de fecha no validada

https://translate.googleusercontent.com/translate_f 99/223
6/1/2021 Intitulado
Atenuar mi año tan largo
myYear = InputBox ("Ingresar año")
'Suponga que el usuario ingresa a 2009
Dim myMonth tan largo
myMonth = InputBox ("Ingresar mes")
'Suponga que el usuario ingresa 2
Dim myDay As Long
myDay = InputBox ("Ingresar día")
'Suponga que el usuario ingresa 31
Debug.Print Format $ (DateSerial (myYear, myMonth, myDay), "aaaa-mm-dd")
'impresiones 2009-03-03

End Sub

Lea la manipulación de fecha y hora en línea: https://riptutorial.com/vba/topic/4452/date-time-manipulation

https://riptutorial.com/ 101

Página 117

Capítulo 19: Declaración y asignación de cadenas


Observaciones
Las cadenas son un Tipo de referencia y son fundamentales para la mayoría de las tareas de programación. Se asignan cadenas
texto, incluso si el texto es numérico. Las cadenas pueden tener una longitud cero o cualquier longitud de hasta 2 GB.
Las versiones modernas de VBA almacenan cadenas internamente utilizando una matriz de bytes de conjunto de caracteres de varios bytes
bytes (una alternativa a Unicode).

https://translate.googleusercontent.com/translate_f 100/223
6/1/2021 Intitulado

Ejemplos

Declarar una constante de cadena

Const appName As String = "La aplicación para eso"

Declarar una variable de cadena de ancho variable

Dim surname As String 'apellido puede aceptar cadenas de longitud variable


apellido = "Smith"
apellido = "Johnson"

Declarar y asignar una cadena de ancho fijo

'Declare y asigne una cadena de ancho fijo de 1 carácter


Dim middleInitial As String * 1 'middleInitial debe tener 1 carácter de longitud
middleInitial = "M"

'Declare y asigne una cadena de ancho fijo de 2 caracteres `stateCode`,


'debe tener 2 caracteres de longitud
Dim stateCode como cadena * 2
stateCode = "TX"

Declarar y asignar una matriz de cadenas

'Declare, dimensione y asigne una matriz de cadenas con 3 elementos


Dim departamentos (2) como cadena
departamentos (0) = "Ingeniería"
departamentos (1) = "Finanzas"
departamentos (2) = "Marketing"

'Declare una matriz de cadenas no dimensionada y luego asigne dinámicamente con


'los resultados de una función que devuelve una matriz de cadenas
Dim stateNames () como cadena
stateNames = VBA.Strings.Split ("Texas; California; Nueva York", ";")

'Declare, dimensione y asigne una matriz de cadenas de ancho fijo


Dim stateCodes (2) como cadena * 2
stateCodes (0) = "TX"

https://riptutorial.com/ 102

Página 118

stateCodes (1) = "CA"


stateCodes (2) = "NY"

Asignar caracteres específicos dentro de una cadena usando la declaración Mid

VBA ofrece una función Mid para devolver subcadenas dentro de una cadena, pero también ofrece Mid
Declaración que se puede utilizar para asignar subcadenas o caracteres individuales dentro de una cadena.

La función Mid aparecerá normalmente en el lado derecho de una instrucción de asignación o en un


condición, pero el Mediados Declaración aparece normalmente en el lado izquierdo de una asignación
declaración.

Dim apellido como cadena


apellido = "Smith"

'Use la instrucción Mid para cambiar el tercer carácter de una cadena


Mid (apellido, 3, 1) = "y"
Debug.Print apellido

'Salida:
'Smyth

https://translate.googleusercontent.com/translate_f 101/223
6/1/2021 Intitulado

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 varios bytes), la declaración MidB se puede
usado. En este caso, el segundo argumento para la declaración MidB es la posición basada en 1 del
byte donde comenzará el reemplazo, por lo que la línea equivalente al ejemplo anterior sería
MidB (apellido, 5, 2) = "y" .

Asignación hacia y desde una matriz de bytes

Las cadenas se pueden asignar directamente a matrices de bytes y viceversa. Recuerda que las cadenas se almacenan
en un conjunto de caracteres de varios bytes (consulte las observaciones a continuación), por lo que solo cada otro índice de la matriz resultante
será la parte del carácter que se encuentre dentro del rango ASCII.

Dim bytes () como byte


Ejemplo de atenuación como cadena

ejemplo = "Prueba".
bytes = ejemplo 'Asignación directa.

Recorre los personajes. El paso 2 se utiliza debido a la codificación amplia.


Dim i tan largo
Para i = LBound (bytes) To UBound (bytes) Paso 2
Debug.Print Chr $ (bytes (i)) 'Imprime T, e, s, t, i, n, g,.
próximo

Dim revertido como cadena


revertido = bytes 'Asignación directa.
Debug.Print revertido Imprime "Prueba".

Lea Declarar y asignar cadenas en línea: https://riptutorial.com/vba/topic/3446/declaring-and-


asignar-cadenas

https://riptutorial.com/ 103

Página 119

Capítulo 20: Declaración de variables


Ejemplos

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, el compilador
automáticamente (es decir, "implícitamente") crea variables para usted cuando las usa. Ellos predeterminarán
tipo de variable Variant .

Declaración de subejemplo público ()

someVariable = 10 '
someOtherVariable = "Hola mundo"
'Ambas variables son del tipo Variant.

End Sub

En el código anterior, si se especifica Option Explicit , el código se interrumpirá porque falta el


requeridas declaraciones Dim para someVariable y someOtherVariable .

Opción explícita

Declaración de subejemplo público ()

Atenuar algo Variable siempre que


someVariable = 10

Dim someOtherVariable As String

https://translate.googleusercontent.com/translate_f 102/223
6/1/2021 Intitulado
someOtherVariable = "Hola mundo"

End Sub

Se considera una buena práctica utilizar Option Explicit en los módulos de código, para asegurarse de declarar todos
variables.

Ver VBA Best Practices cómo configurar esta opción de forma predeterminada.

Variables

Alcance
Se puede declarar una variable (en aumento del nivel de visibilidad):

• A nivel de procedimiento, usar la palabra clave Dim en cualquier procedimiento; una variable local .
• A nivel de módulo, utilizando la palabra clave Private en cualquier tipo de módulo; un campo privado .
• A nivel de instancia, usando la palabra clave Friend en cualquier tipo de módulo de clase; un campo amigo .
• A nivel de instancia, usando la palabra clave Public en cualquier tipo de módulo de clase; un campo público .
• Globalmente, usando la palabra clave Public en un módulo estándar ; una variable global .

https://riptutorial.com/ 104

Página 120

Las variables siempre deben declararse con el menor alcance posible: prefiera pasar parámetros
a los procedimientos, en lugar de declarar variables globales.

Ver Acceda a Modificadores para obtener más información.

Variables locales

Utilice la palabra clave Dim para declarar una variable local :

Dim identifierName [como tipo] [, identifierName [como tipo], ...]

La parte [As Type] de la sintaxis de declaración es opcional. Cuando se especifica, establece los datos de la variable
type, que determina cuánta memoria se asignará a esa variable. Esto declara una cadena
variable:

Dim identifierName como cadena

Cuando no se especifica un tipo, el tipo es implícitamente Variant :

Dim identifierName 'As Variant está implícito

La sintaxis de VBA también admite la declaración de múltiples variables en una sola declaración:

Dim someString As String, someVariant, someValue As Long

Tenga en cuenta que se debe especificar [Como tipo] para cada variable (excepto las de 'Variante'). Esto es un
trampa relativamente común:

Dim integer1, integer2, integer3 As Integer 'Solo integer3 es un entero.


El resto son variantes.

Variables estáticas

Las variables locales también pueden ser estáticas . En VBA, la palabra clave estática se usa para hacer una variable
"recordar" el valor que tenía la última vez que se llamó a un procedimiento:

https://translate.googleusercontent.com/translate_f 103/223
6/1/2021 Intitulado

Sub privado DoSomething ()


Valores estáticos como colección
Si los valores no son nada, entonces
Establecer valores = Nueva colección
valores.Añadir "foo"
valores.Añadir "barra"
Terminara si
DoSomethingElse valores
End Sub

Aquí la colección de valores se declara como local estático ; porque es una variable de objeto , es
inicializado en Nothing . La condición que sigue a la declaración verifica si la referencia del objeto fue

https://riptutorial.com/ 105

Página 121

Establecer antes:
si es la primera vez que se ejecuta el procedimiento, la colección se inicializa. Hacer algo más
podría estar agregando o quitando elementos, y todavía estarán en la colección la próxima vez que DoSomething sea
llamado.

Alternativa

La palabra clave estática de VBA puede malinterpretarse fácilmente, especialmente por expertos
programadores que suelen trabajar en otros lenguajes. En muchos idiomas, se usa estática
hacer que un miembro de la clase (campo, propiedad, método, ...) pertenezca al tipo en lugar de
la instancia . El código en contexto estático no puede hacer referencia al código en contexto de instancia . los
La palabra clave estática de VBA significa algo tremendamente diferente.

A menudo, un local estático también podría implementarse como una variable privada de nivel de módulo (campo):
Sin embargo, esto desafía el principio por el cual una variable debe declararse con el mínimo
posible alcance; confíe en sus instintos, use el que prefiera, ambos funcionarán ... pero usando Static
sin entender lo que hace, podría dar lugar a errores interesantes.

Dim vs. Privado

La palabra clave Dim es legal a nivel de módulo y procedimiento; su uso a nivel de módulo es equivalente a
usando la palabra clave privada :

Opción explícita
Dim privateField1 As Long 'igual que Private privateField2 as Long
Private privateField2 As Long 'igual que Dim privateField2 as Long

La palabra clave Privada 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
debe utilizarse de todos modos para declarar un miembro público. Alternativamente, use Dim en todas partes : ¿qué
lo que importa es la coherencia :

"Campos privados"

• DEBE usar Private para declarar una variable a nivel de módulo.


• DO utilizar Dim para declarar una variable local.
• NO use Dim para declarar una variable a nivel de módulo.

"Atenuar en todas partes"

• DO uso Dim para declarar nada privado / local.


• NO use Private para declarar una variable a nivel de módulo.
• EVITE declarar campos públicos . *

* En general, se debe evitar declarar campos públicos o globales de todos modos.

Campos
https://translate.googleusercontent.com/translate_f 104/223
6/1/2021 Intitulado

Una variable declarada a nivel de módulo, en la sección de declaraciones en la parte superior del cuerpo del módulo, es una

https://riptutorial.com/ 106

Página 122

campo . Un campo público declarado en un módulo estándar es una variable global :

Public PublicField siempre que

Se puede acceder a una variable con un alcance global desde cualquier lugar, incluidos otros proyectos de VBA que
haría referencia al proyecto en el que está declarado.

Para hacer que una variable sea global / pública, pero solo visible desde dentro del proyecto, use el modificador Friend :

Amigo amigo campo siempre que

Esto es especialmente útil en complementos, donde la intención es que otros proyectos de VBA hagan referencia al complemento.
proyecto y puede consumir la API pública.

FriendField As Long 'público dentro del proyecto, también conocido como código de "amigo"
Public PublicField As Long 'público dentro y fuera del proyecto

Los campos de amigos no están disponibles en los módulos estándar.

Campos de instancia

Una variable declarada a nivel de módulo, en la sección de declaraciones en la parte superior del cuerpo de una clase
módulo (incluyendo ThisWorkbook , ThisDocument , Worksheet , UserForm y módulos de clase ), es un
campo de instancia : solo existe mientras haya una instancia de la clase alrededor.

'> Clase1
Opción explícita
Public PublicField siempre que

'> Módulo1
Opción explícita
Sub público DoSomething ()
'Class1.PublicField no significa nada aquí
Con New Class1
.PublicField = 42
Terminar con
'Class1.PublicField no significa nada aquí
End Sub

Encapsular campos

Los datos de instancia a menudo se mantienen privados y se denominan encapsulados . Un campo privado puede quedar expuesto
utilizando un procedimiento de propiedad . Para exponer una variable privada públicamente sin dar acceso de escritura a la
llamador, un módulo de clase (o un módulo estándar) implementa un miembro Property Get :

Opción explícita
Privado encapsulado siempre que

https://riptutorial.com/ 107

Página 123

https://translate.googleusercontent.com/translate_f 105/223
6/1/2021 Intitulado
Propiedad pública Get SomeValue () mientras
SomeValue = encapsulado
Propiedad final

Sub público DoSomething ()


encapsulado = 42
End Sub

La clase en sí puede modificar el valor encapsulado, pero el código de llamada solo puede acceder al Public
miembros (y miembros amigos , si la persona que llama está en el mismo proyecto).

Para permitir que la persona que llama modifique:

• Un valor encapsulado , un módulo expone un miembro Property Let .


• Una referencia de objeto encapsulado , un módulo expone un miembro del conjunto de propiedades .

Constantes (Const)

Si tiene un valor que nunca cambia en su aplicación, puede definir una constante con nombre y
utilícelo en lugar de un valor literal.

Puede usar Const solo a nivel de módulo o procedimiento. Esto significa el contexto de declaración para un
la variable debe ser una clase, estructura, módulo, procedimiento o bloque, y no puede ser un archivo fuente,
espacio de nombres o interfaz.

Public Const GLOBAL_CONSTANT As String = "Versión del proyecto # 1.000.000.001"


Private Const MODULE_CONSTANT As String = "Algo relevante para este módulo"

Declaración de subejemplo público ()

Const SOME_CONSTANT As String = "Hola mundo"

Const PI como doble = 3,141592653

End Sub

Si bien se puede considerar una buena práctica especificar tipos de constantes, no es estrictamente necesario. No
especificar el tipo aún resultará en el tipo correcto:

Public Const GLOBAL_CONSTANT = "Versión del proyecto # 1.000.000.001" 'Sigue siendo una cadena
Declaración de subejemplo público ()

Const SOME_CONSTANT = "Hola mundo" 'Todavía una cuerda


Const DERIVED_CONSTANT = SOME_CONSTANT 'DERIVED_CONSTANT también es una cadena
Const VAR_CONSTANT como variante = SOME_CONSTANT 'VAR_CONSTANT es variante / cadena

Const PI = 3,141592653 'Todavía un doble


Const DERIVED_PI = PI 'DERIVED_PI también es un doble
Const VAR_PI como variante = PI 'VAR_PI es variante / doble

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

https://riptutorial.com/ 108

Página 124

da como resultado un tipo de variante.

Si bien es posible declarar explícitamente una constante como una cadena, no es posible declarar una
constante como una cadena usando sintaxis de cadena de ancho fijo

'Esta es una constante de cadena de 5 caracteres válida


Const FOO como cadena = "ABCDE"

'Esta no es una sintaxis válida para una constante de cadena de 5 caracteres


Const FOO como cadena * 5 = "ABCDE"

https://translate.googleusercontent.com/translate_f 106/223
6/1/2021 Intitulado

Modificadores de acceso

La instrucción Dim debe reservarse para variables locales. A nivel de módulo, prefiera el acceso explícito
modificadores:

• Privado para campos privados, a los que solo se puede acceder dentro del módulo en el que están declarados.
• Público para campos públicos y variables globales, a las que se puede acceder mediante cualquier código de llamada.
• Amigo delas variables públicas dentro del proyecto, pero inaccesible a otros VBA de referencia
proyectos (relevante para complementos)
• Global tambiénse puede usar para campos públicos en módulos estándar, pero es ilegal en módulos de clase
y es obsoleto de todos modos - prefiera el modificador Público en su lugar. Este modificador no es legal para
procedimientos tampoco.

Los modificadores de acceso son aplicables tanto a variables como a procedimientos.

Módulo privado Variable como cadena


Public GlobalVariable como cadena

Procedimiento de submódulo privado ()

ModuleVariable = "Esto solo se puede hacer desde el mismo módulo"

End Sub

Procedimiento sub global público ()

GlobalVariable = "Esto se puede hacer desde cualquier módulo dentro de este proyecto"

End Sub

Opción Módulo Privado


Los procedimientos Sub públicos sin parámetros en módulos estándar se exponen como macros y pueden
adjunto a los controles y atajos de teclado en el documento anfitrión.

Por el contrario, los procedimientos de función pública en módulos estándar se exponen como definidos por el usuario
funciones (UDF) en la aplicación host.

Especificar Option Private Module en la parte superior de un módulo estándar evita que sus miembros sean

https://riptutorial.com/ 109

Página 125

expuestos como macros y UDF a la aplicación host.

Sugerencias de tipo

Las sugerencias de tipo están muy desaconsejadas. Existen y están documentados aquí para fines históricos y
razones de compatibilidad con versiones anteriores. En su lugar, debería utilizar la sintaxis As [DataType] .

Declaración de subejemplo público ()

Dim someInteger% '% Equivalente a "As Integer"


Dim someLong & '& Equivalent to "As Long"
Dim someDecimal @ '@ Equivalente a "As Currency"
Dim someSingle! '! Equivalente a "Como soltero"
Dim someDouble # '# Equivalente a "As Double"
Atenuar someString $ '$ Equivalente a "As String"

Dim someLongLong ^ '^ Equivalente a "As LongLong" en hosts VBA de 64 bits


End Sub

Las sugerencias de tipo disminuyen significativamente la legibilidad del código y fomentan un legado Notación húngara

https://translate.googleusercontent.com/translate_f 107/223
6/1/2021 Intitulado
que también dificulta la legibilidad:

Dim strFile $
Dim iFile%

En su lugar, declare las variables más cercanas a su uso y nombre las cosas por lo que se usan, no después
su tipo:

Ruta tenue como cadena


Controlador tenue como entero

Las sugerencias de tipo también se pueden usar en literales para imponer un tipo específico. Por defecto, un literal numérico
menor que 32,768 se interpretará como un literal entero , pero con una sugerencia de tipo que puede controlar
ese:

Variante implícita de Dim foo '


foo = 42 & 'foo ahora es un Long
foo = 42 # 'foo ahora es un Double
Debug.Print TypeName (42!) 'Imprime "Single"

Las sugerencias de tipo generalmente no son necesarias en literales, porque se asignarían a una variable
declarado con un tipo explícito, o convertido implícitamente al tipo apropiado cuando se pasa como
parámetros. Las conversiones implícitas se pueden evitar utilizando una de las conversiones de tipo explícitas
funciones:

'Llama al procedimiento DoSomething y pasa un literal 42 como Long usando una sugerencia de tipo
Hacer algo 42 y

'Llama al procedimiento DoSomething y pasa un literal 42 convertido explícitamente en un Long


Hacer Algo CLng (42)

https://riptutorial.com/ 110

Página 126

Funciones integradas de retorno de cadenas


La mayoría de las funciones integradas que manejan cadenas vienen en dos versiones:
versión que devuelve una variante y una versión fuertemente tipada (que termina en $ ) que devuelve una cadena .
A menos que esté asignando el valor de retorno a una variante , debe preferir la versión que devuelve un
Cadena : de lo contrario, hay una conversión implícita del valor de retorno.

Debug.Print Left (foo, 2) 'Left devuelve una variante


Debug.Print Left $ (foo, 2) 'Left $ devuelve una cadena

Estas funciones son:

• VBA.Conversion.Error -> VBA.Conversion.Error $


• VBA.Conversion.Hex -> VBA.Conversion.Hex $
• VBA.Conversion.Oct -> VBA.Conversion.Oct $
• VBA.Conversion.Str -> VBA.Conversion.Str $
• VBA.FileSystem.CurDir -> VBA.FileSystem.CurDir $
• VBA. [_ HiddenModule] .Input -> VBA. [_ HiddenModule] .Input $
• VBA. [_ HiddenModule] .InputB -> VBA. [_ HiddenModule] .InputB $
• VBA.Interaction.Command -> VBA.Interaction.Command $
• VBA.Interaction.Environ -> VBA.Interaction.Environ $
• VBA.Strings.Chr -> VBA.Strings.Chr $
• VBA.Strings.ChrB -> VBA.Strings.ChrB $
• VBA.Strings.ChrW -> VBA.Strings.ChrW $
• VBA.Strings.Format -> VBA.Strings.Format $

https://translate.googleusercontent.com/translate_f 108/223
6/1/2021 Intitulado
• VBA.Strings.LCase -> VBA.Strings.LCase $
• VBA.Strings.Left -> VBA.Strings.Left $
• 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 sugerencias de tipo . La función Izquierda 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 versiones muy tempranas de VBA, el signo $ no es un carácter permitido y el nombre de la función tenía que ser
entre corchetes. En Word Basic, hubo muchas, muchas más funciones que devolvieron
cadenas que terminan en $.

https://riptutorial.com/ 111

Página 127

Declarar cadenas de longitud fija

En VBA, las cadenas se pueden declarar con una longitud específica; se rellenan o truncan automáticamente
para mantener esa longitud declarada.

Sub público TwoTypesOfStrings ()

Dim FixedLengthString As String * 5 'declara una cadena de 5 caracteres


Dim NormalString como cadena

Debug.Print FixedLengthString 'Imprime ""


Debug.Print NormalString 'Imprime ""

FixedLengthString = "123" 'FixedLengthString ahora es igual a "123"


NormalString = "456" 'NormalString ahora es igual a "456"

FixedLengthString = "123456" 'FixedLengthString ahora es igual a "12345"


NormalString = "456789" 'NormalString ahora es igual a "456789"

End Sub

Cuándo usar una variable estática

Una variable estática declarada localmente no se destruye y no pierde su valor cuando el Sub
se sale del procedimiento. Las llamadas posteriores al procedimiento no requieren reinicialización o
asignación aunque es posible que desee "poner a cero" los valores recordados.

Estos son particularmente útiles cuando se vincula tarde un objeto en un sub 'auxiliar' que se llama repetidamente.

Fragmento 1: reutilización de unObjeto de scripting.Dictionary en muchas hojas de trabajo

Opción explícita

Sub principal()
Dim w tan largo

Para w = 1 a las hojas de trabajo.


processDictionary ws: = Hojas de trabajo (w)
Siguiente w
End Sub

https://translate.googleusercontent.com/translate_f 109/223
6/1/2021 Intitulado
Subproceso Diccionario (ws como hoja de trabajo)
Dim i tan largo, rng como rango
Dictado estático como objeto

Si dict no es nada entonces


'inicializa y configura el objeto de diccionario
Establecer dict = CreateObject ("Scripting.Dictionary")
dict.CompareMode = vbTextCompare
Más
'eliminar todas las entradas de diccionario preexistentes
'esto puede ser deseable o no si un solo diccionario de entradas
'de todas las hojas de trabajo es preferible
dict.RemoveAll
Terminara si

https://riptutorial.com/ 112

Página 128

Con ws

'trabajar con un nuevo objeto de diccionario para cada hoja de trabajo


'sin construir / destruir un nuevo objeto cada vez
'o no borre el diccionario en usos posteriores y
'crea un diccionario que contenga entradas de todas las hojas de trabajo

Terminar con
End Sub

Fragmento 2: cree una UDF de hoja de trabajo que enlace tarde el objeto VBScript.RegExp

Opción explícita

Números de función Solo (str As String, _


Delimitar opcionalmente como cadena = ",")
Dim n As Long, nums () As Variant
Rgx estático como objeto, cmat como objeto

'con rgx como estático, solo debe crearse una vez


'esto es beneficioso cuando se llena una columna larga con esta UDF
Si rgx no es nada, entonces
Establecer rgx = CreateObject ("VBScript.RegExp")
Más
Establecer cmat = Nada
Terminara si

Con rgx
.Global = Verdadero
.MultiLine = Verdadero
.Patrón = "[0-9] {1,999}"
Si .Test (str) Entonces
Establecer cmat = .Execute (str)
'cambiar el tamaño de la matriz nums para aceptar las coincidencias
ReDim nums (recuento cmat - 1)
'rellenar la matriz nums con las coincidencias
Para n = LBound (nums) a UBound (nums)
nums (n) = cmat.Item (n)
Siguiente n
'convierte la matriz nums en una cadena delimitada
numbersOnly = Unir (nums, delim)
Más
numerosOnly = vbNullString
Terminara si
Terminar con
Función final

https://translate.googleusercontent.com/translate_f 110/223
6/1/2021 Intitulado

https://riptutorial.com/ 113

Página 129

Ejemplo de UDF con objeto estático llenado a través de medio millón de filas

* Tiempos transcurridos para llenar 500K filas con UDF:


- con Dim rgx como objeto : 148,74 segundos
- con Static rgx como objeto : 26,07 segundos
* Estos deben considerarse solo para comparación relativa. Sus propios resultados variarán según el
complejidad y
Alcance de las operaciones realizadas.

Recuerde que una UDF no se calcula una sola vez en la vida útil de un libro. Incluso un no volátil
UDF 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
que fue declarado y asignado.
• Las variables estáticas solo se pueden declarar localmente.
• La variable estática tiene muchas de las mismas propiedades de una variable de nivel de módulo privado pero con una
alcance más restringido.

Referencia relacionada: Estático (Visual Basic)

Lea Declaración de variables en línea: https://riptutorial.com/vba/topic/877/declaring-variables

https://riptutorial.com/ 114

Página 130

https://translate.googleusercontent.com/translate_f 111/223
6/1/2021 Intitulado

Capítulo 21: Manejo de errores


Ejemplos

Evitando condiciones de error

Cuando ocurre un error en tiempo de ejecución, un buen código debería manejarlo. La mejor estrategia de manejo de errores es
escribir código que compruebe condiciones de error y simplemente evite ejecutar código que resulte en una
Error de tiempo de ejecución.

Un elemento clave para reducir los errores en tiempo de ejecución es escribir pequeños procedimientos que hagan una sola cosa . los
Menos razones por las que los procedimientos tienen que fallar, más fácil es depurar el código en su conjunto.

Evitar el error de tiempo de ejecución 91 - Objeto o Con variable de bloque no establecida:

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:

Private Sub DoSomething (destino ByVal como hoja de trabajo)


Debug.Print target.Name
End Sub

Si al objetivo no se le asigna una referencia, el código anterior generará un error que se puede evitar fácilmente mediante
comprobar si el objeto contiene una referencia de objeto real:

Private Sub DoSomething (destino ByVal como hoja de trabajo)


Si el objetivo no es nada, salga de Sub
Debug.Print target.Name
End Sub

Si el destino no tiene asignada una referencia, la referencia no asignada nunca se usa y no hay error
ocurre.

Esta forma de salir anticipadamente de un procedimiento cuando uno o más parámetros no son válidos, se denomina guardia
cláusula .

Evitando el error de tiempo de ejecución 9 - Subíndice fuera de rango:

Este error se genera cuando se accede a una matriz fuera de sus límites.

Private Sub DoSomething (índice ByVal como entero)


Debug.Print ActiveWorkbook.Worksheets (índice)
End Sub

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 protección puede evitar que:

https://riptutorial.com/ 115

Página 131

Private Sub DoSomething (índice ByVal como entero)


Si index> ActiveWorkbook.Worksheets.Count Or index <= 0 Luego salga de Sub
Debug.Print ActiveWorkbook.Worksheets (índice)
End Sub

La mayoría de los errores en tiempo de ejecución se pueden evitar verificando cuidadosamente los valores que estamos usando antes de usar
ellos, y ramificarse en otra ruta de ejecución en consecuencia utilizando una declaración If simple - en guardia
cláusulas que no hacen suposiciones y validan los parámetros de un procedimiento, o incluso en el cuerpo

https://translate.googleusercontent.com/translate_f 112/223
6/1/2021 Intitulado
de procedimientos más grandes.

En declaración de error

Incluso con las cláusulas de protección , uno no siempre puede tener en cuenta de manera realista todas las posibles condiciones de error.
que podría plantearse 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 tiempo de ejecución.
Después de manejar un error, el código puede reanudar su ejecución "normal" usando la palabra clave Resume .

Las etiquetas de línea denotan subrutinas : porque las subrutinas se originan a partir del código BASIC heredado y utiliza
GoTo y GoSub saltos
y declaraciones de retorno para volver a la rutina "principal", es bastante fácil
escriba un código espagueti difícil de seguir si las cosas no están estructuradas rigurosamente. Por eso es mejor
ese:

• un procedimiento tiene una y solo una subrutina de manejo de errores


• la subrutina de manejo de errores solo se ejecuta en un estado de error

Esto significa que un procedimiento que maneja sus errores debe estructurarse así:

Sub privado DoSomething ()


En caso de error, vaya a CleanFail

'código de procedimiento aquí

Limpiar Salida:
'código de limpieza aquí
Salir de Sub

CleanFail:
'código de manejo de errores aquí
Reanudar Limpiar Salir
End Sub

Estrategias de manejo de errores


A veces desea manejar diferentes errores con diferentes acciones. En ese caso, inspeccionará
el objeto Err global , que contendrá información sobre el error que se generó, y actuará
en consecuencia:

Limpiar Salida:

https://riptutorial.com/ 116

Página 132

Salir de Sub

CleanFail:
Seleccione Número de error de caso
Caso 9
MsgBox "El número especificado no existe. Vuelva a intentarlo", vbExclamation
Currículum
Caso 91
'woah, esto no debería estar pasando.
Detener la ejecución se romperá aquí
Reanudar 'presione F8 para saltar a la línea que generó el error
Caso otro
MsgBox "Se ha producido un error inesperado:" & vbNewLine & Err.Description,
vbCritical
Reanudar Limpiar Salir
Finalizar Seleccionar
End Sub

Como pauta general, considere activar el manejo de errores para toda la subrutina o función, y
manejar todos los errores que puedan ocurrir dentro de su alcance. Si solo necesita manejar errores en los pequeños
sección sección del código: active y desactive el manejo de errores en el mismo nivel:
https://translate.googleusercontent.com/translate_f 113/223
6/1/2021 Intitulado

Sub privado DoSomething (CheckValue as Long)

Si CheckValue = 0 entonces
On Error GoTo ErrorHandler 'activa el manejo de errores
'código que puede resultar en error
En caso de error, vaya a 0 'desactivar el manejo de errores - mismo nivel
Terminara si

Limpiar Salida:
Salir de Sub

ErrorHandler:
'código de manejo de errores aquí
'no desactive el manejo de errores aquí
Currículum

End Sub

Línea de números
VBA admite números de línea de estilo heredado (por ejemplo, QBASIC). La propiedad oculta Erl se puede utilizar para
identifique el número de línea que generó el último error. Si no está utilizando números de línea, Erl solo
devuelve 0.

Sub DoSomething ()
10 En caso de error, vaya a 50
20 Debug.Print 42/0
30 Salir Sub
40
50 Debug.Print "Error generado en línea" & Erl 'devuelve 20
End Sub

https://riptutorial.com/ 117

Página 133

Si está utilizando números de línea, pero no de manera consistente, Erl devolverá el último número de línea antes
la instrucción que provocó el error .

Sub DoSomething ()
10 En caso de error, vaya a 50
Debug.Print 42/0
30 Salir Sub

50 Debug.Print "Error generado en línea" & Erl 'devuelve 10


End Sub

Tenga en cuenta que Erl también solo tiene precisión Integer y se desbordará silenciosamente. Esto significa que
números de línea fuera del el rango entero dará resultados incorrectos:

Sub DoSomething ()
99997 En caso de error, vaya a 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 la numeración
Las líneas rápidamente se vuelven tediosas y no son fáciles de mantener.

Reanudar palabra clave

Una subrutina de manejo de errores:

https://translate.googleusercontent.com/translate_f 114/223
6/1/2021 Intitulado
• ejecutar hasta el final del procedimiento, en cuyo caso la ejecución se reanuda en el procedimiento de llamada.
• o utilice la palabra clave Resume para reanudar la ejecución dentro del mismo procedimiento.

La palabra clave Resume solo debe usarse dentro de una subrutina de manejo de errores, porque si VBA
encuentra Reanudar sin estar en un estado de error, el error de tiempo de ejecución 20 "Reanudar sin error" es
elevado.

Hay varias formas en que una subrutina de manejo de errores puede usar la palabra clave Resume :

• Reanudar usadosolo, la ejecución continúa en la declaración que causó el error . Si el error


no se maneja realmente antes de hacer eso, entonces el mismo error se generará nuevamente, y
la ejecución puede entrar en un bucle infinito.
• Resume Next continúala ejecución de la declaración inmediatamente después de la declaración
que causó el error. Si el error no es en realidad maneja antes de hacer eso, la ejecución es, pues,
permitido continuar con datos potencialmente inválidos, lo que puede resultar en errores lógicos y
comportamiento inesperado.
• Reanudar [etiqueta de línea] continúa
la ejecución en la etiqueta de línea especificada (o número de línea, si
utilizando números de línea de estilo heredado). Esto normalmente permitiría ejecutar algún código de limpieza
antes de salir limpiamente del procedimiento, como asegurarse de que una conexión a la base de datos esté cerrada
antes de regresar a la persona que llama.

https://riptutorial.com/ 118

Página 134

En caso de error, reanudar siguiente


La declaración On Error en sí misma puede usar la palabra clave Resume para instruir al tiempo de ejecución de VBA para que
ignore todos los errores .

Si el error no se maneja antes de hacerlo, entonces se permite la ejecución


continuar con datos potencialmente inválidos, que pueden resultar en errores lógicos y
comportamiento inesperado .

El énfasis anterior no se puede enfatizar lo suficiente. En caso de error, reanudar siguiente ignora efectivamente
todos los errores y los mete debajo de la alfombra . Un programa que explota con un error de ejecución
una entrada no válida dada es un mejor programa que uno que sigue ejecutándose con datos desconocidos / no deseados
- ya sea porque el error es mucho más fácil de identificar. En caso de error, reanudar siguiente se puede ocultar fácilmente
bichos .

La instrucción On Error tiene un alcance de procedimiento, por eso normalmente debería haber solo una , una
tal declaración On Error en un procedimiento dado.

Sin embargo, a veces una condición de error no se puede evitar del todo y saltar a un manejo de errores
subrutina solo para Reanudar Siguiente simplemente no se siente bien. En este caso específico, el conocido o posiblemente
La declaración de error se puede envolver entre dos declaraciones de error :

En caso de error, reanudar siguiente


[declaración posiblemente fallida]
Err.Clear 'restablece el error actual
En caso de error, vaya a 0

La instrucción On Error GoTo 0 restablece el manejo de errores en el procedimiento actual, de modo que cualquier
instrucciones adicionales que causen un error en tiempo de ejecución no se manejarían dentro de ese procedimiento y, en su lugar,
pasa la pila de llamadas hasta que es detectada por un controlador de errores activo. Si no hay error activo
handler en la pila de llamadas, se tratará como una excepción no controlada.

Llamador secundario público ()


En caso de error, GoTo Handler

https://translate.googleusercontent.com/translate_f 115/223
6/1/2021 Intitulado
Llamado

Salir de Sub
Manipulador:
Debug.Print "Error" & Err.Number & "in Caller".
End Sub

Destinatario público secundario ()


En caso de error, GoTo Handler

Err.Raise 1 'Esto será manejado por el controlador de llamadas.


On Error GoTo 0 'Después de esta declaración, los errores se pasan a la pila.
Err.Raise 2 'Esto será manejado por el manejador de llamadas.

Salir de Sub
Manipulador:

https://riptutorial.com/ 119

Página 135

Debug.Print "Error" & Err.Number & "in Callee".


Reanudar Siguiente
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
definir un tipo de Enum dedicado :

Opción explícita
Public Enum FoobarError
Err_FooWasNotBarred = vbObjectError + 1024
Err_BarNotInitialized
Err_SomethingElseHappened
End Enum

El uso de la constante incorporada vbObjectError garantiza que los códigos de error personalizados no se superpongan con
códigos de error reservados / existentes. Solo el primer valor de enumeración debe especificarse explícitamente, para el
El valor subyacente de cada miembro Enum es 1 mayor que el miembro anterior, por lo que el
El valor de Err_BarNotInitialized es implícitamente vbObjectError + 1025 .

Generando sus propios errores en tiempo de ejecución


Se puede generar un error en tiempo de ejecución utilizando la instrucción Err.Raise , por lo que el Err_FooWasNotBarred personalizado
El error se puede generar de la siguiente manera:

Err.Raise Err_FooWasNotBarred

El método Err.Raise también puede tomar parámetros personalizados de Descripción y Fuente , por esta razón es
Es una buena idea definir también constantes para contener la descripción de cada error personalizado:

Private Const Msg_FooWasNotBarred As String = "El foo no fue bloqueado".


Private Const Msg_BarNotInitialized As String = "La barra no se inicializó".

Y luego crea un método privado dedicado para generar cada error:

Private Sub OnFooWasNotBarredError (fuente ByVal como cadena)


Err.Raise Err_FooWasNotBarred, fuente, Msg_FooWasNotBarred
End Sub

Private Sub OnBarNotInitializedError (fuente ByVal como cadena)


Err.Raise Err_BarNotInitialized, source, Msg_BarNotInitialized
End Sub

https://translate.googleusercontent.com/translate_f 116/223
6/1/2021 Intitulado
La implementación de la clase puede simplemente llamar a estos procedimientos especializados para generar el error:

Sub público DoSomething ()


'genera el error personalizado' BarNotInitialized 'con "DoSomething" como fuente:

https://riptutorial.com/ 120

Página 136

If Me.Bar Is Nothing Then OnBarNotInitializedError "DoSomething"


'...
End Sub

El código del cliente puede manejar Err_BarNotInitialized como lo haría con cualquier otro error, dentro de su propio
subrutina de manejo de errores.

Nota: la palabra clave heredada Error también se puede utilizar en lugar de Err.Raise , pero es
obsoleto / desaprobado.

Lea Manejo de errores en línea: https://riptutorial.com/vba/topic/3211/error-handling

https://riptutorial.com/ 121

Página 137

https://translate.googleusercontent.com/translate_f 117/223
6/1/2021 Intitulado

Capítulo 22: Eventos


Sintaxis
• Módulo de origen : Evento [público] [identificador] ([lista_argumentos])

• Módulo controlador : Dim | Privado | Público WithEvents [identificador] Como [tipo]

Observaciones
• Un evento solo puede ser público . El modificador es opcional porque los miembros del módulo de clase
(incluidos los eventos) son implícitamente públicos de forma predeterminada.

• Una variable WithEvents puede ser Privada o Pública , pero no Amiga . 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 variable. Por lo tanto, la palabra clave Dim debe usarse si un modificador de acceso
no está presente.

Ejemplos

Fuentes y controladores

¿Qué son los eventos?


VBA está controlado por eventos : el código VBA se ejecuta en respuesta a eventos generados por la aplicación host o el
documento host: comprender los eventos es fundamental para comprender VBA.

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 un nuevo libro,
abierto, activado o cerrado. O cada vez que se calcula una hoja de trabajo. O justo antes de que un archivo sea
salvado. O inmediatamente después. Un botón en un formulario genera un evento Click cuando el usuario hace clic en él,
el formulario de 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
código que maneja estos eventos y ejecuta código personalizado cada vez que se disparan estos eventos: eso es
cómo 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 trabajo.

Un objeto que expone eventos es una fuente de eventos . Un método que maneja un evento es un controlador .

Manipuladores

https://riptutorial.com/ 122

Página 138

Los módulos de documentos de VBA (por ejemplo , ThisDocument , ThisWorkbook , Sheet1 , etc.) y los módulos de UserForm son
módulos de clase que implementan interfaces especiales que exponen una serie de eventos . Puedes navegar
estas interfaces en el menú desplegable del lado izquierdo en la parte superior del panel de código:

https://translate.googleusercontent.com/translate_f 118/223
6/1/2021 Intitulado

El menú desplegable del lado derecho enumera los miembros de la interfaz seleccionados en el menú desplegable del lado izquierdo:

El VBE genera automáticamente un código auxiliar del controlador de eventos cuando se selecciona un elemento en el lado derecho
list, o navega allí si el controlador existe.

Puede definir una variable WithEvents de ámbito de módulo en cualquier módulo:

Privado WithEvents Foo As Workbook


Barra privada WithEvents como hoja de trabajo

Cada declaración WithEvents está disponible para seleccionar en el menú desplegable del lado izquierdo. Cuando un
El evento está seleccionado en el menú desplegable del lado derecho, el VBE genera un código auxiliar del controlador de eventos llamado
después del objeto WithEvents y el nombre del evento, unido con un guión bajo:

Privado WithEvents Foo As Workbook


Barra privada WithEvents como hoja de trabajo

Sub privado Foo_Open ()

End Sub

Private Sub Bar_SelectionChange (ByVal Target As Range)

End Sub

Únicos tipos que exponen al menos un evento se pueden utilizar con WithEvents y WithEvents declaraciones
no se le puede asignar una referencia sobre el terreno con la palabra clave New . Este código es ilegal:

Privado WithEvents Foo As New Workbook 'ilegal

https://riptutorial.com/ 123

Página 139

La referencia al objeto debe establecerse 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 durante el tiempo que sea
existe una instancia.

Fuentes
Cualquier módulo de clase (o módulo de documento o formulario de usuario) puede ser un origen de eventos. Usa el evento
palabra clave para definir la firma del evento, en la sección de declaraciones del módulo:

Evento público SomethingHappened (ByVal algo como cadena)

La firma del evento determina cómo se genera el evento y qué harán los controladores de eventos.
parece.

https://translate.googleusercontent.com/translate_f 119/223
6/1/2021 Intitulado
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 generan con la palabra clave RaiseEvent ; Los argumentos del evento se proporcionan en ese punto:

Sub público DoSomething ()


RaiseEvent SomethingHappened ("hola")
End Sub

Sin el código que maneja el evento SomethingHappened , la ejecución del procedimiento DoSomething seguirá
plantee el evento, pero no pasará nada. Suponiendo que la fuente del evento es el código anterior en una clase
llamado Algo , este código en ThisWorkbook mostraría un cuadro de mensaje que decía "hola" siempre que
test.DoSomething se llama:

Prueba privada WithEvents como algo

Sub libro privado_Open ()


Establecer prueba = algo nuevo
prueba.hacer algo
End Sub

Private Sub test_SomethingHappened (barra ByVal como cadena)


'este procedimiento se ejecuta siempre que' prueba 'genera el evento' SomethingHappened '
Barra MsgBox
End Sub

Pasar datos a la fuente del evento

Usando parámetros pasados por referencia


Un evento puede definir un parámetro ByRef destinado a ser devuelto a la persona que llama:

Evento público BeforeSomething (ByRef cancelar como booleano)


Evento público AfterSomething ()

https://riptutorial.com/ 124

Página 140

Sub público DoSomething ()


Dim cancelar como booleano
RaiseEvent BeforeSomething (cancelar)
Si cancela, salga de Sub

'todo: realmente hacer algo

RaiseEvent AfterAlgo
End Sub

Si el evento BeforeSomething tiene un controlador que establece su parámetro de cancelación en True , entonces cuando
La ejecución regresa del controlador, cancel será True y AfterSomething nunca se generará.

Privado WithEvents foo como algo

Sub privado foo_BeforeSomething (ByRef cancelar como booleano)


cancel = MsgBox ("¿Cancelar?", vbYesNo) = vbYes
End Sub

Sub privado foo_AfterSomething ()


MsgBox "¡No canceló!"
End Sub

Suponiendo que la referencia del objeto foo está asignada en algún lugar, cuando se ejecuta foo.DoSomething , aparece un mensaje
cuadro pregunta si se debe cancelar, y un segundo cuadro de mensaje dice "no canceló" solo cuando no se
seleccionado.

https://translate.googleusercontent.com/translate_f 120/223
6/1/2021 Intitulado

Usando objetos mutables


También puede pasar una copia de un objeto mutable ByVal y permitir que los controladores modifiquen el
propiedades; la persona que llama puede leer los valores de propiedad modificados y actuar en consecuencia.

'módulo de clase ReturnBoolean


Opción explícita
Privado encapsulado como booleano

Propiedad pública Obtener ReturnValue () como booleano


'Atributo ReturnValue.VB_UserMemId = 0
ReturnValue = encapsulado
Propiedad final

Propiedad pública Let ReturnValue (valor ByVal como booleano)


encapsulado = valor
Propiedad final

Combinado con el tipo Variant , esto se puede usar para crear formas bastante no obvias de devolver un
valor para la persona que llama:

Evento público SomeEvent (ByVal foo como variante)

Sub público DoSomething ()


Resultado atenuado como ReturnBoolean

https://riptutorial.com/ 125

Página 141

result = New ReturnBoolean

RaiseEvent SomeEvent (resultado)

If result Then 'If result.ReturnValue Then


'handler cambió el valor a True
Más
'handler no modificó el valor
Terminara si
End Sub

El controlador se vería así:

Private Sub source_SomeEvent (ByVal foo As Variant) 'foo es en realidad un objeto ReturnBoolean
foo = True 'True está realmente asignado a foo.ReturnValue, el miembro predeterminado de la clase
End Sub

Leer eventos en línea: https://riptutorial.com/vba/topic/5278/events

https://translate.googleusercontent.com/translate_f 121/223
6/1/2021 Intitulado

https://riptutorial.com/ 126

Página 142

Capítulo 23: Estructuras de control de flujo


Ejemplos

Seleccione el caso

Seleccionar caso se
puede utilizar cuando son posibles muchas condiciones diferentes. Se comprueban las condiciones
de arriba a abajo y solo se ejecutará el primer caso que coincida.

Sub TestCase ()
Dim MyVar como cadena

Select Case MyVar 'Seleccionamos la variable MyVar para trabajar


Case "Hello" 'Ahora simplemente verificamos los casos que queremos verificar
MsgBox "Este caso"
Caso "Mundo"
MsgBox "Importante"
Caso "Cómo"
MsgBox "Cosas"
Caso "son"
MsgBox "Me estoy quedando sin ideas"
Case "You?", "Today" 'Puede separar varias condiciones con una coma
MsgBox "Uuuhm ..." 'si alguno coincide, irá al caso
Caso otro 'Si ninguno de los otros casos es afectado
MsgBox "Todos los demás casos fallaron"
Finalizar Seleccionar

Dim i como entero


Seleccione el caso i
Case Is> 2 'Se puede usar "Is" en lugar de la variable en las condiciones.
MsgBox "i es mayor que 2"
'Case 2 <Is' "Is" sólo se puede utilizar al principio de la condición.
'Case Else es opcional
Finalizar Seleccionar
End Sub

La lógica del bloque Seleccionar caso se puede invertir para admitir la prueba de diferentes variables también, en
En este tipo de escenario también podemos utilizar operadores lógicos:

Dim x como entero


Dim y como entero

x=2
y=5

Seleccionar caso verdadero


Caso x> 3
MsgBox "x es mayor que 3"
Caso y <2

https://translate.googleusercontent.com/translate_f 122/223
6/1/2021 Intitulado
MsgBox "y es menor que 2"
Caso x = 1
MsgBox "x es igual a 1"
Caso x = 2 Xor y = 3
MsgBox "Ir a leer sobre" "Xor" ""

https://riptutorial.com/ 127

Página 143

Caso no y = 5
MsgBox "y no es 5"
Caso x = 3 O x = 10
MsgBox "x = 3 o 10"
Caso y <10 y x <10
MsgBox "xey son menores que 10"
Caso otro
MsgBox "No se encontró ninguna coincidencia"
Finalizar Seleccionar

Las declaraciones de casos también pueden utilizar operadores aritméticos. Donde se usa un operador aritmético
en comparación con el valor Seleccionar caso , debe ir precedido de la palabra clave Is :

Dim x como entero

x=5

Seleccionar caso x
Caso 1
MsgBox "x es igual a 1"
Caso 2, 3, 4
MsgBox "x es 2, 3 o 4"
Caso 7 a 10
MsgBox "x está entre 7 y 10 (inclusive)"
El caso es <2
MsgBox "x es menor que uno"
El caso es> = 7
MsgBox "x es mayor o igual que 7"
Caso otro
MsgBox "no se encontró ninguna coincidencia"
Finalizar Seleccionar

Para cada bucle

La construcción de bucle For Each es ideal para iterar todos los elementos de una colección.

Public Sub IterateCollection (elementos ByVal como colección)

'Para cada iterador siempre debe ser variante


Elemento de atenuación como variante

Para cada elemento en artículos


'asume que el elemento se puede convertir en una cadena
Elemento Debug.Print
próximo

End Sub

Use For Each al iterar colecciones de objetos:

Atenuar hoja como hoja de trabajo


Para cada hoja en ActiveWorkbook.
Debug.Print sheet.Name
próximo

https://riptutorial.com/ 128

https://translate.googleusercontent.com/translate_f 123/223
6/1/2021 Intitulado
Página 144

Evite For Each al iterar matrices; un bucle For ofrecerá un rendimiento significativamente mejor con
matrices. Por el contrario, un bucle For Each ofrecerá un mejor rendimiento al iterar una colección .

Sintaxis
Para cada [artículo] en [colección]
[declaraciones]
Proximo articulo]

La palabra clave Next puede ir seguida opcionalmente por la variable iteradora; esto puede ayudar a aclarar anidado
bucles, aunque hay mejores formas de aclarar el código anidado, como extraer el bucle interno en
su propio procedimiento.

Dim book como libro de trabajo


Para cada libro en la aplicación.

Debug.Print book.FullName

Atenuar hoja como hoja de trabajo


Para cada hoja en ActiveWorkbook.
Debug.Print sheet.Name
Siguiente hoja
Siguiente libro

Hacer bucle

DoLoop secundario público ()


Entrada atenuada como cadena
entrada = ""
'Equivalente a un bucle While solicitará cadenas hasta "Stop" en dado
'Prefiero usar un bucle While en lugar de esta forma de bucle Do
Hacer mientras ingresa <> "Detener"
entry = InputBox ("Ingrese una cadena, detener hasta el final")
Debug.Print entrada
Lazo

'Equivalente al ciclo anterior, pero la condición solo se comprueba DESPUÉS de


'primera iteración del ciclo, por lo que se ejecutará incluso al menos una vez incluso
'si la entrada es igual a "Detener" antes de entrar al bucle (como en este caso)
Hacer
entry = InputBox ("Ingrese una cadena, detener hasta el final")
Debug.Print entrada
Bucle mientras entrada <> "Detener"

'Equivalente a escribir la entrada Hacer mientras no = "Detener"


'
'Debido a que el Hasta está en la parte superior del ciclo,
'no se ejecuta porque la entrada sigue siendo igual a "Detener"
'al evaluar la condición
Hacer hasta la entrada = "Parar"
entry = InputBox ("Ingrese una cadena, detener hasta el final")
Debug.Print entrada
Lazo

https://riptutorial.com/ 129

Página 145

'Equivalente a escribir Do ... Loop While Not i> = 100


Hacer
entry = InputBox ("Ingrese una cadena, detener hasta el final")
Debug.Print entrada
Bucle hasta entrada = "Detener"
End Sub

https://translate.googleusercontent.com/translate_f 124/223
6/1/2021 Intitulado

Mientras bucle

'Devolverá si un elemento está presente en la matriz


Función pública IsInArray (valores () como cadena, ByVal whatToFind como cadena) como booleano
Dim i como entero
i=0

Mientras i <UBound (valores) Y valores (i) <> whatToFind


yo = yo + 1
Encaminarse a

IsInArray = valores (i) = whatToFind


Función final

En bucle

El ciclo For se utiliza para repetir la sección adjunta de código un número determinado de veces. El seguimiento
Un ejemplo simple ilustra la sintaxis básica:

Dim i como entero 'Declaración de i


Para i = 1 a 10 'Declare cuántas veces se ejecutará el ciclo
Debug.Print i 'El fragmento de código que se repite
Siguiente yo 'El final del ciclo

El código anterior declara un entero i . El bucle For asigna todos los valores 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 el
ventana. Tenga en cuenta que la variable de bucle se incrementa con la siguiente instrucción, es decir, después de la adjunta
el código se ejecuta en lugar de antes de que se ejecute.

De forma predeterminada, el contador se incrementará en 1 cada vez que se ejecute el ciclo. Sin embargo, un paso puede
ser especificado para cambiar la cantidad del incremento como un valor literal o de retorno de un
función. Si el valor inicial, el valor final o el valor de Paso es un número de punto flotante, será
redondeado al valor entero más cercano. El paso puede ser un valor positivo o negativo.

Dim i como entero


Para i = 1 a 10 Paso 2
Debug.Print i 'Imprime 1, 3, 5, 7 y 9
próximo

En general, un bucle For se usaría en situaciones en las que se sabe antes de que comience el bucle cómo
muchas veces para ejecutar 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 entrada en el ciclo, como lo demuestra este código:

https://riptutorial.com/ 130

Página 146

Iteraciones privadas siempre que 'Alcance del módulo

Subejemplo público ()
Dim i tan largo
Iteraciones = 10
Para i = 1 a iteraciones
Debug.Print Iterations 'Imprime de 10 a 1, en orden descendente.
Iteraciones = Iteraciones - 1
próximo
End Sub

Un bucle For se puede salir antes con la instrucción Exit For :

Dim i como entero

Para i = 1 a 10
Si i> 5 Entonces
Salir para
Terminara si

https://translate.googleusercontent.com/translate_f 125/223
6/1/2021 Intitulado
Debug.Print i 'Imprime 1, 2, 3, 4, 5 antes de que el ciclo salga antes.
próximo

Lea las estructuras de control de flujo en línea: https://riptutorial.com/vba/topic/1873/flow-control-structures

https://riptutorial.com/ 131

Página 147

Capítulo 24: Cuerda de uso frecuente


manipulación
Introducción
Ejemplos rápidos de funciones de cadena MID LEFT y RIGHT usando INSTR FIND y LEN.

¿Cómo encuentras el texto entre dos términos de búsqueda (digamos: después de dos puntos y antes de una coma)?
¿Cómo se obtiene el resto de una palabra (utilizando MID o RIGHT)? Cual de estas funciones
utilizar parámetros de base cero y códigos de retorno frente a uno? ¿Qué pasa cuando las cosas salen mal?
¿Cómo manejan cadenas vacías, resultados no encontrados y números negativos?

Ejemplos

Manipulación de cadenas ejemplos de uso frecuente

Mejor MID () y otros ejemplos de extracción de cadenas, que actualmente no se encuentran en la web. por favor, ayúdame
haz un buen ejemplo, o completa este aquí. Algo como esto:

DIM strEmpty como cadena, strNull como cadena, el texto como cadena
DIM idx como entero

https://translate.googleusercontent.com/translate_f 126/223
6/1/2021 Intitulado
DIM letterCount como entero
Resultado DIM como String

strNull = NADA
strEmpty = ""
theText = "1234, 78910"

'-----------------
'Extrae la palabra después de la coma "," y antes de "910" resultado: "78" ***
'-----------------

'Obtener el índice (lugar) de la coma usando INSTR


idx = ... 'alguna explicación aquí
if idx <... 'compruebe si no se encuentran comas en el texto

'u obtenga el índice de coma usando FIND


idx = ... 'alguna explicación aquí ... Nota: La diferencia es ...
if idx <... 'compruebe si no se encuentran comas en el texto

resultado = MID (theText, ..., LEN (...

'Recuperar la palabra restante después de la coma


result = MID (theText, idx + 1, LEN (theText) - idx + 1)

'Obtener palabra hasta la coma usando LEFT


resultado = IZQUIERDA (elTexto, idx - 1)

'Obtener el texto restante después de la coma y el espacio usando DERECHA


resultado = ...

https://riptutorial.com/ 132

Página 148

'¿Qué pasa cuando las cosas van mal?


resultado = MID (strNothing, 1, 2) 'esto causa ...
result = MID (strEmpty, 1, 2) 'que causa ...
result = MID (theText, 30, 2) 'y ahora ...
result = MID (theText, 2, 999) 'no se preocupe ...
resultado = MID (theText, 0, 2)
resultado = MID (theText, 2, 0)
resultado = MID (theText -1, 2)
resultado = MID (elTexto 2, -1)
idx = INSTR (strNothing, "123")
idx = INSTR (theText, strNothing)
idx = INSTR (elTexto, strEmpty)
i = LEN (estricto)
i = LEN (strNothing) '...

No dude en editar este ejemplo y mejorarlo. Mientras permanezca claro y tenga en él


prácticas de uso comunes.

Lea la manipulación de cadenas de uso frecuente en línea: https://riptutorial.com/vba/topic/8890/frecuencia-


manipulación-de-cuerda-usada

https://translate.googleusercontent.com/translate_f 127/223
6/1/2021 Intitulado

https://riptutorial.com/ 133

Página 149

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 un
La interfaz es una lista de firmas de métodos (nombre, parámetros y tipo de retorno). Una clase que tiene todo
se dice que los métodos "implementan" esa interfaz.

En VBA, el uso de interfaces le permite al compilador verificar que un módulo implementa todos sus métodos. UN
La variable o el parámetro se pueden definir en términos de una interfaz en lugar de una clase específica.

Ejemplos

Interfaz simple - Volable

La interfaz Flyable es un módulo de clase con el siguiente código:

Submarino público ()
' Sin código.
End Sub

Función pública GetAltitude () As Long


' Sin código.
Función final

Un módulo de clase, Aeroplano , usa la palabra clave Implements para decirle al compilador que genere un error a menos que
tiene dos métodos: un sub Flyable_Fly () y una función Flyable_GetAltitude () que devuelve un Long .

Implementos Flyable

Public Sub Flyable_Fly ()


Debug.Print "¡Volando con motores a reacción!"
End Sub

Función pública Flyable_GetAltitude () tan largo


Flyable_GetAltitude = 10000
Función final

Un módulo de segunda clase, Duck , también implementa Flyable :

Implementos Flyable

Public Sub Flyable_Fly ()

https://translate.googleusercontent.com/translate_f 128/223
6/1/2021 Intitulado
Debug.Print "¡Volando con alas!"
End Sub

Función pública Flyable_GetAltitude () tan largo


Flyable_GetAltitude = 30
Función final

https://riptutorial.com/ 134

Página 150

Podemos escribir una rutina que acepte cualquier valor Flyable , sabiendo que responderá a un comando
de Fly o GetAltitude :

Public Sub FlyAndCheckAltitude (F como volante)


F.Fly
Debug.Print F.GetAltitude
End Sub

Debido a que la interfaz está definida, la ventana emergente de IntelliSense mostrará Fly y GetAltitude para F
.

Cuando ejecutamos el siguiente código:

Dim MyDuck como nuevo pato


Dim MyAirplane como nuevo avión

FlyAndCheckAltitude MyDuck
FlyAndCheckAltitude MyAirplane

La salida es:

¡Volando con alas!


30
¡Volando con motores a reacción!
10000

Tenga en cuenta que aunque la subrutina se denomina Flyable_Fly tanto en Airplane como en Duck , se puede
llamado Fly cuando la variable o parámetro se define como Flyable . Si la variable está definida
específicamente como pato , tendría que llamarse Flyable_Fly .

Múltiples interfaces en una clase: se puede volar y se puede nadar

Usando el ejemplo de Flyable como punto de partida, podemos agregar una segunda interfaz, Swimmable , con el
siguiente código:

Sub Swim ()
' Sin código
End Sub

El objeto Duck puede implementar tanto volar como nadar:

Implementos Flyable
Implementos Swimmable

Public Sub Flyable_Fly ()


Debug.Print "¡Volando con alas!"
End Sub

Función pública Flyable_GetAltitude () tan largo


Flyable_GetAltitude = 30
Función final

https://riptutorial.com/ 135

https://translate.googleusercontent.com/translate_f 129/223
6/1/2021 Intitulado

Página 151

Público Sub Swimmable_Swim ()


Debug.Print "Flotando en el agua"
End Sub

Una clase Fish también puede implementar Swimmable :

Implementos Swimmable

Público Sub Swimmable_Swim ()


Debug.Print "Nadar bajo el agua"
End Sub

Ahora, podemos ver que el objeto Duck se puede pasar a un Sub como Flyable en una mano, y un
Nadable en el otro:

Prueba de interfaz secundaria ()

Dim MyDuck como nuevo pato


Dim MyAirplane como nuevo avión
Dim MyFish como pez nuevo

Debug.Print "Fly Check ..."

FlyAndCheckAltitude MyDuck
FlyAndCheckAltitude MyAirplane

Depurar. Imprimir "Prueba de natación ..."

TrySwimming MyDuck
TrySwimming MyFish

End Sub

Public Sub FlyAndCheckAltitude (F como volante)


F.Fly
Debug.Print F.GetAltitude
End Sub

Prueba pública secundaria (S como para nadar)


S. Nadar
End Sub

El resultado de este código es:

Comprobación de moscas ...

¡Volando con alas!

30

¡Volando con motores a reacción!

10000

Comprobación de natación ...

https://riptutorial.com/ 136

Página 152

Flotando en el agua

Nadando bajo el agua

Leer interfaces en línea: https://riptutorial.com/vba/topic/8784/interfaces

https://translate.googleusercontent.com/translate_f 130/223
6/1/2021 Intitulado

https://riptutorial.com/ 137

Página 153

Capítulo 26: Macro seguridad y firma de


Proyectos / módulos VBA
Ejemplos

Cree un certificado autofirmado digital válido SELFCERT.EXE

Para ejecutar macros y mantener la seguridad que brindan las aplicaciones de Office contra códigos maliciosos,
necesario para firmar digitalmente el VBAProject.OTM desde el editor VBA> Herramientas> Firma digital .

https://translate.googleusercontent.com/translate_f 131/223
6/1/2021 Intitulado

Office viene con una utilidad para crear un certificado digital autofirmado que puede emplear en la PC
para firmar tus proyectos.

Esta utilidad SELFCERT.EXE se encuentra en la carpeta del programa de Office,

Haga clic en Certificado digital para proyectos VBA para abrir el asistente de certificados .

En el cuadro de diálogo, introduzca un nombre adecuado para el certificado y haga clic en Aceptar.

https://riptutorial.com/ 138

Página 154

Si todo va bien, verá una confirmación:

https://translate.googleusercontent.com/translate_f 132/223
6/1/2021 Intitulado

Ahora puede cerrar el asistente SELFCERT y centrar su atención en el certificado que tiene
creado.

Si intenta utilizar el certificado que acaba de crear y comprueba sus propiedades

https://riptutorial.com/ 139

Página 155

https://translate.googleusercontent.com/translate_f 133/223
6/1/2021 Intitulado

Verá que el certificado no es de confianza y el motivo se indica en el cuadro de diálogo.

El certificado se ha creado en Usuario actual> Personal> Almacén de certificados. Tiene que ir


en Equipo local> Autoridades de certificación raíz de confianza> Almacén de certificados, por lo que debe
exportar del primero e importar al segundo.

Al presionar la tecla de Windows + R, se abrirá la ventana 'Ejecutar'. luego ingrese 'mmc' en la ventana como

https://riptutorial.com/ 140

Página 156

que se muestra a continuación y haga clic en "Aceptar".

Microsoft Management Console se abrirá y tendrá el siguiente aspecto.

https://translate.googleusercontent.com/translate_f 134/223
6/1/2021 Intitulado
En el menú Archivo, seleccione Agregar o quitar complemento ... Luego, en el cuadro de diálogo siguiente, haga doble clic
Certificados y luego haga clic en Aceptar

https://riptutorial.com/ 141

Página 157

Expanda el menú desplegable en la ventana izquierda para Certificados - Usuario actual 'y seleccione certificados como
mostrado a continuación. El panel central luego mostrará los certificados en esa ubicación, que incluirá
el certificado que creó anteriormente:

https://riptutorial.com/ 142
https://translate.googleusercontent.com/translate_f 135/223
6/1/2021 Intitulado

Página 158

Haga clic con el botón derecho en el certificado y seleccione Todas las tareas> Exportar:

https://riptutorial.com/ 143

Página 159

https://translate.googleusercontent.com/translate_f 136/223
6/1/2021 Intitulado

Asistente de exportación

https://riptutorial.com/ 144

Página 160

https://translate.googleusercontent.com/translate_f 137/223
6/1/2021 Intitulado

Haga clic en Siguiente

https://riptutorial.com/ 145

Página 161

la única opción preseleccionada estará disponible, así que haga clic en 'Siguiente' nuevamente:

https://translate.googleusercontent.com/translate_f 138/223
6/1/2021 Intitulado

El elemento superior ya estará preseleccionado. Haga clic en Siguiente nuevamente y elija un nombre y una ubicación para
guarde el certificado exportado.

https://riptutorial.com/ 146

Página 162

Haga clic en Siguiente nuevamente para guardar el certificado.

Una vez que el foco se devuelve a la Consola de administración.

Expanda el menú Certificados y, en el menú Autoridades de certificación raíz de confianza, seleccione


Certificados .

https://translate.googleusercontent.com/translate_f 139/223
6/1/2021 Intitulado

https://riptutorial.com/ 147

Página 163

Botón derecho del ratón. Seleccionar todas las tareas e importar

https://translate.googleusercontent.com/translate_f 140/223
6/1/2021 Intitulado

https://riptutorial.com/ 148

Página 164

Haga clic en siguiente y guarde en la tienda Trusted Root Certification Authorities :

https://translate.googleusercontent.com/translate_f 141/223
6/1/2021 Intitulado
https://riptutorial.com/ 149

Página 165

Luego Siguiente> Finalizar, ahora cierre la Consola.

Si ahora usa el certificado y verifica sus propiedades, verá que es un certificado confiable
y puedes usarlo para firmar tu proyecto:

Lea la seguridad de macros y la firma de proyectos / módulos VBA en línea:


https://riptutorial.com/vba/topic/7733/macro-security-and-signing-of-vba-projects--modules

https://riptutorial.com/ 150

Página 166

Capítulo 27: Medición de la longitud de cuerdas

https://translate.googleusercontent.com/translate_f 142/223
6/1/2021 Intitulado

Observaciones
La longitud de una cuerda se puede medir de dos formas: La medida de longitud más utilizada es la
número de caracteres que utilizan las funciones de Len , pero VBA también puede revelar el número de bytes utilizando
Funciones LenB . Un carácter de doble byte o Unicode tiene más de un byte de longitud.

Ejemplos

Use la función Len para determinar el número de caracteres en una cadena

Const baseString As String = "Hola mundo"

Dim charLength As Long

charLength = Len (baseString)


'charlength = 11

Utilice la función LenB para determinar el número de bytes en una cadena

Const baseString As String = "Hola mundo"

Dim byteLength tan largo

byteLength = LenB (baseString)


'byteLength = 22

Prefiera `If Len (myString) = 0 Then` sobre` If myString = "" Then`

Al verificar si una cadena tiene longitud cero, es una mejor práctica y más eficiente inspeccionar el
longitud de la cadena en lugar de comparar la cadena con una cadena vacía.

Const myString como cadena = vbNullString

'Prefiera este método al verificar si myString es una cadena de longitud cero


Si Len (myString) = 0 Entonces
Debug.Print "myString es de longitud cero"
Terminara si

'Evite usar este método al verificar si myString es una cadena de longitud cero
Si myString = vbNullString Entonces
Debug.Print "myString es de longitud cero"
Terminara si

Leer Medición de la longitud de cuerdas en línea: https://riptutorial.com/vba/topic/3576/measuring-the-


longitud-de-cuerdas

https://riptutorial.com/ 151

Página 167

Capítulo 28: Convenciones de nomenclatura


Ejemplos

Nombres de variables

Las variables contienen datos. Nómbrelos según para qué se utilizan, no según su tipo de datos o alcance,
usando un sustantivo . Si se siente obligado a numerar sus variables (por ejemplo , cosa1, cosa2, cosa3 ), entonces
en su lugar, considere utilizar una estructura de datos adecuada (por ejemplo, una matriz, una colección o un diccionario ).

Nombres de variables que representan un conjunto iterable de valores, por ejemplo, una matriz, una colección , una
https://translate.googleusercontent.com/translate_f 143/223
6/1/2021 Intitulado
El diccionario , o un rango de celdas, debe estar en plural.

Algunas convenciones de nombres de VBA comunes son así:

Para variables a nivel de procedimiento :

el caso de Carmel

Nombre de subejemplo público (ByVal inputValue As Long, ByRef inputVariable As Long)

Procedimiento de atenuación Variable siempre que


Dim someOtherVariable As String

End Sub

Para variables de nivel de módulo:

PascalCase

Public GlobalVariable siempre que


Módulo privado Variable como cadena

Para constantes:

SHOUTY_SNAKE_CASE se usa comúnmente para diferenciar constantes de variables:

Public Const GLOBAL_CONSTANT As String = "Versión del proyecto # 1.000.000.001"


Private Const MODULE_CONSTANT As String = "Algo relevante para este módulo"

Sub Público SomeProcedure ()

Const PROCEDURE_CONSTANT Tan largo = 10

End Sub

Sin embargo, los nombres de PascalCase crean un código de aspecto más limpio y son igual de buenos, dado IntelliSense
utiliza diferentes iconos para variables y constantes:

https://riptutorial.com/ 152

Página 168

Notación húngara
Nómbrelos según para qué se utilizan, no según 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"

Si escribe su código, como los procedimientos, se adhiere al principio de responsabilidad única (ya que
debería), nunca debería mirar una pantalla llena de declaraciones de variables en la parte superior de cualquier
procedimiento; declarar las variables lo más cerca posible de su primer uso, y su tipo de datos
estar siempre a la vista si los declara con un tipo explícito. El atajo Ctrl + i de VBE se puede

https://translate.googleusercontent.com/translate_f 144/223
6/1/2021 Intitulado
también se usa para mostrar el tipo de una variable en una información sobre herramientas.
Para qué se utiliza una variable es información mucho más útil que su tipo de datos, especialmente en un
lenguaje como VBA que feliz e implícitamente convierte un tipo en otro según sea necesario.

Considere iFile y strFile en este ejemplo:

Función bReadFile (ByVal strFile como cadena, ByRef strData como cadena) como booleano
Dim bRetVal como booleano
Dim iFile como entero

En caso de error, vaya a CleanFail

iFile = FreeFile
Abra strFile para la entrada como #iFile
Entrada #iFile, strData

bRetVal = Verdadero

Limpiar Salida:
Cerrar #iFile
bReadFile = bRetVal
Función de salida
CleanFail:
bRetVal = Falso
Reanudar Limpiar Salir
Función final

Comparar con:

Función CanReadFile (ruta ByVal como cadena, ByRef outContent como cadena) como booleano

https://riptutorial.com/ 153

Página 169

En caso de error, vaya a CleanFail

Controlador tenue como entero


handle = FreeFile

Abrir ruta para entrada como #handle


Entrada #handle, outContent

Resultado atenuado como booleano


resultado = Verdadero

Limpiar Salida:
Cerrar #handle
CanReadFile = resultado
Función de salida
CleanFail:
resultado = Falso
Reanudar Limpiar Salir
Función final

strData se
pasa ByRef en el ejemplo superior, pero además del hecho de que tenemos la suerte de verlo
se pasa explícitamente como tal, no hay ninguna indicación de que strData sea realmente devuelto por la función.

El ejemplo inferior lo nombra outContent ; esto a cabo prefijo es lo que se inventó la notación húngara
para: para ayudar a aclarar para qué se utiliza una variable , en este caso para identificarla claramente como una "salida"
parámetro.

Esto es útil, porque IntelliSense por sí mismo no muestra ByRef , incluso cuando el parámetro es
pasado explícitamente por referencia:

Lo que lleva a...

https://translate.googleusercontent.com/translate_f 145/223
6/1/2021 Intitulado

Húngaro bien hecho

La notación húngara originalmente no tenía nada que ver con los tipos de variables. De hecho, húngaro
La notación bien hecha es realmente útil. Considere este pequeño ejemplo ( ByVal y As Integer eliminado
por brevedad):

Subcopia pública (iX1, iY1, iX2, iY2)


End Sub

Comparar con:

Subcopia pública (srcColumn, srcRow, dstColumn, dstRow)


End Sub

src y dst son


prefijos de notación húngara , y transmiten información útil que no puede
de lo contrario, ya se infiere de los nombres de los parámetros o IntelliSense mostrándonos el declarado
tipo.

https://riptutorial.com/ 154

Página 170

Por supuesto, hay una mejor manera de transmitirlo todo, utilizando la abstracción adecuada y palabras reales que pueden ser
pronunciado en voz alta y tiene sentido, como un ejemplo artificial:

Tipo de coordenadas
RowIndex tan largo
ColumnIndex tan largo
Tipo final

Copia secundaria (origen como coordenadas, destino como coordenadas)


End Sub

Nombres de procedimientos

Los procedimientos hacen algo . Nómbrelos por lo que están haciendo, usando un verbo . Si nombra con precisión
un procedimiento no es posible, es probable que el procedimiento esté haciendo demasiadas cosas y deba romperse
en procedimientos más pequeños y especializados.

Algunas convenciones de nombres de VBA comunes son así:

Para todos los procedimientos:

PascalCase

Sub DoThing público ()

End Sub

Función privada ReturnSomeValue () como [DataType]

Función final

Para los procedimientos del controlador de eventos:

ObjectName_EventName

Public Sub Workbook_Open ()

End Sub

Botón secundario público1_Click ()

End Sub

https://translate.googleusercontent.com/translate_f 146/223
6/1/2021 Intitulado
Los controladores de eventos suelen ser nombrados automáticamente por el VBE; renombrarlos sin renombrar el
objeto y / o el evento manejado romperá el código - el código se ejecutará y compilará, pero el controlador
El procedimiento quedará huérfano y nunca se ejecutará.

Miembros booleanos

Considere una función de retorno booleano:

Función bReadFile (ByVal strFile como cadena, ByRef strData como cadena) como booleano

https://riptutorial.com/ 155

Página 171

Función final

Comparar con:

Función CanReadFile (ruta ByVal como cadena, ByRef outContent como cadena) como booleano
Función final

El prefijo Can tiene el mismo propósito que el prefijo b : identifica el valor de retorno de la función
como booleano . Pero Can se lee mejor que b :

Si CanReadFile (ruta, contenido) Entonces

Comparado con:

Si bReadFile (strFile, strData) Entonces

Considere usar prefijos como Can , Is o Has delante de los miembros que devuelven booleanos (funciones
y propiedades), pero solo cuando aporta valor. Esto se ajusta a laactual Microsoft namin g
directrices .

Lea las convenciones de nomenclatura en línea: https://riptutorial.com/vba/topic/1184/naming-conventions

https://translate.googleusercontent.com/translate_f 147/223
6/1/2021 Intitulado

https://riptutorial.com/ 156

Página 172

Capítulo 29: Caracteres no latinos


Introducción
VBA puede leer y escribir cadenas en cualquier idioma o script usando Unicode . Sin embargo, hay
reglas más estrictas para Tokens de identificación .

Ejemplos

Texto no latino en código VBA

En la celda A1 de la hoja de cálculo, tenemos el siguiente pangrama árabe:

‫ﻌﻄﺎر‬
ِ ِ‫ﻀﺠﯿ ُﻊ ﺑِﮭﺎ ﻧَﺠﻼ َء ﻣ‬ ِ ‫ﺻﻒ ﺧَﻠﻖَ ﺧَﻮ ِد َﻛﻤِ ﺜ ِﻞ اﻟﺸ‬
َ ‫ ﯾَﺤﻈﻰ اﻟ‬- ‫َﻤﺲ إِذ ﺑَﺰَ ﻏَﺖ‬ ِ

VBA proporciona las funciones AscW y ChrW para trabajar con códigos de caracteres multibyte. También podemos
use matrices de bytes para manipular la variable de cadena directamente:

Sub NonLatinStrings ()

Atenuar como rango


Establecer rng = Rango ("A1")
Hacer hasta rng = ""
Dim MyString como cadena
MyString = rng.Value

'Funciones AscW
Dim char como cadena
char = AscW (Izquierda (MyString, 1))
Debug.Print "Primer carácter (ChrW):" & char
Debug.Print "Primer carácter (binario):" & BinaryFormat (carácter, 12)

'Funciones ChrW
Dim uString como cadena
uString = ChrW (carácter)
Debug.Print "Valor de cadena (texto):" & uString ¡Falla! Aparece como '?'
Debug.Print "Valor de cadena (AscW):" & AscW (uString)

'Usando una cadena de bytes


Dim StringAsByt () como byte
StringAsByt = MyString
Dim i tan largo
Para i = 0 a 1 Paso 2
Debug.Print "Valores de bytes (en decimal):" & _
StringAsByt (i) y "|" & StringAsByt (i + 1)
Debug.Print "Valores de bytes (binarios):" & _
BinaryFormat (StringAsByt (i)) & "|" & BinaryFormat (StringAsByt (i + 1))
Siguiente yo
Debug.Print ""

'Error al imprimir la cadena completa en la ventana inmediata (todos los'? ')


Debug.Print "Cadena completa" & vbNewLine & rng.Value
Establecer rng = rng.Offset (1)

https://riptutorial.com/ 157

Página 173

Lazo

End Sub

https://translate.googleusercontent.com/translate_f 148/223
6/1/2021 Intitulado

Esto produce la siguiente salida para el Letra árabe triste :

Primer carácter (ChrW): 1589


Primer carácter (binario): 00011000110101
Valor de cadena (texto):?
Valor de cadena (AscW): 1589
Valores de bytes (en decimal): 53 | 6
Valores de bytes (binarios): 00110101 | 00000110

Cadena entera
??? ????? ????? ??????? ??????? ??? ??????? - ????? ???????? ???? ???????
???????

Tenga en cuenta que VBA no puede imprimir texto no latino en la ventana inmediata aunque la cadena
las funciones funcionan correctamente. Esta es una limitación del IDE y no del idioma.

Identificadores no latinos y cobertura de idiomas

Los identificadores de VBA (nombres de variables y funciones) pueden usar la escritura latina y también pueden usar
japonés ,Corea ,Chino simplificado yEscrituras tradicionales chinas .

La escritura latina extendida tiene una cobertura completa para muchos idiomas:
Inglés, francés, español, alemán, italiano, bretón, catalán, danés, estonio, finlandés, islandés,
Indonesio, irlandés, lojban, mapudungun, noruego, portugués, gaélico escocés, sueco,
Tagalo

Algunos idiomas están cubiertos solo parcialmente:


Azerí, croata, checo, esperanto, húngaro, letón, lituano, polaco, rumano, serbio,
Eslovaco, esloveno, turco, yoruba, galés

Algunos idiomas tienen poca o ninguna cobertura:


Árabe, búlgaro, cherokee, dzongkha, griego, hindi, macedonio, malayalam, mongol,
Ruso, sánscrito, tailandés, tibetano, urdu, uigur

Las siguientes declaraciones de variables son todas válidas:

Dim Yec'hed As String 'Breton


Dim «Dóna» As String 'Catalán
Dim fræk As String 'danés
Dim tšellomängija As String 'estonio
Dim Törkylempijävongahdus As String 'finlandés
Dim j'examine As String 'Francés
Dim Paß As String 'Alemán
Dim þjófum As String 'islandés
Dim hÓighe As String 'irlandés
Dim sofybakni As String 'Lojban (.o'i no funciona)
Dim ñizol As String 'Mapudungun

https://riptutorial.com/ 158

Página 174

Dim Vår As String 'Noruego


Dim «brações» As String 'Portugués
Dim d'fhàg As String 'gaélico escocés

Tenga en cuenta que en el IDE de VBA, un solo apóstrofo 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 utilizan dos ángulos para indicar una cita «» pueden utilizar los de variable
los nombres describen el hecho de que las comillas de tipo "" no lo son.

Leer caracteres no latinos en línea: https://riptutorial.com/vba/topic/10555/non-latin-characters

https://translate.googleusercontent.com/translate_f 149/223
6/1/2021 Intitulado

https://riptutorial.com/ 159

Página 175

Capítulo 30: VBA orientado a objetos


Ejemplos

Abstracción

Los niveles de abstracción ayudan a determinar cuándo dividir las cosas.

La abstracción se logra implementando funcionalidad con código cada vez más detallado. La entrada
El punto de una macro debe ser un pequeño procedimiento con un alto nivel de abstracción que facilite la
capte de un vistazo lo que está pasando:

Sub público DoSomething ()


Con el nuevo SomeForm
Establecer .Model = CreateViewModel
.Mostrar vbModal
Si .IsCancelled, salga de Sub
ProcessUserData .Model
Terminar con
End Sub

https://translate.googleusercontent.com/translate_f 150/223
6/1/2021 Intitulado

El procedimiento DoSomething tiene un alto nivel de abstracción : podemos decir que está mostrando un formulario y
creando algún modelo y pasando ese objeto a algún procedimiento ProcessUserData que sepa qué
que ver con eso - cómo se crea el modelo es el trabajo de otro procedimiento:

Función privada CreateViewModel () como ISomeModel


Resultado atenuado como ISomeModel
Establecer resultado = SomeModel.Create (Ahora, Environ $ ("UserName"))
result.AvailableItems = GetAvailableItems
Establecer CreateViewModel = resultado
Función final

La función CreateViewModel solo es responsable de crear alguna instancia de ISomeModel . Parte de eso
La responsabilidad es adquirir una variedad de elementos disponibles ; cómo se adquieren estos elementos es una
detalles de implementación que se resumen detrás del procedimiento GetAvailableItems :

Función privada GetAvailableItems () como variante


GetAvailableItems = DataSheet.Names ("AvailableItems"). RefersToRange
Función final

Aquí el procedimiento es la lectura de los valores disponibles de un rango con nombre en una Hoja de datos de hoja de cálculo.
También podría leerlos de una base de datos, o los valores podrían estar codificados: es un
detalles de implementación que no son motivo de preocupación para ninguno de los niveles de abstracción más altos.

Encapsulamiento

La encapsulación oculta los detalles de implementación del código del cliente.

https://riptutorial.com/ 160

Página 176

los El ejemplo de manejo de QueryClose demuestra la encapsulación: el formulario tiene un control de casilla de verificación,
pero su código de cliente no funciona con él directamente: la casilla de verificación es un detalle de implementación , lo que
El código del cliente necesita saber si la configuración está habilitada o no.

Cuando el valor de la casilla de verificación cambia, el controlador asigna un miembro de campo privado:

TView de tipo privado


IsCancelled como booleano
SomeOtherSetting como booleano
'otras propiedades omitidas por brevedad
Tipo final
Privado esto como TView

'...

Sub privado SomeOtherSettingInput_Change ()


this.SomeOtherSetting = CBool (SomeOtherSettingInput.Value)
End Sub

Y cuando el código del cliente quiere leer ese valor, no necesita preocuparse por una casilla de verificación:
en su lugar, simplemente usa la propiedad SomeOtherSetting :

Propiedad pública Obtener SomeOtherSetting () como booleano


SomeOtherSetting = this.SomeOtherSetting
Propiedad final

La propiedad SomeOtherSetting encapsula el estado de la casilla de verificación; el código del cliente no necesita saber
que hay una casilla de verificación involucrada, solo que hay una configuración con un valor booleano. por encapsulado
el valor booleano , hemos agregado una capa de abstracción alrededor de la casilla de verificación.

Usar interfaces para imponer la inmutabilidad

https://translate.googleusercontent.com/translate_f 151/223
6/1/2021 Intitulado

Llevemos eso un paso más allá encapsulando el modelo del formulario en un módulo de clase dedicado. Pero si
hicimos una propiedad pública para el nombre de usuario y la marca de tiempo , tendríamos que exponer la propiedad Let
accesores, haciendo que las propiedades sean mutables, y no queremos que el código del cliente tenga la capacidad de
cambie estos valores una vez establecidos.

La función CreateViewModel en el ejemplo de Abstraction devuelve una clase ISomeModel : esa es nuestra
interfaz , y se parece a esto:

Opción explícita

Propiedad pública Obtener marca de tiempo () como fecha


Propiedad final

Propiedad pública Obtener UserName () como cadena


Propiedad final

Propiedad pública Obtener AvailableItems () como variante


Propiedad final

Propiedad pública Let AvailableItems (valor ByRef como variante)

https://riptutorial.com/ 161

Página 177

Propiedad final

Propiedad pública Obtener SomeSetting () como cadena


Propiedad final

Propiedad pública Let SomeSetting (valor ByVal como cadena)


Propiedad final

Propiedad pública Obtener SomeOtherSetting () como booleano


Propiedad final

Propiedad pública Let SomeOtherSetting (valor ByVal como booleano)


Propiedad final

Observe que las propiedades de marca de tiempo y nombre de usuario solo exponen un descriptor de acceso de obtención de propiedad . Ahora el SomeModel
la clase puede implementar esa interfaz:

Opción explícita
Implementa ISomeModel

Modelo privado de tipo


Marca de tiempo como fecha
Nombre de usuario como cadena
SomeSetting como cadena
SomeOtherSetting como booleano
AvailableItems como variante
Tipo final
Privado esto como TModel

Propiedad privada Obtenga ISomeModel_Timestamp () como fecha


ISomeModel_Timestamp = this.Timestamp
Propiedad final

Propiedad privada Obtenga ISomeModel_UserName () como cadena


ISomeModel_UserName = this.UserName
Propiedad final

Propiedad privada Obtenga ISomeModel_AvailableItems () como variante


ISomeModel_AvailableItems = this.AvailableItems
Propiedad final

Propiedad privada Let ISomeModel_AvailableItems (valor ByRef como variante)


this.AvailableItems = valor
Propiedad final

Propiedad privada Obtenga ISomeModel_SomeSetting () como cadena


ISomeModel_SomeSetting = this.SomeSetting
Propiedad final

https://translate.googleusercontent.com/translate_f 152/223
6/1/2021 Intitulado

Propiedad privada Let ISomeModel_SomeSetting (valor ByVal como cadena)


this.SomeSetting = valor
Propiedad final

Propiedad privada Obtenga ISomeModel_SomeOtherSetting () como booleano


ISomeModel_SomeOtherSetting = this.SomeOtherSetting
Propiedad final

Propiedad privada Let ISomeModel_SomeOtherSetting (valor ByVal como booleano)


this.SomeOtherSetting = valor
Propiedad final

https://riptutorial.com/ 162

Página 178

Propiedad pública Obtener marca de tiempo () como fecha


Timestamp = this.Timestamp
Propiedad final

Propiedad pública Let Timestamp (valor ByVal como fecha)


this.Timestamp = valor
Propiedad final

Propiedad pública Obtener UserName () como cadena


Nombre de usuario = this.UserName
Propiedad final

Propiedad pública Let UserName (valor ByVal como cadena)


this.UserName = valor
Propiedad final

Propiedad pública Obtener AvailableItems () como variante


AvailableItems = this.AvailableItems
Propiedad final

Propiedad pública Let AvailableItems (valor ByRef como variante)


this.AvailableItems = valor
Propiedad final

Propiedad pública Obtener SomeSetting () como cadena


SomeSetting = this.SomeSetting
Propiedad final

Propiedad pública Let SomeSetting (valor ByVal como cadena)


this.SomeSetting = valor
Propiedad final

Propiedad pública Obtener SomeOtherSetting () como booleano


SomeOtherSetting = this.SomeOtherSetting
Propiedad final

Propiedad pública Let SomeOtherSetting (valor ByVal como booleano)


this.SomeOtherSetting = valor
Propiedad final

Los miembros de la interfaz son todos privados y todos los miembros de la interfaz deben implementarse para
el código para compilar. Los miembros públicos no forman parte de la interfaz y, por lo tanto, no
expuestos al código escrito en la interfaz ISomeModel .

Usando un método de fábrica para simular un constructor

Usando un Atributo VB_PredeclaredId , podemos hacer que laclase SomeModel tenga una instancia predeterminada , y
escriba una función que funcione como un miembro de nivel de tipo ( compartido en VB.NET, estático en C #) que el cliente
el código puede llamar sin necesidad de crear primero una instancia, como hicimos aquí:

Función privada CreateViewModel () como ISomeModel


Resultado atenuado como ISomeModel
Establecer resultado = SomeModel.Create (Ahora, Environ $ ("UserName"))
result.AvailableItems = GetAvailableItems
Establecer CreateViewModel = resultado

https://translate.googleusercontent.com/translate_f 153/223
6/1/2021 Intitulado

https://riptutorial.com/ 163

Página 179

Función final

Este método de fábrica asigna los valores de propiedad que son de solo lectura cuando se accede desde el
Interfaz ISomeModel , aquí Timestamp y UserName :

Función pública Crear (ByVal pTimeStamp como fecha, ByVal pUserName como cadena) como ISomeModel
Con nuevo SomeModel
.Timestamp = pTimeStamp
.UserName = pUserName
Establecer Crear = .Self
Terminar con
Función final

Propiedad pública Get Self () As ISomeModel


Establecer yo = Yo
Propiedad final

Y ahora podemos codificar contra la interfaz ISomeModel , que expone Timestamp y UserName como
propiedades de solo lectura que nunca se pueden reasignar (siempre que el código esté escrito en
interfaz).

Polimorfismo

El polimorfismo es la capacidad de presentar la misma interfaz para diferentes


implementaciones subyacentes.

La capacidad de implementar interfaces permite desacoplar completamente la lógica de la aplicación de la UI,


o de la base de datos, o de esta o aquella hoja de trabajo.

Supongamos que tiene una interfaz ISomeView que implementa el formulario en sí:

Opción explícita

Propiedad pública Obtener IsCancelled () como booleano


Propiedad final

Propiedad pública Obtener modelo () como ISomeModel


Propiedad final

Modelo de conjunto de propiedades públicas (valor ByVal como ISomeModel)


Propiedad final

Sub Show público ()


End Sub

El código subyacente del formulario podría verse así:

Opción explícita
Implementa ISomeView

TView de tipo privado


IsCancelled como booleano
Modelo como ISomeModel

https://riptutorial.com/ 164

Página 180

Tipo final
Privado esto como TView

https://translate.googleusercontent.com/translate_f 154/223
6/1/2021 Intitulado
Propiedad privada Obtenga ISomeView_IsCancelled () como booleano
ISomeView_IsCancelled = this.IsCancelled
Propiedad final

Propiedad privada Obtenga ISomeView_Model () como ISomeModel


Establecer ISomeView_Model = this.Model
Propiedad final

Conjunto de propiedades privadas ISomeView_Model (valor de ByVal como ISomeModel)


Establezca this.Model = value
Propiedad final

Sub privado ISomeView_Show ()


Me.Show vbModal
End Sub

Sub privado SomeOtherSettingInput_Change ()


this.Model.SomeOtherSetting = CBool (SomeOtherSettingInput.Value)
End Sub

'... otros controladores de eventos ...

Sub privado OkButton_Click ()


Me.Hide
End Sub

Sub privado CancelButton_Click ()


this.IsCancelled = True
Me.Hide
End Sub

Private Sub UserForm_QueryClose (Cancelar como entero, CloseMode como entero)


Si CloseMode = VbQueryClose.vbFormControlMenu, entonces
Cancelar = Verdadero
this.IsCancelled = True
Me.Hide
Terminara si
End Sub

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 :

Opción explícita
Implementa ISomeView

TView de tipo privado


IsCancelled como booleano
Modelo como ISomeModel
Tipo final
Privado esto como TView

Propiedad pública Obtener IsCancelled () como booleano


IsCancelled = this.IsCancelled
Propiedad final

Propiedad pública Let IsCancelled (valor ByVal como booleano)


this.IsCancelled = valor

https://riptutorial.com/ 165

Página 181

Propiedad final

Propiedad privada Obtenga ISomeView_IsCancelled () como booleano


ISomeView_IsCancelled = this.IsCancelled
Propiedad final

Propiedad privada Obtenga ISomeView_Model () como ISomeModel


Establecer ISomeView_Model = this.Model
Propiedad final

Conjunto de propiedades privadas ISomeView_Model (valor de ByVal como ISomeModel)


Establezca this.Model = value
Propiedad final

https://translate.googleusercontent.com/translate_f 155/223
6/1/2021 Intitulado
Sub privado ISomeView_Show ()
'hacer nada
End Sub

Y ahora podemos cambiar el código que funciona con un UserForm y hacerlo funcionar desde ISomeView
interfaz, por ejemplo, dándole el formulario como parámetro en lugar de instanciarlo:

Public Sub DoSomething (vista ByVal como ISomeView)


Con vista
Establecer .Model = CreateViewModel
.Mostrar
Si .IsCancelled, salga de Sub
ProcessUserData .Model
Terminar con
End Sub

Debido a que el HacerAlgo método depende de una interfaz (es decir, una abstracción ) y no un hormigón
clase (por ejemplo, un UserForm específico ), podemos escribir una prueba unitaria automatizada que asegure que
ProcessUserData no se ejecuta cuando view.IsCancelled es True , al hacer que nuestra prueba cree un
SomeViewMock , estableciendo su propiedad IsCancelled en True y pasándola a DoSomething .

El código comprobable depende de abstracciones

Se pueden escribir pruebas unitarias en VBA, hay complementos que incluso lo integran en el
IDE. Pero cuando el código está estrechamente vinculado con una hoja de trabajo, una base de datos, un formulario o el sistema de archivos,
luego, la prueba unitaria comienza a requerir una hoja de trabajo, base de datos, formulario o sistema de archivos real, y estos
Las dependencias son nuevos puntos de falla fuera de control que el código comprobable debe aislar, de modo que la unidad
las pruebas no requieren una hoja de trabajo, una base de datos, un formulario o un sistema de archivos reales.

Escribiendo código contra interfaces, de una manera que permita que el código de prueba inyecte stub / mock
implementaciones (como el ejemplo anterior de SomeViewMock ), puede escribir pruebas en un "control
entorno ", y simular lo que sucede cuando cada una de las 42 posibles permutaciones
de las interacciones del usuario en los datos del formulario, sin siquiera mostrar un formulario y hacer clic manualmente
en un control de formulario.

Lea VBA orientado a objetos en línea: https://riptutorial.com/vba/topic/5357/object-oriented-vba

https://riptutorial.com/ 166

Página 182

Capítulo 31: Operadores


Observaciones
Los operadores se evalúan en el siguiente orden:

• Operadores matemáticos
• Operadores bit a bit
• Operadores de concatenación
• Operadores de comparación
• Operadores logicos

Los operadores con precedencia coincidente se evalúan de izquierda a derecha. El orden predeterminado puede ser
anulado mediante el uso de paréntesis ( y ) para agrupar expresiones.

Ejemplos

https://translate.googleusercontent.com/translate_f 156/223
6/1/2021 Intitulado
Operadores matemáticos
Listados en orden de precedencia:

Nombre del token Descripción

Devuelve el resultado de elevar el operando de la izquierda a la potencia de


el operando de la derecha. Tenga en cuenta que el valor devuelto por
^ Exponenciación exponenciación es siempre un doble , independientemente de los tipos de valor
estar dividido. Cualquier coerción del resultado en un tipo de variable toma
lugar después de realizar el cálculo.

Devuelve el resultado de dividir el operando de la izquierda por el de la derecha.


operando de mano. Tenga en cuenta que el valor devuelto por la división es siempre un
/ División 1 Doble ,
independientemente de los tipos de valor que se dividan. Cualquier coacción de
el resultado en un tipo de variable tiene lugar después de que el cálculo es
realizado.

* Multiplicación 1 Devuelve el producto de 2 operandos.

Devuelve el resultado entero de dividir el operando de la izquierda por el


operando de la derecha después de redondear ambos lados con .5 redondeo
abajo. Cualquier resto de la división se ignora. Si la mano derecha
Entero
\ operando (el divisor) es 0 , un error en tiempo de ejecución 11: la división por cero
División
resultado. Tenga en cuenta que esto es después de realizar todo el redondeo:
expresiones como 3 \ 0.4 también resultarán en una división por cero
error.

Modificación Modulo Devuelve el resto entero de dividir el operando de la izquierda por

https://riptutorial.com/ 167

Página 183

Nombre del token Descripción

el operando de la derecha. El operando de cada lado se redondea a


un número entero antes de la división, con .5 redondeando hacia abajo. Por ejemplo,
tanto 8.6 Mod 3 como 12 Mod 2.6 dan como resultado 0 . Si el operando de la derecha
(el divisor) es 0 , un error en tiempo de ejecución 11: resultará una división por cero.
Tenga en cuenta que esto es después de realizar todo el redondeo: expresiones como
como 3 Mod 0.4 también resultará en una división por error cero.

Devuelve el resultado de restar el operando de la derecha del


- Resta 2
operando de la izquierda.

Devuelve la suma de 2 operandos. Tenga en cuenta que este token también se trata como
+ Adición 2 un operador de concatenación cuando se aplica a una cadena . Ver
Operadores de concatenación .

1 Se considera que la multiplicación y la división tienen la misma precedencia.

2 La suma y la resta se tratan como si tuvieran la misma precedencia.

Operadores de concatenación

VBA admite 2 operadores de concatenación diferentes, + y &, y ambos realizan exactamente lo mismo
función cuando se utiliza con Cuerda tipos - de la derecha de cadena se añade al final de la izquierda
cuerda de mano .

Si el operador & se usa con un tipo de variable que no sea String , se convierte implícitamente en String
antes de ser concatenados.

https://translate.googleusercontent.com/translate_f 157/223
6/1/2021 Intitulado
Tenga en cuenta que el operador de concatenación + es una sobrecarga del operador de suma + . El comportamiento de +
está determinado por el tipos de variables de los operandos y precedencia de los tipos de operadores. Si ambos
los operandos se escriben como String o Variant con un subtipo de String , están concatenados:

Subejemplo público ()
Atenuar a la izquierda como cadena
Dim right As String

izquierda = "5"
derecha = "5"

Debug.Print left + right 'Imprime "55"


End Sub

Si cualquiera de los lados es de tipo numérico y el otro lado es una cadena que se puede convertir en un número,
la precedencia de tipos de los operadores matemáticos hace que el operador sea tratado como la suma
operador y se añaden los valores numéricos:

Subejemplo público ()
Atenuar a la izquierda como variante
Dim right As String

https://riptutorial.com/ 168

Página 184

izquierda = 5
derecha = "5"

Debug.Print izquierda + derecha 'Imprime 10


End Sub

Este comportamiento puede provocar errores sutiles y difíciles de depurar, especialmente si se utilizan tipos de variantes ,
por lo que solo se debe usar el operador & para la concatenación.

Operadores de comparación

Nombre del token Descripción

Devuelve True si los operandos de la izquierda y la derecha son


= Igual a igual. Tenga en cuenta que esto es una sobrecarga de la tarea
operador.

Devuelve True si los operandos de la izquierda y la derecha son


<> No igual a
no es igual.

Devuelve True si el operando de la izquierda es mayor que el


> Mas grande que
operando de la derecha.

Devuelve True si el operando de la izquierda es menor que el de la derecha.


< Menos que
operando de mano.

Devuelve True si el si el operando de la izquierda es mayor que


>= Mayor que o igual
o igual al operando de la derecha.

Devuelve True si el operando de la izquierda es menor que o


<= Menor o igual
igual al operando de la derecha.

Devuelve True si la referencia del objeto de la izquierda es la misma


instancia como referencia de objeto de la derecha. También puede ser
se usa con Nothing (la referencia de objeto nulo) en cualquier lado.
Nota: El operador Is intentará coaccionar ambos operandos
en un Objeto antes de realizar la comparación. Si alguno
side es un tipo primitivo o una variante que no contiene
Es Equidad de referencia

https://translate.googleusercontent.com/translate_f 158/223
6/1/2021 Intitulado
un
La objeto (ya seadará
comparación un subtipo no objetoun
como resultado o vtEmpty ), elen tiempo de ejecución: "Objeto
error 424
required ". Si alguno de los operandos pertenece a una interfaz diferente
del mismo objeto, la comparación devolverá True . Si tu
necesidad de probar la equidad tanto de la instancia como de la
interfaz, utilice ObjPtr (izquierda) = ObjPtr (derecha) en su lugar.

Notas

https://riptutorial.com/ 169

Página 185

La sintaxis de VBA permite "cadenas" de operadores de comparación, pero estas construcciones deben
generalmente debe evitarse. Las comparaciones siempre se realizan de izquierda a derecha en solo 2 operandos a la vez.
time, y cada comparación da como resultado un booleano . Por ejemplo, la expresión ...

a = 2: b = 1: c = 0
expr = a> b> c

... puede ser leído en algunos contextos como una prueba de si b es entre una y c . En VBA, esto evalúa
como sigue:

a = 2: b = 1: c = 0
expr = a> b> c
expr = (2> 1)> 0
expr = Verdadero> 0
expr = -1> 0 'CInt (verdadero) = -1
expr = Falso

Cualquier operador de comparación que no sea Se usa con un Objeto como operando se ejecutará en
el valor de retorno del objeto s'miembro predeterminado . Si el objeto no tiene un miembro predeterminado, el
la comparación dará como resultado un error 438 en tiempo de ejecución: "El objeto no admite su propiedad o método".

Si el objeto no está inicializado, la comparación dará como resultado un error en tiempo de ejecución 91 - "Variable de objeto o
Con variable de bloque no establecida ".

Si el literal Nothing se usa con cualquier operador de comparación que no sea Is , resultará en una compilación
error - "Uso no válido del objeto".

Si el miembro predeterminado del objeto es otro objeto , VBA llamará continuamente al miembro predeterminado
de cada valor de retorno sucesivo hasta que se devuelve un tipo primitivo o se genera un error. Por ejemplo,
suponga que SomeClass tiene un miembro predeterminado de Value , que es una instancia de ChildClass con un valor predeterminado
miembro de ChildValue . La comparación...

Establecer x = New SomeClass


Depurar Imprimir x> 42

... será evaluado como:

Establecer x = New SomeClass


Debug.Print x.Value.ChildValue> 42

Si alguno de los operandos es de tipo numérico y el otro operando es una cadena o una variante del subtipo Cadena ,
se realizará una comparación numérica. En este caso, si la Cadena no se puede convertir en un número, un
Error de tiempo de ejecución 13 - "No coinciden los tipos" como resultado de la comparación.

Si ambos operandos son una Cadena o una Variante del subtipo Cadena , se realizará una comparación de cadenas
basado en el Opción Comparar configuración del módulo de código. Estas comparaciones se realizan en un
carácter por carácter. Tenga en cuenta que la representación de caracteres de una cadena que contiene un
https://translate.googleusercontent.com/translate_f 159/223
6/1/2021 Intitulado
número no es lo mismo que una comparación de los valores numéricos:

https://riptutorial.com/ 170

Página 186

Subejemplo público ()
Atenuar a la izquierda como variante
Dim a la derecha como variante

izquierda = "42"
derecha = "5"
Depurar Imprimir izquierda> derecha 'Imprime falso
Debug.Print Val (izquierda)> Val (derecha) 'Prints True
End Sub

Por esta razón, asegúrese de que las variables String o Variant se conviertan en números antes de realizar
comparaciones numéricas de desigualdad sobre ellos.

Si un operando es una fecha , se realizará una comparación numérica del valor Double subyacente si
el otro operando es numérico o se puede convertir a un tipo numérico.

Si el otro operando es una Cadena o una Variante del subtipo Cadena que se puede convertir a una Fecha usando el
configuración regional actual, la cadena se convertirá en una fecha . Si no se puede convertir a una fecha en la configuración regional actual,
Error de tiempo de ejecución 13 - "No coinciden los tipos" como resultado de la comparación.

Se debe tener cuidado al hacer comparaciones entre valores dobles o simples yBooleanos.
A diferencia de otros tipos numéricos, no se puede suponer que los valores distintos de cero sean verdaderos debido al comportamiento de VBA
de promover el tipo de datos de una comparación que involucra un número de punto flotante a Double :

Subejemplo público ()
Prueba de atenuación como doble

Prueba = 42 Debug.Print CBool (prueba) 'Imprime True.


'Verdadero se promueve a doble: la prueba no se convierte en booleano
Debug.Print Test = True 'Imprime falso

'Con elencos explícitos:


Debug.Print CBool (Prueba) = True 'Imprime True
Debug.Print CDbl (-1) = CDbl (True) 'Imprime True
End Sub

Operadores bit a bit \ lógicos

Todos los operadores lógicos en VBA se pueden considerar como "anulaciones" de los operadores bit a bit del
mismo nombre. Técnicamente, siempre se tratan como operadores bit a bit. Toda la comparación
los operadores en VBA devuelven un Booleano , que siempre no tendrá ninguno de sus bits establecido ( Falso ) o todos sus
bits establecidos ( Verdadero ). Pero tratará un valor con cualquier bit establecido como Verdadero . Esto significa que el resultado de la
convertir el resultado bit a bit de una expresión en un booleano (ver Operadores de comparación) siempre será
lo mismo que tratarlo como una expresión lógica.

Asignar el resultado de una expresión usando uno de estos operadores dará el resultado bit a bit. Nota
que en las tablas de verdad a continuación, 0 es equivalente a Falso y 1 es equivalente a Verdadero .

Devuelve Verdadero si las expresiones en ambos lados se evalúan como Verdadero .

https://riptutorial.com/ 171

Página 187

Operando de la mano izquierda Resultado del operando de la mano derecha

https://translate.googleusercontent.com/translate_f 160/223
6/1/2021 Intitulado

0 0 0

0 1 0

1 0 0

1 1 1

Devuelve Verdadero si cualquiera de los lados de la expresión se evalúa como Verdadero .

Operando de la mano izquierda Resultado del operando de la mano derecha

0 0 0

0 1 1

1 0 1

1 1 1

No

Devuelve True si la expresión se evalúa como False y False si la expresión se evalúa como True .

Resultado del operando de la derecha

0 1

1 0

No esel único operando sin operando a la izquierda. El Editor de Visual Basic automáticamente
simplificar expresiones con un argumento a la izquierda. Si escribe ...

Debug.Print x No y

... el VBE cambiará la línea a:

Debug.Print No x

Se harán simplificaciones similares a cualquier expresión que contenga un operando de la izquierda (incluyendo
expresiones) para Not .

Xor

https://riptutorial.com/ 172

Página 188

También conocido como "exclusivo o". Devuelve True si ambas expresiones evalúan resultados diferentes.

Operando de la mano izquierda Resultado del operando de la mano derecha

0 0 0

0 1 1

1 0 1

https://translate.googleusercontent.com/translate_f 161/223
6/1/2021 Intitulado
1 1 0

Tenga en cuenta que aunque el operador Xor se puede utilizar como un operador lógico, no hay absolutamente ningún
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 el mismo resultado.

Operando de la mano izquierda Resultado del operando de la mano derecha

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 la mucho más legible
No (x Xor y) .

Diablillo

También conocido como "implicación". Devuelve True si ambos operandos son iguales o si el segundo operando es
Cierto .

Operando de la mano izquierda Resultado del operando de la mano derecha

0 0 1

0 1 1

1 0 0

1 1 1

Tenga en cuenta que la función Imp se utiliza muy raramente. Una buena regla general es que si no puede explicar qué

https://riptutorial.com/ 173

Página 189

significa que debes usar otra construcción.

Leer operadores en línea: https://riptutorial.com/vba/topic/5813/operators

https://translate.googleusercontent.com/translate_f 162/223
6/1/2021 Intitulado

https://riptutorial.com/ 174

Página 190

Capítulo 32: Pasando argumentos por Ref o


ByVal
Introducción
Los modificadores ByRef y ByVal son parte de la firma de un procedimiento e indican cómo es un argumento.
pasado a un procedimiento. En VBA se pasa un parámetro ByRef a 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 especificar los modificadores ByRef explícitamente para evitar posibles
confusión.

Observaciones

Pasando matrices
Las matrices deben pasarse por referencia. Este código se compila, pero genera el error 424 en tiempo de ejecución "Objeto
Necesario":

Subprueba pública ()
Matriz DoSomething (1, 2, 3)
End Sub

Private Sub DoSomething (ByVal foo como variante)

https://translate.googleusercontent.com/translate_f 163/223
6/1/2021 Intitulado
foo.Añadir 42
End Sub

Este código no compila:

Private Sub DoSomething (ByVal foo () As Variant) 'ByVal es ilegal para matrices
foo.Añadir 42
End Sub

Ejemplos

Pasar variables simples ByRef y ByVal

Pasar ByRef o ByVal indica si el valor real de un argumento se pasa al


CalledProcedure por
el CallingProcedure , o si una referencia (llamado un puntero en alguna otra
languages) se pasa al CalledProcedure .

Si se pasa un argumento ByRef , la dirección de memoria del argumento se pasa al


CalledProcedure ycualquier modificación a ese parámetro por el CalledProcedure se realiza en el valor
en el CallingProcedure .

https://riptutorial.com/ 175

Página 191

Si se pasa un argumento ByVal , el valor real, no una referencia a la variable, se pasa al


CalledProcedure .

Un ejemplo simple ilustrará esto claramente:

Sub CalledProcedure (ByRef X As Long, ByVal Y As Long)


X = 321
Y = 654
End Sub

Sub CallingProcedure ()
Dim A tan largo
Dim B tan largo
A = 123
B = 456

Debug.Print "ANTES DE LLAMAR => A:" & CStr (A), "B:" & CStr (B)
'' Resultado: ANTES DE LLAMAR => A: 123 B: 456

Procedimiento llamado X: = A, Y: = B

Debug.Print "AFTER CALL = A:" & CStr (A), "B:" & CStr (B)
'' Resultado: DESPUÉS DE LLAMADA => A: 321 B: 456
End Sub

Otro ejemplo:

Sub principal()
Dim IntVarByVal como entero
Dim IntVarByRef como entero

IntVarByVal = 5
IntVarByRef = 10

SubChangeArguments IntVarByVal, IntVarByRef '5 entra como una "copia". 10 entra como
referencia
Debug.Print "IntVarByVal:" & IntVarByVal 'imprime 5 (sin cambios realizados por SubChangeArguments)
Debug.Print "IntVarByRef:" & IntVarByRef 'imprime 99 (la variable se cambió en
SubChangeArguments)
End Sub

Sub SubChangeArguments (ByVal ParameterByVal como entero, ByRef ParameterByRef como entero)
ParameterByVal = ParameterByVal + 2 '5 + 2 = 7 (cambiado solo dentro de este Sub)
ParameterByRef = ParameterByRef + 89 '10 + 89 = 99 (cambia el propio IntVarByRef - en
el Sub principal)

https://translate.googleusercontent.com/translate_f 164/223
6/1/2021 Intitulado
End Sub

ByRef

Modificador predeterminado
Si no se especifica ningún modificador para un parámetro, ese parámetro se pasa implícitamente por referencia.

Public Sub DoSomething1 (foo As Long)

https://riptutorial.com/ 176

Página 192

End Sub

Public Sub DoSomething2 (ByRef foo As Long)


End Sub

El parámetro foo se pasa ByRef en DoSomething1 y DoSomething2 .

¡Cuidado! Si vienes a VBA con experiencia en otros idiomas, esto es muy


probablemente el comportamiento exactamente opuesto al que está acostumbrado. En muchos otros
lenguajes de programación (incluido VB.NET), el modificador implícito / predeterminado pasa
parámetros por valor.

Pasando por referencia

• Cuando se pasa un valor ByRef , el procedimiento recibe una referencia al valor.

Subprueba pública ()
Dim foo tan largo
foo = 42
Hacer algo foo
Debug.Print foo
End Sub

Sub privado DoSomething (ByRef foo As Long)


foo = foo * 2
End Sub

Llamar a las salidas 84 del procedimiento de prueba anterior . DoSomething recibe foo y recibe un
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.

Subprueba pública ()
Colección Dim foo As
Set foo = Nueva colección
Hacer algo foo
Debug.Print foo.Count
End Sub

Private Sub DoSomething (ByRef foo As Collection)


foo.Añadir 42
Establecer foo = Nada
End Sub

El código anterior plantea error 91 en tiempo de ejecución , porque la persona que llama está llamando almiembro Count de
un objeto que ya no existe, porque DoSomething recibió una referencia al objeto
puntero y lo asignó a Nothing antes de regresar.

https://translate.googleusercontent.com/translate_f 165/223
6/1/2021 Intitulado

Forzar ByVal en el sitio de la llamada

https://riptutorial.com/ 177

Página 193

Usando paréntesis en el sitio de la llamada, puede anular ByRef y forzar que se pase un argumento
ByVal :

Subprueba pública ()
Dim foo tan largo
foo = 42
Hacer algo (foo)
Debug.Print foo
End Sub

Sub privado DoSomething (ByRef foo As Long)


foo = foo * 2
End Sub

El código anterior genera 42, independientemente de si ByRef se especifica implícita o explícitamente.

¡Cuidado! Debido a esto, el uso de paréntesis extraños en llamadas a procedimientos puede


introducir errores fácilmente. Preste atención al espacio en blanco entre el nombre del procedimiento
y la lista de argumentos:

bar = DoSomething (foo) 'llamada a la función, sin espacios en blanco; parens son parte de la lista de argumentos
Llamada al procedimiento DoSomething (foo) ', observe los espacios en blanco; parens NO son parte de argumentos
lista
La llamada al procedimiento DoSomething foo 'no obliga al parámetro foo a ser ByVal

ByVal

Pasando por valor

• Cuando se pasa un valor ByVal , el procedimiento recibe una copia del valor.

Subprueba pública ()
Dim foo tan largo
foo = 42
Hacer algo foo
Debug.Print foo
End Sub

Sub privado DoSomething (ByVal foo As Long)


foo = foo * 2
End Sub

Llamar a las salidas 42 del procedimiento de prueba anterior . DoSomething recibe foo y recibe una copia de
el valor. La copia se multiplica por 2 y luego se descarta cuando finaliza el procedimiento; la
la copia de la persona que llama nunca fue alterada.

• Cuando se pasa una referencia ByVal , el procedimiento recibe una copia del puntero.

Subprueba pública ()
Colección Dim foo As
Set foo = Nueva colección
Hacer algo foo
Debug.Print foo.Count

https://riptutorial.com/ 178

Página 194

https://translate.googleusercontent.com/translate_f 166/223
6/1/2021 Intitulado
End Sub

Private Sub DoSomething (ByVal foo As Collection)


foo.Añadir 42
Establecer foo = Nada
End Sub

Llamar a las salidas del procedimiento de prueba anteriores 1. DoSomething recibe foo y recibe una copia de
el puntero al objeto Collection . Porque la variable de objeto foo en los puntos de alcance de prueba
al mismo objeto, agregar un elemento en DoSomething agrega el elemento al mismo objeto. Porque
es una copia del puntero, establecer su referencia en Nothing no afecta la propia copia de la persona que llama.

Lea Pasando argumentos ByRef o ByVal en línea: https://riptutorial.com/vba/topic/7363/passing-


argumentos-byref-or-byval

https://riptutorial.com/ 179

Página 195

Capítulo 33: Llamadas a procedimientos


Sintaxis
• IdentifierName [ argumentos ]
• Nombre de identificador de llamada [ (argumentos) ]
• [Let | Set] expresión = IdentifierName [ (argumentos) ]

https://translate.googleusercontent.com/translate_f 167/223
6/1/2021 Intitulado
• [Let | Set] IdentifierName [ (argumentos) ] = expresión

Parámetros

Parámetro Información

IdentifierName El nombre del procedimiento a llamar.

argumentos Una lista de argumentos separados por comas que se pasarán al procedimiento.

Observaciones
Las dos primeras sintaxis son para llamar a procedimientos Sub ; observe que la primera sintaxis no implica
paréntesis.

Ver Esto es confuso. ¿Por qué no usar siempre paréntesis? para una explicación detallada del
diferencias entre las dos primeras sintaxis.

La tercera sintaxis es para llamar a los procedimientos de obtención de funciones y propiedades ; cuando hay parámetros,
los paréntesis son siempre obligatorios. La palabra clave Let es opcional al asignar un valor , pero
la palabra clave Set es necesaria al asignar una referencia .

La cuarta sintaxis es para llamar a los procedimientos Property Let y Property Set ; la expresión de la derecha
El lado de la mano de la asignación se pasa al parámetro de valor de la propiedad.

Ejemplos

Sintaxis de llamada implícita

Nombre del procedimiento


Nombre de procedimiento argumento1, argumento2

Llame a un procedimiento por su nombre sin paréntesis.

Caso extremo
https://riptutorial.com/ 180

Página 196

La palabra clave Call solo es necesaria en un caso extremo:

Llamar a DoSomething: DoSomethingElse

DoSomething y DoSomethingElse son


procedimientos que se llaman. Si se eliminó la palabra clave Call ,
entonces DoSomething se analizaría como una etiqueta de línea en lugar de una llamada a procedimiento, que se rompería
el código:

DoSomething: DoSomethingElse 'solo DoSomethingElse se ejecutará

Valores devueltos

Para recuperar el resultado de una llamada a procedimiento (por ejemplo, procedimientos de obtención de función o propiedad ), coloque la llamada en
el lado derecho de una tarea:

resultado = nombreProcedimiento
resultado = nombreProcedimiento (argumento1, argumento2)

https://translate.googleusercontent.com/translate_f 168/223
6/1/2021 Intitulado

Los paréntesis deben estar presentes si hay parámetros. Si el procedimiento no tiene parámetros, el
los paréntesis son redundantes.

Esto es confuso. ¿Por qué no usar siempre paréntesis?

Los paréntesis se utilizan para encerrar los argumentos de las llamadas a funciones . Usándolos para llamadas a procedimientos
puede causar problemas inesperados.

Debido a que pueden introducir errores, tanto en tiempo de ejecución pasando un valor posiblemente no intencionado al
procedimiento, y en tiempo de compilación simplemente siendo sintaxis inválida.

Tiempo de ejecución
Los paréntesis redundantes pueden introducir errores. Dado un procedimiento que toma una referencia de objeto como
un parámetro ...

Sub DoSomething (destino ByRef como rango)


End Sub

... y llamado entre paréntesis:

DoSomething (Application.ActiveCell) 'genera un error en tiempo de ejecución

Esto generará un error de tiempo de ejecución "Objeto requerido" # 424. Otros errores son posibles en otros
circunstancias: aquí la referencia del objeto Application.ActiveCell Range se está evaluando y
pasado por valor independientemente de la firma del procedimiento que especifica que el objetivo se pasaría
ByRef . El valor real pasado ByVal a DoSomething en el fragmento anterior es
Application.ActiveCell.Value .

https://riptutorial.com/ 181

Página 197

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 de resultado evaluado no coincide con el
tipo esperado y no se puede convertir implícitamente, se genera un error de tiempo de ejecución.

Tiempo de compilación
Este código no se podrá compilar:

MsgBox ("Código no válido", vbCritical)

Porque la expresión ("¡Código no válido!", VbCritical) no se puede evaluar como un valor.

Esto compilaría y funcionaría:

MsgBox ("¡Código no válido!"), (VbCritical)

Pero definitivamente se vería tonto. Evite los paréntesis redundantes.

Sintaxis de llamada explícita

Nombre de procedimiento de llamada


Llamar NombreProcedimiento (argumento1, argumento2)

La sintaxis de llamada explícita requiere la palabra clave 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 el

https://translate.googleusercontent.com/translate_f 169/223
6/1/2021 Intitulado
Se agregó una sintaxis de llamada implícita más moderna a VB.

Argumentos opcionales

Algunos procedimientos tienen argumentos opcionales. Los argumentos opcionales siempre vienen después de required
argumentos, pero el procedimiento se puede llamar sin ellos.

Por ejemplo, si la función, NombreProcedimiento tuviera dos argumentos obligatorios ( argumento1 ,


argumento2 ), y un argumento opcional, optArgument3 , se podría llamar al menos de cuatro formas:

'Sin argumento opcional


resultado = NombreProcedimiento ("A", "B")

'Con argumento opcional


resultado = NombreProcedimiento ("A", "B", "C")

'Usar argumentos con nombre (permite un orden diferente)


resultado = NombreProcedimiento (optArgumento3: = "C", argumento1: = "A", argumento2: = "B")

'Mezcla de argumentos con nombre y sin nombre


resultado = nombreProcedimiento ("A", "B", optArgument3: = "C")

La estructura del encabezado de la función que se llama aquí se vería así:

https://riptutorial.com/ 182

Página 198

Función Nombre del procedimiento (argumento1 como cadena, argumento2 como cadena, opcional optArgument3 como
String) como cadena

La palabra clave opcional indica que este argumento se puede omitir. Como se mencionó antes, cualquier
Los argumentos opcionales introducidos en el encabezado deben aparecer al final, después de cualquier requisito
argumentos.

También puede proporcionar un valor predeterminado para el argumento en el caso de que no se pase un valor al
función:

Función Nombre del procedimiento (argumento1 como cadena, argumento2 como cadena, opcional optArgument3 como
String = "C") como cadena

En esta función, si no se proporciona el argumento para c , su valor será por defecto "C" . Si se proporciona un valor
entonces esto anulará el valor predeterminado.

Lea las llamadas de procedimiento en línea: https://riptutorial.com/vba/topic/1179/procedure-calls

https://translate.googleusercontent.com/translate_f 170/223
6/1/2021 Intitulado

https://riptutorial.com/ 183

Página 199

Capítulo 34: Lectura de archivos de 2GB + en binario en


VBA y hashes de archivos
Introducción
Hay 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áximo de tipo de datos Long). A medida que la tecnología evoluciona, este límite de 2 GB se
violado. por ejemplo, una imagen ISO del disco DVD de instalación del sistema operativo. Microsoft proporciona una forma
para superar esto a través de la API de Windows de bajo nivel y aquí hay una copia de seguridad.

También demuestre (Leer parte) para calcular File Hashes sin un programa externo como fciv.exe
de Microsoft.

Observaciones

MÉTODOS PARA LA CLASE DE MICROSOFT

Nombre del método Descripción

Esta abierto Devuelve un booleano para indicar si el archivo está abierto.

OpenFile ( sFileNam e
Abre el archivo especificado por el argumento sFileName.
Como cuerda)

Cerrar el archivo Cierra el archivo abierto actualmente.

ReadBytes ( Lee ByteCount bytes y los devuelve en una matriz de bytes Variant y
ByteCount tan largo) mueve el puntero.

WriteBytes ( Escribe el contenido de la matriz de bytes en la posición actual del archivo.


DataBytes () como byte) y mueve el puntero.

Enjuagar Obliga a Windows a vaciar la caché de escritura.

Mueve el puntero del archivo a la posición designada desde el principio


SeekAbsolute ( del archivo. Aunque VBA trata los DWORDS como valores firmados, el
HighPos tan largo, API los trata como sin firmar. Haga que el argumento de orden superior no sea
LowPos tan largo) cero para superar los 4 GB. El DWORD de orden inferior será negativo para
valores entre 2GB y 4GB.

Mueve el puntero del archivo hasta +/- 2GB desde la ubicación actual. usted
SeekRelative ( Desplazamiento
https://translate.googleusercontent.com/translate_f 171/223
6/1/2021 Intitulado
Tanto tiempo) puede reescribir este método para permitir compensaciones superiores a 2 GB por
convertir un desplazamiento con signo de 64 bits en dos valores de 32 bits.

https://riptutorial.com/ 184

Página 200

PROPIEDADES DE LA CLASE POR MICROSOFT

Propiedad Descripción

El identificador de archivo para el archivo abierto actualmente. Esto no es compatible con el archivo VBA
FileHandle
manejas.

Nombre del archivo


El nombre del archivo abierto actualmente.

AutoFlush Establece / indica si WriteBytes llamará automáticamente al método Flush.

MÓDULO NORMAL

Función Notas

Simplemente agregue la ruta completa para aplicar el hash, Blocksize para usar
GetFileHash ( sFile As
(número de bytes) y el tipo de Hash que se utilizará, uno de los
String, uBlockSize As
constantes: HashTypeMD5 , HashTypeSHA1 , HashTypeSHA256 ,
Doble, sHashType como
HashTypeSHA384 , HashTypeSHA512 . Esto fue diseñado para ser
Cuerda)
tan genérico como sea posible.

Debe anular / comentar uFileSize como doble en consecuencia. He probado MD5 y SHA1.

Ejemplos

Esto tiene que estar en un módulo de clase, los ejemplos más adelante se denominarán "aleatorios"

'Cómo buscar más allá del límite de archivos de 2GB de VBA


Fuente: https://support.microsoft.com/en-us/kb/189981 (Archivado)
'Esto debe estar en un módulo de clase

Opción explícita

Enumeración pública W32F_Errors


W32F_UNKNOWN_ERROR = 45600
W32F_FILE_ALREADY_OPEN
W32F_PROBLEM_OPENING_FILE
W32F_FILE_ALREADY_CLOSED
W32F_Problem_seeking
End Enum

Private Const W32F_SOURCE = "Objeto Win32File"


Const privada GENERIC_WRITE = & H40000000
Const privada GENERIC_READ = & H80000000
Const privada FILE_ATTRIBUTE_NORMAL = & H80
Const privada CREATE_ALWAYS = 2
Const privada OPEN_ALWAYS = 4
Const privada INVALID_HANDLE_VALUE = -1

https://riptutorial.com/ 185

Página 201

https://translate.googleusercontent.com/translate_f 172/223
6/1/2021 Intitulado

Const privada FILE_BEGIN = 0, FILE_CURRENT = 1, FILE_END = 2

Const privada FORMAT_MESSAGE_FROM_SYSTEM = & H1000

Función de declaración privada FormatMessage Lib "kernel32" Alias "FormatMessageA" (_


ByVal dwFlags As Long, _
lpSource siempre que, _
ByVal dwMessageId tan largo, _
ByVal dwLanguageId As Long, _
ByVal lpBuffer como cadena, _
ByVal nSize As Long, _
Argumentos como cualquiera) siempre que

Función de declaración privada ReadFile Lib "kernel32" (_


ByVal hFile tan largo, _
lpBuffer como cualquiera, _
ByVal nNumberOfBytesToRead tan largo, _
lpNumberOfBytesRead As Long, _
ByVal lp Superpuesto siempre que)

Función de declaración privada CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long

Función de declaración privada WriteFile Lib "kernel32" (_


ByVal hFile tan largo, _
lpBuffer como cualquiera, _
ByVal nNumberOfBytesToWrite como largo, _
lpNumberOfBytesWritten As Long, _
ByVal lp Superpuesto siempre que)

Función de declaración privada CreateFile Lib "kernel32" Alias "CreateFileA" (_


ByVal lpFileName como cadena, _
ByVal dwDesiredAccess siempre que, _
ByVal dwShareMode Tan largo, _
ByVal lpSecurityAttributes siempre que, _
ByVal dwCreationDisposition As Long, _
ByVal dwFlagsAndAttributes As Long, _
ByVal hTemplateFile As Long) As Long

Función de declaración privada SetFilePointer Lib "kernel32" (_


ByVal hFile tan largo, _
ByVal lDistanceToMove tan largo, _
lpDistanceToMoveHigh tan largo, _
ByVal dwMoveMethod As Long) As Long

Función de declaración privada FlushFileBuffers Lib "kernel32" (ByVal hFile As Long) As Long

HFile privado tan largo, sFName como cadena, fAutoFlush como booleano

Propiedad pública Obtener FileHandle () tan largo


Si hFile = INVALID_HANDLE_VALUE Entonces
RaiseError W32F_FILE_ALREADY_CLOSED
Terminara si
FileHandle = hFile
Propiedad final

Propiedad pública Obtener FileName () como cadena


Si hFile = INVALID_HANDLE_VALUE Entonces
RaiseError W32F_FILE_ALREADY_CLOSED
Terminara si
FileName = sFName
Propiedad final

https://riptutorial.com/ 186

Página 202

Propiedad pública Obtener IsOpen () como booleano


IsOpen = hFile <> INVALID_HANDLE_VALUE
Propiedad final

Propiedad pública Obtener AutoFlush () como booleano


Si hFile = INVALID_HANDLE_VALUE Entonces
RaiseError W32F_FILE_ALREADY_CLOSED
Terminara si
AutoFlush = fAutoFlush
Propiedad final

https://translate.googleusercontent.com/translate_f 173/223
6/1/2021 Intitulado

Propiedad pública Let AutoFlush (ByVal NewVal como booleano)


Si hFile = INVALID_HANDLE_VALUE Entonces
RaiseError W32F_FILE_ALREADY_CLOSED
Terminara si
fAutoFlush = NewVal
Propiedad final

Public Sub OpenFile (ByVal sFileName como cadena)


Si hFile <> INVALID_HANDLE_VALUE Entonces
RaiseError W32F_FILE_ALREADY_OPEN, sFName
Terminara si
hFile = CreateFile (sFileName, GENERIC_WRITE o GENERIC_READ, 0, 0, OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL, 0)
Si hFile = INVALID_HANDLE_VALUE Entonces
RaiseError W32F_PROBLEM_OPENING_FILE, sFileName
Terminara si
sFName = sFileName
End Sub

Public Sub CloseFile ()


Si hFile = INVALID_HANDLE_VALUE Entonces
RaiseError W32F_FILE_ALREADY_CLOSED
Terminara si
CloseHandle hFile
sFName = ""
fAutoFlush = Falso
hFile = INVALID_HANDLE_VALUE
End Sub

Función pública ReadBytes (ByVal ByteCount tan largo) como variante


Dim BytesRead tan largo, bytes () como byte
Si hFile = INVALID_HANDLE_VALUE Entonces
RaiseError W32F_FILE_ALREADY_CLOSED
Terminara si
ReDim Bytes (0 a ByteCount - 1) Como Byte
ReadFile hFile, Bytes (0), ByteCount, BytesRead, 0
ReadBytes = Bytes
Función final

Public Sub WriteBytes (DataBytes () como byte)


Dim fSuccess tan largo, BytesToWrite tan largo, BytesWritten tan largo
Si hFile = INVALID_HANDLE_VALUE Entonces
RaiseError W32F_FILE_ALREADY_CLOSED
Terminara si
BytesToWrite = UBound (DataBytes) - LBound (DataBytes) + 1
fSuccess = WriteFile (hFile, DataBytes (LBound (DataBytes)), BytesToWrite, BytesWritten, 0)
Si fAutoFlush, entonces enjuague
End Sub

https://riptutorial.com/ 187

Página 203

Descarga secundaria pública ()


Si hFile = INVALID_HANDLE_VALUE Entonces
RaiseError W32F_FILE_ALREADY_CLOSED
Terminara si
FlushFileBuffers hFile
End Sub

Public Sub SeekAbsolute (ByVal HighPos como largo, ByVal LowPos como largo)
Si hFile = INVALID_HANDLE_VALUE Entonces
RaiseError W32F_FILE_ALREADY_CLOSED
Terminara si
LowPos = SetFilePointer (hFile, LowPos, HighPos, FILE_BEGIN)
End Sub

Public Sub SeekRelative (ByVal Offset As Long)


Dim TempLow tan largo, TempErr tan largo
Si hFile = INVALID_HANDLE_VALUE Entonces
RaiseError W32F_FILE_ALREADY_CLOSED
Terminara si
TempLow = SetFilePointer (hFile, Offset, ByVal 0 &, FILE_CURRENT)
Si TempLow = -1 entonces
TempErr = Err.LastDllError

https://translate.googleusercontent.com/translate_f 174/223
6/1/2021 Intitulado
Si TempErr entonces
RaiseError W32F_Problem_seeking, "Error" & TempErr & "." & vbCrLf y CStr (TempErr)
Terminara si
Terminara si
End Sub

Private Sub Class_Initialize ()


hFile = INVALID_HANDLE_VALUE
End Sub

Subclase privada_Terminate ()
Si hFile <> INVALID_HANDLE_VALUE, entonces CloseHandle hFile
End Sub

Private Sub RaiseError (ByVal ErrorCode como W32F_Errors, sExtra opcional)


Dim Win32Err tan largo, Win32Text como cadena
Win32Err = Err.LastDllError
Si Win32Err entonces
Win32Text = vbCrLf & "Error" & Win32Err & vbCrLf & _
DecodeAPIErrors (Win32Err)
Terminara si
Seleccionar código de error de caso
Caso W32F_FILE_ALREADY_OPEN
Err.Raise W32F_FILE_ALREADY_OPEN, W32F_SOURCE, "El archivo '" & sExtra & "' es
ya abierto ". & Win32Text
Caso W32F_PROBLEM_OPENING_FILE
Err.Raise W32F_PROBLEM_OPENING_FILE, W32F_SOURCE, "Error al abrir" & sExtra &
"'." & Win32Text
Caso W32F_FILE_ALREADY_CLOSED
Err.Raise W32F_FILE_ALREADY_CLOSED, W32F_SOURCE, "No hay archivo abierto".
Caso W32F_Problem_seeking
Err.Raise W32F_Problem_seeking, W32F_SOURCE, "Error de búsqueda". & vbCrLf & sExtra
Caso otro
Err.Raise W32F_UNKNOWN_ERROR, W32F_SOURCE, "Error desconocido". & Win32Text
Finalizar Seleccionar
End Sub

Función privada DecodeAPIErrors (ByVal ErrorCode tan largo) como cadena


Dim sMessage como cadena, MessageLength tan largo

https://riptutorial.com/ 188

Página 204

sMessage = Espacio $ (256)


MessageLength = FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, 0 &, ErrorCode, 0 &, sMessage,
256 &, 0 &)
Si MessageLength> 0 entonces
DecodeAPIErrors = Izquierda (sMessage, MessageLength)
Más
DecodeAPIErrors = "Error desconocido".
Terminara si
Función final

Código para calcular el hash de archivo en un módulo estándar

Private Const HashTypeMD5 As String = "MD5" 'https://msdn.microsoft.com/en-


us / library / system.security.cryptography.md5cryptoserviceprovider (v = frente a 110) .aspx
Private Const HashTypeSHA1 As String = "SHA1" 'https://msdn.microsoft.com/en-
us / library / system.security.cryptography.sha1cryptoserviceprovider (v = frente a 110) .aspx
Private Const HashTypeSHA256 As String = "SHA256" 'https://msdn.microsoft.com/en-
us / library / system.security.cryptography.sha256cryptoserviceprovider (v = frente a 110) .aspx
Private Const HashTypeSHA384 As String = "SHA384" 'https://msdn.microsoft.com/en-
us / library / system.security.cryptography.sha384cryptoserviceprovider (v = frente a 110) .aspx
Private Const HashTypeSHA512 As String = "SHA512" 'https://msdn.microsoft.com/en-
us / library / system.security.cryptography.sha512cryptoserviceprovider (v = frente a 110) .aspx

Private uFileSize As Double 'Comente si no está probando el rendimiento con FileHashes ()

Sub FileHashes ()
Dim tStart As Date, tFinish As Date, sHash como cadena, aTestFiles como variante, oTestFile como
Variante, aBlockSizes como variante, oBlockSize como variante
Atenuar BLOCKSIZE como doble

'Esto realiza pruebas de rendimiento en diferentes tamaños de archivo y tamaños de bloque


aBlockSizes = Array ("2 ^ 12-1", "2 ^ 13-1", "2 ^ 14-1", "2 ^ 15-1", "2 ^ 16-1", "2 ^ 17-1 "," 2 ^ 18-1 ",

https://translate.googleusercontent.com/translate_f 175/223
6/1/2021 Intitulado
"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 "Archivos de prueba:" & Join (aTestFiles, "|")
Debug.Print "BlockSizes:" & Join (aBlockSizes, "|")
Para cada oTestFile en aTestFiles
Debug.Print oTestFile
Para cada oBlockSize en aBlockSizes
BLOCKSIZE = Evaluar (oBlockSize)
tStart = Ahora
sHash = GetFileHash (CStr (oTestFile), BLOCKSIZE, HashTypeMD5)
tFinish = Ahora
Debug.Print sHash, uFileSize, Format (tFinish - tStart, "hh: mm: ss"), oBlockSize & "
(" & TAMAÑO DE BLOQUE & ")"
próximo
próximo
End Sub

Función privada GetFileHash (ByVal sFile como cadena, ByVal uBlockSize como doble, ByVal
sHashType como cadena) como cadena
Dim oFSO As Object '"Scripting.FileSystemObject"
Dim oCSP As Object 'Uno de los "CryptoServiceProvider"
Dim oRnd As Random 'La clase "Random" de Microsoft, debe estar en el mismo archivo
Dim uBytesRead como doble, uBytesToRead como doble, bDone como booleano

https://riptutorial.com/ 189

Página 205

Dim aBlock () As Byte, aBytes As Variant 'Arrays para almacenar bytes


Dim aHash () como byte, sHash como cadena, i tan largo
'Dim uFileSize As Double' Anula el comentario si GetFileHash () se va a utilizar individualmente

Establecer oRnd = New Random 'Class de Microsoft: Random


Establecer oFSO = CreateObject ("Scripting.FileSystemObject")
Establezca oCSP = CreateObject ("System.Security.Cryptography." & SHashType &
"CryptoServiceProvider")

Si oFSO es nada o oRnd es nada o oCSP es nada, entonces


MsgBox "No se pueden crear uno o más objetos obligatorios"
Ir a limpieza
Terminara si

uFileSize = oFSO.GetFile (sFile) .Size 'FILELEN () tiene 2GB como máximo.


uBytesRead = 0
bDone = Falso
sHash = String (oCSP.HashSize / 4, "0") 'Cada hexadecimal tiene 4 bits

Application.ScreenUpdating = Falso
'Procesar el archivo en trozos de uBlockSize o menos
Si uFileSize = 0 entonces
ReDim aBlock (0)
oCSP.TransformFinalBlock aBlock, 0, 0
bDone = Verdadero
Más
Con oRnd
.OpenFile sFile
Hacer
Si uBytesRead + uBlockSize <uFileSize, entonces
uBytesToRead = uBlockSize
Más
uBytesToRead = uFileSize - uBytesRead
bDone = Verdadero
Terminara si
'Leer en algunos bytes
aBytes = .ReadBytes (uBytesToRead)
aBlock = aBytes
Si bDone entonces
oCSP.TransformFinalBlock aBlock, 0, uBytesToRead
uBytesRead = uBytesRead + uBytesToRead
Más
uBytesRead = uBytesRead + oCSP.TransformBlock (aBlock, 0, uBytesToRead,
aBloque, 0)
Terminara si

https://translate.googleusercontent.com/translate_f 176/223
6/1/2021 Intitulado
DoEvents
Bucle hasta bDone
.Cerrar el archivo
Terminar con
Terminara si
Si bDone entonces
'convierte la matriz de bytes Hash en una cadena hexadecimal
aHash = oCSP.hash
Para i = 0 a UBound (aHash)
Mid $ (sHash, i * 2 + (aHash (i)> 15) + 2) = Hex (aHash (i))
próximo
Terminara si
Application.ScreenUpdating = True
' Limpiar
oCSP.Clear
Limpiar:

https://riptutorial.com/ 190

Página 206

Establecer oFSO = Nada


Establecer oRnd = Nada
Establecer oCSP = Nada
GetFileHash = sHash
Función final

La salida es bastante interesante, mis archivos de prueba indican que BLOCKSIZE = 131071 (2 ^ 17-1)
ofrece el mejor rendimiento general con Office 2010 de 32 bits en Windows 7 x64, el siguiente mejor es
2 ^ 16-1 (65535) . Nota 2 ^ 27-1 produce Memoria insuficiente .

Tamaño del archivo


Nombre del 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

Calcular todos los archivos hash desde una carpeta raíz

Otra variación del código anterior le brinda más rendimiento cuando desea obtener hash
códigos de todos los archivos de una carpeta raíz, incluidas todas las subcarpetas.

Ejemplo de hoja de trabajo:

Código

Opción explícita

Private Const HashTypeMD5 As String = "MD5" 'https://msdn.microsoft.com/en-


us / library / system.security.cryptography.md5cryptoserviceprovider (v = frente a 110) .aspx
Private Const HashTypeSHA1 As String = "SHA1" 'https://msdn.microsoft.com/en-
us / library / system.security.cryptography.sha1cryptoserviceprovider (v = frente a 110) .aspx
Private Const HashTypeSHA256 As String = "SHA256" 'https://msdn.microsoft.com/en-
us / library / system.security.cryptography.sha256cryptoserviceprovider (v = frente a 110) .aspx
Private Const HashTypeSHA384 As String = "SHA384" 'https://msdn.microsoft.com/en-
us / library / system.security.cryptography.sha384cryptoserviceprovider (v = frente a 110) .aspx

https://translate.googleusercontent.com/translate_f 177/223
6/1/2021 Intitulado
Private Const HashTypeSHA512 As String = "SHA512" 'https://msdn.microsoft.com/en-
us / library / system.security.cryptography.sha512cryptoserviceprovider (v = frente a 110) .aspx

Const privada BLOCKSIZE como doble = 131071 '2 ^ 17-1

https://riptutorial.com/ 191

Página 207

OFSO privado como objeto


OCSP privado como objeto
Private ornd As Random 'Requiere la clase de Microsoft https://support.microsoft.com/en-
nosotros / kb / 189981
Private sHashType como cadena
SRootFDR privado como cadena
Privado oRng como rango
UFileCount privado como doble

Sub AllFileHashes () 'El botón Active-X llama a esto


Atenuar como hoja de trabajo
'| A: FileHash | B: Tamaño de archivo | C: FileName | D: FilaName y Path | E: Archivo último
Hora de modificación | F: El tiempo requerido para calcular tiene código (segundos)
Con este libro de trabajo
'Borrar todas las entradas antiguas en todas las hojas de trabajo
Para cada oWS en .Worksheets
Establecer oRng = Intersecar (oWS.UsedRange, oWS.UsedRange.Offset (2))
Si no oRng no es nada, entonces oRng.ClearContents
próximo
Con .hojas de trabajo (1)
sHashType = Trim (.Range ("A1"). Valor) 'Rango (A1)
sRootFDR = Trim (.Range ("C1"). Value) 'Range (C1) Columna B para el tamaño del archivo
Si Len (sHashType) = 0 o Len (sRootFDR) = 0, salga de Sub
Set oRng = .Range ("A3") 'Primera entrada en la primera página
Terminar con
Terminar con

uFileCount = 0
Si oRnd no es nada, entonces establezca oRnd = New Random 'Class de Microsoft: Random
Si oFSO no es nada, establezca oFSO = CreateObject ("Scripting.FileSystemObject") 'Solo para
obtener FileSize correcto
Si oCSP no es nada, establezca oCSP = CreateObject ("System.Security.Cryptography." &
sHashType y "CryptoServiceProvider")

ProcessFolder oFSO.GetFolder (sRootFDR)

Application.StatusBar = False
Application.ScreenUpdating = True
oCSP.Clear
Establecer oCSP = Nada
Establecer oRng = Nada
Establecer oFSO = Nada
Establecer oRnd = Nada
Debug.Print "Recuento total de archivos:" & uFileCount
End Sub

Carpeta de subproceso privada (ByRef oFDR como objeto)


Dim oFile como objeto, oSubFDR como objeto, sHash como cadena, dStart como fecha, dFinish como fecha
Application.ScreenUpdating = Falso
Para cada oFile en oFDR.
uFileCount = uFileCount + 1
Application.StatusBar = uFileCount & ":" & Derecha (oFile.Path, 255 - Len (uFileCount) -
2)
oCSP.Initialize 'Reinicializar el CryptoServiceProvider
dStart = Ahora
sHash = GetFileHash (oFile, BLOCKSIZE, sHashType)
dFinish = Ahora
Con oRng
.Value = sHash
.Offset (0, 1) .Value = oFile.Size 'Tamaño del archivo en bytes

https://riptutorial.com/ 192

Página 208
https://translate.googleusercontent.com/translate_f 178/223
6/1/2021 Intitulado

.Offset (0, 2) .Value = oFile.Name 'Nombre de archivo con extensión


.Offset (0, 3) .Value = oFile.Path 'Nombre de archivo completo y ruta
.Offset (0, 4) .Value = FileDateTime (oFile.Path) 'Última modificación de fecha y hora de
archivo
.Offset (0, 5) .Value = dFinish - dStart 'Tiempo requerido para calcular el código hash
Terminar con
Si oRng.Row = Rows.Count Entonces
'Se alcanzó el número máximo de filas, comience en la siguiente hoja
Si oRng.Worksheet.Index + 1> ThisWorksheets.Worksheets.Count Then
MsgBox "Se han utilizado todas las filas de todas las hojas de trabajo, cree más hojas"
Fin
Terminara si
Establecer oRng = ThisWorkbook.Sheets (oRng.Worksheet.Index + 1) .Range ("A3")
oRng.Worksheet.Activar
Más
'Mover a la siguiente fila de lo contrario
Establecer oRng = oRng.Offset (1)
Terminara si
próximo
'Application.StatusBar = False
Application.ScreenUpdating = True
oRng.Activar
Para cada oSubFDR en oFDR.
ProcessFolder oSubFDR
próximo
End Sub

Función privada GetFileHash (ByVal sFile como cadena, ByVal uBlockSize como doble, ByVal
sHashType como cadena) como cadena
Dim uBytesRead como doble, uBytesToRead como doble, bDone como booleano
Dim aBlock () As Byte, aBytes As Variant 'Arrays para almacenar bytes
Dim aHash () como byte, sHash como cadena, i tan largo, oTmp como variante
Dim uFileSize As Double 'Un-Comment si GetFileHash () se va a utilizar individualmente

Si oRnd no es nada, entonces establezca oRnd = New Random 'Class de Microsoft: Random
Si oFSO no es nada, establezca oFSO = CreateObject ("Scripting.FileSystemObject") 'Solo para
obtener FileSize correcto
Si oCSP no es nada, establezca oCSP = CreateObject ("System.Security.Cryptography." &
sHashType y "CryptoServiceProvider")

Si oFSO es nada o oRnd es nada o oCSP es nada, entonces


MsgBox "No se pueden crear uno o más objetos obligatorios"
Función de salida
Terminara si

uFileSize = oFSO.GetFile (sFile) .Size 'FILELEN () tiene 2GB como máximo


uBytesRead = 0
bDone = Falso
sHash = String (oCSP.HashSize / 4, "0") 'Cada hexadecimal tiene 4 bits

'Procesar el archivo en trozos de uBlockSize o menos


Si uFileSize = 0 entonces
ReDim aBlock (0)
oCSP.TransformFinalBlock aBlock, 0, 0
bDone = Verdadero
Más
Con oRnd
En caso de error, GoTo CannotOpenFile
.OpenFile sFile
Hacer
Si uBytesRead + uBlockSize <uFileSize, entonces

https://riptutorial.com/ 193

Página 209

uBytesToRead = uBlockSize
Más
uBytesToRead = uFileSize - uBytesRead
bDone = Verdadero
Terminara si
'Leer en algunos bytes
aBytes = .ReadBytes (uBytesToRead)
aBlock = aBytes
Si bDone entonces

https://translate.googleusercontent.com/translate_f 179/223
6/1/2021 Intitulado
oCSP.TransformFinalBlock aBlock, 0, uBytesToRead
uBytesRead = uBytesRead + uBytesToRead
Más
uBytesRead = uBytesRead + oCSP.TransformBlock (aBlock, 0, uBytesToRead,
aBloque, 0)
Terminara si
DoEvents
Bucle hasta bDone
.Cerrar el archivo
No puede abrir el archivo:
If Err.Number <> 0 Then 'Cambie el código hash a la descripción del error
oTmp = Dividir (Err.Description, vbCrLf)
sHash = oTmp (1) & ":" & oTmp (2)
Terminara si
Terminar con
Terminara si
Si bDone entonces
'convierte la matriz de bytes Hash en una cadena hexadecimal
aHash = oCSP.hash
Para i = 0 a UBound (aHash)
Mid $ (sHash, i * 2 + (aHash (i)> 15) + 2) = Hex (aHash (i))
próximo
Terminara si
GetFileHash = sHash
Función final

Lea Lectura de archivos de 2GB + en binario en VBA y File Hashes en línea:


https://riptutorial.com/vba/topic/8786/reading-2gbplus-files-in-binary-in-vba-and-file-hashes

https://riptutorial.com/ 194

Página 210

Capítulo 35: Recurrencia


Introducción
Se dice que una función que se llama a sí misma es recursiva . La lógica recursiva a menudo se puede implementar como
bucle también. La recursividad debe controlarse con un parámetro, para que la función sepa cuándo detenerse
recurriendo y profundizando la pila de llamadas. La recursividad infinita eventualmente causa un error en tiempo de ejecución '28':
"Fuera de espacio de pila".

Ver Recurrencia .

Observaciones
La recursividad permite llamadas repetidas y autoreferenciadas de un procedimiento.
https://translate.googleusercontent.com/translate_f 180/223
6/1/2021 Intitulado

Ejemplos

Factoriales

Función Factorial (valor tan largo) tan largo


Si Valor = 0 O Valor = 1 Entonces
Factorial = 1
Más
Factorial = Factorial (Valor - 1) * Valor
Terminara si
Función final

Recurrencia de carpeta

Early Bound (con una referencia a Microsoft Scripting Runtime )

Sub EnumerateFilesAndFolders (_
FolderPath como cadena, _
MaxDepth opcional siempre que = -1, _
CurrentDepth opcional tan largo = 0, _
Sangría opcional tan larga = 2)

Atenuar FSO como scripting.FileSystemObject


Establecer FSO = New Scripting.FileSystemObject

'Compruebe que la carpeta existe


Si FSO.FolderExists (FolderPath), entonces
Dim fldr como Scripting.Folder
Establecer fldr = FSO.GetFolder (FolderPath)

'Muestra la ruta del directorio de inicio


Si CurrentDepth = 0 entonces
Debug.Print fldr.Path
Terminara si

https://riptutorial.com/ 195

Página 211

'Enumerar las subcarpetas


Dim subFldr como carpeta de scripts
Para cada subFldr en fldr.SubFolders
Espacio de impresión de depuración $ ((CurrentDepth + 1) * Sangría) & subFldr.Name
Si CurrentDepth <MaxDepth o MaxDepth = -1, entonces
'Llamar recursivamente a EnumerateFilesAndFolders
EnumerateFilesAndFolders subFldr.Path, MaxDepth, CurrentDepth + 1,
Sangría
Terminara si
Siguiente subFldr

'Enumerar los archivos


Dim fil como Scripting.File
Para cada archivo de archivos fldr.
Espacio de depuración $ ((CurrentDepth + 1) * Sangría) & fil.Name
Siguiente fil
Terminara si
End Sub

Lea Recursion en línea: https://riptutorial.com/vba/topic/3236/recursion

https://translate.googleusercontent.com/translate_f 181/223
6/1/2021 Intitulado

https://riptutorial.com/ 196

Página 212

Capítulo 36: Scripting Objeto Diccionario


Observaciones

Debe agregar Microsoft Scripting Runtime al proyecto VBA a través de las herramientas de VBE →
Comando de referencias para implementar el enlace anticipado del objeto Diccionario de secuencias de comandos. Esta
la referencia de la biblioteca se lleva con el proyecto; no tiene que ser re-referenciado cuando el VBA
El proyecto se distribuye y ejecuta en otra computadora.

Ejemplos

Propiedades y métodos

UN El objeto Diccionario de secuencias de comandos almacena información en pares Clave / Elemento. Las claves deben ser únicas y
no es una matriz, pero los elementos asociados se pueden repetir (su singularidad está en manos del compañero
Key) y puede ser de cualquier tipo de variante u objeto.

Un diccionario puede considerarse como una base de datos en memoria de dos campos con un índice primario único en
el primer 'campo' (la Clave ). Este índice único en la propiedad Keys permite 'búsquedas' muy rápidas para
recuperar el valor del artículo asociado a una clave.

Propiedades

nombre leer escribir tipo descripción

Establecer el modo de comparación solo puede


leer / CompareMode realizado en un diccionario vacío. Aceptado
CompareMode
escribir constante los valores son 0 (vbBinaryCompare), 1
(vbTextCompare), 2 (vbDatabaseCompare).

https://translate.googleusercontent.com/translate_f 182/223
6/1/2021 Intitulado
Contar leer
solamente largo sin firmar
entero Un recuento
objeto basado endeuno
de diccionario de los pares
secuencias clave / elemento en el
de comandos.

leer / sin matriz


Llave Cada clave única individual en el diccionario.
escribir variante

Propiedad predeterminada. Cada artículo individual


asociado con una clave en el diccionario. Nota
leer /
Elemento ( clave ) cualquier variante que intentar recuperar un artículo con una llave
escribir
que no existe en el diccionario
agregue implícitamente la clave pasada.

Métodos

https://riptutorial.com/ 197

Página 213

nombre descripción

Agrega una clave y un elemento nuevos al diccionario. La nueva clave no debe existir en el
Agregar ( clave ,
colección de claves actual del diccionario, pero un elemento se puede repetir entre muchos
Artículo )
claves únicas.

Existe ( clave ) Prueba booleana para determinar si una clave ya existe en el diccionario.

Llaves Devuelve la matriz o colección de claves únicas.

Artículos Devuelve la matriz o colección de elementos asociados.

Eliminar(
Elimina una clave de diccionario individual y su elemento asociado.
Clave )

Eliminar todo Borra todas las claves y elementos de un objeto de diccionario.

Código de muestra

'Rellenar, enumerar, localizar y eliminar entradas en un diccionario que se creó


'con encuadernación tardía
Sub iterateDictionaryLate ()
Dim k como variante, dictar como objeto

Establecer dict = CreateObject ("Scripting.Dictionary")


dict.CompareMode = vbTextCompare 'modelo de comparación no sensible a mayúsculas y minúsculas

'rellenar el diccionario
dict.Add Key: = "Red", Item: = "Balloon"
dict.Add Key: = "Green", Item: = "Balloon"
dict.Add Key: = "Blue", Item: = "Balloon"

'iterar a través de las claves


Para cada k Teclas en dict.
Debug.Print k & "-" & dict.Item (k)
Siguiente k

'localizar el artículo para verde


Debug.Print dict.Item ("Verde")

'eliminar pares clave / elemento del diccionario


dict.Remove "blue" 'eliminar clave individual / par de elementos por clave
dict.RemoveAll 'eliminar todos los pares clave / elemento restantes

End Sub

'Rellenar, enumerar, localizar y eliminar entradas en un diccionario que se creó


'con enlace anticipado (ver Comentarios)
Sub iterateDictionaryEarly ()
Dim d tan largo, k como variante
Dim dict como nueva secuencia de comandos.

https://translate.googleusercontent.com/translate_f 183/223
6/1/2021 Intitulado

dict.CompareMode = vbTextCompare 'modelo de comparación no sensible a mayúsculas y minúsculas

'rellenar el diccionario
dict.Add Key: = "Red", Item: = "Balloon"

https://riptutorial.com/ 198

Página 214

dict.Add Key: = "Green", Item: = "Balloon"


dict.Add Key: = "Blue", Item: = "Balloon"
dict.Add Key: = "White", Item: = "Balloon"

'iterar a través de las claves


Para cada k Teclas en dict.
Debug.Print k & "-" & dict.Item (k)
Siguiente k

'iterar a través de las claves por el recuento


Para d = 0 Para dictar Cuenta - 1
Debug.Print dict.Keys (d) & "-" & dict.Items (d)
Siguiente d

'iterar a través de las claves por los límites de la colección de claves


Para d = LBound (dict.Keys) a UBound (dict.Keys)
Debug.Print dict.Keys (d) & "-" & dict.Items (d)
Siguiente d

'localizar el artículo para verde


Debug.Print dict.Item ("Verde")
'busque el artículo para la primera clave
Debug.Print dict.Item (dict.Keys (0))
'localizar el artículo de la última clave
Debug.Print dict.Item (dict.Keys (UBound (dict.Keys)))

'eliminar pares clave / elemento del diccionario


dict.Quitar "azul" 'eliminar par clave individual / elemento por clave
dict.Eliminar dict.Keys (0) 'eliminar la primera clave / elemento por posición de índice
dict.Remove dict.Keys (UBound (dict.Keys)) 'eliminar la última clave / elemento por posición de índice
dict.RemoveAll 'eliminar todos los pares clave / elemento restantes

End Sub

Agregando datos con Scripting.Dictionary (Máximo, Recuento)

Los diccionarios son excelentes para administrar información donde ocurren múltiples entradas, pero solo
relacionado con un solo valor para cada conjunto de entradas: el primer o último valor, el mínimo o
valor máximo, un promedio, una suma, etc.

Considere un libro de trabajo que contiene un registro de la actividad del usuario, con un script que inserta el nombre de usuario y
editar la fecha cada vez que alguien edita el libro de trabajo:

Hoja de trabajo de registro

UN segundo

Beto 12/10/2016 9:00

Alice 13/10/2016 13:00

Beto 13/10/2016 13:30

Alice 13/10/2016 14:00

https://riptutorial.com/ 199

https://translate.googleusercontent.com/translate_f 184/223
6/1/2021 Intitulado
Página 215

UN segundo

Alice 14/10/2016 13:00

Supongamos que desea generar la última hora de edición para cada usuario, en una hoja de trabajo llamada Resumen .

Notas:
1. Se supone que los datos están en ActiveWorkbook .
2. Estamos usando una matriz para extraer los valores de la hoja de trabajo; esto es más eficiente que iterar sobre cada celda.
3. El diccionario se crea utilizando el enlace anticipado.

Sub LastEdit ()
Dim vLog como variante, vKey como variante
Dim dict como nueva secuencia de comandos.
Atenuar lastRow como entero, lastColumn como entero
Dim i as Long
Ancla tenue como rango

Con ActiveWorkbook
Con .Sheets ("Registro")
'Extraiga las entradas del "registro" en una matriz de variantes
lastRow = .Range ("a" & .Rows.Count) .End (xlUp) .Row
vlog = .Range ("a1", .Cells (lastRow, 2)). Value2

'Bucle a través de matriz


Para i = 1 a lastRow
Dim nombre de usuario como cadena
nombre de usuario = vlog (i, 1)
Dim editDate As Date
editDate = vlog (i, 2)

'Si el nombre de usuario aún no está en el diccionario:


Si no dict.Exists (nombre de usuario) Entonces
dict (nombre de usuario) = editDate
ElseIf dict (nombre de usuario) <editDate Entonces
dict (nombre de usuario) = editDate
Terminara si
próximo
Terminar con

Con .Sheets ("Resumen")


'Recorrer las teclas
Para cada vKey en dict.Keys
'Agregue la clave y el valor en la siguiente fila disponible
Anchor = .Range ("A" & .Rows.Count) .End (xlUp) .Offset (1,0)
Anchor = vKey
Anchor.Offset (0,1) = dict (vKey)
Siguiente vKey
Terminar con
Terminar con
End Sub

y la salida se verá así:

Hoja de trabajo de resumen

https://riptutorial.com/ 200

Página 216

UN segundo

Beto 13/10/2016 13:30

Alice 14/10/2016 13:00

https://translate.googleusercontent.com/translate_f 185/223
6/1/2021 Intitulado

Si, por otro lado, desea generar la cantidad de veces que cada usuario editó el libro de trabajo, el cuerpo
del bucle For debería verse así:

'Bucle a través de matriz


Para i = 1 a lastRow
Dim nombre de usuario como cadena
nombre de usuario = vlog (i, 1)

'Si el nombre de usuario aún no está en el diccionario:


Si no dict.Exists (nombre de usuario) Entonces
dict (nombre de usuario) = 1
Más
dict (nombre de usuario) = dict (nombre de usuario) + 1
Terminara si
próximo

y la salida se verá así:

Hoja de trabajo de resumen

UN segundo

Beto 2

alicia 3

Obteniendo valores únicos con Scripting.

El Diccionario permite obtener un conjunto único de valores de forma muy sencilla. Considere la siguiente función:

Función Única (valores como variante) como variante ()


'Pon todos los valores como claves en un diccionario
Dim dict como nueva secuencia de comandos.
Dim val como variante
Para cada valor en valores
dict (val) = 1 'El valor no importa aquí
próximo
Único = dict.Keys
Función final

que luego podrías llamar así:

Atenuar duplicados () como variante


duplicados = Array (1, 2, 3, 1, 2, 3)
Dim uniqueVals () como variante

https://riptutorial.com/ 201

Página 217

uniqueVals = Único (duplicados)

y uniqueVals solo contendría {1,2,3} .

Nota: esta función se puede utilizar con cualquier objeto enumerable.

Leer el objeto Scripting.Dictionary en línea: https://riptutorial.com/vba/topic/3667/scripting-dictionary-


objeto

https://translate.googleusercontent.com/translate_f 186/223
6/1/2021 Intitulado

https://riptutorial.com/ 202

Página 218

Capítulo 37: Scripting.FileSystemObject


Ejemplos

Creando un FileSystemObject

Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8

Sub FsoExample ()
Dim fso As Object 'declarar variable
Establecer fso = CreateObject ("Scripting.FileSystemObject") 'Establecer como un objeto del sistema de archivos

'ahora utilícelo para verificar si existe un archivo


Atenuar myFilePath como cadena
myFilePath = "C: \ mypath \ to \ myfile.txt"
Si fso.FileExists (myFilePath) Entonces
' hacer algo
Más
'archivo no existe
MsgBox "El archivo no existe"
Terminara si
End Sub

https://translate.googleusercontent.com/translate_f 187/223
6/1/2021 Intitulado
Leer un archivo de texto usando un FileSystemObject
Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8

Sub ReadTextFileExample ()
Dim fso como objeto
Establecer fso = CreateObject ("Scripting.FileSystemObject")

Dim sourceFile como objeto


Atenuar myFilePath como cadena
Atenuar myFileText como cadena

myFilePath = "C: \ mypath \ to \ myfile.txt"


Establecer sourceFile = fso.OpenTextFile (myFilePath, ForReading)
myFileText = sourceFile.ReadAll 'myFileText ahora contiene el contenido del archivo de texto
sourceFile.Close 'cierra el archivo
'haz lo que necesites hacer con el texto

'También puedes leerlo línea por línea


Línea tenue como cadena
Establecer sourceFile = fso.OpenTextFile (myFilePath, ForReading)
While Not sourceFile.AtEndOfStream 'mientras no hayamos terminado de leer el archivo
línea = sourceFile.ReadLine
'haz algo con la línea ...
Encaminarse a
sourceFile.Close
End Sub

https://riptutorial.com/ 203

Página 219

Creando un archivo de texto con FileSystemObject

Sub CreateTextFileExample ()
Dim fso como objeto
Establecer fso = CreateObject ("Scripting.FileSystemObject")

Dim targetFile como objeto


Atenuar myFilePath como cadena
Atenuar myFileText como cadena

myFilePath = "C: \ mypath \ to \ myfile.txt"


Set targetFile = fso.CreateTextFile (myFilePath, True) 'esto sobrescribirá cualquier existente
archivo
targetFile.Write "Este es un texto nuevo"
targetFile.Write "Y este texto aparecerá justo después del primer fragmento de texto".
targetFile.WriteLine "Este fragmento de texto incluye un carácter de nueva línea para garantizar que cada escritura
toma su propia línea ".
targetFile.Close 'cierra el archivo
End Sub

Escribir en un archivo existente con FileSystemObject

Const ForReading = 1
Const ForWriting = 2
Const ForAppending = 8

Sub WriteTextFileExample ()
Dim oFso
Establecer oFso = CreateObject ("Scripting.FileSystemObject")

Dim oFile como objeto


Atenuar myFilePath como cadena
Atenuar myFileText como cadena

myFilePath = "C: \ mypath \ to \ myfile.txt"


'Primero verifique si el archivo existe
Si oFso.FileExists (myFilePath) Entonces
'esto sobrescribirá cualquier contenido de archivo existente con cualquier cosa que envíe el archivo
'para agregar datos al final de un archivo existente, use ForAppending en su lugar

https://translate.googleusercontent.com/translate_f 188/223
6/1/2021 Intitulado
Establecer oFile = oFso.OpenTextFile (myFilePath, ForWriting)
Más
'crea el archivo en su lugar
Establecer oFile = oFso.CreateTextFile (myFilePath) 'omitiendo el booleano opcional para
sobrescribir si existe ya que ya comprobamos que el archivo no existe.
Terminara si
oFile.Write "Este es un texto nuevo"
oFile.Write "Y este texto aparecerá justo después del primer fragmento de texto".
oFile.WriteLine "Este fragmento de texto incluye un carácter de nueva línea para garantizar que cada escritura tenga
su propia línea ".
oFile.Close 'cierra el archivo
End Sub

Enumerar archivos en un directorio usando FileSystemObject

Enlace anticipado (requiere una referencia a Microsoft Scripting Runtime):

https://riptutorial.com/ 204

Página 220

Public Sub EnumerateDirectory ()


Dim fso como Scripting.FileSystemObject
Establecer fso = New Scripting.FileSystemObject

Atenuar targetFolder como carpeta


Establecer targetFolder = fso.GetFolder ("C: \")

Dim foundFile como variante


Para cada archivo encontrado en targetFolder.Files
Debug.Print foundFile.Name
próximo
End Sub

Límite tardío:

Public Sub EnumerateDirectory ()


Dim fso como objeto
Establecer fso = CreateObject ("Scripting.FileSystemObject")

Atenuar targetFolder como objeto


Establecer targetFolder = fso.GetFolder ("C: \")

Dim foundFile como variante


Para cada archivo encontrado en targetFolder.Files
Debug.Print foundFile.Name
próximo
End Sub

Enumere carpetas y archivos de forma recursiva

Early Bound (con una referencia a Microsoft Scripting Runtime )

Sub EnumerateFilesAndFolders (_
FolderPath como cadena, _
MaxDepth opcional siempre que = -1, _
CurrentDepth opcional tan largo = 0, _
Sangría opcional tan larga = 2)

Atenuar FSO como scripting.FileSystemObject


Establecer FSO = New Scripting.FileSystemObject

'Compruebe que la carpeta existe


Si FSO.FolderExists (FolderPath), entonces
Dim fldr como Scripting.Folder
Establecer fldr = FSO.GetFolder (FolderPath)

'Muestra la ruta del directorio de inicio


Si CurrentDepth = 0 entonces
Debug.Print fldr.Path
Terminara si

https://translate.googleusercontent.com/translate_f 189/223
6/1/2021 Intitulado
'Enumerar las subcarpetas
Dim subFldr como carpeta de scripts
Para cada subFldr en fldr.SubFolders
Espacio de impresión de depuración $ ((CurrentDepth + 1) * Sangría) & subFldr.Name
Si CurrentDepth <MaxDepth o MaxDepth = -1, entonces
'Llamar recursivamente a EnumerateFilesAndFolders
EnumerateFilesAndFolders subFldr.Path, MaxDepth, CurrentDepth + 1, Sangría

https://riptutorial.com/ 205

Página 221

Terminara si
Siguiente subFldr

'Enumerar los archivos


Dim fil como Scripting.File
Para cada archivo de archivos fldr.
Espacio de depuración $ ((CurrentDepth + 1) * Sangría) & fil.Name
Siguiente fil
Terminara si
End Sub

Salida cuando se llama con argumentos como: EnumerateFilesAndFolders "C: \ Test"

C: \ Prueba
Documentos
Personal
Budget.xls
Recipes.doc
Trabajo
Planning.doc
Descargas
FooBar.exe
ReadMe.txt

Salida cuando se llama con argumentos como: EnumerateFilesAndFolders "C: \ Test", 0

C: \ Prueba
Documentos
Descargas
ReadMe.txt

Salida cuando se llama con argumentos como: EnumerateFilesAndFolders "C: \ Test", 1, 4

C: \ Prueba
Documentos
Personal
Trabajo
Descargas
FooBar.exe
ReadMe.txt

Quitar la extensión de archivo de un nombre de archivo

Dim fso como nuevo scripting.FileSystemObject


Debug.Print fso.GetBaseName ("MyFile.something.txt")

Imprime MyFile.something

Tenga en cuenta que el método GetBaseName () ya maneja varios períodos en un nombre de archivo.

Recuperar solo la extensión de un nombre de archivo

Dim fso como nuevo scripting.FileSystemObject

https://riptutorial.com/ 206

https://translate.googleusercontent.com/translate_f 190/223
6/1/2021 Intitulado

Página 222

Debug.Print fso.GetExtensionName ("MyFile.something.txt")

Imprime txt Tenga en cuenta que el método GetExtensionName () ya maneja varios puntos en un nombre de archivo.

Recuperar solo la ruta de una ruta de archivo

El método GetParentFolderName devuelve la carpeta principal para cualquier ruta. Si bien esto también puede ser
utilizado con carpetas, podría decirse que es más útil para extraer la ruta de una ruta de archivo absoluta:

Dim fso como nuevo scripting.FileSystemObject


Debug.Print fso.GetParentFolderName ("C: \ Users \ Me \ My Documents \ SomeFile.txt")

Imprime C: \ Usuarios \ Yo \ Mis documentos

Tenga en cuenta que el separador de ruta final no se incluye en la cadena devuelta.

Usando FSO.BuildPath para construir una ruta completa a partir de la ruta de la carpeta y el nombre del archivo

Si acepta la entrada del usuario para las rutas de las carpetas, es posible que deba verificar si hay barras diagonales inversas al final ( \ )
antes de crear una ruta de archivo. El método FSO.BuildPath simplifica esto:

Const sourceFilePath As String = "C: \ Temp" '<- Sin barra invertida al final
Const targetFilePath As String = "C: \ Temp \" '<- Con barra invertida al final

Const fileName As String = "Results.txt"

Atenuar FSO como FileSystemObject


Establecer FSO = New FileSystemObject

Debug.Print FSO.BuildPath (sourceFilePath, fileName)


Debug.Print FSO.BuildPath (targetFilePath, fileName)

Salida:

C: \ Temp \ Results.txt
C: \ Temp \ Results.txt

Lea Scripting.FileSystemObject en línea: https://riptutorial.com/vba/topic/990/scripting-


objeto del sistema de archivos

https://riptutorial.com/ 207

Página 223

Capítulo 38: Búsqueda dentro de cadenas de


presencia de subcadenas
https://translate.googleusercontent.com/translate_f 191/223
6/1/2021 Intitulado

Observaciones
Cuando necesita verificar la presencia o posición de una subcadena dentro de una cadena, VBA ofrece la
Funciones InStr e InStrRev que devuelven la posición del carácter de la subcadena en la cadena, si es
presente.

Ejemplos

Use InStr para determinar si una cadena contiene una subcadena

Const baseString As String = "Foo Bar"


Dim containsBar como booleano

'Compruebe si baseString contiene "bar" (no distingue entre mayúsculas y minúsculas)


containsBar = InStr (1, baseString, "bar", vbTextCompare)> 0
'containsBar = True

'Compruebe si baseString contiene bar (no distingue entre mayúsculas y minúsculas)


containsBar = InStr (1, baseString, "bar", vbBinaryCompare)> 0
'containsBar = False

Use InStr para encontrar la posición de la primera instancia de una subcadena

Const baseString As String = "Foo Bar"


Dim containsBar como booleano

Dim posB tan largo


posB = InStr (1, baseString, "B", vbBinaryCompare)
'posB = 5

Utilice InStrRev para encontrar la posición de la última instancia de una subcadena

Const baseString As String = "Foo Bar"


Dim containsBar como booleano

'Encuentra la posición de la última "B"


Dim posX tan largo
'Tenga en cuenta el diferente número y orden de los parámetros para InStrRev
posX = InStrRev (baseString, "X", -1, vbBinaryCompare)
'posX = 0

Lea Buscar dentro de cadenas para detectar la presencia de subcadenas en línea:


https://riptutorial.com/vba/topic/3480/searching-within-strings-for-the-presence-of-substrings

https://riptutorial.com/ 208

Página 224

Capítulo 39: Clasificación


Introducción
A diferencia del marco .NET, 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
ordenar rutinas en otras bibliotecas comúnmente disponibles.

Ejemplos

https://translate.googleusercontent.com/translate_f 192/223
6/1/2021 Intitulado
Implementación de algoritmos: clasificación rápida en una matriz unidimensional

¿Desde la función de clasificación de matriz VBA?

Public Sub QuickSort (vArray como variante, inLow tan largo, inHi tan largo)

Dim pivot como variante


Dim tmpSwap como variante
Dim tmpLow tanto tiempo
Dim tmpHi tan largo

tmpLow = inLow
tmpHi = inHi

pivote = vArray ((inLow + inHi) \ 2)

Mientras (tmpLow <= tmpHi)

Mientras (vArray (tmpLow) <pivote y tmpLow <inHi)


tmpLow = tmpLow + 1
Encaminarse a

Mientras (pivote <vArray (tmpHi) y tmpHi> inLow)


tmpHi = tmpHi - 1
Encaminarse a

Si (tmpLow <= tmpHi) Entonces


tmpSwap = vArray (tmpLow)
vArray (tmpLow) = vArray (tmpHi)
vArray (tmpHi) = tmpSwap
tmpLow = tmpLow + 1
tmpHi = tmpHi - 1
Terminara si

Encaminarse a

If (inLow <tmpHi) Entonces QuickSort vArray, inLow, tmpHi


If (tmpLow <inHi) Entonces QuickSort vArray, tmpLow, inHi

End Sub

https://riptutorial.com/ 209

Página 225

Uso de la biblioteca de Excel para ordenar una matriz unidimensional

Este código aprovecha la clase Sort en la biblioteca de objetos de Microsoft Excel.

Para obtener más información, consulte:

• Copiar un rango a un rango virtual

• ¿Cómo copiar el rango seleccionado en una matriz dada?

SubpruebaExcelSort ()

Dim arr como variante

InitArray arr
ExcelSort arr

End Sub

Private Sub InitArray (arr como variante)

Const tamaño = 10
ReDim arr (tamaño)

Dim i como entero

'Agregue números descendentes a la matriz para comenzar


Para i = 0 al tamaño

https://translate.googleusercontent.com/translate_f 193/223
6/1/2021 Intitulado
arr (i) = tamaño - i
Siguiente yo

End Sub

Private Sub ExcelSort (arr como variante)

'Inicializar los objetos de Excel (requerido)


Dim xl como nueva aplicación de Excel
Dim wbk como libro de trabajo
Establecer wbk = xl.Workbooks.Add
Dim sht como hoja de trabajo
Establecer sht = wbk.ActiveSheet

'Copie la matriz en el objeto Range


Atenuar como rango
Establecer rng = sht.Range ("A1")
Establecer rng = rng.Resize (UBound (arr, 1), 1)
rng.Value = xl.WorksheetFunction.Transpose (arr)

'Ejecute la rutina de clasificación de la hoja de trabajo en el rango


Atenuar MySort como ordenar
Establecer MySort = sht.Sort

Con MySort
.SortFields.Clear
.SortFields.Add rng, xlSortOnValues, xlAscending, xlSortNormal
.SetRange rng
.Encabezado = xlNo
.Aplicar
Terminar con

https://riptutorial.com/ 210

Página 226

'Copia los resultados a la matriz


CopyRangeToArray rng, arr

'Limpia los objetos


Establecer rng = Nada
wbk.Close Falso
xl.

End Sub

Private Sub CopyRangeToArray (rng como rango, arr)

Dim i tan largo


Dim c como rango

'No se puede simplemente establecer la matriz en Range.value (agrega una dimensión)


Para cada c In rng.Cells
arr (i) = c. Valor
yo = yo + 1
Siguiente c

End Sub

Leer Clasificación en línea: https://riptutorial.com/vba/topic/8836/sorting

https://translate.googleusercontent.com/translate_f 194/223
6/1/2021 Intitulado

https://riptutorial.com/ 211

Página 227

Capítulo 40: Literales de cadena: escape, no


caracteres imprimibles y continuaciones de línea
Observaciones
La asignación de cadenas literales 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 de escape, cadenas especiales no imprimibles y literales de cadena larga.

Al asignar cadenas literales que contienen caracteres específicos de una determinada página de códigos,
Es posible que deba considerar las preocupaciones de internacionalización asignando una cadena de un Unicode separado
archivo de recursos.

Ejemplos

Escapando del "personaje

La sintaxis de VBA requiere que aparezca un literal de cadena dentro de las marcas " , por lo que cuando su cadena necesita
contienen comillas, necesitará escapar / anteponer el " carácter con un extra " para que VBA
entiende que tiene la intención de que "" se interprete como una " cadena.

'Las siguientes 2 líneas producen el mismo resultado


Debug.Print "El hombre dijo" "Nunca utilices comillas" ""
Debug.Print "El hombre dijo," & "" "" & "Nunca use comillas de aire" & "" ""

'Salida:
'El hombre dijo: "Nunca uses comillas de aire"
'El hombre dijo: "Nunca uses comillas de aire"

Asignar literales de cadena larga

El editor de VBA solo permite 1023 caracteres por línea, pero generalmente solo los primeros 100-150 caracteres
son visibles sin desplazarse. Si necesita asignar literales de cadena larga, pero desea mantener su
código legible, necesitará 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".

https://translate.googleusercontent.com/translate_f 195/223
6/1/2021 Intitulado
'Salida:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Entero hendrerit maximus arcu, ut
elementum odio varius nec. Integer ipsum enim, iaculis et egestas ac, condimentum ut tellus.

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 continuo), por lo que si tiene cadenas muy largas, deberá asignar y
reasignar con concatenación.

https://riptutorial.com/ 212

Página 228

Dim loremIpsum como cadena

'Asignar la primera parte de la cadena


loremIpsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit." & _
"Integer hendrerit maximus arcu, ut elementum odio varius"
'Reasignar con el valor anterior Y la siguiente sección de la cadena
loremIpsum = loremIpsum & _
"nec. Integer ipsum enim, iaculis et egestas ac, condiment" & _
"Um ut tellus".

Debug.Print loremIpsum

'Salida:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Entero hendrerit maximus arcu, ut
elementum odio varius nec. Integer ipsum enim, iaculis et egestas ac, condimentum ut tellus.

Usando constantes de cadena de VBA

VBA define una serie de constantes de cadena para caracteres especiales como:

• vbCr: Carriage-Return 'Igual que "\ r" en los lenguajes de estilo C.


• vbLf: Line-Feed 'Igual que "\ n" en los lenguajes de estilo C.
• vbCrLf: retorno de carro y avance de línea (una nueva línea en Windows)
• vbTab: carácter de tabulación
• vbNullString: una cadena vacía, como ""

Puede usar estas constantes con concatenación y otras funciones de cadena para construir cadenas literales
con caracteres especiales.

Debug.Print "Hola" & vbCrLf & "Mundo"


'Salida:
'Hola
'Mundo

Debug.Print vbTab & "Hello" & vbTab & "World"


'Salida:
' Hola Mundo

Dim EmptyString como cadena


EmptyString = vbNullString
Debug.Print EmptyString = ""
'Salida:
'Cierto

El uso de vbNullString se considera una mejor práctica que el valor equivalente de "" debido a diferencias
en cómo se compila el código. Se accede a las cadenas mediante un puntero a un área asignada de memoria,
y el compilador de VBA es lo suficientemente inteligente como para usar un puntero nulo para representar vbNullString . El literal ""
se asigna memoria como si fuera una Variante de tipo String, lo que hace que el uso de la constante sea mucho más
eficiente:

Debug.Print StrPtr (vbNullString) 'Imprime 0.


Debug.Print StrPtr ("") Imprime una dirección de memoria.

https://riptutorial.com/ 213
https://translate.googleusercontent.com/translate_f 196/223
6/1/2021 Intitulado

Página 229

Leer literales de cadena: caracteres de escape, no imprimibles y continuaciones de línea en línea:


https://riptutorial.com/vba/topic/3445/string-literals---escaping--non-printable-characters-and-line-
continuaciones

https://riptutorial.com/ 214

Página 230

Capítulo 41: Subcadenas


Observaciones
https://translate.googleusercontent.com/translate_f 197/223
6/1/2021 Intitulado

VBA tiene funciones integradas para extraer partes específicas de cadenas, que incluyen:

• Izquierda / Izquierda $
• Derecha / Derecha $
• Medio / Medio $

• Recortar / Recortar $

Para evitar la conversión de tipo implícita en la sobrecarga (y, por lo tanto, para un mejor rendimiento), use $ -
versión con 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 nulo a una función $ -suffixed generará un error de tiempo de ejecución ("uso no válido de
null "): esto es especialmente relevante para el código que involucra una base de datos.

Ejemplos

Use Left o Left $ para obtener los 3 caracteres más a la izquierda en una cadena

Const baseString As String = "Foo Bar"

Dim leftText As String


leftText = Left $ (baseString, 3)
'leftText = "Foo"

Use Right o Right $ para obtener los 3 caracteres más a la derecha en una cadena

Const baseString As String = "Foo Bar"


Dim rightText As String
rightText = Right $ (baseString, 3)
'rightText = "Barra"

Use Mid o Mid $ para obtener caracteres específicos dentro de una cadena

Const baseString As String = "Foo Bar"

'Obtener la cadena que comienza en el carácter 2 y termina en el carácter 6


Dim midText As String
midText = Mid $ (baseString, 2, 5)
'midText = "oo Ba"

Utilice Recortar para obtener una copia de la cadena sin espacios iniciales o finales

https://riptutorial.com/ 215

Página 231

'Recorte los espacios iniciales y finales en una cadena


Const paddedText As String = "Foo Bar"
Dim trimmedText As String
trimmedText = Recortar $ (paddedText)
'trimmedText = "Foo Bar"

Leer subcadenas en línea: https://riptutorial.com/vba/topic/3481/substrings

https://translate.googleusercontent.com/translate_f 198/223
6/1/2021 Intitulado

https://riptutorial.com/ 216

Página 232

Capítulo 42: Formularios de usuario


Ejemplos

Mejores prácticas

Un UserForm es un módulo de clase con un diseñador y una instancia predeterminada. El diseñador puede ser
se accede presionando Shift + F7 mientras se visualiza el código subyacente , y el código subyacente se puede
se accede presionando F7 mientras se ve el diseñador .

Trabaje con una nueva instancia cada vez.

Al ser un módulo de clase , un formulario es, por tanto, un modelo para un objeto . Porque una forma puede contener un estado
y datos, es una mejor práctica trabajar con una nueva instancia de la clase, en lugar de con el
predeterminado / global:

Con el nuevo UserForm1


.Mostrar vbModal
Si no, se cancela entonces
'...

https://translate.googleusercontent.com/translate_f 199/223
6/1/2021 Intitulado
Terminara si
Terminar con

En vez de:

UserForm1.Show vbModal
Si no es UserForm1.IsCancelled, entonces
'...
Terminara si

Trabajar con la instancia predeterminada puede generar errores sutiles cuando el formulario se cierra con la "X" roja
y / o cuando se usa Unload Me en el código subyacente.

Implemente la lógica en otro lugar.

Un formulario no debe preocuparse más que por la presentación : un botón Controlador de clic que se conecta a
una base de datos y ejecuta una consulta parametrizada basada en la entrada del usuario, está haciendo demasiadas cosas .

En su lugar, implemente la lógica aplicativa en el código que es responsable de mostrar el formulario, o


aún mejor, en módulos y procedimientos dedicados.

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, es
nada de su preocupación.

https://riptutorial.com/ 217

Página 233

La persona que llama no debe preocuparse por los controles.

Cree un modelo bien definido para que el formulario funcione, ya sea en su propio módulo de clase dedicado o
encapsulado dentro del código subyacente del formulario: exponga el modelo con Property Get
procedimientos, y haga que el código del cliente trabaje con estos: esto hace que el formulario sea una abstracción sobre
controles y sus detalles esenciales, exponiendo solo los datos relevantes al código del cliente.

Esto significa código que se ve así:

Con el nuevo UserForm1


.Mostrar vbModal
Si no, se cancela entonces
MsgBox .Message, vbInformation
Terminara si
Terminar con

En lugar de esto:

Con el nuevo UserForm1


.Mostrar vbModal
Si no, se cancela entonces
MsgBox .txtMessage.Text, vbInformation
Terminara si
Terminar con

Maneja el evento QueryClose.

Los formularios suelen tener un botón Cerrar , y los mensajes / diálogos tienen botones Aceptar y Cancelar ; el usuario puede
cierre el formulario usando el cuadro de control del formulario (el botón rojo "X"), que destruye la instancia del formulario
por defecto (otra buena razón para trabajar con una nueva instancia cada vez ).

Con el nuevo UserForm1


.Mostrar vbModal

https://translate.googleusercontent.com/translate_f 200/223
6/1/2021 Intitulado
If Not .IsCancelled Then 'si QueryClose no se maneja, esto puede generar un error de tiempo de ejecución.
'...
Terminar con
Terminar con

La forma más sencilla de manejar el evento QueryClose es establecer el parámetro Cancel en True y luego en
ocultar el formulario en lugar de cerrarlo :

Private Sub UserForm_QueryClose (Cancelar como entero, CloseMode como entero)


Cancelar = Verdadero
Me.Hide
End Sub

De esa manera, el botón "X" nunca destruirá la instancia y la persona que llama puede acceder de manera segura a todos los
miembros públicos.

https://riptutorial.com/ 218

Página 234

Escóndete, no cierres.

El código que crea un objeto debería ser responsable de destruirlo: no es el formulario


responsabilidad de descargar y darse de baja.

Evite usar Unload Me en el código subyacente de un formulario. Call Me.Hide en su lugar, para que el código de llamada pueda
todavía usa el objeto que creó cuando se cierra el formulario.

Nombra cosas.

Utilice la ventana de herramientas de propiedades ( F4 ) para nombrar cuidadosamente cada control en un formulario. El nombre de un
control se usa en el código subyacente, por lo que a menos que esté usando una herramienta de refactorización que pueda manejar esto,
cambiar el nombre de un control romperá el código , por lo que es mucho más fácil hacer las cosas bien en primer lugar,
que tratar de descifrar exactamente cuál de los 20 cuadros de texto representa TextBox12 .

Tradicionalmente, los controles de UserForm se nombran con prefijos de estilo húngaro:

• lblUserName para un control de etiqueta que indica un nombre de usuario.


• txtUserName para un control TextBox donde el usuario puede ingresar un nombre de usuario.
• cboUserName para un control ComboBox donde el usuario puede ingresar o elegir un nombre de usuario.
• lstUserName para un control ListBox donde el usuario puede elegir un nombre de usuario.
• btnOk o cmdOk para un control de botón con la etiqueta "Ok".

El problema es que cuando, por ejemplo, la interfaz de usuario se rediseña y un ComboBox cambia a un ListBox , el
El nombre debe cambiar para reflejar el nuevo tipo de control: es mejor nombrar los controles para lo que
representar, en lugar de su tipo de control, para desacoplar el código de la interfaz de usuario tanto como
posible.

• UserNameLabel parauna etiqueta de solo lectura que indica un nombre de usuario.


• UserNameInput paraun control donde el usuario puede ingresar o elegir un nombre de usuario.
• OkButton para un botón de comando con la etiqueta "Ok".

Cualquiera que sea el estilo elegido, cualquier cosa es mejor que dejar todos los controles con sus nombres predeterminados.
La coherencia en el estilo de los nombres también es ideal.

Manejo de QueryClose

El evento QueryClose se genera cada vez que un formulario está a punto de cerrarse, ya sea a través de la acción del usuario
o programáticamente. El parámetro CloseMode contiene un valor de enumeración VbQueryClose que indica
cómo se cerró el formulario:
https://translate.googleusercontent.com/translate_f 201/223
6/1/2021 Intitulado

Constante Descripción Valor

vbFormControlMenu El formulario se cierra en respuesta a la acción del usuario 0

vbFormCode El formulario se cierra en respuesta a una declaración de descarga 1

vbAppWindows La sesión de Windows está finalizando 2

https://riptutorial.com/ 219

Página 235

Constante Descripción Valor

vbAppTaskManager El Administrador de tareas de Windows está cerrando la aplicación host 3

vbFormMDIForm No es compatible con VBA 4

Para una mejor legibilidad, es mejor usar estas constantes en lugar de usar su valor directamente.

Un formulario de usuario cancelable


Dado un formulario con un botón Cancelar

El código subyacente del formulario podría verse así:

Opción explícita
TView de tipo privado
IsCancelled como booleano
SomeOtherSetting como booleano
'otras propiedades omitidas por brevedad
Tipo final
Privado esto como TView

Propiedad pública Obtener IsCancelled () como booleano


IsCancelled = this.IsCancelled
Propiedad final

Propiedad pública Obtener SomeOtherSetting () como booleano


SomeOtherSetting = this.SomeOtherSetting
Propiedad final

'... más propiedades ...

Sub privado SomeOtherSettingInput_Change ()


this.SomeOtherSetting = CBool (SomeOtherSettingInput.Value)
End Sub

Sub privado OkButton_Click ()


Me.Hide
End Sub

https://translate.googleusercontent.com/translate_f 202/223
6/1/2021 Intitulado
https://riptutorial.com/ 220

Página 236

Sub privado CancelButton_Click ()


this.IsCancelled = True
Me.Hide
End Sub

Private Sub UserForm_QueryClose (Cancelar como entero, CloseMode como entero)


Si CloseMode = VbQueryClose.vbFormControlMenu, entonces
Cancelar = Verdadero
this.IsCancelled = True
Me.Hide
Terminara si
End Sub

El código de llamada podría mostrar el formulario y saber si se canceló:

Sub público DoSomething ()


Con el nuevo UserForm1
.Mostrar vbModal
Si .IsCancelled, salga de Sub
Si .SomeOtherSetting Entonces
'la configuración está habilitada
Más
'la configuración está deshabilitada
Terminara si
Terminar con
End Sub

La propiedad IsCancelled devuelve True cuando se hace clic en el botón Cancelar o cuando el usuario cierra
el formulario usando la caja de control .

Leer formularios de usuario en línea: https://riptutorial.com/vba/topic/5351/user-forms

https://riptutorial.com/ 221

Página 237

Capítulo 43: Palabra clave de opción de VBA

https://translate.googleusercontent.com/translate_f 203/223
6/1/2021 Intitulado

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

Requerir declaración de variable en el módulo en el que está especificado (idealmente todos


Explícito ellos); con esta opción especificada, usando un no declarado (/ mal escrito)
variable se convierte en un error de compilación.

Hace que las comparaciones de cadenas del módulo no distingan entre mayúsculas y minúsculas, según
Comparar texto
configuración regional del sistema, priorizando la equivalencia alfabética (por ejemplo, "a" = "A").

Modo de comparación de cadenas predeterminado. Hace la cadena del módulo


Comparar binario las comparaciones distinguen entre mayúsculas y minúsculas, comparando cadenas utilizando el binario
representación / valor numérico de cada carácter (por ejemplo, ASCII).

(Solo MS-Access) Hace que las comparaciones de cadenas del módulo funcionen
Comparar base de datos
como lo harían en una declaración SQL.

Evita que se acceda al miembro público del módulo desde


fuera del proyecto en el que reside el módulo, ocultando efectivamente
Módulo privado
procedimientos de la aplicación de host (es decir, no disponible para utilizar como
macros o funciones definidas por el usuario).

Configuración predeterminada. Establece el límite inferior de la matriz implícita en 0 en un módulo.


Opción Base 0 Cuando se declara una matriz sin un valor límite inferior explícito, 0
se utilizará.

Establece el límite inferior de la matriz implícita en 1 en un módulo. Cuando una matriz es


Opción Base 1
declarada sin un valor límite inferior explícita, 1 se utilizará.

Observaciones
Es mucho más fácil controlar los límites de las matrices declarando los límites explícitamente en lugar de
que dejar que el compilador recurra a una declaración {0 | 1} de Option Base . Esto se puede hacer así:

https://riptutorial.com/ 222

Página 238

Dim myStringsA (0 To 5) As String '// Esto tiene 6 elementos (0 - 5)


Dim myStringsB (1 To 5) As String '// Esto tiene 5 elementos (1-5)
Dim myStringsC (6 To 9) As String '// Esto tiene 3 elementos (6 - 9)

Ejemplos

Opción explícita

Se considera una buena práctica usar siempre Option Explicit en VBA, ya que obliga al desarrollador a
declare todas sus variables antes de su uso. Esto también tiene otros beneficios, como la capitalización automática de
nombres de variables declaradas e IntelliSense.

https://translate.googleusercontent.com/translate_f 204/223
6/1/2021 Intitulado
Opción explícita

Sub OptionExplicit ()
Atenuar como entero
a=5
b = 10 '// Provoca un error de compilación ya que' b 'no está declarado
End Sub

Configuración Requerir declaración de variable dentro de las herramientas de VBE ► Opciones ► Editor
página de propiedades colocará la instrucción Option Explicit en la parte superior de cada nueva creación
hoja de código.

Esto evitará errores de codificación tontos, como errores ortográficos, además de influir en el uso de los
tipo de variable en la declaración de variable. (Algunos ejemplos más se dan enSIEMPRE use la opción "
Explícito " .)

Opción Comparar {Binario | Texto | Base de datos}

Opción Comparar binario

https://riptutorial.com/ 223

Página 239

La comparación binaria hace que todas las verificaciones de la igualdad de cadenas dentro de un módulo / clase sean sensibles a mayúsculas y minúsculas .
Técnicamente, con esta opción, las comparaciones de cadenas se realizan utilizando el orden de clasificación del binario
representaciones de cada personaje.

A <B <E <Z <a <b <e <z

Si no se especifica ninguna opción de comparación en un módulo, se utiliza Binary de forma predeterminada.

Opción Comparar binario

Sub CompareBinary ()

Dim foo como cadena


Barra de atenuación como cadena

'// Distingue mayúsculas y minúsculas


foo = "abc"
bar = "ABC"

Debug.Print (foo = bar) '// Imprime "False"

'// Todavía diferencia los caracteres acentuados


foo = "ábc"
bar = "abc"

Debug.Print (foo = bar) '// Imprime "False"

https://translate.googleusercontent.com/translate_f 205/223
6/1/2021 Intitulado

'// "b" (Chr 98) es mayor que "a" (Chr 97)


foo = "a"
barra = "b"

Debug.Print (bar> foo) '// Imprime "True"

'// "b" (Chr 98) NO es mayor que "á" (Chr 225)


foo = "á"
barra = "b"

Debug.Print (bar> foo) '// Imprime "False"

End Sub

Opción Comparar texto


Option Compare Text hace que todas las comparaciones de cadenas dentro de un módulo / clase utilicen mayúsculas y minúsculas
comparación.

(A | a) <(B | b) <(Z | z)

Opción Comparar texto

Sub CompareText ()

Dim foo como cadena


Barra de atenuación como cadena

'// Insensibilidad a mayúsculas y minúsculas

https://riptutorial.com/ 224

Página 240

foo = "abc"
bar = "ABC"

Debug.Print (foo = bar) '// Imprime "True"

'// Todavía diferencia los caracteres acentuados


foo = "ábc"
bar = "abc"

Debug.Print (foo = bar) '// Imprime "False"

'// "b" todavía viene después de "a" o "á"


foo = "á"
barra = "b"

Debug.Print (bar> foo) '// Imprime "True"

End Sub

Opción Comparar base de datos


Option Compare Database solo está disponible en MS Access. Establece el módulo / clase para usar el
la configuración actual de la base de datos para determinar si usar el modo Texto o Binario.

Nota: Se desaconseja el uso de esta configuración a menos que el módulo se utilice para escribir acceso personalizado
UDF (funciones definidas por el usuario) que deben tratar las comparaciones de texto de la misma manera que SQL
consultas 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 en el módulo
nivel y es válido solo para el módulo actual.

De forma predeterminada (y por lo tanto si no se especifica ninguna base de opción), la base es 0. Lo que significa que la primera
https://translate.googleusercontent.com/translate_f 206/223
6/1/2021 Intitulado

elemento de cualquier matriz declarada en el módulo tiene un índice de 0.

Si se especifica Option Base 1 , el primer elemento de la matriz tiene el índice 1

Ejemplo en Base 0:

Opción Base 0

Sub BaseZero ()

Atenuar myStrings como variante

'Cree una matriz a partir de la variante, con 3 elementos de frutas


myStrings = Array ("Manzana", "Naranja", "Melocotón")

Debug.Print LBound (myStrings) 'Esto imprime "0"


Debug.Print UBound (myStrings) 'Esta impresión es "2", porque tenemos 3 elementos que comienzan en 0
-> 0,1,2

https://riptutorial.com/ 225

Página 241

Para i = 0 a UBound (myStrings)

Debug.Print myStrings (i) 'Esto imprimirá "Apple", luego "Orange", luego "Peach"

Siguiente yo

End Sub

Mismo ejemplo con Base 1


Opción Base 1

Sub BaseOne ()

Atenuar myStrings como variante

'Cree una matriz a partir de la variante, con 3 elementos de frutas


myStrings = Array ("Manzana", "Naranja", "Melocotón")

Debug.Print LBound (myStrings) 'Esto imprime "1"


Debug.Print UBound (myStrings) 'Esta impresión es "3", porque tenemos 3 elementos que comienzan en 1
-> 1,2,3

Para i = 0 a UBound (myStrings)

Debug.Print myStrings (i) 'Esto activa un error 9 "Subíndice fuera de rango"

Siguiente yo

End Sub

El segundo ejemplo generó una Subíndice fuera de rango (Error 9) en la primera etapa del ciclo porque
se hizo un intento de acceder al índice 0 de la matriz, y este índice no existe como el
el módulo se declara con Base 1

El código correcto con Base 1 es:

Para i = 1 a UBound (myStrings)

Debug.Print myStrings (i) 'Esto imprimirá "Apple", luego "Orange", luego "Peach"

Siguiente yo

Cabe señalar que el La función de división siempre crea una matriz con un índice de elemento de base cero
https://translate.googleusercontent.com/translate_f 207/223
6/1/2021 Intitulado
independientemente de cualquier configuración de Option Base . Se pueden encontrar ejemplos sobre cómo usar la función Split
aquí

Función dividida
Devuelve una matriz unidimensional de base cero que contiene un número específico de subcadenas.

En Excel, las propiedades Range.Value y Range.Formula para un rango multicelular siempre devuelven un 1-
matriz de variantes 2D basada.

https://riptutorial.com/ 226

Página 242

Del mismo modo, en ADO, el método Recordset.GetRows siempre devuelve una matriz 2D basada en 1.

Una 'mejor práctica' recomendada es utilizar siempre el LBound yFunciones UBound para determinar
las extensiones de una matriz.

'para matriz unidimensional


Debug.Print LBound (arr) & ":" & UBound (arr)
Dim i tan largo
Para i = LBound (arr) To UBound (arr)
Debug.Print arr (i)
Siguiente yo

'para matriz de dos dimensiones


Debug.Print LBound (arr, 1) & ":" & UBound (arr, 1)
Debug.Print LBound (arr, 2) & ":" & UBound (arr, 2)
Dim i tan largo, j tan largo
Para i = LBound (arr, 1) To UBound (arr, 1)
Para j = LBound (arr, 2) a UBound (arr, 2)
Debug.Print arr (i, j)
Siguiente j
Siguiente yo

La Option Base 1 debe estar en la parte superior de cada módulo de código donde se crea o se vuelve a
dimensionado si las matrices se van a crear de forma coherente con un límite inferior de 1.

Lea la palabra clave de la opción VBA en línea: https://riptutorial.com/vba/topic/3992/vba-option-keyword

https://translate.googleusercontent.com/translate_f 208/223
6/1/2021 Intitulado

https://riptutorial.com/ 227

Página 243

Capítulo 44: Errores en tiempo de ejecución de VBA


Introducción
El código que se compila aún puede generar errores en tiempo de ejecución. Este tema enumera los más comunes,
sus causas y cómo evitarlas.

Ejemplos

Error en tiempo de ejecución '3': retorno sin GoSub

Código incorrecto

Sub DoSomething ()
GoSub DoThis
Hacer esto:
Debug.Print "¡Hola!"
Regreso
End Sub

¿Por qué no funciona esto?

La ejecución ingresa al procedimiento DoSomething , salta a la etiqueta DoThis , imprime "¡Hola!" a la depuración
salida, vuelve a la instrucción inmediatamente después de la llamada a GoSub , imprime "¡Hola!" otra vez, y luego
encuentra una declaración de retorno , pero no hay ningún lugar al que regresar ahora, porque no llegamos aquí
con una declaración GoSub .

Código correcto

Sub DoSomething ()
GoSub DoThis
Salir de Sub
Hacer esto:
Debug.Print "¡Hola!"
Regreso
End Sub

¿Por qué funciona esto?

Al introducir una instrucción Exit Sub antes de la etiqueta de línea DoThis , hemos separado el DoThis
subrutina del resto del cuerpo del procedimiento: la única forma de ejecutar la subrutina DoThis es
a través del salto GoSub .

Otras notas

https://riptutorial.com/ 228

Página 244

GoSub / Return está


obsoleto y debe evitarse en favor de las llamadas a procedimientos reales. Un procedimiento
no debe contener subrutinas que no sean controladores de errores.

https://translate.googleusercontent.com/translate_f 209/223
6/1/2021 Intitulado
Esto es muy similar a Error en tiempo de ejecución '20': reanudar sin error; en ambas situaciones, la solución es
para 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 ).

Error en tiempo de ejecución '6': desbordamiento

código incorrecto

Sub DoSomething ()
Atenuar fila como entero
Para fila = 1 a 100000
'hacer cosas
próximo
End Sub

¿Por qué no funciona esto?

El tipo de datos Integer es un entero de 16 bits con signo con un valor máximo de 32,767; asignándolo a
cualquier cosa más grande que eso desbordará el tipo y generará este error.

Código correcto

Sub DoSomething ()
Fila tenue tan larga
Para fila = 1 a 100000
'hacer cosas
próximo
End Sub

¿Por qué funciona esto?

Al usar un entero largo (32 bits) en su lugar, ahora podemos hacer un bucle que itera más de 32,767
veces sin desbordar el tipo de variable de contador.

Otras notas
Ver Tipos de datos y límites para obtener más información.

Error en tiempo de ejecución '9': subíndice fuera de rango

código incorrecto

Sub DoSomething ()
Dim foo (1 a 10)

https://riptutorial.com/ 229

Página 245

Dim i tan largo


Para i = 1 a 100
foo (i) = i
próximo
End Sub

¿Por qué no funciona esto?

foo esuna matriz que contiene 10 elementos. Cuando el contador del ciclo i alcanza un valor de 11, foo (i) está fuera
de rango . Este error ocurre siempre que se accede a una matriz o colección con un índice que no
existen en esa matriz o colección.

https://translate.googleusercontent.com/translate_f 210/223
6/1/2021 Intitulado

Código correcto
Sub DoSomething ()
Dim foo (1 a 10)
Dim i tan largo
Para i = LBound (foo) To UBound (foo)
foo (i) = i
próximo
End Sub

¿Por qué funciona esto?

Utilice las funciones LBound y UBound para determinar los límites superior e inferior de una matriz,
respectivamente.

Otras notas
Cuando el índice es una cadena, por ejemplo, ThisWorkbook.Worksheets ("No existo") , este error significa que
El nombre proporcionado no existe en la colección consultada.

Sin embargo, el error real es específico de la implementación; La recopilación generará un error de tiempo de ejecución 5 "No válido
llamada a procedimiento o argumento "en su lugar:

Sub RaisesRunTimeError5 ()
Dim foo como nueva colección
foo.Añadir "foo", "foo"
Debug.Print foo ("barra")
End Sub

Error en tiempo de ejecución '13': no coinciden los tipos

código incorrecto

Sub público DoSomething ()


Hacer algo más "42?"
End Sub

https://riptutorial.com/ 230

Página 246

Sub privado DoSomethingElse (foo As Date)


'Debug.Print MonthName (Mes (foo))
End Sub

¿Por qué no funciona esto?

VBA está intentando realmente convertir el "42?" argumento en un valor de fecha . Cuando falla, la llamada a
DoSomethingElse no
se puede ejecutar, porque VBA no sabe qué fecha pasar, por lo que genera
error 13 en tiempo de ejecución no coincide , porque el tipo de argumento no coincide con el esperado
type (y tampoco se puede convertir implícitamente).

Código correcto
Sub público DoSomething ()
Hacer algo más ahora
End Sub

Sub privado DoSomethingElse (foo As Date)


'Debug.Print MonthName (Mes (foo))
End Sub

https://translate.googleusercontent.com/translate_f 211/223
6/1/2021 Intitulado

¿Por qué funciona esto?

Al pasar un argumento de fecha a un procedimiento que espera un parámetro de fecha , la llamada puede tener éxito.

Error en tiempo de ejecución '91': variable de objeto o con variable de bloque no establecida

código incorrecto

Sub DoSomething ()
Colección Dim foo As
Con foo
.Añadir "ABC"
.Añadir "XYZ"
Terminar con
End Sub

¿Por qué no funciona esto?

Las variables de objeto contienen una referencia y las referencias deben establecerse mediante la palabra clave Set . Este error
ocurre siempre que se realiza una llamada de miembro a un objeto cuya referencia es Nothing . En este caso foo
es una referencia de colección , pero no está inicializada, por lo que la referencia contiene Nothing , y no podemos
llamar .Add en nada .

Código correcto

https://riptutorial.com/ 231

Página 247

Sub DoSomething ()
Colección Dim foo As
Set foo = Nueva colección
Con foo
.Añadir "ABC"
.Añadir "XYZ"
Terminar con
End Sub

¿Por qué funciona esto?

Al asignar a la variable de objeto una referencia válida mediante la palabra clave Set , las llamadas .Add se realizan correctamente.

Otras notas
A menudo, una función o propiedad puede devolver una referencia de objeto; un ejemplo común es Excel
Método Range.Find , que devuelve un objeto Range :

Resultado tenue Fila tan largo


resultRow = SomeSheet.Cells.Find ("Algo"). Fila

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 del miembro .Row encadenada falla.

Antes de llamar a los miembros del objeto, verifique que la referencia esté configurada con Si no, xxxx no es nada
condición:

Resultado atenuado como rango


Establecer resultado = SomeSheet.Cells.Find ("Algo")

Resultado tenue Fila tan largo

https://translate.googleusercontent.com/translate_f 212/223
6/1/2021 Intitulado
Si el resultado no es nada, entonces resultRow = result.Row

Error en tiempo de ejecución '20': reanudar sin error

código incorrecto

Sub DoSomething ()
En caso de error, vaya a CleanFail
Hacer algo más

CleanFail:
Debug.Print Err.Number
Reanudar Siguiente
End Sub

¿Por qué no funciona esto?

Si el procedimiento DoSomethingElse genera un error, la ejecución salta a la etiqueta de línea CleanFail , imprime
el número de error, y la instrucción Reanudar siguiente salta a la instrucción que inmediatamente

https://riptutorial.com/ 232

Página 248

sigue la línea donde ocurrió el error, que en este caso es la instrucción Debug.Print : el error-
la subrutina de manejo se ejecuta sin un contexto de error, y cuando la instrucción Resume Next es
alcanzado, se genera el error 20 en tiempo de ejecución porque no hay ningún lugar al que reanudar.

Código correcto

Sub DoSomething ()
En caso de error, vaya a CleanFail
Hacer algo más

Salir de Sub
CleanFail:
Debug.Print Err.Number
Reanudar Siguiente
End Sub

¿Por qué funciona esto?

Al introducir una instrucción Exit Sub antes de la etiqueta de línea CleanFail , hemos segregado
Subrutina de
manejo de errores CleanFail del resto del cuerpo del procedimiento: la única forma de ejecutar
la subrutina de manejo de errores es mediante un salto en caso de error ; por lo tanto, ninguna ruta de ejecución llega al
Reanudar la instrucción fuera de un contexto de error, lo que evita el error 20 en tiempo de ejecución.

Otras notas
Esto es muy similar a Error en tiempo de ejecución '3': retorno sin GoSub ; en ambas situaciones, la solución es
Asegúrese de que la ruta de ejecución normal no pueda entrar en 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 ).

Lea los errores de tiempo de ejecución de VBA en línea: https://riptutorial.com/vba/topic/8917/vba-run-time-errors

https://translate.googleusercontent.com/translate_f 213/223
6/1/2021 Intitulado

https://riptutorial.com/ 233

Página 249

Capítulo 45: Trabajar con ADO


Observaciones
Los ejemplos que se muestran en este tema utilizan el enlace anticipado para mayor claridad y requieren una referencia al
Biblioteca de Microsoft ActiveX Data Object xx. Se pueden convertir en enlace tardío reemplazando el
referencias fuertemente tipadas con Object y reemplazando la creación de objetos usando New con CreateObject
donde corresponda.

Ejemplos

Hacer 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 conexión ADO . Esto es
Normalmente se hace usando una cadena de conexión para especificar los parámetros de la fuente de datos, aunque también es
es posible abrir una conexión DSN pasando el DSN, el ID de usuario y la contraseña al .Open
método.

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
El proveedor de ODBC se puede conectar con la cadena de conexión adecuada. Aunque específico
Las cadenas de conexión 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.

Const SomeDSN As String = "DSN = SomeDSN; Uid = UserName; Pwd = MyPassword;"

Subejemplo público ()
Dim base de datos como ADODB.Connection
Establecer base de datos = OpenDatabaseConnection (SomeDSN)
Si la base de datos no es nada, entonces
'... Hacer trabajo.
base de datos.Cerrar 'Asegúrese de cerrar todas las conexiones a la base de datos.
Terminara si
End Sub

Función pública OpenDatabaseConnection (ConnString como cadena) como ADODB.Connection


En caso de error, GoTo Handler
Dim base de datos como ADODB.Connection
Establecer base de datos = New ADODB.Connection

Con base de datos


.ConnectionString = ConnString
.ConnectionTimeout = 10 'El valor se da en segundos.
.Abierto
Terminar con

OpenDatabaseConnection = base de datos

Función de salida
Manipulador:
Debug.Print "Error en la conexión a la base de datos. Verifique la cadena de conexión".

https://translate.googleusercontent.com/translate_f 214/223
6/1/2021 Intitulado

https://riptutorial.com/ 234

Página 250

Función final

Tenga en cuenta que la contraseña de la base de datos se incluye en la cadena de conexión en el ejemplo anterior solo para
en aras de la claridad. Las mejores prácticas dictarían no almacenar las contraseñas de la base de datos en el código. Esto puede
puede lograrse tomando la contraseña a través de la entrada del usuario o usando la autenticación de Windows.

Recuperar registros con una consulta

Las consultas se pueden realizar de dos formas, las cuales devuelven un objeto Recordset de ADO que es un
colección de filas devueltas. Tenga en cuenta que los dos ejemplos siguientes utilizan OpenDatabaseConnection
función de la Hacer una conexión a un ejemplo de fuente de datos por razones de brevedad.
Recuerde que la sintaxis del SQL que se pasa a la fuente de datos es específica del proveedor.

El primer método es pasar la instrucción SQL directamente al objeto Connection, y es el más fácil
método para ejecutar consultas simples:

Public Sub DisplayDistinctItems ()


En caso de error, GoTo Handler
Dim base de datos como ADODB.Connection
Establecer base de datos = OpenDatabaseConnection (SomeDSN)

Si la base de datos no es nada, entonces


Atenuar registros como ADODB.Recordset
Establecer registros = base de datos.Ejecutar ("SELECT DISTINCT Item FROM Table")
Recorra el Recordset devuelto.
Do While Not records.EOF 'EOF es falso cuando hay más registros.
Los campos individuales se indexan por nombre o por ordinal basado en 0.
'Tenga en cuenta que esto está utilizando el miembro .Fields predeterminado del Recordset.
Debug.Print registros ("Elemento")
'Pasar al siguiente registro.
records.MoveNext
Lazo
Terminara si
Limpiar Salida:
Si Not registra no es nada, entonces registra.
Si la base de datos no es nada y database.State = adStateOpen entonces
base de datos.Cerrar
Terminara si
Salir de Sub
Manipulador:
Debug.Print "Error" & Err.Number & ":" & Err.Description
Reanudar Limpiar Salir
End Sub

El segundo método consiste en crear un objeto de comando ADO para la consulta que desea ejecutar. Esta
requiere un poco más de código, pero es necesario para utilizar consultas parametrizadas:

Public Sub DisplayDistinctItems ()


En caso de error, GoTo Handler
Dim base de datos como ADODB.Connection
Establecer base de datos = OpenDatabaseConnection (SomeDSN)

Si la base de datos no es nada, entonces


Atenuar consulta como ADODB.Command
Establecer consulta = Nuevo ADODB.Command

https://riptutorial.com/ 235

Página 251

'Cree el comando para pasar a la fuente de datos.


Con consulta

https://translate.googleusercontent.com/translate_f 215/223
6/1/2021 Intitulado
.ActiveConnection = base de datos
.CommandText = "SELECT DISTINCT Item FROM Table"
.CommandType = adCmdText
Terminar con
Atenuar registros como ADODB.Recordset
'Ejecute el comando para recuperar el juego de registros.
Establecer registros = query.Execute ()

Hacer mientras no graba.


Debug.Print registros ("Elemento")
records.MoveNext
Lazo
Terminara si
Limpiar Salida:
Si Not registra no es nada, entonces registra.
Si la base de datos no es nada y database.State = adStateOpen entonces
base de datos.Cerrar
Terminara si
Salir de Sub
Manipulador:
Debug.Print "Error" & Err.Number & ":" & Err.Description
Reanudar Limpiar Salir
End Sub

Tenga en cuenta que los comandos enviados a la fuente de datos son vulnerables a la inyección de SQL , ya sea intencionalmente
o no intencional. En general, las consultas no deben crearse concatenando la entrada del usuario de ningún tipo.
En su lugar, deben parametrizarse (ver Creación de comandos parametrizados ).

Ejecutando funciones no escalares

Las conexiones ADO se pueden utilizar para realizar prácticamente cualquier función de base de datos que el proveedor
Soporta vía SQL. En este caso, no siempre es necesario utilizar el Recordset devuelto por el
Función de ejecución , aunque puede ser útil para obtener asignaciones de teclas después de instrucciones INSERT
con @@ Identity o comandos SQL similares. Tenga en cuenta que el ejemplo siguiente utiliza la
Función OpenDatabaseConnection de laHacer una conexión a un ejemplo de fuente de datos para el
propósito de la brevedad.

Public Sub UpdateTheFoos ()


En caso de error, GoTo Handler
Dim base de datos como ADODB.Connection
Establecer base de datos = OpenDatabaseConnection (SomeDSN)

Si la base de datos no es nada, entonces


Actualización tenue como ADODB.Command
Establecer actualización = Nuevo comando ADODB
'Cree el comando para pasar a la fuente de datos.
Con actualización
.ActiveConnection = base de datos
.CommandText = "UPDATE Table SET Foo = 42 WHERE Bar IS NULL"
.CommandType = adCmdText
.Ejecutar 'No necesitamos el retorno de la base de datos, así que ignórelo.
Terminar con
Terminara si
Limpiar Salida:

https://riptutorial.com/ 236

Página 252

Si la base de datos no es nada y database.State = adStateOpen entonces


base de datos.Cerrar
Terminara si
Salir de Sub
Manipulador:
Debug.Print "Error" & Err.Number & ":" & Err.Description
Reanudar Limpiar Salir
End Sub

Tenga en cuenta que los comandos enviados a la fuente de datos son vulnerables a la inyección de SQL , ya sea intencionalmente
o no intencional. En general, las sentencias SQL no deben crearse concatenando la entrada del usuario de
cualquier tipo. En su lugar, deben parametrizarse (verCreación de comandos parametrizados ).

https://translate.googleusercontent.com/translate_f 216/223
6/1/2021 Intitulado

Crear comandos parametrizados

Siempre que SQL ejecutado a través de una conexión ADO necesita contener la entrada del usuario, se considera
la mejor práctica para parametrizarlo con el fin de minimizar la posibilidad de inyección SQL. Este método es
también más legible que las concatenaciones largas y facilita un código más robusto y fácil de mantener
(es decir, utilizando una función que devuelve una matriz de parámetros ).

En la sintaxis estándar de ODBC, ¿se dan los parámetros ? "marcadores de posición" en el texto de la consulta y luego
los parámetros se añaden al comando en el mismo orden en que aparecen en la consulta.

Tenga en cuenta que el ejemplo siguiente utiliza la función OpenDatabaseConnection de laHaciendo un


conexión a una fuente de datos para mayor brevedad.

Public Sub UpdateTheFoos ()


En caso de error, GoTo Handler
Dim base de datos como ADODB.Connection
Establecer base de datos = OpenDatabaseConnection (SomeDSN)

Si la base de datos no es nada, entonces


Actualización tenue como ADODB.Command
Establecer actualización = Nuevo comando ADODB
'Cree el comando para pasar a la fuente de datos.
Con actualización
.ActiveConnection = base de datos
.CommandText = "UPDATE Table SET Foo =? WHERE Bar =?"
.CommandType = adCmdText

'Cree los parámetros.


Dim fooValue como ADODB.Parameter
Establecer fooValue = .CreateParameter ("FooValue", adNumeric, adParamInput)
fooValue.Value = 42

Condición tenue Como ADODB.Parameter


Establecer condición = .CreateParameter ("Condición", adBSTR, adParamInput)
condition.Value = "Bar"

'Agregue los parámetros al comando


.Parameters.Append fooValue
.Parámetros.Añadir condición
.Ejecutar
Terminar con
Terminara si
Limpiar Salida:

https://riptutorial.com/ 237

Página 253

Si la base de datos no es nada y database.State = adStateOpen entonces


base de datos.Cerrar
Terminara si
Salir de Sub
Manipulador:
Debug.Print "Error" & Err.Number & ":" & Err.Description
Reanudar Limpiar Salir
End Sub

Nota: El ejemplo anterior muestra una instrucción UPDATE parametrizada, pero cualquier SQL
La declaración puede tener parámetros.

Lea Trabajar con ADO en línea: https://riptutorial.com/vba/topic/3578/working-with-ado

https://translate.googleusercontent.com/translate_f 217/223
6/1/2021 Intitulado

https://riptutorial.com/ 238

Página 254

Capítulo 46: Trabajar con archivos y


Directorios sin utilizar FileSystemObject
Observaciones
El Scripting.FileSystemObject es mucho más robusto que los métodos heredados en este tema. Debería
ser preferido en casi todos los casos.

Ejemplos

Determinar si existen carpetas y archivos

Archivos:

Para determinar si existe un archivo, simplemente pase el nombre del archivo a la función Dir $ y pruebe para ver si
devuelve un resultado. Tenga en cuenta que Dir $ admite comodines, por lo que para probar un archivo específico , el
pathName debe probarse para asegurarse de que no los contenga. El siguiente ejemplo plantea una
error: si este no es el comportamiento deseado, la función se puede cambiar para simplemente devolver False .

Archivo de función pública Existe (nombre de ruta como cadena) como booleano
Si InStr (1, pathName, "*") O InStr (1, pathName, "?") Entonces
'Función de salida' Devuelve falso en comodines.
Err.Raise 52 'Error de subida en comodines.
Terminara si
FileExists = Dir $ (nombre de ruta) <> vbNullString
Función final

https://translate.googleusercontent.com/translate_f 218/223
6/1/2021 Intitulado

Carpetas (método Dir $):

La función Dir $ () también se puede utilizar para determinar si existe una carpeta especificando el paso
vbDirectory para
el parámetro de atributos opcionales . En este caso, el valor de pathName pasado debe terminar
con un separador de ruta ( \ ), ya que los nombres de archivo coincidentes provocarán falsos positivos. Tenga en cuenta que salvaje
Las tarjetas solo se permiten después del último separador de ruta, por lo que la función de ejemplo a continuación 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, descomente On Error Resume Next en la parte superior de la función. También recuerda que
Dir $ admiterutas de archivo relativas (es decir, .. \ Foo \ Bar ), por lo que solo se garantiza que los resultados sean válidos mientras
ya que el directorio de trabajo actual no se modifica.

Función pública FolderExists (ByVal pathName como cadena) como booleano


'Descomente la línea "En caso de error" si las rutas con comodines deben devolver False
'en lugar de generar un error.
'En caso de error, reanudar siguiente
Si pathName = vbNullString o Right $ (pathName, 1) <> "\" Entonces
Función de salida
Terminara si
FolderExists = Dir $ (pathName, vbDirectory) <> vbNullString

https://riptutorial.com/ 239

Página 255

Función final

Carpetas (método ChDir):

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 ejecuta VBA, por lo que si eso es una consideración, el Dir $
en su lugar, debería utilizarse el método. Tiene la ventaja de ser mucho menos indulgente con su
parámetro. Este método también admite rutas de archivo relativas, por lo que tiene la misma advertencia que Dir $
método.

Función pública FolderExists (ByVal pathName como cadena) como booleano


'Caché el directorio de trabajo actual
Dim almacenado en caché como cadena
caché = CurDir $

En caso de error, reanudar siguiente


ChDir pathName
FolderExists = Err.Number = 0
En caso de error, vaya a 0
'Vuelva al directorio de trabajo almacenado en caché.
ChDir almacenado en caché
Función final

Crear y eliminar carpetas de archivos

NOTA: Para mayor brevedad, los ejemplos siguientes utilizan la función FolderExists de Determining If
Ejemplo de Carpetas y archivos existentes en este tema.

La instrucció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 el nombre de la unidad o UNC (es decir, \ Foo ), la carpeta se crea en la unidad actual. Esto puede
o puede que no sea la misma unidad que el directorio de trabajo actual.

Public Sub MakeNewDirectory (ByVal pathName como cadena)


'MkDir fallará si el directorio ya existe.
Si FolderExists (nombre de ruta), salga de Sub
'Esto aún puede fallar debido a permisos, etc.

https://translate.googleusercontent.com/translate_f 219/223
6/1/2021 Intitulado
Nombre de ruta de MkDir
End Sub

La instrucción RmDir se puede utilizar para eliminar carpetas existentes. Acepta caminos en las mismas formas que
MkDir yusa la misma relación con el directorio de trabajo y la unidad actuales. Tenga en cuenta que el
La declaración es similar al comando de shell rd de Windows , por lo que arrojará un error 75 en tiempo de ejecución: "Ruta / Archivo
error de acceso "si el directorio de destino no está vacío.

Public Sub DeleteDirectory (ByVal pathName como cadena)


Si es Derecha $ (pathName, 1) <> "\" Entonces

https://riptutorial.com/ 240

Página 256

pathName = pathName & "\"


Terminara si
'Rmdir fallará si el directorio no existe.
Si no existe una carpeta (nombre de ruta), salga de Sub
'Rmdir fallará si el directorio contiene archivos.
Si Dir $ (pathName & "*") <> vbNullString, salga de Sub

'Rmdir fallará si el directorio contiene directorios.


Dim subDir como cadena
subDir = Dir $ (nombre de ruta & "*", directorio_vb)
Hacer
Si subDir <> "." Y subDir <> ".." Luego salga de Sub
subdirectorio = Dir $ (, vbDirectory)
Bucle mientras subDir <> vbNullString

'Esto aún puede fallar debido a permisos, etc.


Nombre de ruta de RmDir
End Sub

Lea Trabajar con archivos y directorios sin usar FileSystemObject en línea:


https://riptutorial.com/vba/topic/5706/working-with-files-and-directories-without-using-
objeto del sistema de archivos

https://translate.googleusercontent.com/translate_f 220/223
6/1/2021 Intitulado

https://riptutorial.com/ 241

Página 257

Créditos
S.
Capítulos Colaboradores
No

0m3r ,Andre Terra , Benno Grimm, Bookeater, Comintern,


comunidad ,Derpcode, Kaz, lfrandom, litelita, Furgoneta Maarten
1 Empezando con VBA
Stam ,Macro Man , Máté Juhász, Nick Dewitt,
PankajKushwaha, RubberDuck, Stefan Pinnow

2 Llamadas API paul bica

Comintern ,Dave , Hubisan, jamheadart, Josan Iracheta,


3 Matrices
Maarten van Stam, Mark.R, Taza de Mat, Miguel_Ryu ,Tazaf

Asignar cadenas con


4 ThunderFrame
caracteres repetidos

5 Atributos hymced ,Taza de Mat, RamenChef, RubberDuck

Automatización o uso de otros


6 Branislav Kollár
Bibliotecas de aplicaciones

7 Colecciones Comintern

Comintern ,Hosch250, Johnny C, litelita, Hombre Macro,


8 Comentarios
Nijin22 ,Shawn V. Wilson, ThunderFrame

9 Concatenar cadenas ThunderFrame

10 compilación condicional Macro hombre ,Taza de Mat, RubberDuck, Steve Rindsberg

Conversión de otros tipos a


11 ThunderFrame
instrumentos de cuerda

Copiar, devolver y
12 Mark.R
pasando matrices

CreateObject vs.
13 Branislav Kollár ,Dave , Tim
GetObject

Branislav Kollár ,Hombre macro, Taza de Mat, Neil Mussett ,


14 Creación de una clase personalizada
ThunderFrame

Comintern ,LiamH ,Taza de Mat, Sivaprasath Vadivel ,


15 Creación de un procedimiento
Tomas Zubiri

16 estructuras de datos Blackhawk

https://riptutorial.com/ 242

Página 258

Comintern ,Hombre libre , Neil Mussett, StackzOfZtuff,


17 Tipos de datos y límites
https://translate.googleusercontent.com/translate_f 221/223
6/1/2021 Intitulado
Stephen Leppik, ThunderFrame

18 Manipulación de fecha y hora Comintern ,Hombre Libre , Thomas G

Declarar y asignar
19 Comintern ,ThunderFrame
instrumentos de cuerda

Comintern ,papá, Dave, Franck Dernoncourt, Jeeped,


Kaz ,lfrandom , litelite, Hombre Macro, Mark.R, Taza de Mat ,
20 Declaración de variables
Neil Mussett ,RubberDuck, Shawn V. Wilson, SWa,
Thierry Dalon ,ThunderFrame, Tom, Víctor Moraes, Zaider

21 Manejo de errores Comintern ,Logan Reed, Taza de Mat

22 Eventos Taza de Mat

Benno Grimm ,Comintern , Kelly Tessena Keck, Leviatán,


23 Estructuras de control de flujo litelita ,Macro hombre ,Martín, Taza de Mat, Roland ,Siva ,
ThunderFrame

Cadena de uso frecuente


24 pashute
manipulación

25 interfaces Neil Mussett

Macro seguridad y firma


26 0m3r
de proyectos / módulos VBA

Midiendo la longitud de
27 Steve Rindsberg, ThunderFrame
instrumentos de cuerda

28 convenciones de nomenclatura Hombre Libre ,Kaz ,Taza de Mat, Víctor Moraes

29 caracteres no latinos Neil Mussett

30 VBA orientado a objetos IvenBach , taza de Mat

31 operadores Comintern ,Hombre macro

Pasando argumentos por Ref Branislav Kollár ,Comintern, Taza de Mat, R3uK ,
32
o ByVal RamenChef ,ZygD

33 Llamadas a procedimientos Macro hombre ,Taza de Mat, Neil Mussett, Sam Johnson

Leyendo archivos de 2GB + en


34 binario en VBA y archivo Patricio
Hashes

35 Recurrencia Taza de Mat, ThunderFrame

https://riptutorial.com/ 243

Página 259

Comintern ,Jeeped, Kyle, RamenChef, Tim, Lobo, Zev


36 Objeto de scripting.Dictionary
Perro de Pomerania

Comintern ,Dave , hombre macro, Mikegrann, RubberDuck,


37 Scripting.FileSystemObject
Siva ,Steve Rindsberg, ThunderFrame

Buscando dentro de cadenas


38 por la presencia de ThunderFrame
subcadenas

https://translate.googleusercontent.com/translate_f 222/223
6/1/2021 Intitulado
39 Clasificación Neil Mussett
Literales de cadena - Escapar,
40 caracteres no imprimibles Comintern ,ThunderFrame
y continuaciones de línea

41 subcadenas Taza de Mat, ThunderFrame

42 formularios de usuario Taza de Mat

Jeeped ,Maarten van Stam, Hombre Macro, Taza de Mat ,


43 Palabra clave de opción de VBA RamenChef ,RubberDuck, Stefan Pinnow, Thomas G,
ThunderFrame

44 Errores en tiempo de ejecución de VBA Branislav Kollár ,Hombre macro, Taza de Mat

45 Trabajar con ADO Comintern ,Lavandera, Tazaf

Trabajar con archivos y


46 Directorios sin usar Comintern ,Hombre Macro , SandPiper
FileSystemObject

https://riptutorial.com/ 244

https://translate.googleusercontent.com/translate_f 223/223

También podría gustarte