API Tutorial
API Tutorial
API
As a programmer you might never have to use a Windows API.... Nahhh! The fact is that
serious programmers use API all the time. When they need to do something that VB
cannot handle, they turn to the Windows API! The API are procedures that exist in files
on your PC which you can call from within your VB program - and there are thousands of
them!. Written by Microsoft, debugged by tens of thousands of users, and available for
free with Windows - the API are one of the very best tools you have available to add
power to your VB application.
When Microsoft wrote Windows they put a huge amount of code into procedure libraries
which programmers can access. No matter which language you're using (VB, C++, ...)
you can use the Windows API to greatly expand the power of your application.
There are a lot of Windows programs whose code is spread across multiple files. The .EXE
file does not always contain all of the code that a programmer might use. For example, by
creating his own library of procedures (usually in the form of a file with a .DLL extension)
a programmer can allow more than one of his applications to access the same code.
Microsoft does a similar thing with Windows. There are many files which have code that
you can access, but the three most often named files are:
z user32.dll - controls the visible objects that you see on the screen
z gdi32 - home of most graphics oriented API
z kernel32.dll - provides access to low level operating system features
Later, I'll bring up some of the other files whose procedures you might want access.
However, there are some key issues which you should note before making a decision to
use an API call.
z Version Compatibility
Microsoft has long been known to update it's files without much fanfare - read that
as without telling anyone about it until it's already happened! And often, the
updated code may not perform exactly as did the older version. Users often find
this out by seeing unexected errors or by having their system crash and/or lock up
on them! In VB5 there were a huge number of programmer's who got bit by this
problem.
If you stick with the basic 3 OS files listed above, you won't see to much of this.
But the further away you go from the main 3 files, the more likely you are to get
into code which hasn't seen the testing and improvement cycle that the main
Windows OS files have gone through.
z File Size
One of the very major downsides to the concept of API is that all of this great
code lives in some very big files! Worse yet, sometimes the API you want are
spread over multiple files and you may be using only one or two procedures from
enormous files which have hundreds of procedures in them. Where this becomes a
problem is in a)load time - where it can takes several seconds to load the
procedure libraries, and b) - where you want to distribute your application and in
order to make sure that all of the procedure libraries are on your user's machine,
you have to put all of them into the distribute files. This can add many megabytes
of files to your distribution applications. It is a major problem for distribution of
software over the net, where 5 minutes per megabyte can deter a usage from
trying out an application just because he doesn't want to wait for the download!
z Documentation
Finding the documentation of what procedures are in a library and how to use them
can be very difficult. On my PC I have 3,380 files with a .DLL extension with a total
Page 2 of 8
size of 539MB. That's a lot of code! Unfortunately I can count on one hand the
pages of documentation that I have to tell me what that code is or does! You'll
learn how to use DLLs in this tutorial, but without the documentation from the
creator of the DLLs you cannot use them successfully.
Despite these problems, the powerful magic of the API is that they are code which you
don't have to write. If you've read my Beginner's section you know that I am a big fan of
using 3rd party software to lighten my own programming load. As with 3rd party controls,
the API provide procedures which someone else wrote, debugged, and made availble for
you to benefit from. In the Windows DLLs files, there are literally thousands of
procedures. The key to API programming is learning which of these procedures are useful
and which ones you are unlikely to ever need! This tutorial tries to address just that
problem.
Getting Started It's actually simpler than you might imagine. By now, you've already
written procedures for your own VB programs. Using procedures from other files is almost
exactly the same as using procedures from within your own program.
The one big difference is that you must tell your application which file the procedure is
contained in. To do so, you must put 1 line of code into your VB program. And, you have
to do this for every external procedure that you plan to use. I suppose it would be nice for
VB to have the ability to find the procedures for you - but you can see that searching
through the 3,380 procedures on my PC might slow my applications down a lot!
Ok, let's get to an example. Telling VB about the procedure you want to use is known as
"declaring" the procedure, and (no surprise) it uses a statement which starts with the
word declare. Here's what a declaration looks like:
z "Declare"
This is reserved word that VB uses to begin a declaration. There is no alternative -
you have to use it.
z "Function"
Also a reserved word, but in this case it distinguishes between a SUB procedured
and a FUNCTION procedure. The API use Function procedures so that they can
return a value to indicate the results of the action. Although you can discard the
returned value, it's also possible to check the return value to determine that the
action was successfully completed. completed. alternative - you have to use it.
z "ExitWindowsEx"
Inside each DLL is a list of the procedures that it contains. Normally, in a VB
declaration statement you simply type in the name of the procedure just as it is
named in the DLL. Sometimes, the DLL true name of the procedure may be a name
that is illegal in VB. For those cases, VB allows you to put in the text string "Alias
NewProcedurename" right behind the filename. In this example, VB would make a
call to the procedure by using the name "NewProcedureName".
z "Lib 'user32'"
Here's where you tell VB which file the procedure is in. Normally you would put
"user32.dll", showing the extension of the procedure library. For the special case of
the three Windows system DLLs listed above, the API will recognize the files when
simply named "user32", "kernel32", and "gdi32" - without the DLL extensions
shown. In most other cases you must give the complete file name. Unless the file
is in the system PATH, you must also give the complete path to the file.
z "(ByVal uFlags as Long ...)"
Exactly like your own procedures, Windows API functions can have a list of
arguments. However, while your VB procedures often use arguments passed by
reference (i.e., their values can be changed), most Windows API require that the
arguments be passed by value (i.e, a copy of the argument is passed to the DLL
and the originial variable cannot be changed).
Also, you'll note that a constant or variable is normally used as the argument for
an API call. It's technically acceptable to simply use a number for an argument but
it is common practice among experienced programmers to create constants (or
variables) whose name is easy to remember and then to use those in the argument
list. When you're reading or debugging your code later, the use of these easy to
read constant/variable names makes it much easier to figure out what went wrong!
Page 3 of 8
z "as Long"
This is exactly like the code you use to create your own functions. Windows API are
functions which return values and you must define what type of variable is
returned.
While I make it sound simple (and it is), there are still issues which ought to concern you
when using the Windows API. Because the API code executes outside the VB program
itself, your own program is susceptable to error in the external procedure. If the external
procedure crashes, then your own program will crash as well. It is very common for an
API problem to freeze your system and force a reboot.
The biggest issue that VB programmers would see in this case is that any unsaved code
will be lost!. So remember the rule when using API - save often!
Because many of the DLLs you will use have been debugged extensively you probably
won't see many cases where the DLL crashes because of programming bug. Far more
frequently VB programmers will see a crash because they passed arguments to the
procedure which the procedure could not handle! For example, passing a string when an
integer was needed will likely crash the system. The DLLs don't include extensive
protection in order to keep their own code size small and fast.
It is simple to say that if you pass the correct type of argument, that you won't see API
crashes. However, the documentation is not always clear exactly what argument type is
needed, plus when writing code it is all too common to simply make a mistake!
Finally, it is the case that most of the DLLs you'll want to use were written in C++. The
significance of this is that the data types in C++ do not map cleanly into the data types
that are used in Visual Basic. Here are some of the issues which you need to be aware of:
z Issue1
z Issue2
Okay, stay with me just a bit longer and we'll get into the actual use of some API. But
first, here is a list of other DLLs which have procedures that could be of use to you. These
DLLs will show up later in this tutorial when we get to the API which I recommend that
you consider for use in your own applications.
z Advapi32.dll - Advanced API services including many security and Registry calls
z Comdlg32.dll - Common dialog API library
z Lz32.dll - 32-bit compression routines
z Mpr.dll - Multiple Provider Router library
z Netapi32.dll - 32-bit Network API library
z Shell32.dll - 32-bit Shell API library
z Version.dll - Version library
z Winmm.dll - Windows multimedia library
z Winspool.drv - Print spoolder interface
Often, the documentation that you might find for an API will be written for a C++
programmer. Here's a short table which helps you translate the C++ variable type
declaration to its equivalent in Visual Basic:
We're not quite ready to get into using the API. Here is a scattering of issues/comments
about using API which you will want to be aware of:
z Declare
{ DECLARE in standard module are PUBLIC by default and be used anywhere
in your app
{ DECLARE in any other module are PRIVATE to that module and MUST BE
marked PRIVATE
{ Procedure names are CASE-SENSITIVE
{ You cannot Declare a 16-bit API function in VB6
z ALIAS
{ Is the "real" name of the procedure as found in the DLL
{ If the API uses string, you MUST use ALIAS with "A" to specify the correct
character set (A=ANSI W=UNICODE)
{ WinNT supports W, but Win95/Win98 do not
{ Some DLLs have illegal VB name, so you must use ALIAS to rename the
procedure
{ Can also be the ordinal number of the procedure
z Variable Type
{ Very few DLLs recognize VARIANT
{ ByRef is VB default
{ Most DLLs expect ByVal
{ In C documentation, C passes all arguments except arrays by value
{ AS ANY can be used but it turns off all type checking
z Strings
{ API generally require fixed length strings
{ Pass string ByVal means passing pointer to first data byte in the string
{ Pass string ByRef means passing memory address to another memory
addresss which refers to first data byte in the string
{ Most DLLs expect LPSTR (ASCIIZ) strings (end in a null character), which
point to the first data byte
{ VB Strings should be passed ByVal (in general)
{ VB uses BSTR strings (header + data bytes) - BSTR is passed as a pointer
to the header
{ DLL can modify data in a string variable that it receives as an argument -
WARNING: if returned value is longer than passed value, system error
occurs!
{ Generally, API do not expect string buffers longer than 255 characters
{ C & VB both treat a string array as an array of pointers to string data
{ Most API require you to pass the length of the string and to fill the string
wih spaces
z Arrays
{ Pass entire array by passing the first element of the array ByRef
{ Pass individual elements of array just like any other variable
{ If pass pass binary data to DLL, use array of Byte characters
z Callback Function
{ Use AddressOf to pass a user-defined function that the DLL procedure can
use
{ Must have specific set of arguments, AS DEFINED by the API procedure
{ Procedure MUST be in a .BAS module
{ Passed procedure must be As Any or As Long
z Passing a null value
{ To pass a null value - zero-length string ("") will not work
{ To pass a null value - use vbNullString
{ To pass a null value - change Type to Long and then use 0&
z Window Handle
{ A handle is simply a number assigned by Windows to each window
{ In VB, the handle is the same as the property hWnd
{ Handles are always Long variable types
z Callbacks
{ Some API can run one of you own VB functions. Your VB function is called a
"Callback"
{ VB supports callbacks with a function "AddressOf", which give the API the
location of the function to execute
Page 5 of 8
In case you don't know, VB6 comes with a tool to help you use API in your own
applications. The API Viewer is installed automatically with VB, and to use it go to the
Start/Programs/VB/Tools menu and select "API Viewer". The viewer actions much like my
own VB Information Center Code Librarian in that you can browse through the various
API, select one for copying to the clipboard, and then paste the declaration into your own
application's code window. You'll definitely want to try this out. The data file that comes
with the viewer if very extensive, listing 1550 API Declarations.
In my case I use API regularly, but I've never come close to using 1550 API. At best, I
barely have broken the 100 mark. It seems that for the most part I can get VB to do
whatever task I want without resorting to the API. However, in some cases you just can
do any better than a few lines of API code to get the job done! So, here's my own list of
useful tasks and the API needed to perform them:
Find prior Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal
instance of lpClassName As String, ByVal lpWindowName As String) As Long
EXE
Invert colors Declare Function InvertRect Lib "user32" Alias "InvertRect" (ByVal hdc As
of rectangle Long, lpRect As RECT) As Long
Get cursor Declare Function GetCursorPos Lib "user32" Alias "GetCursorPos" (lpPoint
position As POINTAPI) As Long
Text alignmentDeclare Function GetTextAlign Lib "gdi32" Alias "GetTextAlign" (ByVal hdc
As Long) As Long
Declare Function SetTextAlign Lib "gdi32" Alias "SetTextAlign" (ByVal hdc
As Long, ByVal wFlags As Long) As Long
Flash a title Declare Function FlashWindow Lib "user32" Alias "FlashWindow" (ByVal
bar hwnd As Long, ByVal bInvert As Long) As Long
Manipulate Declare Function BitBlt Lib "gdi32" Alias "BitBlt" (ByVal hDestDC As Long,
bitmaps ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight
As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long,
ByVal dwRop As Long) As Long
Declare Function PatBlt Lib "gdi32" Alias "PatBlt" (ByVal hdc As Long,
ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight
As Long, ByVal dwRop As Long) As Long
Declare Function StretchBlt Lib "gdi32" Alias "StretchBlt" (ByVal hdc As
Long, ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal
nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc
As Long, ByVal nSrcWidth As Long, ByVal nSrcHeight As Long, ByVal
dwRop As Long) As Long
Declare Function CreateCompatibleBitmap Lib "gdi32" Alias
"CreateCompatibleBitmap" (ByVal hdc As Long, ByVal nWidth As Long,
ByVal nHeight As Long) As Long
Declare Function CreateCompatibleDC Lib "gdi32" Alias
"CreateCompatibleDC" (ByVal hdc As Long) As Long
Drawing Declare Function MoveToEx Lib "gdi32" Alias "MoveToEx" (ByVal hdc As
functions Long, ByVal x As Long, ByVal y As Long, lpPoint As POINTAPI) As Long
Declare Function LineTo Lib "gdi32" Alias "LineTo" (ByVal hdc As Long,
ByVal x As Long, ByVal y As Long) As Long
Declare Function Ellipse Lib "gdi32" Alias "Ellipse" (ByVal hdc As Long,
ByVal X1 As Long, ByVal Y1 As Long, ByVal X2 As Long, ByVal Y2 As
Long) As Long
Get icon Function ExtractIcon Lib "shell32.dll" Alias "ExtractIconA" (ByVal hInst As
Declare Long, ByVal lpszExeFileName As String, ByVal nIconIndex As Long) As
Long
Screen captureDeclare Function SetCapture Lib "user32" Alias "SetCapture" (ByVal hwnd
As Long) As Long
Declare Function CreateDC Lib "gdi32" Alias "CreateDCA" (ByVal
lpDriverName As String, ByVal lpDeviceName As String, ByVal lpOutput
As String, lpInitData As DEVMODE) As Long
Declare Function DeleteDC Lib "gdi32" Alias "DeleteDC" (ByVal hdc As
Long) As Long
Declare Function BitBlt Lib "gdi32" Alias "BitBlt" (ByVal hDestDC As Long,
ByVal x As Long, ByVal y As Long, ByVal nWidth As Long, ByVal nHeight
As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long,
ByVal dwRop As Long) As Long
Declare Function ReleaseCapture Lib "user32" Alias "ReleaseCapture" ()
As Long
Declare Function ClientToScreen Lib "user32" Alias
"ClientToScreen" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long
Hopefully, this section of the tutorial has sparked some excitement! You should now see
that a door of tremendous proportions has been opened to you. You've begun to leave the
limitations of VB behind and joined the rest of the programming community who have
already been using the API for years. I hope to add quite a bit to this tutorial section so
check back often over the next few weeks.