What is an API?
API (Application Program Interface) is a function in DLL
(Dynamic link library). Windows operating system is based on a couple of DLLs,
such as Kernel32, User32, and GDI32. These APIs form the core part of Windows operating system. A
DLL is a collection of functions (APIs). DLL is loaded into memory when any of
the function is referred by an application. And once a DLL is loaded in to memory DLL remains in
memory and functions in DLL are dynamically bound to applications. That means when an application calls a function
in a DLL, the code of the function is not inserted into application (if it is
done, it is called as static linking) and instead at run time the code of
function is made available to application from DLL.
Dynamic linking is especially very efficient in Windows
operating system, as a collection of application can run at the same time and
may also use the same set of functions. So instead of placing one copy of each
function in each application, it is better to provide one copy of functions and
let all applications dynamically bind to functions.
Why to call APIs from Visual Basic?
Well, APIs are functions in DLLs and these APIs are what
applications use indirectly or directly to get the job done in Windows OS. For
instance, to show a window (a form in Visual Basic), to resize a window or to
add an item to list box Windows use APIs.
All that is fine. But why should a Visual Basic programmer worry about
all this? Because you say, I add an item using AddItem method of List box and show a form using Show method and so on. Accepted. But
that is not the entire programming.
There are tasks (as you will see later) that you cannot
accomplish just with commands of Visual Basic. You need to go beyond Visual
Basic and access these APIs to get the job done. As you can see in figure 15.1,
in most of the cases a command in Visual Basic ends up calling one of the APIs.
But in some cases you do not find any command in Visual Basic that does the job
for you. In this case you need to call APIs for VB application.
Figure 14.1:
Calling API from Visual Basic application.
However, to call an API you need to know everything about
API. First of all you should know whether there is any API that does the job
that Visual Basic cannot do for you.
Then you must know the number of parameters, type of each parameter and
the type of return value. The following
are the details you should have before you call an API.
¨
The name of API
¨
Details of Parameters such as number of
parameters and type of each parameter
¨
The library (DLL) in which API is available
¨
What type of value the API returns?
How to call an API from Visual Basic?
In order to call an API from VB, you have to take two steps,
they are :
¨
Declaring API using Declare Function or Declare
Sub statement.
¨
Calling API just like how you call a Visual
Basic function or procedure.
Declaring an API
The first thing that you have to do to call an API is
declare it in your project. This is generally done in code module. However, it
can be done in General/Declarations of any module.
Here is the complete syntax of Declare statement.
Declare
{Function|Sub} FunctionName Lib “LibraryName”
[Alias
“Aliasname”] (Argument
list) [As Returntype]
The following sections will explain how to use each part of
the syntax.
Function or Sub
Specifies whether API returns a value or not. If API returns
a value then it is to be declared as a Function otherwise as a Subroutine.
(Sub)
FunctionName
This is the name that you want to use to call API in your
program. This name may be different from the actual name of the API. In this
case, you also have to specify Alias
and give actual name as the alias.
Lib “LibraryName”
Specifies the name of the library (DLL) in which the
declared API is existing. This indicates
to Visual Basic where to look for API. The library should be available for
Visual Basic. If it is not a standard library such as Kernel32, User32 or GDI32
then it is better you specify the complete path.
Note: Suffix 32 for a
library name denotes 32-bit library. If you are using 16-bit library, i.e. for
windows 3.x then you just have to give Kernel and not Kernel32.
Alias “AliasName”
Specifies the actual name of API when FuctionName is different from actual name. This enables you to
change the name of API in your program so that name is more easier to call or
more meaningful.
Argument List
Specifies the list of arguments (also called as parameters).
For each argument you have to specify how argument is passed – by value or by
reference, the name of argument and type of argument.
An argument is passed either by value or by reference. When
a value is passed by value, its value is passed to function and changes made to
the argument that corresponds to the parameter will not effect the value
passed. That means, for example, if you
pass variable X to a function by value then changes made by function argument will not effect the value of
variable X. On the other hand, if an
argument is passed by reference, the reference(address) of the variable is
passed to function and as the result any changes made to argument in function will
effect the value of variable that is passed to function.
Keyword ByVal is used to specify pass by
value and ByRef is used to specify pass by reference.
Passing Strings
For strings, ByVal means convert a Visual Basic
string to C string. It doesn’t mean that the string is passed by value. String
is always passed by reference as its address is passed and not the value.
Also note, that when you pass a string, you have to create
required amount of space in Visual Basic string before it is passed to an API.
Because APIs use C string convention, which assumes that the string points the
location that is allocated to it.
Here is an example:
‘ declare a string of 255
locations
Dim st as string * 255
‘ call API and pass string
to it
V = APIFunction(st)
The above example can also be rewritten in this way:
‘ Declare a normal Visual Basic string
Dim st as string
St = space (255) ‘
create space for 255 spaces
V = APIFunction (st)
Data Types used in API calls
When we deal with APIs we deal with C data types. So we have
to convert Visual Basic data types to C data types. The following table lists out the C data
types and corresponding Visual Basic data types.
C Data Type
|
Size
|
Visual Basic Data Type
|
BOOL
|
32
|
Boolean
|
BYTE
|
8
|
Byte
|
Char
|
8
|
String * 1
|
Double
|
64
|
Double
|
DWORD
|
32
|
Long
|
Float
|
32
|
Single
|
HANDLE
|
32
|
Long
|
Int
|
32
|
Long
|
Long
|
32
|
Long
|
LPTSTR
|
32
|
No equivalent
|
LPCTSTR
|
32
|
No equivalent
|
Short
|
16
|
Integer
|
UINT
|
32
|
Long
|
ULONG
|
32
|
Long
|
USHORT
|
16
|
Integer
|
UCHAR
|
8
|
String * 1
|
WORD
|
16
|
Integer
|
Table 14.1: C
data types and their equivalent data types in Visual Basic.
What is a Handle?
As long as you use Visual Basic command you live under
cover. You do not know what is really happening outside Visual Basic. But the
moment you decide to call an API, you need to understand what is happening under
the hood. Handle is one of them. VB allows you to access object using object
oriented syntax. But what’s really happening in Windows is concealed.
Every window is assigned and identified by a handle, which
is a 32 bit number ( long integer). Windows OS identifies windows using handle.
Remember each control, such as Text box, Command button, is also a window.
These windows are called as control windows. So each control and form has a
handle using which Windows OS identifies the controls and forms.
If you ever have to take the handle of a control or a form
in Visual Basic, use hWnd property
of the form or control. This property returns the handle of the form or control
that is assigned by Windows OS.
Getting API declaration from WIN32API.TXT
When you want to get declarations of standard APIs, you can
use WIN32API.TXT text file. It contains Visual Basic declarations for all
standard APIs, constants, and Types.
Use program API Text View to load the text file and get
required declarations. API Text Viewer is an Add-in. So it is to be first added
to VBIDE.
You can run it using the following steps:
1.
Select Add-Ins
menu and choose Add-In Manager
option.
2.
Visual Basic displays Add-In Manager as shown in figure 14.2.
3.
Double click on VB
6 API Viewer to load it into VBIDE.
4.
Then click on
Ok to close Add-In Manager window.
This adds API Viewer to Add-Ins menu.
5.
Now again select Add-Ins
menu and select API Viewer option.
6.
API Viewer starts. It doesn’t display anything
initially. See figure 14.3.
7.
Select File->
Load Text File… option and select WIN32API.TXT
file.
8.
API Viewer displays all the function declarations form
WIN32API.TXT as shown in figure 14.2.
Figure 14.2:
Loading Visual Basic 6 API Viewer.
Figure 14.3: API
Viewer displaying WIN32API.TXT.
Sample Application
We will develop an application to display information
regarding the following in different tabs.
¨
Windows Operating system
¨
Processor and Memory
¨
Selected Disk
Each tab displays information regarding one of the above
mentioned topics. We will use TabStrip
control to displays multiple tabs.
What is TabStrip Control?
TabStrip control is used to display multiple pages of
information in one page by displaying one page at a time. Each page is called
as a tab. Each tab is like a mini-form. Each tab contains a title. When user
clicks on the title of the tab, the page that corresponds to the tab will be
displayed.
To load TabStrip
control into project:
1. Select
Project -> Components
2.
In Components dialog box, check Microsoft Windows Common Controls 6.0.
3. Click
on OK.
When a TabStrip control is placed on the form, it has only
one tab. You need to create additional tabs, if you want, using the following
procedure.
To create tabs in
TabStrip control:
1.
Invoke property pages of TabStrip control by selecting Properties option in Context menu.
2.
Select Tabs tab
in Property Pages.
3.
Click on Insert
Tab button to add a new tab. Repeat the process for each tab.
Note: TabStrip is not
a container control. You have to use other containers such as Frame control to
place controls on Tabs of TabStrip control.
We will understand more about TabStrip control, as we will
proceed.
Designing User Interface
As I have already mentioned in this application user
interface is consisting of TabStrip control with three different tabs. First we
will create three tabs using the procedure explained above, and then change Caption property of first tab to "Windows Information", second tab
to "System Information" and third tab to "Disk
Information".
See figure 14.4, 14.5 and 14.6 to know how these three tabs
appear at runtime, what is the information displayed in each of these tabs and
how controls are arranged.
Figure 14.4:Windows
Information Tab.
Figure 14.5: System Information Tab.
Figure 14.6: Disk
Information tab displaying information regarding selected drive.
Follow the steps given below to create required controls:
Create a Frame and change the following properties
Name Frames
Caption ""
(Null string)
Index 1
Index property is
used to create a control array. Control array concept explained in chapter 8. A
control array is a collection of controls that have the same name but different
values for Index property. For all
controls in a control array there is only one event procedure for each event.
Place second frame and change the following properties.
Name Frames
Index 2
Caption ""
(Null string)
Place one more frame (third frame) and change the following
properties.
Name Frames
Index 3
Caption ""
(Null string)
Adding Control to Frames
After frames are added, place required controls on each
frame. See figure 17.4, 17.5 and 17.6 for layout of the controls. Most of the
controls are Labels. We set BorderStyle property to 1-Fixed
Single for labels that display the values.
However, in third frame (Disk information), we have to place
a DriveListbox control, which allows user to select
the drive for which the user wants to get details.
Adding a module to contain API declarations
Generally we place all API declarations in a code module.
Now we add a code module to the project using Project -> Add Module.
Add the Type declarations shown in table 14.2 using API
Viewer.
To get the Type
declaration from API Viewer, do the following:
1. Load
Win32Api.txt using File-> Load
Text File…
2.
Select Types
in API Types dropdown list box.
3.
Select one type at a time and click on Add button to add the Type declaration
to Selected Items.
4.
Repeat the process until all types listed in table 14.2
are added.
At the end of the above process all three Type declarations
should be copied to General/Declarations of the code module, as shown in
listing 14.1.
Here is the list of Types taken from API Viewer and what
they contain.
Type
|
Meaning |
MEMORYSTATUS
|
Contains fields that return
the information regarding total physical memory, available memory etc.
|
SYSTEM_INFO
|
Contains fields that return
information regarding number of processors, type of processor etc.
|
OSVERSIONINFO
|
Contains fields that return
information regarding platform id, major and minor version etc.
|
Table 14.2: Type
declarations required for sample application.
Add API declarations for the APIs listed in table 14.3 using
API Viewer.
To add API
declarations, do the following:
1.
Select Declares
in API Type dropdown list box.
2.
Select each function listed in table 14.3 and click on Add button to send its declaration to
Selected Items.
To transfer selected
items to code module in Visual Basic project:
1.
Once all Types and Declarations are copied to Selected
Items, click on Copy button to copy
selected items to clipboard.
2. Then
activate code module in Visual Basic project and select General/Declarations.
3.
Choose Edit->Paste
in VB IDE to paste Type declarations and API declarations that are copied into
clipboard, into code module.
Public Type MEMORYSTATUS
dwLength As Long
dwMemoryLoad As
Long
dwTotalPhys As Long
dwAvailPhys As Long
dwTotalPageFile As
Long
dwAvailPageFile As
Long
dwTotalVirtual As
Long
dwAvailVirtual As
Long
End Type
Public Type SYSTEM_INFO
dwOemID As Long
dwPageSize As Long
lpMinimumApplicationAddress As Long
lpMaximumApplicationAddress As Long
dwActiveProcessorMask As Long
dwNumberOrfProcessors As Long
dwProcessorType As
Long
dwAllocationGranularity As Long
dwReserved As Long
End Type
Public Type OSVERSIONINFO
dwOSVersionInfoSize
As Long
dwMajorVersion As
Long
dwMinorVersion As
Long
dwBuildNumber As
Long
dwPlatformId As
Long
szCSDVersion As
String * 128 'Maintenance string for PSS usage
End Type
Public Declare Function GetWindowsDirectory
Lib "kernel32" Alias
"GetWindowsDirectoryA" (ByVal lpBuffer As String, ByVal nSize
As Long) As Long
Public Declare Function GetTempPath
Lib "kernel32" Alias "GetTempPathA" (ByVal nBufferLength As
Long, ByVal lpBuffer As String) As Long
Public Declare Sub GetSystemInfo Lib "kernel32"
(lpSystemInfo As SYSTEM_INFO)
Public Declare Function GetUserName
Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As
String, nSize As Long) As Long
Public Declare Function GetComputerName
Lib "kernel32" Alias "GetComputerNameA" (ByVal lpBuffer As
String, nSize As Long) As Long
Public Declare Function GetDiskFreeSpace
Lib "kernel32" Alias "GetDiskFreeSpaceA" (ByVal
lpRootPathName As String, lpSectorsPerCluster As Long, lpBytesPerSector As
Long, lpNumberOfFreeClusters As Long, lpTotalNumberOfClusters As Long) As Long
Public Declare Function GetVersionEx
Lib "kernel32" Alias "GetVersionExA" (lpVersionInformation
As OSVERSIONINFO) As Long
Public Declare Function GetVolumeInformation
Lib "kernel32" Alias "GetVolumeInformationA" (ByVal
lpRootPathName As String, ByVal lpVolumeNameBuffer As String, ByVal
nVolumeNameSize As Long, lpVolumeSerialNumber As Long, lpMaximumComponentLength
As Long, lpFileSystemFlags As Long, ByVal lpFileSystemNameBuffer As String,
ByVal nFileSystemNameSize As Long) As Long
Public Declare Sub GlobalMemoryStatus
Lib "kernel32" (lpBuffer As MEMORYSTATUS)
Public Declare Function GetDriveType Lib "kernel32"
Alias "GetDriveTypeA" (ByVal nDrive As String) As Long
Listing 14.1: Type declarations and API declarations.
Here is the list of functions
used in the sample application and what they do?
API
|
Meaning
|
GetWindowsDirectory
|
Returns the name of the
directory into which Windows OS is installed.
|
GetTempPath
|
Returns path for temporary
directory (temp).
|
GetSystemInfo
|
Returns information regarding
system into a variable of SYSTEM_INFO type.
|
GetUserName
|
Returns the name of the
current user.
|
GetComputerName
|
Returns the name of the
computer.
|
GetDiskFreeSpace
|
Returns the space details of
the given disk.
|
GetVersionEx
|
Returns details regarding
windows version into a variable of type OSVERSIONINFO.
|
GetVolumeInformation
|
Returns the details of the
specified volume.
|
GlobalMemoryStatus
|
Returns memory statistics into
a variable of type MEMORYSTATUS.
|
GetDriveType
|
Returns the type of the
specified drive.
|
Table 14.3: APIs used in the sample application.
Writing code to get required information
Write three user-defined functions,
GetSystemInformation, GetDiskInformation, and GetWindowsInformation. These user-defined functions call APIs and
get the required information. These functions also populate corresponding
labels with the required information. Listing 14.2 shows the code for these
three user-defined functions.
Public Sub
GetWindowsInformation()
Dim winfo As
OSVERSIONINFO
Dim wdir As String * 255
Dim wlen As Long
' get windows platform
wlen =
GetWindowsDirectory(wdir, 255)
lblwindir.Caption =
Left(wdir, wlen)
wlen = GetTempPath(255,
wdir)
' get
lbltemppath.Caption =
Left(wdir, wlen)
winfo.dwOSVersionInfoSize = Len(winfo)
wlen =
GetVersionEx(winfo)
With winfo
If .dwPlatformId = 0
Then
lblwinplatform.Caption = "Windows 3.X"
ElseIf .dwPlatformId
= 1 Then
lblwinplatform.Caption = "Windows 95"
ElseIf .dwPlatformId
= 2 Then
lblwinplatform.Caption = "Windows NT"
Else
lblwinplatform.Caption = "Unknown"
End If
lblversion.Caption =
.dwMajorVersion & "." & .dwMinorVersion
End With
End Sub
Public Sub
GetSystemInformation()
Dim sinfo As SYSTEM_INFO
Dim minfo As MEMORYSTATUS
Dim slen As Long
Dim cname As String * 100
Dim rcode As Long
' call API to get
information
GetSystemInfo sinfo
With sinfo
lblprocessor.Caption = .dwProcessorType
End With
' get memory
information
minfo.dwLength =
Len(minfo)
GlobalMemoryStatus
minfo
With minfo
lbltotalmemory.Caption = .dwTotalPhys
lblfreememory.Caption = .dwAvailPhys
lblutilization.Caption = .dwMemoryLoad
End With
' get computer name
slen = 100
rcode =
GetComputerName(cname, slen)
lblcomputername.Caption = Left(cname, slen)
' get current user
name
slen = 100
rcode =
GetUserName(cname, slen)
lblcuruser.Caption =
Left(cname, slen)
End Sub
Private Sub
Drive1_Change()
GetDiskInformation
Left(Drive1.drive, 1) & ":\"
End Sub
Private Sub Form_Load()
x = TabStrip1.Left +
40
Y = TabStrip1.Top +
300
For i = 1 To 3
frames(i).Visible
= False
frames(i).Move x,
Y, TabStrip1.Width, TabStrip1.Height - 300
Next
frames(1).Visible =
True
' get the information
GetWindowsInformation
GetSystemInformation
' get current drives
information
GetDiskInformation
Left(CurDir, 3)
End Sub
Private Sub
TabStrip1_Click()
' make all frames
invisible
For i = 1 To 3
frames(i).Visible =
False
Next
' make the selected
frame visible
frames(TabStrip1.SelectedItem.Index).Visible = True
End Sub
Public Sub
GetDiskInformation(drive As String)
Dim vname As String * 100
Dim vserial As Long
Dim mcl As Long
Dim vfsys As Long
Dim vfsysname As String * 100
Dim x As Long
Dim dtype As Long
Dim dt As String
' get volume
information
x =
GetVolumeInformation(drive, vname, 100, vserial, mcl, _
vfsys, vfsysname,
100)
lblvolume.Caption =
vname
lblserial.Caption =
vserial
lblFilesystem.Caption
= vfsysname
' get disk
information
x =
GetDiskFreeSpace(drive, nspc, bps, fc, tnc)
lblsectors.Caption =
nspc
lblbytespersector.Caption = bps
lblfreeclusters.Caption = fc
lblclusters.Caption =
tnc
' get drive type
dtype =
GetDriveType(drive)
Select Case dtype
Case 0
dt =
"Unknown"
Case 1
dt = "Not Available"
Case 2
dt =
"Removable"
Case 3
dt =
"Fixed"
Case 4
dt =
"Remote"
Case 5
dt =
"CDROM"
Case 6
dt =
"RAM Disk"
End Select
lbldrivetype.Caption
= dt
End Sub
Listing 14.2: Code for Sample application.
When you run the project, you will see the first tab
(Windows Information) as we have shown that in Load event of the form. Whenever user clicks on any other tab, Click event of TabStrip control occurs.
We take Index of the selected
item tab and use that index to display the frame that has the same index. See
the code for Click event of TabStrip1 (see listing 14.1) for complete code.
Whenever user selects a different drive letter in DriveListBox
of Disk Information tab, we invoke GetDiskInformation by sending the
name of the selected drive.
The ability to call an API from Visual Basic application is
a very important facility. In several cases you find that what you want, cannot
be done in Visual Basic and you need to call an API. What we have seen in our
sample application is a tiny list of APIs. There are thousands of APIs. Try to
understand as many APIs as possible. Because, using APIs you can push limits.