Accessing the
API 32 functions and C structures
from Visual dBASE 7.01
by Nicolas Martin
Acknowledgments: I would like to thank especially Romain Strieff and Dan Howard for their advice and their kind contribution to the proofread of this article.

Introduction

Visual dBASE can do almost whatever you can imagine, thanks to the richness of its functions and language. This richness comes from a substantial heritage brought by the former versions since its origins as the first databases language for PCs. The arrival of the latest Windows versions, the introduction of the OOP as the backbone for the data management and the powerful user interface, have endowed the product with the best capabilities to design excellent quality databases applications.

A Visual dBASE application is above all a Windows application. In other words, it complies to the rules and meet the requirements of this operating system. In order to keep a certain homogeneity and provide a good integration within the system, it is necessary for dBASE to use and run all the resources and libraries that this operating system provides to build an application. These resources are provided through the Windows Application programming interface commonly referred to as the Windows API.

Visual dBASE, through all of its up to date visual tools is able to perform most of the complex operations necessary to build such an application, while offering an excellent compromise between the complexity of API and the simplicity and richness of its capabilities. Being a Windows application, a Visual dBASE application already uses many functions from the Windows 32 API - but the main advantage of such a tool is that it can transform in a more accessible way a domain initially reserved to specialists; and especially, it allows us to concentrate our development efforts on the application characteristics, instead of the system programming.

In order to cope with particular situations, it happens sometimes that some options or functions are not directly available under the Visual dBASE tools or language. In that case, it is necessary to leave the user-friendly environment and dive into the mystery of Windows programming and its API 32 functions.

The contents of this article contain:

  1. Introduction
  2. API 32 functions presentation
  3. Basics of C language
  4. Strings and pointers in C
  5. Prototyping the API functions in Visual dBASE
  6. API 32 constants declarations
  7. Running an API 32 function
  8. C structures and Visual dBASE
  9. Creating an executable including the structure files
  10. Going further with the structures
  11. Conclusion

API 32 functions presentation

The Visual dBASE designers have introduced in the product a way to access the 32 bit functions contained in DLL files. Visual dBASE 7.01 can only access 32 bit libraries, as opposed to its eldest 5.7 that knows only about the 16 bit world, to keep compatibility with Win 3.1.

DLL files are binary files containing code and/or resources (bitmaps, icons) which can be shared by many applications at the same time. Windows itself is built around these DLLs which we can use in our own applications.

These functions are called in Visual dBASE “external functions”. The detailed use of such a function is in the on line help. Look for the word “extern” or key in help extern in the command window to find more information.

We are going to see how to use these functions and point specifically to those offered by the Win 32 API in order to understand their requirements and limitations. The purpose is, after all, to acquire a technique that will enable us to operate these Windows API 32 functions.

This is not the only difficulty when getting into the Win 32 API, because, generally, the key point will consist in finding, among the numerous available API functions, the one that will perform the desired action.

All versions of Visual dBASE 7.01 includes a Windows help file named “Win 32 Programmer's Reference”. I will refer to it as the “API 32 OLH” (on-line help).

We will first consider, as an example for this article, the API 32 function named : ShellExecute. This function can run commands and launch other applications from within Visual dBASE without viewing the DOS window that appears when executing the RUN() function.

Find this function in the API 32 help file. Look for ShellExecute. You will get the following page :

Let's look in detail at the different parts of this function, pointed in red :

The types used in Win 32 API functions is an important topic that requires us to get some basic notions of the C programming language. Let's get a little bit into this.

Basics of C language

The Windows programming interface can appear unfriendly at first glance, especially when compared to a high level programming language like Visual dBASE. Actually, Windows itself has been designed and built in C, initially to be used by C programmers. Thus, the main difficulty for using that API is to adapt to that language's particularities.

The purpose of this chapter is not to learn C, not even C++. The concern here is to get the few elements of that language that will enable us to use the API functions.

One main difference between C and Visual dBASE lies in the data types and structures. Unlike dBASE, C data variables are always declared with an explicit type. C also separates variables from pointers.  Because of this it is important to understand the main differences between these 2 languages :

As you can see, in C the memory management is performed manually. The programmer decides on the amount of memory he needs and when he has to release it when it's no longer needed. When you think at the number of different allocation/release operations on memory that are needed in an OOP language (add/modify properties, method, object instances, ...), you can easily understand why some C++ programmers that have experienced another language with automated memory management, don't want to go back!

To get back to the data types, the Windows API types are based on the native C data types. These native C data types are lowercase. The derived types are generally uppercase.

A pointer can be explicitly declared in C; in that case, its name starts with an asterisk (*). In derived types, the * is generally contained in the type name, if it is a derived type like Windows ones. The type name often starts by LP, for Long Pointer.

Here are some examples of variables declarations in C :

char  c = 'a'      // char variable, on 1 byte, initialized to the letter 'a'.
int   *k           // Pointer on an integer

Example of C array :

short   tab[2][3]        // Creates a 2 x 3 array, containing "short" elements
                         // tab is in fact a pointer on the first
                         // short of the memory buffer reserved for the array

Example of string in C :

char  st[] = "Bonjour!"    //  Creates a string, whose size is exactly
                           //  its length + 1 (because of the Null at the end),
                           //  and pointed to by the pointer st.
                           //  This string is considered as fixed in memory.

char  st_tab[256]          //  Here, an array of 256 bytes is reserved to store,
                           //  for instance, characters, maximum 255 + '\0'

The following table lists the basic variables and pointer types used in Windows, that derive from C types :
 

Native C Type Memory size (bytes) Other equivalent types used in Windows (not exhaustive list) Visual dBASE type Variable declaration in function's prototype under Visual dBASE Pointer declaration in function's prototype under Visual dBASE
char 1 BYTE Numeric CCHAR   
unsigned char 1 UCHAR Numeric CUCHAR  
short 2 WORD Numeric CSHORT CPTR SHORT
unsigned short 2 USHORT Numeric CUSHORT CPTR CUSHORT
int 4 DWORD, HWND, BOOL, HDC Numeric CINT CPTR CINT
UINT 4   Numeric CUINT CPTR CUINT
long 4 LPVOID Numeric CLONG CPTR CLONG
unsigned long 4 ULONG Numeric CULONG CPTR CULONG
float 4   Numeric CFLOAT CPTR CFLOAT
double 8   Numeric CDOUBLE CPTR CDOUBLE
LDOUBLE 10   Numeric CLDOUBLE CPTR CLDOUBLE
LOGICAL 1   Logical CLOGICAL CPTR CLOGICAL
void N/A    N/A CVOID

Some explanations about this table :

It's important to keep in mind that it's not the type's name that is relevant for us, but rather its corresponding MEMORY SIZE, direct or pointed to. Visual dBASE then automatically converts the parameters supplied when calling the function into the corresponding declared type, accordingly to the prototype declaration.

Windows uses, in the function prototypes declarations, many types derived from the direct C types in the previous table. All of these Windows types can be declared in the EXTERN function statement with Visual dBASE types.

One exception is however not currently supported by Visual dBASE, it's the CALLBACK type, that we will not talk about in this article. Roughly, it could be an equivalent of the Visual dBASE Function Pointer (FP) type.

Strings and pointers in C

A particular case concerns the strings. This chapter deals with character strings and pointers in C, and their use in Visual dBASE with the API 32 functions prototypes.

A character string is, obviously, a series of characters. These characters can be stored :

At the limit, a Unicode string can be seen as a byte string, as 1 Short= 2 Chars. In that case, one byte is alternatively set to chr(0). Visual dBASE uses the Unicode convention to store strings internally, as do most 32 bit applications. Thus, caution is required when directly manipulating bytes in a Visual dBASE string, using the setByte and getByte functions, as they act at the byte level.

Run the following code to see how strings are stored in dBASE. Notice that j start at 0.

s = new String("Bonjour")
for j = 0 to (s.Length*2)-1
  ?s.getByte(j), chr(s.getByte(j))
next j
When a character string must be supplied to an API 32 function, you must respect the exact expected type, Unicode or byte.

Note: The last character of a C string must be a chr(0), also called Nullchar, or '\0'. Visual dBASE takes into account this requirement when calling extern functions with a string passed as a parameter, but this rule must be kept in mind, especially when conversions Byte <-> Unicode take place.

A C String always consists of a series of CHAR or WORD (if the string is  Unicode), that is “pointed to” by a C char or word pointer. This pointer is itself a variable that contains a memory address to the address of the first character of the pointed string. When you declare a string in C, you actually declare a pointer - a memory address - to that string. The length of this string is defined implicitly by the first Null in the string.

To use strings in external functions, two keywords exist in Visual dBASE: CSTRING and CPTR. Both designate a pointer to a string, but here are the fundamental differences between them :
 

CSTRING Declaration CPTR Declaration
automatic implicit conversion from Unicode to Byte when calling the extern function.
The string can contain Null chars according to the OLH, but I experienced problems when Null chars are present.
No conversion takes place.

The string can contain Null chars.

automatic implicit conversion from Byte to Unicode when the extern function returns a string.
The Null char rule applies also here, with the same problem experienced.
The function return type cannot be CPTR.

Prototyping the API functions in Visual dBASE

Let's go back to the ShellExecute function, seen in the API 32 functions presentation chapter. We are now going to prototype - that is to say declare this function before using it, in order to explicitly tell to Visual dBASE how it must call this function in a program.

Let's see first the general syntax of an extern function. The OLH, “extern” topic, proposes two possible wordings, but they can generalize to the second one :

In order, we find :

Let's come back to the ShellExecute function. According to the API 32 OLH indications, the following types are used : These types are Windows types, except INT. We now need to find the equivalent Visual dBASE types.

Fortunately, the job is almost already done. The _DBWINHOME\Include directory contains some prototype files, (files with extension .h), containing the declarations used by the API 32 functions.

The file containing the Windows and C types is the file Windef.h. Thus, it is simply necessary to include that file in the source code of the program :
// Include Windef.h file
#include <Windef.h>
Now, the function must be declared with a rigorous respect of the specified types. Here again, the _DBWINHOME\Include directory contains the desired information. It includes a file, named win32api.prg, that contains the API 32 functions declarations. Now prototyping the function becomes a child's play : look for the ShellExecute function and simply copy it in to the program source code :
// Prototype declaration for ShellExecute function in win32API.prg
extern HINSTANCE ShellExecute(HWND, LPCSTR, LPCSTR, LPCSTR, ;
                              LPCSTR, CINT) shell32 ;
                              from "ShellExecuteA"

Compile the program with those two lines of code and an error appears. This is due to a declaration that is incompatible, HWND , which causes the error. In fact, HWND is a Visual dBASE keyword, so there's a conflict.

The best solution is to replace the declaration HWND by HANDLE, that will give the correct result. So the corrected declaration becomes :

// Prototype declaration for ShellExecute function
extern HINSTANCE ShellExecute(HANDLE, LPCSTR, LPCSTR, LPCSTR, ;
                              LPCSTR, CINT) shell32 ;
                              from "ShellExecuteA"

Recompile. This time , it's correct. The function is now declared and ready to be used.

This problem due to HWND is the only one I have encountered up to now, all the other types of functions in the win32API.prg  file work properly.

To illustrate what has been said earlier concerning the from keyword in the command, replace the function declaration by the following, that eliminates the from keyword :

// Prototype declaration for function ShellExecuteA, without the keyword from
extern HINSTANCE ShellExecuteA(HANDLE, LPCSTR, LPCSTR, LPCSTR, ;
                              LPCSTR, CINT) shell32

Compile : it's OK, the function must then be called by issuing a ShellExecuteA(<Parameters>) instead of a ShellExecute(<Parameters>).

In summary, the delicate step of prototyping the API function has been limited to :


API 32 constants declarations

Let's consider again the same function ShellExecute and the corresponding API OLH page. Now, we are going to examine the nShowCmd parameter. This parameter represents the way the new application's window will be opened. It can take the following values :

Now, the question is, how can we know these values ? Once again, the answer is in the _DBWINHOME\Include directory. Other prototypes files can be found there, that contain constant declarations used by API 32 functions. There is no rule of thumb for including a given file, it depends on the API functions that you are using. Constants that belong to the same topic are generally grouped in the same file. As a general rule, the approach could be the following : In this case, the SW_...constants are all defined in the Winuser.h  file. To check that, open this file and look for “SW_”.

The file contains the following section of declarations :
. . .
//
// ShowWindow() Commands
//
#define SW_HIDE              0
#define SW_SHOWNORMAL        1
#define SW_NORMAL            1
#define SW_SHOWMINIMIZED     2
#define SW_SHOWMAXIMIZED     3
#define SW_MAXIMIZE          3
#define SW_SHOWNOACTIVATE    4
#define SW_SHOW              5
#define SW_MINIMIZE          6
#define SW_SHOWMINNOACTIVE   7
#define SW_SHOWNA            8
#define SW_RESTORE           9
#define SW_SHOWDEFAULT      10
#define SW_MAX              10
. . .
For this example, a single line of code in the header part of the source code is necessary to declare all the necessary constants :

// Include Winuser.h file
#include <Winuser.h>

An alternative to the use of include files for API constants and functions prototypes could be to declare directly these ones in the code, using #define primitives and available native Visual dBASE types. This is possible, but more complex because all the function and constant definitions need to be rewritten carefully, with a risk of error. The Visual dBASE include files can do all this stuff for us.

Finally, to close this chapter, purists may have noticed that since the Winuser.h  file is included, the file Windef.h  doesn't need to be included anymore. In fact, the Winuser.h file contains itself (take a look at the beginning of the file) an include statement of the Windef.h  file. In our case,  including the Winuser.h   file will declare simultaneously all the types and constants required by ShellExecute.

Running an API 32 function

Now, let's see how to execute an API function. We are going to run the Windows calculator. This application can be found in the Windows directory, called here C:\Windows; its name is : Calc.exe

Let's look again in the API OLH file for the ShellExecute function, especially the section that lists the parameters :

Let's write now the complete Visual dBASE lines of code, including the declarative statements seen in the chapters : It will be :

// Include Winuser.h file
#include <Winuser.h>

// Prototype declaration for ShellExecute function
extern HINSTANCE ShellExecute(HANDLE, LPCSTR, LPCSTR, LPCSTR, ;
                              LPCSTR, CINT) shell32 ;
                              from "ShellExecuteA"

ShellExecute( _app.FrameWin.hwnd, "open", "calc.exe", Null, "C:\Windows", SW_SHOWNORMAL )

Run this program. The Windows calculator is displayed. This example has shown the use of parameters of different types, numeric, strings, API 32 constants.

Now remains a last parameter type, whose existence has just been revealed previously : the C structures. They are explained at the end of this article, because their handling requires us to have acquired the basic notions developed up to here.

C structures and Visual dBASE

If the C language has been considered for long as reference in software development before OOP languages were introduced, it's partly due to the power provided by structures.

To support the C structures, we will now consider the case of the API 32 function named GetVersionEx, function that can get the computer's Operating System version it's running on.

First, let's find the help page about this function in the API help file :

This function uses a single parameter called lpVersionInformation, which is a C pointer to a structure named OSVERSIONINFO. Click on this link OSVERSIONINFO shown in the parameter. You get the following screen :

Let's see now the different indications in red :

Since we have proposed this analogy between C structures and objects, here are some fundamental differences between them, that will help understand the structure concept :
 
C Structure Classes and Objects
The C structure is a static entity.

It's a list of variables or pointers of fixed length. They are placed one after the other in memory, in the order where they are declared. Their position in memory never changes.

The memory space occupied by a C structure is fixed, and corresponds exactly to the sum of the variables sizes that compose it.

As opposed, an objet is entirely dynamic.

It contains elements (properties, methods) that can be modified, added, released, etc. ...

The memory occupation of an object's members is not necessarily contiguous, as a dynamic memory space management is performed.

The size of an object is variable, and depends upon its content.

A structure can only contain variables and pointers. An object can contain properties (that are variables or pointers), and methods.

To better represent a structure, here is the memory occupation of the OSVERSIONINFO C structure :
 

Memory occupation : Total = 148 bytes Structure member
Offset : n to n + 3 dwOSVersionInfoSize
Offset : n + 4 to n + 7 dwMajorVersion
Offset : n + 8 to n + 11 dwMinorVersion
Offset : n + 12 to n + 15 dwBuildNumber
Offset : n + 16 to n + 19 dwPlatformId
Offset : n + 20 to n + 147 szCSDVersion

Structures and classes being different by nature, it is not possible to use the second one to operate the first one.

Handling a structure's content with Visual dBASE requires access to a memory buffer, representing the structure's content (the members), in which changes can be made byte per byte.

Basically, the only mechanism supplied is to represent this memory buffer in Visual dBASE as a string. We can then, using the setByte and getByte string methods, read and modify the content of the string byte per byte. Even if this method can be used, it is very hard and heavy, and you need to spend a significant amount of time before getting to the appropriate result.

Fortunately, there is a much more efficient method.

Even if Visual dBASE doesn't know anything about C structures, there is a much more powerful tool : the classes and the objects.

We are now going to see how to simulate the behavior of a C structure, and in an OOP language like Visual dBASE, we'll replace structures by classes, and get the structures working as easily and flexibly as objects.

Among the tools and samples supplied with Visual dBASE 7.01, a set of files will help to achieve this goal. The files are the following :

We are going to see how to use these 4 files.
  1. Each C structure will be represented by an object created from the Structure class, defined in the _DBWINHOME\Samples\Structure.prg file.

  2. This Structure class holds a .value property, and  addMember(), setMember(), getMember(), and  length()methods that will control the created object.
  3. The .value  property holds a Visual dBASE string, representing the memory buffer that holds the contents of the C variables of the C structure.
  4. In order to describe the C structure fields, the addMember() method will add new structure members to the object.

  5. To describe this member, you must give, like in C, its type (so its size), and its name.
    The members must be declared in the same order as in the C structure. Thanks to the type supplied when calling addMember, the member's position and occupation in the .value string is computed and kept with the member's description.
  6. To access a particular member, 2 methods setMember()and getMember() can read and modify the specified member's content, from the  .value string.
  7. Last, the structure's size, in bytes, can be retrieved using the length()method .
The properties and methods of the Structure class are described in the comment header of the _DBWINHOME\Samples\Structure.prg  file.

Now, let's look at a real case. We are going to call the API 32 function GetVersionEx , and then access the OSVERSIONINFO structure members.

The described lines of code below are not shown in the order they would be in the source code, but it helps for better explanations and understanding.

First, the include files. A quick search on the API constants used by GetVersionEx and OSVERSIONINFO shows that the following files are needed.
The file StructAPI.h  must also be included because we will use it with the Structure class :

// necessary include files
#include <Windef.h>
#include <Winbase.h>
#include <Structapi.h>

Then, the Structure class must be loaded, it is in the _DBWINHOME\Samples\Structure.prg file :

// load the Structure class
set procedure to '&_dbwinhome.samples\structure.prg' additive

Now, let's see how to create the OSVERSIONINFO object equivalent to the C structure. It is an instance of the Structure class, defined in the _DBWINHOME\Samples\Structure.prg  file just previously loaded. Then, the addMember method is used to declare the Structure members. This method uses as parameters :

The members must be entered in the same order as for the C structure. In our example, the declaration will look like :

// This class definition corresponds to the C structure,
// type _OSVERSIONINFO. The addMember method creates the structure
// members, using the member's type and name.
class _OSVERSIONINFO of Structure
   super::addMember( TYPE_DWORD,   "dwOSVersionInfoSize" )
   super::addMember( TYPE_DWORD,   "dwMajorVersion" )
   super::addMember( TYPE_DWORD,   "dwMinorVersion" )
   super::addMember( TYPE_DWORD,   "dwBuildNumber" )
   super::addMember( TYPE_DWORD,   "dwPlatformId" )
   super::addMember( TYPE_STRING,  "szCSDVersion", 128 )

   // The following line of code initializes the dwOSVersionInfoSize member of
   // the structure, that must, as indicated in the API 32 help file, contain the
   // structure's size.
   // The Structure class length() method returns the overall size of the structure,
   // in bytes. When an object is created using the _OSVERSIONINFO class, this member
   // will be automatically initialized.
  super::setMember( "dwOSVersionInfoSize", this.length( ))
endclass

As you can see, the last line of code in the _OSVERSIONINFO  class calls the setMember method. Actually,  the API help about OSVERSIONINFO indicates that the dwOSVersionInfoSize member must be set to the total size of the structure. By calling the length() method in the class constructor's code, the size is set automatically.

Now, the prototype of the GetVersionEx function can be written by copying the corresponding lines from the _DBWINHOME\Include\Win32api.prg  file :

// GetVersionEx function prototype as it is written in Win32api.prg
extern BOOL        GetVersionEx( LPSTRUCTURE ) kernel32 ;
                   from "GetVersionExA"

Some local variables are set up, especially OSVERSIONINFO , the structure object created from the _OSVERSIONINFO class :
local  OSVERSIONINFO, dwPlatformId

Now, the  OSVERSIONINFO object is created as an instance of the _OSVERSIONINFO class :

// Creates an instance of the structure object.
OSVERSIONINFO = new _OSVERSIONINFO( )

Now that the structure object OSVERSIONINFO is created, the function GetVersionEx can be called to update the content of the object.

NOTICE that the parameter passed in the function call is the .value property, as this string will represents the memory buffer where the C structure members are stored. :

// Call to the GetVersionEx function, input parameter is OSVERSIONINFO.value,
// it will represent the contents of the C structure in memory.
GetVersionEx( OSVERSIONINFO.value )

The remaining code simply displays the member's content using the getMember method, as they have been updated by GetVersionEx.

Here, a macro command, named LOWORD, that is declared in Windef.h, returns only the content of the 16 low order bits of a 32 bits word. Its equivalent HIWORD also exists for the 16 high order bits. Take a look at the file Windef.h, it contains a set of useful macros to split and merge binary words.

// Displays the content of the structure members in the command window
? 'Major Version', OSVERSIONINFO.getMember( 'dwMajorVersion' )
? 'Minor Version', OSVERSIONINFO.getMember( 'dwMinorVersion' )
? 'Build Number', LOWORD( OSVERSIONINFO.getMember( 'dwBuildNumber' ))
dwPlatformId = OSVERSIONINFO.getMember( 'dwPlatformId' )

do case
 case dwPlatformId == VER_PLATFORM_WIN32s
  ? 'Win32s on Win 3.1'
 case dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
  ? 'Win32 on Windows 95'
 case dwPlatformId == VER_PLATFORM_WIN32_NT
  ? 'Win32 on Windows NT'
endcase

The complete Visual dBASE program for this example can be loaded using the link at the bottom of the page. Run this program. In the command window, it displays the Windows version number, its build number, and the Operating System version.

Creating an executable including the structure files

You can use the method provided before in an executable program built with Visual dBASE. Just follow these guidelines :

  1. Include in your project file .prj a reference to the following files :
  2. For the application deployment, place a copy of the DLL file  Structmem.dll in the same directory as the executable.

Going further with the structures

Despite being an excellent starting point, the Structure class provided in Structure.prg  suffers from a few gaps, that sometimes restricts its fields of application.

For this reason, I have created my own StructureEx class, compatible with the Structure class, but enhanced with the points listed below. This class can replace the Structure class.

Here are, in a few points, the added capabilities :

  1. The supported types by the Structure class can be easily extended, as other types, declared in the file _DBWINHOME\Include\StructAPI.h,  are supported by the DLL file Structmem.dll. Particularly, the TYPE_CHAR , or TYPE_BYTE which is often used in C structures, and the TYPE_POINTER for pointer declarations.
  2. The Structure class is a simple object class (class object()), accessing a member is performed by a linear search on his name, that can be sometimes long in case the structure contains a lot of members. The StructureEx rewritten is a subclass of the AssocArray class, which is better suited for this application. Access speed is greatly enhanced and the class is simpler.
  3. Some C structures, like the DCB structure for serial communications, (look for it in the API help), use bit fields. In other words, some members are described as groups of bits. Accessing those bit fields is not very easy with the Structure class. In the StructureEx, this is made very easy, as it is possible to declare directly bit fields members.
The description and use of this StructureEx class going beyond this first article's boundaries, it will be described and available in a next article.

Conclusion

After all, using direct Windows API 32 calls from within Visual dBASE is not so a difficult task, as soon as you use a rational method. This article does not intend to be an exhaustive presentation of the topic, but rather a first approach to get started. Of course, other methods are possible, everyone is free to use his own; but I thought that this one, with the few notions of C language it requires, was worth being presented; due to its simple implementation.

Visual dBASE shows once again, that, thanks to its OOP language, it can adapt to a particular situation for which it has not especially been designed for.

Anyway, this Windows API  can remain sometimes difficult to approach, due to its initial design features.

Now, it's your turn !

Nicolas Martin
 

To load the sample program,  click here
(It's a 31 Kb autoexecutable)