Access
 sql >> Base de données >  >> RDS >> Access

Instructions DefType dans VBA :le côté obscur de la rétrocompatibilité

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 :

  1. Pour vous encourager à explicitement déclarer les variables Variant As Variant
  2. 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.

Références externes

Instructions Deftype (VBA)Rubrique de référence Office VBAMicrosoft Docso365devx Déclarations d'API Windows dans VBA pour 64 bitsComment convertir vos déclarations d'API en 64 bits. - Mythes communs démystifiés, facteurs clés expliqués !CodekabinettPhilipp Stiefel

Articles référencés

Respect de la rétrocompatibilité Une fonctionnalité qui était largement utilisée par un très petit pourcentage d'utilisateurs expérimentés a été maintenue au cours des cinq mises à niveau ultérieures (et plus encore). Maintenant, cela montre le respect de la rétrocompatibilité. Plus définiMike Wolfe Classe RegOp pour VBA 64 bitsMise à jour d'un module de classe de lecture et d'écriture de registre VBA classique pour la compatibilité 64 bits. Plus définiMike Wolfe