Skip to content

Class_WINAPI

Ryan N edited this page Jan 15, 2022 · 1 revision

Download this module here!

This class module contains call wrappers for interacting with the WINAPI, making things just a little bit easier for those who aren't familiar with them. This page won't go over in detail what each wrapper does, as the WINAPI documentation on MSDN covers all of that already. What this page will go over is the under-the-hood features that make it work, as well as how to use some of these features.

x32/x64 Windows API

When the WINAPI was first introduced, 32-bit computing was the norm. Thanks to innovation, 64-bit computing is now ubiquitous, and software made to be compatible with both system types is just as common. But when you need to interact with software that is compatible with both processing types, there will usually be separate functions and data types between software versions. This is where this module comes in handy, allowing users to use these API calls without having to worry about compatibility. The appropriate APIs will be called based on processing type automatically.

The Variant Trick

The fanciest "trick" being used within this module is utilizing variants to copy memory. Most VBA developers probably are not aware that the Variant data type is actually a structured object. It's not an explicit data type that only stores a single type of information. The overall structure of a variant is briefly described below, but you can read slightly outdated information about it here: Variant Description | Variant Structure

Note that all variant data is stored in little-endian format

  • [2] VARTYPE - A value representing the data type the variant will contain. Same value returned with the VarType() function
  • [2] wReserved1 - Data reserved for use when variants refer to complex data types such as arrays
  • [2] wReserved2 - Data reserved for use when variants refer to complex data types such as arrays
  • [2] wReserved3 - Data reserved for use when variants refer to complex data types such as arrays
  • [4] Long / [8] LongLong - This field is used to store the value of numeric data types, or is used to store a pointer to complex data types elsewhere in memory. The field size varies between processing types.

Some of you may be reading this thinking to yourself, why is this relevant, and how is this used to copy memory? That last data field is the key here.

Being able to manipulate data using pointers can be a powerful thing. Variants (and object references in general) use pointers to refer to data located elsewhere in memory. When this is done, it is known as ByRef, or by reference. This referencing is what allows Variants to "store" various data types. They merely point to where the value they are representing is located elsewhere in memory.

So if we use two variants, we can use one of them to store the pointer to the value we are reading, and the other to store the data type of the referenced value being pointed to by the other variant. Linking them together in this way allows us to link the data type of a location in memory by reference, enabling us to read/write data in memory without requiring further API calls. We're just using variants in an unexpected way!

Why use the Variant trick?

The goal of the WINAPI class modules, was to reduce the number of files needed to easily interact with the WINAPI. Because of this, I needed a way to transfer user defined types, or STRUCTs between class modules, because VBA does not allow this. Instead of adding more files to publicly store UDTs, I can copy memory between two pointers to transfer data between procedures of different classes.

Why can't you use the CopyMemory API?

It turns out that using this API is slow, and does significantly affect performance based on system factors. Instead of needing to repeatedly use this slow API call, I can use it the first time, to establish the link between static variants, and then reuse those variants to copy data. The result is a surprisingly effective method of moving data between classes!

Clone this wiki locally