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:
- Para incentivá-lo a explicitamente declarar variáveis Variant
As Variant
- 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.