Ce n'est pas parce que vous pouvez faire quelque chose que vous devriez le faire.
Je crois profondément au caractère sacré de la rétrocompatibilité. Mais cela vient avec un côté sombre. Parfois, les anciennes façons de faire tombent en disgrâce. Leur utilisation devient si obscure que nous avons même tendance à oublier leur existence.
Il en va de même avec les instructions DefType.
Ce que vous ne savez pas peut vous blesser
Il y a plusieurs mois, j'ai écrit un article sur le module de classe Registry Operations de Romke Soldaat.
J'ai publié les modifications que j'ai apportées aux déclarations d'API de Romke pour que le code s'exécute sous VBA 64 bits. Chaque appel d'API était enveloppé dans #If VBA7
balises de compilation conditionnelle et mis à jour avec le PtrSafe
mot-clé.
Il n'y avait qu'un seul problème.
J'ai oublié d'inclure une modification clé que j'avais apportée à l'une des déclarations au niveau du module dans le code de Romke. Sans ce changement, le code modifié de Romke ne serait pas compilé sous VBA 64 bits. L'erreur de compilation s'est produite sur la ligne suivante :
Le message d'erreur était "Non-concordance du type d'argument ByRef " et la variable en surbrillance était hCurKey
.
Voici la ligne de code incriminée du module de classe original de Romke :
Private hCurKey
Pour corriger l'erreur de compilation, la ligne de code ci-dessus peut être remplacée par ceci :
Private hCurKey As Variant
Mais attendez, dites-vous, ces deux lignes de code ne font-elles pas la même chose ?!?! Tout le monde sait que si vous ne déclarez pas le type d'une variable dans VBA, elle est implicitement déclarée en tant que Variant. ... Ou est-ce ?
Explicit est mieux qu'implicite
Alors que se passe-t-il vraiment ici ?
Le problème est que la première ligne de code ci-dessus–Private hCurKey
–définissait la variable hCurKey comme un Long
Type de données.
Comment est-ce possible ?
C'était à cause de cette ligne bizarre en haut du module de classe de Romke :
DefLng H-I, L, N
Que fait cette ligne ? Cela signifie que chaque variable déclarée dans le module actuel sans type explicitement déclaré dont le nom de variable commence par H
, I
, L
, ou N
, sera traité par le compilateur comme un Long
type de données.
Et donc, la ligne Private hCurKey
l'a fait implicitement déclarer un type pour la variable hCurKey, mais la déclaration implicite était un type de données Long au lieu d'un Variant.
Pourquoi Variant Compiler mais Long N'est-ce pas ?
Pourquoi le code se compile-t-il lorsque hCurKey
est une variante mais échoue lorsqu'il s'agit d'un long, c'est une question de processus de conversion de 32 bits à 64 bits.
Pour trouver la source du problème, nous devons examiner le code migré pour la déclaration de l'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
Lorsque nous appelons RegCreateKeyEx
à partir du code, nous passons le hCurKey
variable comme avant-dernier argument de la fonction. En d'autres termes, il est passé en tant que phkResult
argument. Notez que dans la version pré-VBA7 (Access 2007 et versions antérieures), phkResult
est déclaré en tant que Long, mais dans la version VBA7, il est déclaré en tant que LongPtr
.
C'est parce que le phkResult
reçoit un handle à la clé de registre créée ou ouverte. Chaque fois que vous voyez le mot "handle" associé à un appel d'API, vous pouvez le traduire en toute sécurité dans votre tête en "adresse mémoire". C'est pourquoi l'argument est redéfini comme un LongPtr
dans le code VBA7 :lors de l'exécution dans un environnement 32 bits, un LongPtr
est traité comme un Long
32 bits entier, mais dans un environnement 64 bits, un LongPtr
est traité comme un LongLong
64 bits entier.
Déclarer hCurKey
car Variant est un peu un raccourci. L'adaptation suivante fonctionnerait également (et fonctionnerait plus rapidement, bien que l'augmentation de la vitesse soit probablement imperceptible pour l'utilisateur à moins qu'elle ne soit appelée plusieurs fois à l'intérieur d'une boucle) :
#If VBA7 Then
Private hCurKey As LongPtr
#Else
Private hCurKey As Long
#End If
Comme je l'ai dit, l'approche ci-dessus est plus explicite dans la transmission de l'intention du développeur, fonctionne mieux et générera plus d'erreurs de compilation que le Private hCurKey As Variant
alternative.
Mais je suis connu pour être paresseux, et Private hCurKey As Variant
est presque aussi bon avec beaucoup moins de frappe.
Utilisez vos connaissances pour le bien
Maintenant, souvenez-vous de ce que j'ai dit au début de cet article ?
Ce n'est pas parce que vous pouvez faire quelque chose que vous devriez le faire.
J'ai écrit cet article pour deux raisons :
- Pour vous encourager à explicitement déclarer les variables Variant
As Variant
- Pour sensibiliser à un aspect obscur de VBA qui pourrait vous faire trébucher si vous maintenez (ou copiez-collez) le code de quelqu'un d'autre
JE N'AI PAS écrivez cet article pour vous inspirer à écrire des instructions DefType dans votre propre code. NE FAITES PAS CELA!!! N'oubliez pas que ce n'est pas parce que vous pouvez faire quelque chose que vous devez le faire.