Access
 sql >> Baza danych >  >> RDS >> Access

Instrukcje DefType w języku VBA:ciemna strona kompatybilności wstecznej

To, że możesz coś zrobić, nie oznacza, że ​​powinieneś.

Głęboko wierzę w świętość wstecznej kompatybilności. Ale ma też ciemną stronę. Czasami stare sposoby robienia rzeczy wypadają z łask. Ich użycie staje się tak tajemnicze, że mamy tendencję do zapominania, że ​​nawet istnieją.

Tak samo jest z deklaracjami DefType.

To, czego nie wiesz, może cię zranić

Kilka miesięcy temu napisałem artykuł o module klasy Registry Operations Romke Soldaat.

Opublikowałem zmiany, które wprowadziłem do deklaracji API Romke'a, aby kod działał pod 64-bitowym VBA. Każde wywołanie API zostało opakowane w #If VBA7 warunkowe tagi kompilacji i zaktualizowane za pomocą PtrSafe słowo kluczowe.

Był tylko jeden problem.

Zapomniałem zawrzeć kluczową zmianę, którą wprowadziłem do jednej z deklaracji na poziomie modułu w kodzie Romkego. Bez tej zmiany zmodyfikowany kod Romkego nie skompilowałby się w 64-bitowym VBA. Wystąpił błąd kompilacji w następującym wierszu:

Komunikat o błędzie to „Niezgodność typu argumentu ByRef ", a podświetloną zmienną był hCurKey .

Oto obraźliwy wiersz kodu z oryginalnego modułu klasy Romke:

Private hCurKey

Aby naprawić błąd kompilacji, powyższy wiersz kodu może zostać zmieniony na następujący:

Private hCurKey As Variant

Ale czekaj, mówisz, czy te dwie linijki kodu nie robią tego samego?!?! Wszyscy wiedzą, że jeśli nie zadeklarujesz typu zmiennej w VBA, zostanie ona domyślnie zadeklarowana jako Wariant. ... A może tak jest?

Jasne jest lepsze niż niejawne

Więc co się tutaj naprawdę dzieje?

Problem polega na tym, że pierwsza linijka kodu powyżej – Private hCurKey – definiował zmienną hCurKey jako Long typ danych.

Jak to możliwe?

To z powodu tej dziwnej linii na górze modułu klasy Romke:

DefLng H-I, L, N

Co robi ta linia? Oznacza to, że każda zadeklarowana zmienna w bieżącym module bez jawnie zadeklarowanego typu, której nazwa zmiennej zaczyna się od H , I , L lub N , będzie traktowane przez kompilator jako Long typ danych.

I tak, wiersz Private hCurKey zrobił domyślnie zadeklarować typ dla zmiennej hCurKey, ale niejawna deklaracja była typem danych Long zamiast Variant.

Dlaczego Wariant Kompiluj, ale długo Nie?

Dlaczego kod kompiluje się, gdy hCurKey? jest Wariantem, ale kończy się niepowodzeniem, gdy jest Długi, to kwestia procesu konwersji 32-bitowej na 64-bitową.

Aby znaleźć źródło problemu, musimy sprawdzić zmigrowany kod dla deklaracji 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

Kiedy wywołujemy RegCreateKeyEx z kodu przekazujemy hCurKey zmienna jako przedostatni argument w funkcji. Innymi słowy, jest przekazywany jako phkResult argument. Zauważ, że w wersji wcześniejszej niż VBA7 (Access 2007 i wcześniejsze) phkResult jest zadeklarowany jako Long, ale w wersji VBA7 jest zadeklarowany jako LongPtr .

To dlatego, że phkResult otrzymuje uchwyt do utworzonego lub otwartego klucza rejestru. Za każdym razem, gdy zobaczysz słowo „uchwyt” skojarzone z wywołaniem API, możesz bezpiecznie przetłumaczyć je w swojej głowie na „adres pamięci”. Dlatego argument został przedefiniowany jako LongPtr w kodzie VBA7:podczas wykonywania w środowisku 32-bitowym LongPtr jest traktowany jako 32-bitowy Long liczba całkowita, ale w środowisku 64-bitowym LongPtr jest traktowany jako 64-bitowy LongLong liczba całkowita.

Deklaracja hCurKey bo Variant to trochę na skróty. Poniższa adaptacja również zadziała (i będzie działać szybciej, chociaż wzrost prędkości prawdopodobnie będzie niezauważalny dla użytkownika, chyba że zostanie wywołany wiele razy w pętli):

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

Jak powiedziałem, powyższe podejście jest bardziej wyraźne w przekazywaniu intencji programisty, działa lepiej i spowoduje więcej błędów w czasie kompilacji niż Private hCurKey As Variant alternatywa.

Ale jestem znany z tego, że jestem leniwy i Private hCurKey As Variant jest prawie tak dobre, z dużo mniejszą ilością pisania.

Wykorzystuj swoją wiedzę na dobre

A teraz pamiętasz, co powiedziałem na początku tego artykułu?

Tylko dlatego, że możesz coś zrobić, nie oznacza, że ​​powinieneś.

Napisałem ten artykuł z dwóch powodów:

  1. Aby zachęcić Cię do wyraźnego zadeklaruj zmienne wariantu As Variant
  2. Aby podnieść świadomość na temat tajemnego aspektu VBA, który może Cię potykać, jeśli utrzymujesz (lub kopiujesz i wklejasz) kod innej osoby

NIE napisz ten artykuł, aby zainspirować Cię do pisania instrukcji DefType we własnym kodzie. NIE RÓB TEGO!!! Pamiętaj, że tylko dlatego, że możesz coś zrobić, nie oznacza, że ​​powinieneś.

Odniesienia zewnętrzne

Instrukcje Deftype (VBA) Temat referencyjny pakietu Office VBAMicrosoft Docso365devx Deklaracje Windows API w VBA dla wersji 64-bitowejJak przekonwertować deklaracje API na wersję 64-bitową. - Powszechne mity obalone, kluczowe czynniki wyjaśnione!CodekabinettPhilipp Stiefel

Artykuły referencyjne

Reverence for Backwards Compatibility Funkcja, która była intensywnie wykorzystywana przez bardzo mały procent zaawansowanych użytkowników, została utrzymana w ciągu pięciu kolejnych aktualizacji (i wciąż rośnie). To pokazuje szacunek dla wstecznej kompatybilności. Nie można już ustawićMike Wolfe Klasa RegOp dla 64-bitowego VBAAktualizacja klasycznego modułu klasy odczytu i zapisu rejestru VBA w celu zapewnienia zgodności z 64-bitową. Nie można już ustawićMike Wolfe
  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Zalety i wady stosowania procedur składowanych

  2. Znaczenie utrzymywania bazy danych zgodnej z HIPAA

  3. Jak utworzyć formularz nawigacji w programie Microsoft Access

  4. Jak dodać tytuł do nagłówka raportu w programie Microsoft Access

  5. Złącze Access Dataverse jest już dostępne do testowania