sql >> Base de Datos >  >> RDS >> Access

Declaraciones DefType en VBA:el lado oscuro de la compatibilidad con versiones anteriores

El hecho de que puedas hacer algo no significa que debas hacerlo.

Creo profundamente en la santidad de la retrocompatibilidad. Pero viene con un lado oscuro. A veces, las viejas formas de hacer las cosas caen en desgracia. Su uso se vuelve tan arcano que tenemos una tendencia a olvidar que incluso existen.

Así sucede con las sentencias DefType.

Lo que no sabes puede hacerte daño

Hace varios meses, escribí un artículo sobre el módulo de clase de operaciones de registro de Romke Soldaat.

Publiqué los cambios que hice en las declaraciones de la API de Romke para que el código se ejecutara en VBA de 64 bits. Cada llamada a la API se envolvió en #If VBA7 etiquetas de compilación condicional y actualizadas con PtrSafe palabra clave.

Solo había un problema.

Olvidé incluir un cambio clave que hice en una de las declaraciones de nivel de módulo en el código de Romke. Sin este cambio, el código modificado de Romke no se compilaría bajo VBA de 64 bits. El error de compilación ocurrió en la siguiente línea:

El mensaje de error fue "No coincide el tipo de argumento ByRef " y la variable resaltada era hCurKey .

Aquí está la línea de código ofensiva del módulo de clase original de Romke:

Private hCurKey

Para corregir el error de compilación, la línea de código anterior se puede cambiar a esto:

Private hCurKey As Variant

Pero espera, dices, ¿¡¿esas dos líneas de código no están haciendo lo mismo?!?! Todo el mundo sabe que si no declara el tipo de una variable en VBA, se declara implícitamente como Variante. ...  ¿O lo es?

Explícito es mejor que implícito

Entonces, ¿qué está pasando realmente aquí?

El problema es que la primera línea de código anterior:Private hCurKey –estaba definiendo la variable hCurKey como Long tipo de datos.

¿Cómo podría ser esto?

Fue por esta extraña línea en la parte superior del módulo de clase de Romke:

DefLng H-I, L, N

¿Qué hace esa línea? Está diciendo que cada variable declarada en el módulo actual sin un tipo declarado explícitamente cuyo nombre de variable comience con H , I , L , o N , será tratado por el compilador como Long tipo de datos.

Y así, la línea Private hCurKey hizo implícitamente declarar un tipo para la variable hCurKey, pero la declaración implícita fue como un tipo de datos Long en lugar de Variant.

Por que Variante Compilar pero largo ¿No?

En cuanto a por qué el código se compila cuando hCurKey es una variante pero falla cuando es larga, eso es cuestión del proceso de conversión de 32 bits a 64 bits.

Para encontrar el origen del problema, debemos examinar el código migrado para la declaración de la API RegCreateKeyEx:

#If VBA7 Then
    Private Declare PtrSafe Function RegCreateKeyEx _
      Lib "advapi32.dll" Alias "RegCreateKeyExA" ( _
          ByVal hKey As LongPtr, ByVal lpSubKey As String, _
          ByVal Reserved As Long, ByVal lpClass As String, _
          ByVal dwOptions As Long, ByVal samDesired As Long, _
          lpSecurityAttributes As SECURITY_ATTRIBUTES, _
          phkResult As LongPtr, lpdwDisposition As Long) As Long
#Else
    Private Declare Function RegCreateKeyEx _
      Lib "advapi32.dll" Alias "RegCreateKeyExA" ( _
          ByVal hKey As Long, ByVal lpSubKey As String, _
          ByVal Reserved As Long, ByVal lpClass As String, _
          ByVal dwOptions As Long, ByVal samDesired As Long, _
          lpSecurityAttributes As SECURITY_ATTRIBUTES, _
          phkResult As Long, lpdwDisposition As Long) As Long
#End If

Cuando llamamos a RegCreateKeyEx del código, estamos pasando la hCurKey variable como penúltimo argumento en la función. En otras palabras, se pasa como phkResult argumento. Tenga en cuenta que en la versión anterior a VBA7 (Access 2007 y anteriores), phkResult se declara como Long, pero en la versión VBA7 se declara como LongPtr .

Eso es porque phkResult recibe un identificador a la clave de registro creada o abierta. Cada vez que vea la palabra "manejar" asociada con una llamada API, puede traducirla de manera segura en su cabeza a "dirección de memoria". Es por eso que el argumento se redefine como LongPtr en el código VBA7:cuando se ejecuta en un entorno de 32 bits, un LongPtr se trata como un Long de 32 bits entero, pero en un entorno de 64 bits, un LongPtr se trata como un LongLong de 64 bits entero.

Declarando hCurKey as Variant es un poco un atajo. La siguiente adaptación también funcionaría (y funcionaría más rápido, aunque es probable que el aumento de velocidad sea imperceptible para el usuario a menos que se llame muchas veces dentro de un ciclo):

#If VBA7 Then
    Private hCurKey As LongPtr
#Else
    Private hCurKey As Long
#End If

Como dije, el enfoque anterior es más explícito al transmitir la intención del desarrollador, funciona mejor y generará más errores en tiempo de compilación que Private hCurKey As Variant alternativa.

Pero soy conocido por ser perezoso y Private hCurKey As Variant es casi tan bueno con mucho menos tipeo.

Use Your Knowledge for Good

Ahora, ¿recuerdas lo que dije al principio de este artículo?

El hecho de que puedas hacer algo no significa que debas hacerlo.

Escribí este artículo por dos razones:

  1. Para alentarlo a explícitamente declarar variables Variant As Variant
  2. Para crear conciencia sobre un aspecto arcano de VBA que podría hacerle tropezar si está manteniendo (o copiando y pegando) el código de otra persona

Yo NO escriba este artículo para inspirarlo a escribir sentencias DefType en su propio código. ¡¡¡NO HAGAS ESO!!! Recuerda, el hecho de que puedas hacer algo no significa que debas hacerlo.

Referencias externas

Declaraciones de Deftype (VBA)Tema de referencia de Office VBAMicrosoft Docso365devx Declaraciones de API de Windows en VBA para 64 bitsCómo convertir sus declaraciones de API a 64 bits. - Mitos comunes desacreditados, factores clave explicados!CodekabinettPhilipp Stiefel

Artículos referenciados

Reverencia por la compatibilidad con versiones anteriores Una característica que fue muy utilizada por un porcentaje muy pequeño de usuarios avanzados se ha mantenido en el transcurso de cinco actualizaciones posteriores (y contando). Ahora que está mostrando reverencia a la compatibilidad con versiones anteriores. Ya no apareceMike Wolfe Clase RegOp para VBA de 64 bitsActualización de un módulo de clase de lectura y escritura de registros VBA clásico para compatibilidad con 64 bits. Ya no apareceMike Wolfe