Access
 sql >> база данни >  >> RDS >> Access

Изявления на DefType във VBA:Тъмната страна на обратната съвместимост

Само защото можете да направите нещо, не означава, че трябва.

Вярвам дълбоко в светостта на обратната съвместимост. Но идва с тъмна страна. Понякога старите начини за правене на нещата изпадат в немилост. Използването им става толкова загадъчно, че сме склонни да забравяме, че дори съществуват.

Така че върви с операторите DefType.

Това, което не знаете, може да ви нарани

Преди няколко месеца написах статия за модула за клас Операции на системния регистър на Romke Soldaat.

Публикувах промените, които направих в декларациите на API на Romke, за да накарам кода да работи под 64-битов VBA. Всяко API извикване беше обвито в #If VBA7 маркери за условна компилация и актуализирани с PtrSafe ключова дума.

Имаше само един проблем.

Забравих да включа ключова промяна, която направих в една от декларациите на ниво модул в кода на Romke. Без тази промяна модифицираният код на Romke няма да се компилира под 64-битов VBA. Възникна грешка при компилиране на следния ред:

Съобщението за грешка беше „Несъответствие на типа аргумент на ByRef " и маркираната променлива беше hCurKey .

Ето обидния ред код от оригиналния клас модул на Romke:

Private hCurKey

За да коригирате грешката при компилиране, горният ред код може да бъде променен на това:

Private hCurKey As Variant

Но чакайте, казвате вие, тези два реда код не правят ли едно и също нещо?!?! Всеки знае, че ако не декларирате типа на променлива във VBA, тя имплицитно се декларира като Variant. ...  Или е така?

Изричното е по-добро от имплицитното

И така, какво всъщност се случва тук?

Проблемът е, че първият ред от кода по-горе – Private hCurKey – дефинира променливата hCurKey като Long тип данни.

Как може да бъде това?

Това беше заради тази странна линия в горната част на модула за клас на Romke:

DefLng H-I, L, N

Какво прави тази линия? Казва, че всяка декларирана променлива в текущия модул без изрично деклариран тип, чието име на променлива започва с H , I , L или N , ще се третира от компилатора като Long тип данни.

И така, редът Private hCurKey направи имплицитно декларирайте тип за променливата hCurKey, но имплицитната декларация беше като тип данни Long вместо Variant.

Защо има Вариант Компилиране, но Дълго Не?

Що се отнася до защо кодът се компилира, когато hCurKey е вариант, но не успява, когато е дълъг, това е въпрос на 32-битов в 64-битов процес на преобразуване.

За да открием източника на проблема, трябва да проверим мигрирания код за декларацията на 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

Когато извикаме RegCreateKeyEx от кода, ние предаваме hCurKey променлива като предпоследен аргумент във функцията. С други думи, той се предава като phkResult аргумент. Обърнете внимание, че във версията преди VBA7 (Access 2007 и по-стари), phkResult е деклариран като Long, но във версията VBA7 е деклариран като LongPtr .

Това е така, защото phkResult получава ръкохватка към създадения или отворен ключ на системния регистър. Всеки път, когато видите думата „дръжка“, свързана с извикване на API, можете безопасно да я преведете в главата си на „адрес на паметта“. Ето защо аргументът се предефинира като LongPtr в кода на VBA7:когато се изпълнява в 32-битова среда, LongPtr се третира като 32-битов Long цяло число, но в 64-битова среда, LongPtr се третира като 64-битов LongLong цяло число.

Деклариране на hCurKey тъй като Variant е малко пряк път. Следната адаптация също ще работи (и работи по-бързо, въпреки че увеличението на скоростта вероятно ще бъде незабележимо за потребителя, освен ако не бъде извикано много пъти в цикъл):

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

Както казах, горният подход е по-ясен при предаването на намерението на разработчика, работи по-добре и ще доведе до повече грешки по време на компилиране от Private hCurKey As Variant алтернатива.

Но е известно, че съм мързелив и Private hCurKey As Variant е почти също толкова добре с много по-малко писане.

Използвайте знанията си за добро

Сега си спомняте какво казах в началото на тази статия?

Само защото можете да направите нещо, не означава, че трябва.

Написах тази статия по две причини:

  1. За да ви насърчим да изрично декларирайте Вариантни променливи As Variant
  2. За повишаване на осведомеността относно тайнствен аспект на VBA, който може да ви препъне, ако поддържате (или копирате и поставяте) код на някой друг

АЗНЕ напишете тази статия, за да ви вдъхнови да пишете изявления DefType във вашия собствен код. НЕ ПРАВИ ТОВА!!! Не забравяйте, че само защото можете да направите нещо, не означава, че трябва.

Външни препратки

Изявления на Deftype (VBA) Референтна тема на Office VBA Microsoft Docso365devx Декларации за API на Windows във VBA за 64-битова Как да конвертирате вашите API декларации в 64-битови. - Развенчани често срещани митове, обяснени ключови фактори!CodekabinettPhilipp Stiefel

Референтни статии

Уважение към обратната съвместимост. Функция, която беше силно използвана от много малък процент опитни потребители, беше поддържана в хода на пет последващи надстройки (и се брои). Сега това показва благоговение към обратната съвместимост. Вече не се задава Майк Улф Клас RegOp за 64-битов VBAU Актуализиране на класически VBA модул за четене и запис на клас за 64-битова съвместимост. Вече не се задава Майк Улф
  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Кога е време за надстройка до SQL?

  2. ODBC достъп от Windows Server Core

  3. 5 неща, които трябва да знаете за „Windows 10 S“

  4. Как се използват базите данни в електронната търговия

  5. Лесен ли е за научаване Microsoft Access?