sql >> Databáze >  >> RDS >> Access

Příkazy DefType ve VBA:Temná strana zpětné kompatibility

To, že něco umíš, neznamená, že bys měl.

Hluboce věřím v posvátnost zpětné kompatibility. Ale přichází to s temnou stránkou. Někdy staré způsoby dělání věcí upadnou v nemilost. Jejich používání se stává tak tajemným, že máme tendenci zapomínat, že vůbec existují.

Tak je to s příkazy DefType.

Co nevíte, může vám ublížit

Před několika měsíci jsem napsal článek o modulu Romke Soldaat's Registry Operations.

Zveřejnil jsem změny, které jsem provedl v deklaracích Romkeho API, aby kód běžel pod 64bitovým VBA. Každé volání API bylo zabaleno do #If VBA7 tagy podmíněné kompilace a aktualizovány pomocí PtrSafe klíčové slovo.

Vyskytl se pouze jeden problém.

Zapomněl jsem zahrnout klíčovou změnu, kterou jsem provedl v jedné z deklarací na úrovni modulu v Romkeho kódu. Bez této změny by se upravený kód Romke nezkompiloval pod 64bitovým VBA. Na následujícím řádku došlo k chybě kompilace:

Chybová zpráva byla „Neshoda typu argumentu ByRef “ a zvýrazněná proměnná byla hCurKey .

Zde je problematický řádek kódu z původního modulu třídy Romke:

Private hCurKey

Chcete-li opravit chybu kompilace, výše uvedený řádek kódu může být změněn na tento:

Private hCurKey As Variant

Ale počkat, říkáte si, nedělají ty dva řádky kódu totéž?!?! Každý ví, že pokud nedeklarujete typ proměnné ve VBA, je implicitně deklarována jako varianta. ...  Nebo ano?

Explicitní je lepší než implicitní

Tak co se tu vlastně děje?

Problém je v tom, že první řádek kódu výše – Private hCurKey –definoval proměnnou hCurKey jako Long datový typ.

Jak by to mohlo být?

Bylo to kvůli této podivné řádce v horní části modulu třídy Romke:

DefLng H-I, L, N

Co ta linka dělá? Říká se, že každá deklarovaná proměnná v aktuálním modulu bez explicitně deklarovaného typu, jejíž název proměnné začíná H , I , L , nebo N , bude kompilátor považován za Long datový typ.

A tak řádek Private hCurKey udělal implicitně deklarovat typ pro proměnnou hCurKey, ale implicitní deklarace byla jako datový typ Long namísto Variant.

Proč varianta Kompilace, ale Dlouhá Není?

Proč se kód kompiluje, když hCurKey je varianta, ale selže, když je dlouhá, to je záležitost procesu převodu z 32 bitů na 64 bitů.

Abychom našli zdroj problému, musíme prozkoumat migrovaný kód pro deklaraci RegCreateKeyEx API:

#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

Když zavoláme RegCreateKeyEx z kódu předáváme hCurKey proměnná jako předposlední argument ve funkci. Jinými slovy, je předán jako phkResult argument. Všimněte si, že ve verzi před VBA7 (Access 2007 a starší) phkResult je deklarován jako Long, ale ve verzi VBA7 je deklarován jako LongPtr .

To proto, že phkResult obdrží kliku na vytvořený nebo otevřený klíč registru. Kdykoli uvidíte slovo „handle“ spojené s voláním API, můžete si to v hlavě bezpečně přeložit na „adresu paměti“. Proto je argument předefinován jako LongPtr v kódu VBA7:při provádění v 32bitovém prostředí se zobrazí LongPtr je považován za 32bitový Long celé číslo, ale v 64bitovém prostředí LongPtr je považován za 64bitový LongLong celé číslo.

Deklarování hCurKey protože Variant je trochu zkratka. Následující přizpůsobení by také fungovalo (a fungovalo rychleji, ačkoli zvýšení rychlosti bude pravděpodobně pro uživatele nepostřehnutelné, pokud není voláno mnohokrát uvnitř smyčky):

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

Jak jsem řekl, výše uvedený přístup jasněji vyjadřuje záměr vývojáře, funguje lépe a způsobí více chyb při kompilaci než Private hCurKey As Variant alternativa.

Ale je o mně známo, že jsem líný, a Private hCurKey As Variant je téměř stejně dobré s mnohem méně psaním.

Použijte své znalosti pro dobro

Pamatujete si, co jsem řekl na začátku tohoto článku?

To, že něco dokážeš, neznamená, že bys měl.

Tento článek jsem napsal ze dvou důvodů:

  1. Abych vás povzbudil, abyste výslovně deklarovat proměnné varianty As Variant
  2. Zvýšit povědomí o tajemném aspektu VBA, který by vás mohl podrazit, pokud udržujete (nebo kopírujete a vkládáte) kód někoho jiného.

NEMĚL napište tento článek, který vás inspiruje k psaní příkazů DefType ve vašem vlastním kódu. NEDĚLEJ TO!!! Pamatujte, že to, že něco umíte, neznamená, že byste to měli dělat.

Externí reference

Příkazy Deftype (VBA) Referenční téma VBA sady OfficeMicrosoft Docso365devx Deklarace rozhraní API systému Windows ve VBA pro 64bitové verze Jak převést deklarace rozhraní API na 64bitové. - Běžné mýty vyvráceny, klíčové faktory vysvětleny! CodekabinettPhilipp Stiefel

Odkazované články

Úcta ke zpětné kompatibilitě Funkce, kterou hojně využívalo velmi malé procento zkušených uživatelů, byla zachována během pěti následných upgradů (a přibývajících). Nyní to ukazuje úctu ke zpětné kompatibilitě. Už neset Mike Wolfe RegOp Class pro 64bitovou verzi VBA Aktualizace klasického modulu třídy pro čtení a zápis registru VBA pro 64bitovou kompatibilitu. Už neset Mike Wolfe
  1. VYTVOŘIT JAZYK plpython3u – PostgreSQL 9.6

  2. ROLLBACK TRUNCATE v SQL Server

  3. GROUP BY / zmatek agregačních funkcí v SQL

  4. TNS-12519 bez dosažení maximálního počtu procesů