Anatomy of a Declare Statement
Here is an example of the Declare statement for the GetTempPath function, which returns the path to the Microsoft® Windows® temporary folder:
Private Declare Function GetTempPath Lib "kernel32" _ Alias "GetTempPathA" (ByVal nBufferLength As Long, _ ByVal lpBuffer As String) As Long
The Declare keyword alerts VBA that you want to include the definition for a DLL function in your project. A Declare statement in a standard module can be public or private, depending on whether you want the API function to be available only to a single module or to the entire project. In a class module, a Declare statement must be private.
The name of the function that follows the Function keyword is the name you use to call the function from VBA. This name can be identical to the name of the API function itself, or you can use the Alias keyword within the Declare statement to indicate that you intend to call the function by a different name (an alias) in VBA.
In the previous example, the name of the API function in the DLL is GetTempPathA, and the name by which you would call it from VBA is GetTempPath.
Note The actual name of the DLL function appears after the Alias keyword.
Note GetTempPath is the name the Win32API.txt file uses to alias the function, but you could change this to be any name you wanted.
Here are a few reasons why you might want to use an alias within a Declare statement:
- Some API function names begin with an underscore character (_), which is not legal in VBA. To call the function from VBA, you must use an alias name.
- Because an alias makes it possible for you to name a DLL function anything you want to, you can make the function name conform to your own naming standards within VBA.
- Because API functions are case-sensitive and VBA functions are not, you can use an alias to change the case of a function name.
- Some DLL functions have arguments that can take different data types. The VBA Declare statements for these functions define these arguments as type Any. Calling a DLL function with arguments declared as Any can be perilous, because VBA does not perform any data type checking for you. If you want to avoid the hazards of passing arguments as Any, you can declare multiple versions of the same DLL function, each with a different name and a different data type.
- The Windows API contains two versions of all functions that take string arguments: an ANSI version and a Unicode version. The ANSI version has an "A" suffix, as shown in the previous example, while the Unicode version has a "W" suffix. Although VBA uses Unicode internally, it converts all strings to ANSI strings before calling a function in a DLL, so you usually will use the ANSI version when calling a Windows API function from VBA. The API Viewer add-in automatically aliases all functions that take string arguments, so you can call the function without including the "A" suffix.
The Lib keyword specifies which DLL contains the function. Note that the name of the DLL is contained in a string within the Declare statement. If the DLL specified after the Lib keyword is not found on the user's system, a call to the function will fail with run-time error number 48, "Error in loading DLL." Because you can handle this error in your VBA code, you can write robust code that deals with the error gracefully.
Note This is not an issue if you are calling a function in one of the basic Windows DLLs, because those DLLs must be present for your application to load.
The following table describes the most commonly used DLLs in the Windows API:
|Kernel32.dll||Low-level operating system functions, such as those for memory management and resource handling.|
|User32.dll||Windows management functions, such as those for message handling, timers, menus, and communications.|
|GDI32.dll||The Graphics Device Interface (GDI) library, which contains functions for device output, such as those for drawing, display context, and font management.|
Most DLLs, including those in the Windows API, are written in C or C++. Passing arguments to a DLL function therefore requires some understanding of the arguments and data types expected by a C or C++ function, which differ in several ways from those expected by a VBA function.
In addition, many arguments to DLL functions are passed by value. By default, arguments in VBA are passed by reference, so it is imperative you include the ByVal keyword in the function definition when the DLL function requires that an argument be passed by value. Omitting the ByVal keyword in a function definition might cause an invalid page fault in your application in some cases. In other cases, the VBA run-time error number 49, "Bad DLL calling convention," might occur.
Passing an argument by reference passes the memory location of that argument to the procedure being called. If the procedure modifies that argument's value, it modifies the only copy of that argument, so when execution returns to the calling procedure, the argument contains the modified value.
Passing an argument to a DLL function by value, on the other hand, passes a copy of the argument; the function operates on a copy of the argument instead. This prevents that function from modifying the contents of the actual argument. When execution returns to the calling procedure, the argument contains the same value it did before the other procedure was called.
Because passing by reference makes it possible for an argument to be modified in memory, if you incorrectly pass an argument by reference, the DLL function might overwrite memory that it should not, causing an error or otherwise unexpected behavior. Windows maintains many values that should not be overwritten. For example, Windows assigns to every window a unique 32-bit identifier called a handle. Handles are passed to API functions by value, because if Windows were to modify a window's handle, it would no longer be able to track that window.
Note Although the ByVal keyword appears in front of some arguments of type String, strings always are passed to Windows API functions by reference.
API Basics | What Is an API? | Why Use VBA to Call the Windows API? | API Resources | Accessing Functions in a DLL | Constants and User-Defined Types | Understanding Handles | Calling DLL Functions | Passing Arguments by Value or by Reference | Getting the Most Out of Visual Basic for Applications