> ## Content Index
> Fetch the complete content index at: https://nolongerset.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# DefType Statements in VBA: The Dark Side of Backward Compatibility
- URL: https://nolongerset.com/deftype-statements/
- Published: 2022-01-11T04:36:31.000Z
- Updated: 2026-05-08T13:00:17.000Z
- Description: Young VBA programmer, be not tempted by the dark side. DefType statements must be understood, but never used!
- Author: Mike Wolfe
- Tags: Hidden Features, #Import 2026-05-20 02:59

Just because you can do something, doesn't mean you should.

I believe deeply in the [sanctity of backward compatibility](https://nolongerset.com/reverence-for-backwards-compatibility/). But it comes with a dark side. Sometimes the old ways of doing things fall out of favor. Their usage becomes so arcane that we have a tendency to forget they even exist.

So it goes with [DefType statements](https://docs.microsoft.com/en-us/office/vba/language/concepts/getting-started/deftype-statements).

## What You Don't Know Can Hurt You

Several months ago, I [wrote an article](https://nolongerset.com/regop-class-for-64-bit-vba/) about Romke Soldaat's Registry Operations class module. 

I published the changes I made to Romke's API declarations to make the code run under 64-bit VBA. Every API call was wrapped in `#If VBA7` conditional compilation tags and updated with the `PtrSafe` keyword.

There was only one problem.

I forgot to include a key change that I had made to one of the module-level declarations in Romke's code. Without this change, Romke's modified code would not compile under 64-bit VBA. The compile error occurred on the following line:

![](https://storage.ghost.io/c/eb/d7/ebd732c1-5f03-4f07-b386-5d08557e15c9/content/images/2022/01/image-22.png)

The error message was "*ByRef argument type mismatch*" and the highlighted variable was `hCurKey`. 

Here's the offending line of code from Romke's original class module:

```vba
Private hCurKey
```

To fix the compile error, the above line of code may be changed to this:

```vba
Private hCurKey As Variant
```

But wait, you say, aren't those two lines of code doing the same thing?!?! Everybody knows that if you don't declare a variable's type in VBA it is implicitly declared as a Variant. ... Or is it?

## Explicit is Better Than Implicit

So what's really going on here?

The problem is that the first line of code above–`Private hCurKey`–was defining the hCurKey variable as a `Long` datatype. 

How could this be? 

It was because of this weird line at the top of Romke's class module:

```vba
DefLng H-I, L, N
```

What is that line doing? It's saying that every declared variable in the current module without an explicitly declared type whose variable name begins with `H`, `I`, `L`, or `N`, will be treated by the compiler as a `Long` data type.

And so, the line `Private hCurKey` did *implicitly* declare a type for the hCurKey variable, but the implicit declaration was as a Long data type instead of a Variant.

## Why Does *Variant* Compile But *Long* Does Not?

As to why the code compiles when `hCurKey` is a Variant but fails when it's a Long, that's a matter of the [32-bit to 64-bit conversion process](https://codekabinett.com/rdumps.php?Lang=2&targetDoc=windows-api-declaration-vba-64-bit).

To find the source of the problem, we need to examine the migrated code for the RegCreateKeyEx API declaration:

```vba
#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
```

When we call `RegCreateKeyEx` from the code, we are passing the `hCurKey` variable as the second to last argument in the function. In other words, it's being passed as the `phkResult` argument. Notice that in the pre-VBA7 version (Access 2007 and earlier), `phkResult` is declared as a Long, but in the VBA7 version it is declared as a `LongPtr`. 

That's because the `phkResult` receives a *handle* to the created or opened registry key. Whenever you see the word "handle" associated with an API call, you can safely translate that in your head to "memory address." That's why the argument is redefined as a `LongPtr` in the VBA7 code: when executing in a 32-bit environment, a `LongPtr` is treated as a 32-bit `Long` integer, but in a 64-bit environment, a `LongPtr` is treated as a 64-bit `LongLong` integer.

Declaring `hCurKey` as Variant is a bit of a shortcut. The following adaptation would also work (and perform faster, though the speed increase is likely to be imperceptible to the user unless it's called many times inside of a loop):

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

As I said, the above approach is more explicit in conveying the developer's intent, performs better, and will raise more compile-time errors than the `Private hCurKey As Variant` alternative.

But I'm known to be lazy, and `Private hCurKey As Variant` is *almost* as good with a lot less typing.

## Use Thy Knowledge For Good

Now, remember what I said at the beginning of this article?

> Just because you can do something, doesn't mean you should.

I wrote this article for two reasons:

1. To encourage you to *explicitly* declare Variant variables `As Variant`
2. To raise awareness about an arcane aspect of VBA that could trip you up if you are maintaining (or copy-pasting) someone else's code

I **DID NOT**write this article to inspire you to write DefType statements in your own code. DO NOT DO THAT!!! Remember, just because you can do something doesn't mean you should.

---

### External references

[Deftype statements (VBA)Office VBA reference topicMicrosoft Docso365devx![](https://docs.microsoft.com/en-us/media/logos/logo-ms-social.png)](https://docs.microsoft.com/en-us/office/vba/language/concepts/getting-started/deftype-statements)

[Windows API declarations in VBA for 64-bitHow to convert your API Declarations to 64-bit. - Common myths debunked, key factors explained!CodekabinettPhilipp Stiefel![](https://codekabinett.com/images/mvp_hor.png)](https://codekabinett.com/rdumps.php?Lang=2&targetDoc=windows-api-declaration-vba-64-bit)

### Referenced articles

[Reverence for Backwards CompatibilityA feature that was heavily used by a very small percentage of power users has been maintained over the course of five subsequent upgrades (and counting). Now that is showing reverence to backwards compatibility.![](https://nolongerset.com/favicon.png)No Longer SetMike Wolfe![](https://images.unsplash.com/photo-1508455858334-95337ba25607?ixlib=rb-1.2.1&q=80&fm=jpg&crop=entropy&cs=tinysrgb&w=2000&fit=max&ixid=eyJhcHBfaWQiOjExNzczfQ)](https://nolongerset.com/reverence-for-backwards-compatibility/)

[RegOp Class for 64-bit VBAUpdating a classic VBA registry reading and writing class module for 64-bit compatibility.![](https://nolongerset.com/favicon.png)No Longer SetMike Wolfe![](https://storage.ghost.io/c/eb/d7/ebd732c1-5f03-4f07-b386-5d08557e15c9/content/images/2021/02/64-Bit-RegOp-Refresh.jpg)](https://nolongerset.com/regop-class-for-64-bit-vba/)

*Image by [mm91](https://pixabay.com/users/mm91-3061029/?utm%5Fsource=link-attribution&utm%5Fmedium=referral&utm%5Fcampaign=image&utm%5Fcontent=1661865) from [Pixabay](https://pixabay.com/?utm%5Fsource=link-attribution&utm%5Fmedium=referral&utm%5Fcampaign=image&utm%5Fcontent=1661865)*