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:
- Per incoraggiarti a esplicitamente dichiarare le variabili Variant
As Variant
- 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.