Access
 sql >> Database >  >> RDS >> Access

Dichiarazioni DefType in VBA:il lato oscuro della compatibilità con le versioni precedenti

Solo perché puoi fare qualcosa, non significa che dovresti.

Credo profondamente nella santità della compatibilità con le versioni precedenti. Ma ha un lato oscuro. A volte i vecchi modi di fare le cose cadono in disgrazia. Il loro uso diventa così arcano che abbiamo la tendenza a dimenticare che esistono.

Così va con le istruzioni DefType.

Quello che non sai può farti del male

Diversi mesi fa, ho scritto un articolo sul modulo di classe Registry Operations di Romke Soldaat.

Ho pubblicato le modifiche apportate alle dichiarazioni API di Romke per eseguire il codice in VBA a 64 bit. Ogni chiamata API è stata racchiusa in #If VBA7 tag di compilazione condizionali e aggiornati con il PtrSafe parola chiave.

Si è verificato un solo problema.

Ho dimenticato di includere una modifica chiave che avevo apportato a una delle dichiarazioni a livello di modulo nel codice di Romke. Senza questa modifica, il codice modificato di Romke non verrebbe compilato in VBA a 64 bit. L'errore di compilazione si è verificato nella riga seguente:

Il messaggio di errore era "Tipo di argomento ByRef non corrispondente " e la variabile evidenziata era hCurKey .

Ecco la riga di codice incriminata dal modulo di classe originale di Romke:

Private hCurKey

Per correggere l'errore di compilazione, la riga di codice sopra può essere modificata in questo:

Private hCurKey As Variant

Ma aspetta, dici, quelle due righe di codice non fanno la stessa cosa?!?! Tutti sanno che se non si dichiara il tipo di una variabile in VBA, viene implicitamente dichiarato come Variant. ...  O no?

L'esplicito è meglio che implicito

Allora, cosa sta succedendo davvero qui?

Il problema è che la prima riga di codice sopra – Private hCurKey –stava definendo la variabile hCurKey come Long tipo di dati.

Come può essere?

Era a causa di questa strana riga nella parte superiore del modulo di classe di Romke:

DefLng H-I, L, N

Che cosa sta facendo quella linea? Sta dicendo che ogni variabile dichiarata nel modulo corrente senza un tipo dichiarato esplicitamente il cui nome di variabile inizia con H , I , L o N , verrà trattato dal compilatore come un Long tipo di dati.

E così, la riga Private hCurKey fatto implicitamente dichiarare un tipo per la variabile hCurKey, ma la dichiarazione implicita era un tipo di dati Long anziché una Variant.

Perché Variant Compila ma Lungo No?

Sul motivo per cui il codice viene compilato quando hCurKey è una variante ma non riesce quando è un lungo, è una questione del processo di conversione da 32 bit a 64 bit.

Per trovare l'origine del problema, dobbiamo esaminare il codice migrato per la dichiarazione dell'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

Quando chiamiamo RegCreateKeyEx dal codice, stiamo passando il hCurKey variabile come penultimo argomento nella funzione. In altre parole, viene passato come phkResult discussione. Si noti che nella versione precedente a VBA7 (Access 2007 e precedenti), phkResult è dichiarato come Long, ma nella versione VBA7 è dichiarato come LongPtr .

Questo perché phkResult riceve un handle alla chiave di registro creata o aperta. Ogni volta che vedi la parola "handle" associata a una chiamata API, puoi tranquillamente tradurla nella tua testa in "indirizzo di memoria". Ecco perché l'argomento viene ridefinito come LongPtr nel codice VBA7:durante l'esecuzione in un ambiente a 32 bit, un LongPtr viene trattato come un Long a 32 bit intero, ma in un ambiente a 64 bit, un LongPtr viene trattato come un LongLong a 64 bit intero.

Dichiarando hCurKey come Variant è un po' una scorciatoia. Anche il seguente adattamento funzionerebbe (e funzionerebbe più velocemente, anche se è probabile che l'aumento di velocità sia impercettibile per l'utente a meno che non venga chiamato più volte all'interno di un ciclo):

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

Come ho detto, l'approccio di cui sopra è più esplicito nel trasmettere l'intento dello sviluppatore, ha prestazioni migliori e genererà più errori in fase di compilazione rispetto a Private hCurKey As Variant alternativa.

Ma sono noto per essere pigro e Private hCurKey As Variant è quasi altrettanto buono con molta meno digitazione.

Usa la tua conoscenza per sempre

Ora, ricordi cosa ho detto all'inizio di questo articolo?

Solo perché puoi fare qualcosa, non significa che dovresti.

Ho scritto questo articolo per due motivi:

  1. Per incoraggiarti a esplicitamente dichiarare le variabili Variant As Variant
  2. Per aumentare la consapevolezza su un aspetto arcano di VBA che potrebbe inciampare se stai mantenendo (o copiando e incollando) il codice di qualcun altro

NON HO scrivi questo articolo per ispirarti a scrivere istruzioni DefType nel tuo codice. NON FARLO!!! Ricorda, solo perché puoi fare qualcosa non significa che dovresti.

Riferimenti esterni

Istruzioni Deftype (VBA) Argomento di riferimento VBA di Office Microsoft Docso365devx Dichiarazioni API di Windows in VBA per 64 bitCome convertire le dichiarazioni API a 64 bit. - Miti comuni sfatati, fattori chiave spiegati!CodekabinettPhilipp Stiefel

Articoli referenziati

Rispetto per la compatibilità con le versioni precedenti Una funzionalità che è stata ampiamente utilizzata da una percentuale molto piccola di utenti esperti è stata mantenuta nel corso di cinque aggiornamenti successivi (e contando). Ora che sta mostrando riverenza alla compatibilità con le versioni precedenti. Non è più impostatoMike Wolfe Classe RegOp per VBA a 64 bit Aggiornamento di un classico modulo di lettura e scrittura del registro VBA per la compatibilità a 64 bit. Non è più impostatoMike Wolfe