Bare fordi du kan gøre noget, betyder det ikke, at du skal.
Jeg tror dybt på helligheden af bagudkompatibilitet. Men det kommer med en mørk side. Nogle gange falder de gamle måder at gøre tingene på. Deres brug bliver så mystisk, at vi har en tendens til at glemme, at de overhovedet eksisterer.
Så det går med DefType-udsagn.
Hvad du ikke ved kan skade dig
For flere måneder siden skrev jeg en artikel om Romke Soldaats Registry Operations klassemodul.
Jeg offentliggjorde de ændringer, jeg lavede i Romkes API-deklarationer for at få koden til at køre under 64-bit VBA. Hvert API-kald blev pakket ind i #If VBA7
betingede kompileringstags og opdateret med PtrSafe
søgeord.
Der var kun ét problem.
Jeg glemte at inkludere en nøgleændring, som jeg havde lavet til en af deklarationerne på modulniveau i Romkes kode. Uden denne ændring ville Romkes modificerede kode ikke kompilere under 64-bit VBA. Kompileringsfejlen opstod på følgende linje:
Fejlmeddelelsen var "ByRef argument type mismatch " og den fremhævede variabel var hCurKey
.
Her er den stødende kodelinje fra Romkes originale klassemodul:
Private hCurKey
For at rette kompileringsfejlen kan ovenstående kodelinje ændres til denne:
Private hCurKey As Variant
Men vent, siger du, gør de to linjer kode ikke det samme?!?! Alle ved, at hvis du ikke erklærer en variabels type i VBA, er den implicit erklæret som en Variant. ... Eller er det?
Eksplicit er bedre end implicit
Så hvad sker der egentlig her?
Problemet er, at den første kodelinje ovenfor-Private hCurKey
– var ved at definere hCurKey-variablen som en Long
datatype.
Hvordan kunne dette være?
Det var på grund af denne mærkelige streg i toppen af Romkes klassemodul:
DefLng H-I, L, N
Hvad laver den linje? Det siger, at hver deklarerede variabel i det aktuelle modul uden en eksplicit erklæret type, hvis variabelnavn begynder med H
, I
, L
eller N
, vil blive behandlet af compileren som en Long
datatype.
Og så linjen Private hCurKey
gjorde implicit erklære en type for variablen hCurKey, men den implicitte erklæring var som en lang datatype i stedet for en variant.
Hvorfor variant Kompiler men lang Gør det ikke?
Med hensyn til hvorfor koden kompileres når hCurKey
er en variant, men fejler, når den er en lang, det er et spørgsmål om 32-bit til 64-bit konverteringsprocessen.
For at finde kilden til problemet skal vi undersøge den migrerede kode til RegCreateKeyEx API-erklæringen:
#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
Når vi kalder RegCreateKeyEx
fra koden sender vi hCurKey
variabel som det næstsidste argument i funktionen. Med andre ord bliver det videregivet som phkResult
argument. Bemærk, at i versionen før VBA7 (Access 2007 og tidligere), phkResult
er erklæret som en Long, men i VBA7-versionen er den erklæret som en LongPtr
.
Det er fordi phkResult
modtager et håndtag til den oprettede eller åbnede registreringsnøgle. Når du ser ordet "håndtag" forbundet med et API-kald, kan du roligt oversætte det i dit hoved til "hukommelsesadresse". Det er derfor, argumentet omdefineres som en LongPtr
i VBA7-koden:ved afvikling i et 32-bit miljø, en LongPtr
behandles som en 32-bit Long
heltal, men i et 64-bit miljø, en LongPtr
behandles som en 64-bit LongLong
heltal.
Erklærer hCurKey
da Variant er lidt af en genvej. Følgende tilpasning ville også fungere (og fungere hurtigere, selvom hastighedsstigningen sandsynligvis vil være umærkelig for brugeren, medmindre den kaldes mange gange inde i en løkke):
#If VBA7 Then
Private hCurKey As LongPtr
#Else
Private hCurKey As Long
#End If
Som jeg sagde, er ovenstående tilgang mere eksplicit til at formidle udviklerens hensigt, yder bedre og vil medføre flere kompileringsfejl end Private hCurKey As Variant
alternativ.
Men jeg er kendt for at være doven og Private hCurKey As Variant
er næsten lige så godt med meget mindre skrivning.
Brug din viden til gode
Husk nu, hvad jeg sagde i begyndelsen af denne artikel?
Bare fordi du kan gøre noget, betyder det ikke, at du skal.
Jeg skrev denne artikel af to grunde:
- For at opfordre dig til eksplicit erklære Variantvariabler
As Variant
- For at øge bevidstheden om et mystisk aspekt af VBA, der kan slå dig i stå, hvis du vedligeholder (eller kopierer) en andens kode
JEG HAR IKKE skriv denne artikel for at inspirere dig til at skrive DefType-udsagn i din egen kode. GØR DET IKKE!!! Husk, bare fordi du kan gøre noget, betyder det ikke, at du skal.