Discovering the API Using Visual Basic 6 and Visual Basic .NET

Discovering the API Using Visual Basic 6 and Visual Basic .NET

As a Visual Basic programmer, you are likely to encounter the Windows API. This article will explain in detail what the Windows API is, as well as the different implementations of the API in Visual Basic 6 and Visual Basic .NET.

Definition of the Windows API

The Windows API is a set of several hundred functions and subroutines that are located in a set of files called Dynamic Link Libraries (DLLs). You can make a function from the Windows API available to your Visual Basic program by declaring the function to be callable from your program. You can then use the Windows API function as you would any built-in Visual Basic function or a function that you have written yourself.

End users cannot access these functions; however, programmers can access the code written in the DLLs through the API and use this code in their programs. This enables you to use existent code in the DLLs and save you time in the programming development cycle. The advantage of using Windows APIs in your code is that they can save development time because they contain dozens of useful functions that are already written and waiting to be used. The disadvantage is that Windows APIs can be difficult to work with and unforgiving when things go wrong.

Windows API Library Files

The Dynamic Link Library (DLL) files that make up the Windows API are commonly located in the Windows SYSTEM subdirectory. These files are found on every PC that is running Windows, so you don't have to worry about including them if you create a set of setup disks for distribution. The three Windows DLLs are User32.DLL, Kernel32.DLL , and GDI32.DLL.

Several smaller DLLs, known as Extension DLLs, provide functions in addition to those found in the three major DLLs. Some useful extension DLLs include the following:

Advapi32.dll Advanced API services library supporting numerous APIs, including many security and Registry calls
Comdlg32.dll Common dialog API library
Lz32.dll 32-bit compression routines
Mpr.dll Multiple Provider Router library
Netapi32.dll 32-bit Network API library
Shell32.dll 32-bit Shell API library
Version.dll Version library
Winmm.dll Windows multimedia library
Winspool.drv Print spooler interface that contains the print spooler API calls

USER32.DLL

Contains functions that relate to managing the Windows environment, such as:

  1. Handling messages between windows
  2. Managing cursors
  3. Managing menus
  4. Handling other non-display functions

GetCursorPos, SetWindowPos, GetParent, GetActiveWindow, SendMessage

GDI32.DLL

Graphics Device Interface library contains functions that help manage output to different devices, especially the screen.

BitBlt, DeleteObject, RoundRect, SelectObject, StretchBlt

KERNEL32.DLL

Contains functions that manage low-level operating system functions. These include:

  1. Memory Management
  2. Task Management
  3. Resource Handling
  4. File and Directory Handling
  5. Module Management

GetSystemDirectory, GetTempFileName, GetModuleFileName, GetVersionEx

The following pages will explain the usage of the Windows API within Visual Basic 6 and Visual Basic .NET.

Discovering the API Using Visual Basic 6 and Visual Basic .NET

Visual Basic 6 Implementation of the Windows API

To include a Windows API function in your VB6 programs, use the Declare statement to "declare" the function to be part of your program. The Declare statement is added to the General Declarations section of either a standard module or a form. If the Declare statement is added to a standard module, the function is considered Public and can be called from anywhere in your application. If the Declare statement is added to the General Declarations section of a form, the function is local to that form and can be called only from within that form. In the latter case, you need to include the Private keyword.

Syntax

The syntax of the Declare statement depends on whether or not the procedure you call returns a value. If the procedure does return a value, you use the Function form of the Declare statement:

[Public | Private] Declare Function publicname Lib "libname" _
[Alias "alias"] [([[ByVal | ByRef] argument [As Type] _
[, [Byval | ByRef] argument [As Type]] ...])] [As Type]

Example

Private Declare Function CopyFile Lib "kernel32" Alias "CopyFileA" _
(ByVal lpExistingFileName As String, ByVal lpNewFileName As String, _
ByVal bFailIfExists As Long) As Long

More information on the CopyFile API

If the procedure does not return a value, you use the Sub form of the Declare statement:

[Public | Private] Declare Sub publicname Lib "libname" _
[Alias "alias"] [([[ByVal | ByRef] argument [As Type] _
[, [ByVal | ByRef] argument [As Type]] ...])]

Example

Public Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" (pDst As Any, pSrc As Any, ByVal ByteLen As Long)

More information on the CopyMemory API

Public or Private

Define the scope of the function, and determines whether or not it can be used outside of a module in which it is declared.

publicname

The name of the function is defined by the publicname parameter.

Lib "libname"

Defines the DLL library in which it is located.

Alias "alias"

Some Windows API functions are named using characters that are illegal in Visual Basic 6; for example, the underscore( _ ). Trying to reference a name that starts with an underscore in Visual Basic 6 generates an error. A way to avoid the error is to "alias" the name in the declare statement.

Example

To use the _lopen API function, the following Declare statement will work:

Declare Function lopen Lib "kernel32" Alias "_lopen" _
(ByVal lpPathname As String, ByVal ireadWrite As Long) As Long

The Windows API function _lopen is renamed lopen so that it is recognised as a legal name in Visual Baisc 6. The Alias keyword lets Visual Basic 6 know that the function it is really working with is _lopen.

Another use of the Alias keyword is to change the name of a function, usually for readability reasons. For example, the _lopen function might be renamed to OpenExistingFile as in:

Declare Function OpenExistingFile Lib
"kernel32" Alias "_lopen" (ByVal lpPathname As String, ByVal
ireadWrite As Long) As Long

More info on the _lopen API function

Sometimes, a Windows API function can be named with its ordinal number rather than a more descriptive text name. Using an ordinal number requires fewer system resources, so it is slightly more efficient than using a text name.

If you want to refer to a function by its ordinal number, use the Alias keyword to refer to the number, as in:

Declare Function GetWindowsDirectory Lib "kernel32" Alias "#432" _
(ByVal lpBuffer As String, ByVal nSize As Long) As Long

To find the ordinal number of a Windows API function, you must use a utility program such as Dumpbin.exe, which is included with Microsoft Visual C++.

ByVal or ByRef

Passing an argument by value means that a copy of the argument is sent to the function. Passing arguments by value means that the function cannot change the value of the actual argument because it is only working with a copy of the argument.

Passing an argument by reference means that the function is actually passing a 32-bit pointer to the memory address where the value of the argument is stored. When an argument is passed by reference, it actually is possible for the function to change the value of the argument because the function is working with the actual memory address where the argument's value is stored, and not just a copy of the argument's value.

Data Types (As Type)

The functions that make up the Windows API are written in C. Here are some of the most common data types you will encounter when using the API.

  1. Integer: Used for 16-bit numeric arguments.
    Equivalent to the short, unsigned short and WORD data types in C
  2. Long: Used for 32-bit arguments.
    Corresponds to the C data types: int, unsigned int, unsigned long, DWORD, and LONG.
  3. String: Equivalent C Data type is LPSTR
  4. Structure: A Structure is the C++ equivalent to a Visual Basic UDT (User Defined Type)
  5. Any: Some functions accept more than one data type for the same argument

Here's a short table that helps you translate the C++ variable type declaration to its equivalent in Visual Basic:

C++ Variable Visual Basic Equivalent
ATOM ByVal variable as Integer
BOOL ByVal variable as Long
BYTE ByVal variable as Byte
CHAR ByVal variable as Byte
COLORREF ByVal variable as Long
DWORD ByVal variable as Long
HWND ByVal variable as Long
HDC ByVal variable as Long
HMENU ByVal variable as Long
INT ByVal variable as Long
UINT ByVal variable as Long
LONG ByVal variable as Long
LPARAM ByVal variable as Long
LPDWORD variable as Long
LPINT variable as Long
LPUINT variable as Long
LPRECT variable as Type any variable of that User Type
LPSTR ByVal variable as String
LPCSTR ByVal variable as String
LPVOID variable As Any use ByVal when passing a string
LPWORD variable as Integer
LPRESULT ByVal variable as Long
NULL ByVal Nothing or ByVal 0& or vbNullString
SHORT ByVal variable as Integer
VOID Sub Procecure not applicable
WORD ByVal variable as Integer
WPARAM ByVal variable as Long

User-defined types can be defined in a Visual Basic application as shown in this code snippet:

Type Customer
   Customer_ID As Integer
   Customer_Name As String
End Type

API Viewer

The WinAPI Viewer application enables you to browse through the declares, constants, and types included in any text file or Microsoft® Jet database. After you find the procedure you want, you can copy the code to the Clipboard and paste it into your Visual Basic application.

To view an API file

  1. From the Add-Ins menu, open the Add-In Manager, and load WinAPI Viewer.
  2. Click WinAPI Viewer from the Add-Ins menu.
  3. Open the text or database file you want to view.

To load a text file into the viewer, click File | Load Text File, and choose the file you want to view.

Note: If the text file you are opening is large, you may be prompted to convert the file to a database. Doing so will make the WinAPI Viewer much faster.

To optimize speed, you can convert the Win32api.txt file, or any large text file containing the information you want, into a Microsoft Access database file. Converting the text files to database files has numerous advantages primarily because it is much faster to display the list when opening a database than when opening a text file.

If the file you are loading is very large, WinAPI Viewer may automatically prompt you to convert the file to a database to optimize speed. To do so, follow the directions in the message box that appears. You can choose to convert any text file you are loading, however.

To convert a text file to a database file

  1. Start the WinAPI Viewer application.
  2. From the File menu, select Load Text File, and open the .txt file you want to convert.
  3. From the File menu, select Convert Text to Database.
  4. Choose a file name and location for your database file; then click OK.

To load a database file, click File | Load Database File

Select the type of item you want to view from the API Type list: Constants, Declares, or Types.

Now, take a look at how Visual Basic .NET implements the API.

Discovering the API Using Visual Basic 6 and Visual Basic .NET

Visual Basic .NET Implementation of the Windows API

Windows API calls were an important part of Visual Basic programming in the past, but are seldom necessary with Visual Basic .NET. Whenever possible, you should use managed code from the .NET Framework to perform tasks instead of Windows API calls. The advantage of using Windows APIs in your code is that they can save development time because they contain dozens of useful functions that are already written and waiting to be used.

You can access the Windows API in Visual Basic.NET in two ways:

  1. Declare statement
  2. DLLImport

Overview of the Declare Statement

Syntax

[Public | Private] Declare [Ansi | Unicode | Auto] Sub | _
Function <name> Lib "<library"> [Alias "<alias>"] [([argument list])]

Example

Private Declare Auto Function CopyFile Lib "kernel32" _
Alias "CopyFileA" (ByVal lpExistingFileName As String, _
ByVal lpNewFileName As String, ByVal bFailIfExists As Long) _
As Long

More information on the CopyFile API

Public or Private

Defines the scope of the function, and determines whether or not it can be used outside of a module in which it is declared.

Auto

The Auto modifier instructs the runtime to convert the string based on the method name according to common language runtime rules (or alias name if specified).

Other modifiers that can be included instead of Auto include Ansi and Unicode:

  • Ansi: Converts all strings to ANSI values. If no modifier is specified, Ansi is the default.
  • Unicode: Converts all strings to Unicode values.

Name

The name of the function is defined by the name parameter.

Lib

Specifies the Lib keyword followed by the name and location of the DLL that contains the function you are calling. You do not need to specify the path for files located in the Windows System directories.

Alias

Use the Alias keyword if the name of the function you are calling is not a valid Visual Basic procedure name, or conflicts with the name of other items in your application. Alias indicates the true name of the function being called.

Argument list

Declares the arguments and their data types. Data types that Windows uses do not correspond to Visual Studio data types. Visual Basic does a lot of the work for you by converting arguments to compatible data types, a process called marshaling. You can explicitly control how arguments are marshaled by using the MarshalAs attribute defined in the System.Runtime.InteropServices namespace.

Previous versions of Visual Basic allowed you to declare parameters As Any, meaning that data of any data type could be used. Visual Basic .NET requires that you use a specific data type for all declare statements.

Datatype Differences

The following table lists data types used in the Win32 API and C-style functions. Many unmanaged libraries contain functions that pass these data types as parameters and return values. The third column lists the corresponding .NET Framework built-in value type or class that you use in managed code. In some cases, you can substitute a type of the same size for the type listed in the table.

Unmanaged type in Wtypes.h Unmanaged C language type Managed class name
HANDLE void* System.IntPtr
BYTE unsigned char System.Byte
SHORT short System.Int16
WORD unsigned short System.UInt16
INT int System.Int32
UINT unsigned int System.UInt32
LONG long System.Int32
BOOL long System.Int32
DWORD unsigned long System.UInt32
ULONG unsigned long System.UInt32
CHAR char System.Char
LPSTR char* System.String or System.StringBuilder
LPCSTR Const char* System.String or System.StringBuilder
LPWSTR wchar_t* System.String or System.StringBuilder
LPCWSTR Const wchar_t* System.String or System.StringBuilder
FLOAT Float System.Single
DOUBLE Double System.Double

In Visual Basic .NET, the Type keyword is not supported. Structure is the keyword for declaring user-defined types in Visual Basic .NET, as follows:

Structure Customer
   Customer_ID As Integer
   Customer_Name As String
End Structure

In Visual Basic .NET, user-defined types are called structures. Structures are in many ways similar to a class. Structures can have constructors, methods, properties, and so on. Structures, however, do not support inheritance. Also, structure variables are value type variables, and they do not use heap memory. A structure inherits from the System.ValueType object. Classes, on the other hand, are reference type variables. Instances of classes are normally allocated on heap memory. Classes support inheritance.

As Any

In Visual Basic .NET, overloaded Declare statements have to be defined, and it allows a native API to be called with two or more data types.

DLLImport

Indicates that the attributed method is exposed by an unmanaged dynamic-link library (DLL) as a static entry point. The DllImport attribute provides the information needed to call a function exported from an unmanaged DLL. As a minimum requirement, you must supply the name of the DLL containing the entry point. The DllImport attribute specifies that the target method is an export from an unmanaged shared library such as the Win32 API.

Example

Imports System.Runtime.InteropServices
<DllImport("KERNEL32.DLL", EntryPoint := "MoveFileW", _
   SetLastError := True, CharSet := CharSet.Auto, _
   ExactSpelling := True, _
   CallingConvention := CallingConvention.StdCall)> _
   Public Shared Function MoveFile(src As String, dst As String) _
   As Boolean
' Leave function empty - DLLImport attribute forwards calls to
' MoveFile to
' MoveFileW in KERNEL32.DLL.
End Function

More Info on DLLImport

API Viewer 2004

Inserting API calls can get quite difficult. Luckily, the API Viewer 2004 makes inserting API calls much easier. You can download the API Viewer 2004 here.

Conclusion

The Windows API is a vast topic. There is still so much more to the Windows API, but this article will make using the Windows API in Visual Basic .NET easier.



About the Author

Hannes du Preez

Hannes du Preez is a Microsoft MVP for Visual Basic. He is a trainer at a South African-based company. He is the co-founder of hmsmp.co.za, a community for South African developers.

Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Instead of only managing projects organizations do need to manage value! "Doing the right things" and "doing things right" are the essential ingredients for successful software and systems delivery. Unfortunately, with distributed delivery spanning multiple disciplines, geographies and time zones, many organizations struggle with teams working in silos, broken lines of communication, lack of collaboration, inadequate traceability, and poor project visibility. This often results in organizations "doing the …

  • With JRebel, developers get to see their code changes immediately, fine-tune their code with incremental changes, debug, explore and deploy their code with ease (both locally and remotely), and ultimately spend more time coding instead of waiting for the dreaded application redeploy to finish. Every time a developer tests a code change it takes minutes to build and deploy the application. JRebel keeps the app server running at all times, so testing is instantaneous and interactive.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds