Access
 sql >> Base de Dados >  >> RDS >> Access

Instruções DefType no VBA:o lado escuro da compatibilidade com versões anteriores


Só porque você pode fazer algo, não significa que você deve.

Eu acredito profundamente na santidade da compatibilidade com versões anteriores. Mas vem com um lado sombrio. Às vezes, as velhas maneiras de fazer as coisas caem em desuso. Seu uso se torna tão misterioso que temos a tendência de esquecer que eles existem.

Assim vai com instruções DefType.

O que você não sabe pode machucá-lo


Vários meses atrás, escrevi um artigo sobre o módulo de classe de operações de registro de Romke Soldaat.

Publiquei as alterações que fiz nas declarações de API do Romke para fazer o código rodar em VBA de 64 bits. Cada chamada de API foi encapsulada em #If VBA7 tags de compilação condicional e atualizadas com o PtrSafe palavra-chave.

Só havia um problema.

Esqueci de incluir uma alteração de chave que fiz em uma das declarações de nível de módulo no código de Romke. Sem essa alteração, o código modificado de Romke não seria compilado em VBA de 64 bits. O erro de compilação ocorreu na seguinte linha:

A mensagem de erro era "Incompatibilidade de tipo de argumento ByRef " e a variável destacada era hCurKey .

Aqui está a linha de código ofensiva do módulo de classe original de Romke:
Private hCurKey

Para corrigir o erro de compilação, a linha de código acima pode ser alterada para:
Private hCurKey As Variant

Mas espere, você diz, essas duas linhas de código não estão fazendo a mesma coisa?!?! Todo mundo sabe que se você não declarar o tipo de uma variável no VBA, ela será declarada implicitamente como Variant. ... Ou é?

Explícito é melhor que implícito


Então, o que realmente está acontecendo aqui?

O problema é que a primeira linha de código acima–Private hCurKey –estava definindo a variável hCurKey como um Long tipo de dados.

Como isso pode ser?

Foi por causa desta linha estranha no topo do módulo de classe de Romke:
DefLng H-I, L, N

O que essa linha está fazendo? Está dizendo que toda variável declarada no módulo atual sem um tipo declarado explicitamente cujo nome de variável começa com H , I , L , ou N , será tratado pelo compilador como um Long tipo de dados.

E assim, a linha Private hCurKey fez implicitamente declare um tipo para a variável hCurKey, mas a declaração implícita foi como um tipo de dados Long em vez de um Variant.

Por que Variante Compilar, mas longo Não?


Por que o código compila quando hCurKey é uma Variant, mas falha quando é um Long, isso é uma questão do processo de conversão de 32 bits para 64 bits.

Para encontrar a origem do problema, precisamos examinar o código migrado para a declaração da 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

Quando chamamos RegCreateKeyEx do código, estamos passando o hCurKey variável como o penúltimo argumento na função. Em outras palavras, está sendo passado como o phkResult argumento. Observe que na versão pré-VBA7 (Access 2007 e anterior), phkResult é declarado como Long, mas na versão VBA7 é declarado como LongPtr .

Isso porque o phkResult recebe um identificador para a chave de registro criada ou aberta. Sempre que você vir a palavra "handle" associada a uma chamada de API, poderá traduzi-la com segurança em sua cabeça para "endereço de memória". É por isso que o argumento é redefinido como um LongPtr no código VBA7:ao executar em um ambiente de 32 bits, um LongPtr é tratado como um Long de 32 bits inteiro, mas em um ambiente de 64 bits, um LongPtr é tratado como um LongLong de 64 bits inteiro.

Declarando hCurKey como Variant é um pouco de um atalho. A adaptação a seguir também funcionaria (e funcionaria mais rápido, embora o aumento de velocidade provavelmente seja imperceptível para o usuário, a menos que seja chamado muitas vezes dentro de um loop):
#If VBA7 Then
    Private hCurKey As LongPtr
#Else
    Private hCurKey As Long
#End If

Como eu disse, a abordagem acima é mais explícita em transmitir a intenção do desenvolvedor, tem melhor desempenho e gerará mais erros de tempo de compilação do que o Private hCurKey As Variant alternativo.

Mas eu sou conhecido por ser preguiçoso e Private hCurKey As Variant é quase tão bom com muito menos digitação.

Use seu conhecimento para o bem


Agora, lembre-se do que eu disse no início deste artigo?
Só porque você pode fazer algo, não significa que você deve.

Escrevi este artigo por dois motivos:
  1. Para incentivá-lo a explicitamente declarar variáveis ​​Variant As Variant
  2. Para aumentar a conscientização sobre um aspecto misterioso do VBA que pode atrapalhar você se você estiver mantendo (ou copiando e colando) o código de outra pessoa

Eu NÃO escreva este artigo para inspirá-lo a escrever instruções DefType em seu próprio código. NÃO FAÇA ISSO!!! Lembre-se, só porque você pode fazer algo não significa que você deva.

Referências externas

Deftype statement (VBA)Tópico de referência do Office VBAMicrosoft Docso365devx Declarações de API do Windows em VBA para 64 bitsComo converter suas declarações de API para 64 bits. - Mitos comuns desmascarados, fatores-chave explicados! CodekabinettPhilipp Stiefel

Artigos referenciados

Reverência pela compatibilidade com versões anteriores Um recurso que foi muito usado por uma porcentagem muito pequena de usuários avançados foi mantido ao longo de cinco atualizações subsequentes (e contando). Agora isso está mostrando reverência à compatibilidade com versões anteriores. Não é mais definidoMike Wolfe Classe RegOp para VBA de 64 bits Atualizando um módulo de classe de leitura e gravação de registro VBA clássico para compatibilidade de 64 bits. Não é mais definidoMike Wolfe