Anatomy of a DLL Procedure Call

We’ve been pretending that the ZAPI functions are written in Basic to be called by Basic, but in reality they are written as a C DLL to be called from C, Pascal, Logo, Scheme, and the current language of the month. The ZAPI library couldn’t be a Visual Basic DLL because it needs to support all languages directly, not through COM Automation. Also, many callers won’t have the Visual Basic run-time DLL on their disks. The last thing the author of ZAPI had in mind was making it easy to call API functions from Basic. Internally, ZAPI uses whatever conventions are most efficient (usually taken from C, but sometimes from Pascal).

In order to call a procedure in a DLL, you need either a type library entry or a Declare statement for it. Since Declare statements are written in Basic, I’ll concentrate on them. The Zapem API function, shown in Figure 2-5, serves as a preliminary model for writing and using Declare statements.

Figure 2-5. Declaring and using a DLL function.

A lot is packed into this short bit of code. Take a look at the labeled sections in Figure 2-5, which correspond to the numbered sections here:

  1. A Declare statement looks sort of like the first line of a procedure definition except that it starts with the Declare keyword. You specify whether the procedure is a Sub or a Function and then give the name of the procedure followed by the argument list and, for Functions, the return value.

  2. You must include the name of the DLL containing the procedure in a Lib clause. If you’re calling your own DLL, you probably know the name. If you’re calling the Windows API, you sometimes have to guess. C programmers don’t need to put the DLL name in their declarations, and since most API documentation is designed for C programmers, you might have trouble figuring it out. Microsoft Visual C++ comes with a file named WIN32API.CSV that tells all for Win32. Another technique is to use the /DUMP option of the LINK program provided with Visual Basic. The command LINK /DUMP /EXPORTS ODBC32.DLL, for example, will show all the functions provided by the ODBC32 DLL. If that doesn’t help, use the trial-and-error method, starting with the DLLs shown in Table 2-1.
Services DLL
Common controls COMCTL32
Common dialogs COMDLG32
Drag and drop, icon extraction, Windows 95 shell SHELL32
Graphics Device Interface GDI32
Graphics (3-D lines and surfaces) OPENGL32 (NT only)
Graphics (games and animation) WING32
Memory, disks, processes, resources, tasks, modules KERNEL32
Multimedia, sound, MIDI, joysticks, timing WINMM
Networks (WNet) MPR
Networks (LanMan) NETAPI32
NT Security, Registry, and other advanced services ADVAPI32
Component Object Model (COM) OLE32
Automation and type conversion OLEAUT32
Version checking VERSION
Windows, menus, strings, messages USER32
Table 2-1. Windows system DLLs.
  1. The big question is whether to pass by value or by reference. Most arguments should be passed by value, but you’ll hear a lot about the exceptions later in this chapter.

  2. The original Basic version of Zapem returned a Boolean value, but the Windows BOOL type isn’t the same as a Basic Boolean. A BOOL is actually an int, which is 32 bits wide. To C programmers, a Boolean is actually a typedef called VARIANT_BOOL that evaluates to a C short (16 bits). In other words, a Boolean is the same size as a Basic Integer. Although you should declare what Windows calls BOOL as Long, you can assign the result to a Boolean. Basic automatically performs the type conversion from Long to Boolean on return values.

That’s the quick introduction to API calls. When you get down to actual coding, though, things get complicated. Every type of argument has its own quirks and patterns, and you must look at each type specifically. Fortunately, the Windows API never uses the Variant, Currency, Single, or Double type. The remaining types fall into patterns that I can discuss one by one.

NOTE

The COM Automation API uses Variant and other Visual Basic data types. Theoretically, you could use them in declarations for the COM Automation system DLLs or for COM Automation–compatible DLLs that you write. You can even use the Optional and ParamArray attributes in Declare statements. This chapter, however, concentrates on the integer and string types used by the Windows API.