sql >> Database >  >> RDS >> Access

DefType-statements in VBA:de donkere kant van achterwaartse compatibiliteit

Alleen omdat je iets kunt doen, wil nog niet zeggen dat je het moet doen.

Ik geloof diep in de heiligheid van achterwaartse compatibiliteit. Maar het komt met een donkere kant. Soms vallen de oude manieren om dingen te doen uit de gratie. Hun gebruik wordt zo geheimzinnig dat we de neiging hebben om te vergeten dat ze bestaan.

Zo gaat het met DefType-statements.

Wat u niet weet, kan u pijn doen

Enkele maanden geleden schreef ik een artikel over de klasse module Registerbewerkingen van Romke Soldaat.

Ik heb de wijzigingen die ik heb aangebracht in de API-declaraties van Romke gepubliceerd om de code onder 64-bits VBA te laten werken. Elke API-aanroep was verpakt in #If VBA7 voorwaardelijke compilatietags en bijgewerkt met de PtrSafe zoekwoord.

Er was maar één probleem.

Ik vergat een belangrijke wijziging op te nemen die ik had aangebracht in een van de declaraties op moduleniveau in de code van Romke. Zonder deze wijziging zou de gewijzigde code van Romke niet worden gecompileerd onder 64-bits VBA. De compileerfout deed zich voor op de volgende regel:

De foutmelding was "ByRef argumenttype komt niet overeen " en de gemarkeerde variabele was hCurKey .

Hier is de beledigende regel code uit de originele klassenmodule van Romke:

Private hCurKey

Om de compileerfout op te lossen, kan de bovenstaande regel code in dit worden gewijzigd:

Private hCurKey As Variant

Maar wacht, zeg je, doen die twee regels code niet hetzelfde?!?! Iedereen weet dat als je het type van een variabele niet declareert in VBA, het impliciet wordt gedeclareerd als een variant. ...  Of toch?

Expliciet is beter dan impliciet

Dus wat is hier echt aan de hand?

Het probleem is dat de eerste regel code hierboven-Private hCurKey –definieerde de hCurKey-variabele als een Long data type.

Hoe kan dit zo zijn?

Het kwam door deze rare regel bovenaan de lesmodule van Romke:

DefLng H-I, L, N

Wat doet die lijn? Het zegt dat elke gedeclareerde variabele in de huidige module zonder een expliciet gedeclareerd type waarvan de variabelenaam begint met H , I , L , of N , wordt door de compiler behandeld als een Long gegevenstype.

En dus, de regel Private hCurKey deed impliciet declareer een type voor de hCurKey-variabele, maar de impliciete declaratie was als een Long-gegevenstype in plaats van een Variant.

Waarom doet Variant Compileren Maar Lang Niet?

Waarom de code compileert wanneer hCurKey is een variant maar mislukt als het een lang is, dat is een kwestie van het 32-bits naar 64-bits conversieproces.

Om de oorzaak van het probleem te vinden, moeten we de gemigreerde code voor de RegCreateKeyEx API-declaratie onderzoeken:

#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

Wanneer we RegCreateKeyEx . aanroepen van de code geven we de hCurKey . door variabele als het voorlaatste argument in de functie. Met andere woorden, het wordt doorgegeven als de phkResult argument. Merk op dat in de pre-VBA7-versie (Access 2007 en eerder), phkResult wordt gedeclareerd als een Long, maar in de VBA7-versie wordt het gedeclareerd als een LongPtr .

Dat komt omdat de phkResult ontvangt een handvat naar de aangemaakte of geopende registersleutel. Telkens wanneer u het woord 'handle' ziet dat is gekoppeld aan een API-aanroep, kunt u dat veilig in uw hoofd vertalen naar 'geheugenadres'. Daarom is het argument opnieuw gedefinieerd als een LongPtr in de VBA7-code:bij uitvoering in een 32-bits omgeving, een LongPtr wordt behandeld als een 32-bits Long geheel getal, maar in een 64-bits omgeving, een LongPtr wordt behandeld als een 64-bits LongLong geheel getal.

hCurKey . declareren als Variant is een beetje een kortere weg. De volgende aanpassing zou ook werken (en sneller werken, hoewel de snelheidsverhoging waarschijnlijk niet waarneembaar is voor de gebruiker, tenzij deze vaak binnen een lus wordt aangeroepen):

#If VBA7 Then
    Private hCurKey As LongPtr
#Else
    Private hCurKey As Long
#End If

Zoals ik al zei, is de bovenstaande benadering explicieter in het overbrengen van de bedoeling van de ontwikkelaar, presteert beter en zal meer compileerfouten veroorzaken dan de Private hCurKey As Variant alternatief.

Maar ik sta bekend als lui en Private hCurKey As Variant is bijna even goed met veel minder typen.

Gebruik uw kennis ten goede

Weet je nog wat ik aan het begin van dit artikel zei?

Alleen omdat je iets kunt doen, wil nog niet zeggen dat je het moet doen.

Ik heb dit artikel om twee redenen geschreven:

  1. Om u aan te moedigen om expliciet declareer Variantvariabelen As Variant
  2. Om het bewustzijn te vergroten over een geheimzinnig aspect van VBA dat u zou kunnen laten struikelen als u de code van iemand anders onderhoudt (of kopieert)

Ik NIET schrijf dit artikel om je te inspireren om DefType-statements in je eigen code te schrijven. DOE DAT NIET!!! Onthoud dat het feit dat je iets kunt doen niet betekent dat je het ook moet doen.

Externe referenties

Deftype-instructies (VBA)Office VBA-referentieonderwerpMicrosoft Docso365devx Windows API-declaraties in VBA voor 64-bit Hoe u uw API-declaraties kunt converteren naar 64-bit. - Veelvoorkomende mythen ontkracht, belangrijke factoren uitgelegd! CodekabinettPhilipp Stiefel

Artikelen waarnaar verwezen wordt

Eerbied voor achterwaartse compatibiliteit Een functie die intensief werd gebruikt door een zeer klein percentage van de krachtige gebruikers, is behouden in de loop van vijf opeenvolgende upgrades (en er worden nog steeds meer). Dat toont eerbied voor achterwaartse compatibiliteit. Mike Wolfe niet langer ingesteld RegOp Class voor 64-bits VBAUpdaten van een klassieke VBA-registerlees- en schrijfklassemodule voor 64-bits compatibiliteit. Mike Wolfe niet langer ingesteld
  1. Kan de id van de laatst ingevoegde rij in Hibernate niet ophalen met Oracle

  2. 4 belangrijke databasebewakingsactiviteiten die elke DBA moet weten

  3. Hoe de korte maandnaam van een datum in MariaDB te krijgen?

  4. PostgreSQL - GROUP BY-clausule