Nur weil Sie etwas tun können, heißt das nicht, dass Sie es tun sollten.
Ich glaube fest an die Heiligkeit der Abwärtskompatibilität. Aber es kommt mit einer dunklen Seite. Manchmal geraten die alten Vorgehensweisen in Ungnade. Ihr Gebrauch wird so geheimnisvoll, dass wir dazu neigen zu vergessen, dass sie überhaupt existieren.
So verhält es sich mit DefType-Anweisungen.
Was Sie nicht wissen, kann Sie verletzen
Vor einigen Monaten habe ich einen Artikel über das Klassenmodul Registry Operations von Romke Soldaat geschrieben.
Ich habe die Änderungen veröffentlicht, die ich an Romkes API-Deklarationen vorgenommen habe, damit der Code unter 64-Bit-VBA ausgeführt werden kann. Jeder API-Aufruf wurde in #If VBA7
eingeschlossen bedingte Kompilierungs-Tags und aktualisiert mit dem PtrSafe
Schlüsselwort.
Es gab nur ein Problem.
Ich habe vergessen, eine wichtige Änderung einzufügen, die ich an einer der Deklarationen auf Modulebene in Romkes Code vorgenommen hatte. Ohne diese Änderung würde der modifizierte Code von Romke nicht unter 64-Bit-VBA kompiliert werden. Der Kompilierfehler ist in der folgenden Zeile aufgetreten:
Die Fehlermeldung lautete „Nichtübereinstimmung des ByRef-Argumenttyps " und die hervorgehobene Variable war hCurKey
.
Hier ist die beleidigende Codezeile aus Romkes ursprünglichem Klassenmodul:
Private hCurKey
Um den Kompilierfehler zu beheben, kann die obige Codezeile wie folgt geändert werden:
Private hCurKey As Variant
Aber warte, sagst du, tun diese beiden Codezeilen nicht dasselbe?!?! Jeder weiß, dass, wenn Sie den Typ einer Variablen nicht in VBA deklarieren, sie implizit als Variant deklariert wird. ... Oder doch?
Explizit ist besser als implizit
Also, was geht hier wirklich vor?
Das Problem ist, dass die erste Codezeile oben – Private hCurKey
–definierte die hCurKey-Variable als Long
Datentyp.
Wie konnte das sein?
Das lag an dieser seltsamen Zeile oben in Romkes Klassenmodul:
DefLng H-I, L, N
Was macht diese Linie? Das heißt, jede deklarierte Variable im aktuellen Modul ohne explizit deklarierten Typ, deren Variablenname mit H
beginnt , I
, L
, oder N
, wird vom Compiler als Long
behandelt Datentyp.
Also die Zeile Private hCurKey
tat implizit Deklarieren Sie einen Typ für die hCurKey-Variable, aber die implizite Deklaration war ein Long-Datentyp anstelle eines Variant.
Warum funktioniert Variant Kompilieren, aber lang Nicht?
Warum der Code kompiliert wird, wenn hCurKey
ein Variant ist, aber fehlschlägt, wenn es ein Long ist, das ist eine Frage des 32-Bit-zu-64-Bit-Konvertierungsprozesses.
Um die Ursache des Problems zu finden, müssen wir den migrierten Code für die RegCreateKeyEx-API-Deklaration untersuchen:
#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
Wenn wir RegCreateKeyEx
aufrufen aus dem Code übergeben wir den hCurKey
Variable als vorletztes Argument in der Funktion. Mit anderen Worten, es wird als phkResult
übergeben Streit. Beachten Sie, dass in der Version vor VBA7 (Access 2007 und früher) phkResult
als Long deklariert, aber in der VBA7-Version als LongPtr
deklariert .
Das liegt daran, dass phkResult
erhält ein Handle zum erstellten oder geöffneten Registrierungsschlüssel. Wann immer Sie das Wort „Handle“ in Verbindung mit einem API-Aufruf sehen, können Sie es in Ihrem Kopf sicher in „Speicheradresse“ übersetzen. Deshalb wird das Argument als LongPtr
neu definiert im VBA7-Code:bei der Ausführung in einer 32-Bit-Umgebung ein LongPtr
wird als 32-Bit Long
behandelt Ganzzahl, aber in einer 64-Bit-Umgebung ein LongPtr
wird als 64-Bit LongLong
behandelt Ganzzahl.
hCurKey
deklarieren as Variant ist eine Art Abkürzung. Die folgende Anpassung würde auch funktionieren (und schneller ablaufen, obwohl die Geschwindigkeitserhöhung für den Benutzer wahrscheinlich nicht wahrnehmbar ist, es sei denn, sie wird viele Male innerhalb einer Schleife aufgerufen):
#If VBA7 Then
Private hCurKey As LongPtr
#Else
Private hCurKey As Long
#End If
Wie ich bereits sagte, vermittelt der obige Ansatz die Absicht des Entwicklers deutlicher, ist leistungsfähiger und führt zu mehr Fehlern bei der Kompilierung als der Private hCurKey As Variant
Alternative.
Aber ich bin ja bekanntlich faul und Private hCurKey As Variant
ist fast genauso gut mit viel weniger Tippen.
Nutzen Sie Ihr Wissen für das Gute
Erinnern Sie sich, was ich am Anfang dieses Artikels gesagt habe?
Nur weil du etwas tun kannst, heißt das nicht, dass du es tun solltest.
Ich habe diesen Artikel aus zwei Gründen geschrieben:
- Um Sie ausdrücklich dazu zu ermutigen Deklarieren Sie Variant-Variablen
As Variant
- Um das Bewusstsein für einen geheimnisvollen Aspekt von VBA zu schärfen, der Sie ins Stolpern bringen könnte, wenn Sie den Code einer anderen Person warten (oder kopieren und einfügen)
ICH HABE NICHT Schreiben Sie diesen Artikel, um Sie dazu zu inspirieren, DefType-Anweisungen in Ihrem eigenen Code zu schreiben. TU DAS NICHT!!! Denken Sie daran, nur weil Sie etwas tun können, heißt das nicht, dass Sie es tun sollten.