HRESULT: Use "Long" and Not "LongPtr"
There's a lot of confusion in the VBA world when it comes to converting 32-bit-only VBA code to 64-bit-compatible code (myself included).
As I've written in the past, the best resource in this area is Philipp Stiefel's article: How to convert Windows API declarations in VBA for 64-bit.
tl;dr: HRESULT
=> Long
(not LongPtr
)
Long vs. LongPtr
Much of the confusion centers around whether to convert a declared Long
type to a LongPtr
type. Here's a relevant excerpt from Philipp's excellent explainer (emphasis mine):
LongPtr is the perfect type for any pointer or handle in your Declare Statement. You can use this data type in both environments, and it will always be appropriately sized to handle the pointer size of your environment.
Misconception: “You should change all Long variables in your Declare Statements and Type declarations to be LongPtr variables when adapting your code for 64-bit.”
...
Only if a function parameter or return value is representing a pointer to a memory location or a handle ... should [it] be declared as LongPtr.
The Leading "H" Heuristic
When converting API declarations, the most reliable resource is the Win32API_PtrSafe.txt file, available from Microsoft.
If you look through that file, you will notice that many of the parameters that get declared as LongPtr
have a single letter "h" prefixing their name. For example:
hWnd
: Window handlehPrinter
: Printer handlehDevice
: Device handlehThread
: Thread handle
As you've likely guessed, the "h" prefix stands for "handle." This represents a pointer to a memory location where the object (Window, Printer, Device, Thread, etc.) is located. In 32-bit Office, the length of this memory address is 32 bits. In 64-bit Office, the memory address length is 64 bits.
So, if you are converting an API call that is not included in the Win32API_PtrSafe.txt file linked above, a good rule of thumb is that a parameter with a letter "h" prefix is a memory handle and thus should be declared As LongPtr
.
The Big Exception
Many COM and Windows API functions return an HRESULT.
What is an HRESULT? It's a 32-bit integer result code where 0 (zero) equals success and every other number is an error code.
Note what HRESULT is not... It is NOT a handle to a memory address. An HRESULT is a 32-bit integer code in both 32-bit VBA AND 64-bit VBA.
Thus, if the return type of an API function call is an HRESULT in the C++ header file, it should be declared as a Long
in VBA.
For example, here's the syntax for the CoCreateGuid
function from the original C++ header file:
HRESULT CoCreateGuid(
[out] GUID *pguid
);
And here's the associated VBA API declaration line for CoCreateGuid:
Notice the return type is a Long
and NOT a LongPtr
.
So Why Is It Called an HRESULT Then?
I covered that in a previous article:
In the world of COM, a leading "H" in a variable name usually indicates a "handle" (i.e., memory address) to an object.
That's not the case with an HRESULT, though. An HRESULT is simply a coded number–it is NOT a handle to an object.
Why the leading "H" then?
According to Microsoft's Raymond Chen, the original COM design called for returning objects (rather than long integers) as the standard return from a function or method call. This allowed doing some very interesting things, but ultimately it was determined to be overkill. For simplicity and performance, the object became a simple 32-bit integer.
The original name stuck, leaving us with a term that literally defies convention.
External references
Referenced articles
Image by Tumisu, please consider ☕ Thank you! 🤗 from Pixabay