Struct
Written 1999 by Christof Lange and Mark Wilden
Placed into Public Domain by The Foxpert!

INTRODUCTION	1
C DATA TYPES	1
GETTING STARTED	6
USING POINTERS, SUBSTRUCTURES, ARRAYS AND BUFFERS	11
CUSTOMIZING THE STRUCT CLASS	18
AN OVERVIEW ON THE DESIGN	19
Introduction
In this document I explain how you can use the Struct class in your own applications. It covers understanding C-structures, converting them into a VFP structure class and using the struct object. The second part of this document covers the possibilities of subclassing the Struct class that are beyond the scope of simply using it. It's especially useful to incorporate the Struct class into your application framework. The last part is targeted at the developer who has a good understanding of structures and explains the design of the Struct class.
C data types
The concept of data types is in my experience what makes many Visual FoxPro developers thinking that API programming is difficult. But it isn't so! Just like Visual FoxPro functions, API functions expect a certain data type when you call them. In Visual FoxPro we have the following data types: Character, Currency, Date, DateTime, Logical, Numeric. In addition we have some field types like Memo, General, Double, Float and Integer that are converted to character or numeric values when they are read into a memory variable.
The same applies to C; the only difference is that C uses different data types. To make use of them, you have to know how to translate a C data type to VFP. Basically, C uses the following data types.
Integers are numeric values that can't have fractions, just like the Integer field type in Visual FoxPro. Integers are distinguished by the memory they allocate. This storage size also defines the maximum range such a data type can hold. 8-bit integers are called byte or char. A 16-bit value is a short, a word and sometimes a short int. A 32-bit value is called integer, long or dword (for double word). Rarely used are 64-bit values that are called longlong or long64.
In addition integers can show up in two variations, signed and unsigned. A signed integer can be negative, but the range of possible positive values decreases by half. For example, a signed char can contain values between -128 and +127, an unsigned char between +0 and +255. Most parameters in API functions and most members in structures are some sort of integer.
Strings don't exist in C. This might sound strange, but actually all strings are arrays of characters. There are basically two types of strings, fixed length strings and flexible length strings. Fixed length are defined with the number of characters and usually filled with CHR(0). A typical declaration lis char variable[32], which defines a 32-character long string. For variable length strings there's nothing that indicates the length of a string. Therefore, C has got a standard definition. A Chr(0) or '\0' in a C program, marks the end of a string. When a C program wants to determine the length of a string, it loops through all characters and looks for a CHR(0) value. The position minus 1 is the length.
Strings consist of characters. Characters can occur in 2 different formats, in ANSI code and in UNICODE. An ANSI code character is one byte and is the character that CHR() returns. A UNICODE character needs two bytes for each character where in western fonts the second byte is always CHR(0). Therefore, a Unicode strings uses CHR(0)+Chr(0) as a termination mark.
Floating-point values are what a FoxPro programmer would say is a numeric value. It can hold large values and fractions. These data types exist in two variations, float or single is a short version that needs 32 bit of memory, as much as an integer value. It has a limited precision and can only have 6 decimal places without loosing precision. A double needs 64 bit of memory and is what Visual FoxPro uses for numeric values. Both types are only used when they are really needed, that is for calculations, and so on. They are handled by the numeric co-processor, and require some special handling. The struct class only supports double, because float or single are hardly used on 32-bit systems.
And that's all. C offers some special data types, like enumeration, but basically these three types cover 99% of all data types used in API programming. That sounds too simple, doesn't it? How are objects handled, what about dates or logical values? And why does the description of an API function contain all these types like HWND, HINSTANCE, POINT and so on?
The reason is that C has got a feature that is called strict-typing. One appearance is that a variable of one type can only accept values that match their type. You can't store a string in a variable first and later a numeric value. In Visual FoxPro we usually try to simulate this by naming conventions. For example, cName is a character variable while nCount is numeric. Strict-typing offers a second feature. You can create a new data type by assigning an existing data type a new name. In Visual FoxPro you can compare that with an alias for a table. You can open the same table several times, using a different alias every time. Each alias can have its own active index, its own filter and its own record pointer, but they all refer to the same table. Just like creating new types: Every type appears to be different from other types, even though internally they are all stored the same.
Windows makes heavy use of this concept. For instance, LONG is actually a long signed int. An UINT is a long unsigned int. Both are 32-bit integers. These names are defined in several include files. If you have got Visual Studio with the VC++ compiler, you can find them in the \VC98\Include directory. To make matters worse, you can use such a user-defined type again in a type declaration. 
Figuring out which of the basic data types a data type used in an API function actually is, is one of the hardest parts in using API functions. A rule of thumb is if you can't find double, char or str somewhere in the name, it's usually a 32-bit integer. It takes some time to get used to it, but after that you routinely convert data types. The following list should help you getting started:
Windows data type	basic C data type
BOOL	32-bit signed integer. 0 means false, anything else means true.
BOOLEAN	the same as BOOL.
BYTE	8-bit integer
CHAR	8-bit integer. You can use CHR() to convert them.
COLORREF	32-bit unsigned integer. The same value that RGB() returns. 
DWORD	32-bit unsigned integer
FLOAT	float
HANDLE	32-bit unsigned integer
HBITMAP	32-bit unsigned integer
HBRUSH	32-bit unsigned integer
HDC	32-bit unsigned integer
HFONT	32-bit unsigned integer
HGDIOBJ	32-bit unsigned integer
HICON	32-bit unsigned integer
HINSTANCE	32-bit unsigned integer
HPEN	32-bit unsigned integer
HWND	32-bit unsigned integer
LONG	32-bit signed integer
SHORT	16-bit signed integer
TCHAR	ANSI code character for ANSI functions, UNICODE character for UNICODE functions.
UCHAR	ANSI code character
UINT	32-bit unsigned integer
ULONG	32-bit unsigned integer
USHORT	16-bit unsigned integer
WCHAR	UNICODE character
WORD	16-bit unsigned integer
In the list above you can see that logical values are treated as numeric values. By definition 0 means .F., anything else is .T. In Visual FoxPro you therefore use:
lReturnValue = ( nReturnValue # 0 )
To convert such a numeric value into a logical Visual FoxPro variable. Another concept that is heavily used in C are pointers. A pointer is a variable that contains the address of the value it points to. The type of a pointer is always defined by the type of the value to which it points; the size is always 4 bytes. For example, a pointer to a SHORT is a 32-bit integer value, as is a pointer to any other data type. The value of the pointer is the memory address, where the 16-bit short integer is stored. By passing the pointer to another function, the called function can change the value at the specified address. Pointers can be quite difficult to C programmers. One reason is that pointer can point to pointers that point to the actual value. Does that sound too complicate? <g> In fact, Visual FoxPro supports a similar system. Take a look at the following codes:
C code	Visual FoxPro code
LONG nValue = 25;	nValue = 25
LONG* lpPointer = &nValue;	lpPointer = "nValue"
	
// access nValue via the pointer	* access nValue via the pointer
*lpPointer;	EVAL( lpPointer )
In both cases the last line returns 25, the contents of nValue. Both codes are not exactly the same; evaluation is not the same as de-referencing, just to make this clear. But this code lets you think of pointers in terms of Visual FoxPro code. When you have to call an API function that receives a pointer to a value, you assign the value to a Visual FoxPro variable and pass the variable by reference. Visual FoxPro is smart enough to pass the address to the variable in that case. For instance:
DECLARE APIFunction in Win32API INTEGER @lpPointer
nValue = 24
APIFunction( @nValue )
I used the same names as in the code above to make the relations clear. APIFunction() can now access the Visual FoxPro variable and change the value. nValue has a different value after the function returns. This technique is often used to return multiple values in one API call.
API functions handle strings slightly different. As I mentioned earlier, strings are actually arrays of characters. In Visual FoxPro, an array can't be passed by value to a function. If you call a Visual FoxPro function like this:
Local laArray[10]
Function( laArray )
The function only receives the first value. Instead you have to pass the array by reference using
Function( @laArray )
This is true for API programming, too. No API function can receive an array by value, only by reference. Since strings are arrays, too, a string is always passed by reference, no matter how you call the API function. Passing by reference means that the called function can change the parameter, but that doesn't happen if you omit the @ in the DECLARE command. How comes that? When you pass a string by value to an API function, Visual FoxPro makes a copy of the string, and passes the copy by reference. Otherwise it passes the original string. Even though the API function modifies the copy, this doesn't affect the Visual FoxPro string. In the C code of the API declaration CONST is used when you can pass a string by value.
Remains one problem. How do you know when an API function receives a parameter as a pointer, that is by reference in Visual FoxPro? The data type indicates this. In pure C, a "*" in front of the type indicates a pointer, as you can see in the C code in the table above. But this convention is hardly used in API programming. Usually you find a declaration like this one:
DWORD GetShortPathName(
  LPCTSTR lpszLongPath,  // pointer to a null-terminated path string
  LPTSTR lpszShortPath,  // pointer to a buffer to receive the 
                         // null-terminated short form of the path
  DWORD cchBuffer        // specifies the size of the buffer pointed 
                         // to by lpszShortPath
);
The first parameter has got the type LPCTSTR. This data type consists of three parts: LP means Long Pointer, in other words, this is a pointer. C stands for Constant, the API function doesn't alter this parameter. TSTR is the actual type. In the list of data types you can find a similar data type TCHAR. TSTR is just like that, but doesn't mean a single character, but rather a string that can by ANSI or UNICODE depending on whether you call the ANSI or UNICODE function.
The second parameter is similar, but doesn't contain a C in the middle. In other words, the API function wants to change that parameter. It's still a pointer, though. The third parameter is a DWORD. In the list of data types you can find that DWORD is an unsigned 32-bit integer value. The full declaration in Visual FoxPro therefore looks like this:
DECLARE GetShortPathName in Win32API ;
   STRING  lpszLongPath, ;
   STRING  @lpszShortPath, ;
   INTEGER cchBuffer
Fortunately, the API is rather consistent with this naming convention. If a data type starts with LP, P or ends with _PTR, it's usually a pointer and you have to use "@" in the DECLARE command in Visual FoxPro. When the parameter is a string and LPC is used, you can omit the @, but only for strings!
By now we covered data types, pointers, how to convert them to Visual FoxPro code, but what about structures? Everything I mentioned so far can be used in plain Visual FoxPro code, mainly using the DECLARE-DLL command. The concept of structures is very similar to the concept of records, a concept, you are quite familiar with. In fact, in some languages structures are called records. A record has got a definition, the table structure. Each field has got a name and a data type. Structures are similar. They are like the definition. A structure has multiple members with a name, a data type and a position inside the structure. A structure is used when one single value isn't sufficient. For example a point on the screen requires two information, the x and y coordinates. In such cases, the Windows API uses a POINT structure that is defined as
typedef struct tagPOINT {
   LONG x;
   LONG y;
} POINT;
When you call an API function that need a screen coordinate, you can fill the x and y member with the according positions and pass a reference to the structure to the API function. If you compare this with a cursor, you can see many similarities:
CREATE CURSOR POINT ( ;
   x I(4), ;
   y I(4) ;
)
To pass a record in this cursor, you can use SCATTER NAME loRecord and pass the object reference to the function. Nothing else is done with structures, except that structures are more flexible. For example, a structure can contain another structure, or it might contain a pointer to a different structure or other values.
The problem is, how can you pass a structure to an API function. After all, you can't pass a cursor instead, although the concepts are similar. The answer to this question lies in the way in that structures are stored in memory. I mentioned earlier, that every data type defines the size of the variable. A 32-bit integer value needs 32-bit or 4 bytes of memory. In memory these values are stored in a special format that is used by the processor. A location in memory is identified by its address, just like a record can be identified with the record number. 
Like a simple data type, a structure is stored in memory, as well. Let's assume that the POINT structure is stored in address adr. Then adr+0 would contain the X member of the structure. adr plus the size of the X member would be the address for Y, in other words, adr+4 holds the Y value. The entire structure occupies 4 bytes + 4 bytes = 8 bytes. That means, a structure is a block of memory that is 8 bytes long. In this block of memory, the individual members are stored in a specific format.
How does Visual FoxPro store a string? It allocates the amount of memory that is necessary to store the string. If you have a string that is 8 bytes long, Visual FoxPro allocates 8 bytes of memory. In both cases, physically we have 8 bytes of allocated memory. That's the reason why a structure has to be passed as a string from Visual FoxPro as it is shown in the Solution.App that ships with Visual FoxPro. The really difficult part is to convert all these values to the format that the API function expects. This is the job of the struct class.
Well, you don't have to understand all of the details, but you have to keep in mind that a structure consists of several values, each of it has a data type that also defines it's size, and all values have a fixed position. The API function doesn't access the members by their name, but by the position within the structure. 
Getting started
In the previous chapter I've explained what a structure is. If you compare that with objects, both share many similarities. The C-definition
typedef struct tagPOINT {
   LONG x;
   LONG y;
} POINT;
looks quite similar to a VFP class definition in code
DEFINE CLASS POINT AS Struct
   x = 0
   y = 0
ENDDEFINE
That's almost how the struct class implements structures. In Struct.Vcx you find a class Struct that is the parent class of all structures you want to define. Every new structure is a subclass. Earlier I highlighted the importance of two aspects of structures that are not yet covered by the class definition shown above. It's not clear what data type the individual properties represent and, though it's less obvious, the order of these properties is not clear, either. Therefore an additional property cMembers is used to define both. This property contains a comma-separated list with the type definition. The order, in which these properties are listed, defines the order in which they are added to the structure. The complete definition looks like this:
DEFINE CLASS POINT AS Struct
   x = 0
   y = 0
   cMembers = "l:x, l:y"
ENDDEFINE
The definition for each member contains of a type definition, followed by a colon, followed by the property name used in the class. "l" is the code for a 32-bit integer; it stands for long. The full definition actually allows you to place a comment in from of the type definition separated by a blank, this can be used, for instance, to specify the C data type. The cMembers property could also look like this:
cMembers = "LONG l:x, LONG l:y"
Defining a structure is therefore not difficult at all, once you identified the basic data type of each structure member. The general syntax for cMembers is:
cMembers = "[text], type:property [, [text] type:property...]"
The type depends of one of the basic C data types I explained above: numeric, strings and structures. The following sections explain the syntax for each individual data type. In the syntax diagram "[]" indicates optional elements. "|" separates alternative codes. For numeric values, type is defined as
[p] [s|u] l|w|b|d
Code	Description
p	It's a pointer to a numeric value. In the C definition of the structure you usually find a type that starts with LP like LPDWORD.
s	The value is signed. This is the default code if you omit s and u. A signed value can be negative (obviously) and at the same time it reduces the number of positive values. Most data types are signed unless unsigned is used in the C data type or it starts with U, for example, UINT. You only use this token when you want to make specifically clear that the value is signed.
u	The value is unsigned and therefore can't be negative. These types are rarely used in Windows API programming.
l	(This is a small "L"!). The value is a 32-bit integer. Most data types used in Windows API programming are 32-bit integer values. A list of the most common data types can be found in the previous chapter.
w	It's a 16-bit integer. This data type is less common and corresponds to the SHORT key word of the DECLARE-DLL command.
b	It's an 8-bit integer, or a byte. This data type is almost never used in simple members, but usually within an array of bytes.
d	It's a floating-point number. This type is rarely used. "d" means "double".
As I mentioned earlier, there are two types of string. One type has got a fixed length. In the C definition, they usually look like arrays, because the length is declared in square parenthesis behind the name, e.g.:
TCHAR FileName[260];
which defines a fixed length string of 260 characters. The other type is a variable length string where CHR(0) is used to mark the end of the string. This type is almost never directly included into a structure, but a pointer type. For example, 
LPTSTR lpszFileName;
means that this string is a null-terminated string where only the address of the actual string is included into the structure. The reason for this is that an API function accesses individual members by their position in the structure. Since variable length strings by definition are variable in length, all following members would have no fixed position. A pointer, on the other hand, is always 4 bytes long, no matter how long the string is to which it points. The syntax of type for string members is
[p] [x|2] ([0]c)|z [length]
Code	Description
p	It's a pointer to a string. It's usually used for flexible length strings, less often for fixed length strings. You can detect a pointer in Windows API programming by looking at the data type. Usually it starts with "LP" or "P". Less common data types that are pointers, too, end in "_PTR" or are followed by "*". Pointer string types are, for instance, LPTSTR, LPCHAR, LPWSTR This code is typically used together with the "z" code.
x	Depending on the operating system on which your application runs, either UNICODE or ANSI is used. A UNICODE character is 2 bytes long, an ANSI character only 1-byte. When you use this token, you have to make sure that you define the proper API function depending on the operating system. The ANSI version of an API function usually ends in "A", the UNICODE version in "W". If you don't specify the version, VFP automatically adds "A" to the name. The documentation of each function contains information about whether there are different versions of this function for UNICODE and ANSI. If you call the ANSI version on Windows NT, Windows NT automatically converts the parameters to UNICODE and internally calls the UNICODE version. Thus, usually you don't have to take care of it, unless you specifically wants to develop application that use non-Western fonts, like Asian applications.
2	This string should always use UNICODE, no matter what operating system is used. Some Windows 9x API functions always expect parameters to be Unicode. This token is required in this case. You can use this token, as well, when you define different structures for Windows NT and Windows 9x.
0	Usually when you define a fixed length string, it's padded with CHR(0) values, but you are not interested in these characters, only the string before them. This token can be used  together with the "c" code and means that all CHR(0) characters are removed from the string, before it's stored into the property.
c	It's a fixed length string. Typically you also specify the length of this string, if you don't, the current length is used. The struct class fills the string with CHR(0) before passing it to the API function. If the string in the struct object is larger than defined in the structure, it's cutted.
z	It's a null-terminated string. The struct class adds the necessary terminator code, before passing it to the structure. 
Some structures contain other structures, either completely, or just a pointer to them. With the struct class you define the contained structure in a second class and then assign an object reference to the inner structure to a property of the outer structure. This way you can link as many structures as you want. That's for example necessary for many structures that contain file information. The time stamp is stored in a separate FILETIME structure that is part of the file information structure. To declare a property as a substructure, you can use the following syntax
[p] o
Code	Description
p	It's a pointer to the substructure. Only the address of the substructure is included into the structure. Usually such a data type starts with LP, for example LPFILETIME.
o	Indicates that you want to insert a structure. The property must contain a reference to another structure object and might not be THIS, because this would lead to an infinite recursion.
Of course, this all is pretty abstract. The following table contains the codes for the most common Windows API data types. An italic xxx indicates that you have to insert the length of the string.
data type	code	data type	code	data type	code
BOOL	l	BOOLEAN	l	BYTE	b
CHAR	cxxx	COLORREF	ul	DWORD	ul
DOUBLE	d	HANDLE	ul or l	HBITMAP	ul or l
HBRUSH	ul or l	HDC	ul or l	HFONT	ul or l
HGDIOBJ	ul or l	HICON	ul or l	HINSTANCE	ul or l
HPEN	ul or l	HWND	ul or l	LONG	l or sl
SHORT	w or sw	TCHAR	x0cxxx or 0cxxx or 20cxxx	UCHAR	0cxxx
UINT	ul	ULONG	ul	USHORT	uw
WCHAR	20cxxx	WORD	uw	LPBOOL	pl
LPBYTE	pb	LPCOLORREF	pul	LPCSTR	pz
LPCTSTR	pz or pxz or p2z	LPCVOID	pz	LPCWSTR	p2z
LPDWORD	pul	LPHANDLE	pul or pl	LPINT	psl or pl
LPLONG	psl or pl	LPSTR	pz	LPTSTR	pz or pxz or p2z
LPVOID	pz	LPWORD	puw	LPWSTR	p2z
With this table you should be able to create a subclass of Struct, adding the members and setting up the cMembers property as needed. You can create a structure either in code or using the Class Designer. The Struct class derives from a Label class, because this allows you to set the caption of the label to something meaningful like the name of the structure. When you add several structures to a form, you can easily distinguish them. WinStruct.Vcx contains several pre-defined structures that you can use as a reference, if you stuck at some point.
After you defined the structure, using it is as simple as using any other Visual FoxPro class. The concept of this class is easy. From your Visual FoxPro application, you only access the struct object with all of its properties. When you call an API function, you request a string that represents the structure with its current values. This string is a copy of your structure in a format that is understandable for the API function. The API function might modify this string, but of course has no access to the Visual FoxPro object. Thus, after the API function returns, you pass the modified string to the structure object and tell it to update its properties with the new values.
To obtain this string you call the GetString() method. The corresponding function to update the object is SetString(). If an API function expects a structure and doesn't modify it, the code looks typically like this:
Local loStruct
Declare APIFunction in Win32API String lpStructure
loStruct = CreateObject( "Structure" )
loStruct.Property1 = SomeValue
loStruct.Property2 = SomeValue
APIFunction( loStruct.GetString() )
When the API function modifies the string, you have to pass it by reference explicitly. In this case you cannot call the method GetString() within the API call, but you have to assign it to a Visual FoxPro variable:
Local loStruct, lcStruct
Declare APIFunction in Win32API String @lpStructure
loStruct = CreateObject( "Structure" )
lcStruct = loStruct.GetString()
APIFunction( @lcStruct )
loStruct.SetString( m.lcStruct )
? loStruct.Property1
? loStruct.Property2
Basically, you have to call GetString() before you call the API function, and SetString() afterwards. When the structure contains pointers - any of the members requires the "p" code in the type definition - the string returned by GetString() becomes invalid as soon as you called GetString() a second time. In other words, in this case you must not store the string and use it later, it's usually safer to call GetString() every time you need the string. If a structure doesn't contain pointers, you can safely safe the string and re-use one structure object this way. This is shown in the ResChange.Scx sample.
Beside these two methods, SizeOf() is often required. It returns the size of the structure in bytes, or in Visual FoxPro terms, the length of the string that is returned. For the API function a structure is just a block of memory that contains no information about how large the structure is that you passed. Often a structure changes with different versions of Windows, new members are added, as they become necessary. Therefore the first member of many structures contains the size of the structure. The API function uses this value to determine which version of the function you passed. Therefore it must match exactly what the function expects. In C code you usually find a sentence like: dwSize must be initialized with sizeof(STRUCTURE) before calling this function. In C sizeof() is a macro that returns the size of a certain type or structure. To make the translation easier for you, the method has got the same name. A typical call with such a structure looks like this:
Local loStruct
loStruct = CreateObject( "STRUCTURE" )
loStruct.dwSize = loStruct.SizeOf()
APIFunction( loStruct.GetString() )
Of course, you can initialize the size member in the Init() event of your structure class, too, if you prefer. These 3 methods, the cMembers property and subclassing the structure is sufficient for many structures you find in the Windows API. 
Using pointers, substructures, arrays and buffers
Simple structures only have simple data types or pointers to simple data types, like those I described above. Except for pointers, most of these structures can relative easily constructed with Visual FoxPro. A lot of tools are available that provide more or less help during this process. Complex structures contain substructures, arrays, pointers to other structures, and handle buffers. In this area this struct class really shines, because it's not getting much more complex.
Some structures require arrays of elements. For example, the CHARSET structure has got an array of 3 32-bit integers:
typedef struct tagCHARSET { 
    DWORD aflBlock[3]; 
    DWORD flLang; 
} CHARSET;
Arrays are handled transparently by the Struct component. All you have to do is to define an array. The Struct class automatically detects that a property is an array and treats it accordingly. The definition of this structure in Visual FoxPro is
DEFINE CLASS CHARSET AS Struct
   DIMENSION aflBlock[3]
   flLang = 0
   cMember = "ul:aflBlock, ul:flLang"
ENDDEFINE
You can access aflBlock like any plain array property. GetString() returns a 16 character long string, just as you would expect. But often, you don't have arrays of simple data types like DWORD, rather an array of other structures. The AXESLIST structure is a good example for this type of structures.
typedef struct tagAXESLIST {
    DWORD axlReserved;
    DWORD axlNumAxes;
    AXISINFO axlAxisInfo[MM_MAX_NUMAXES];
} AXESLIST
The last member axlAxisInfo is an array of AXISINFO structures. To implement this, you first have to know the AXISINFO structure:
typedef struct tagAXISINFO {
    LONG axMinValue;
    LONG axMaxValue;
    TCHAR axAxisName[MM_MAX_AXES_NAMELEN];
} AXISINFO
This is a simple structure that you can define in Visual FoxPro like this:
DEFINE CLASS AXISINFO AS Struct
   axMinValue = 0
   axMaxValue = 0
   axAxisName = ""
   cMembers = "l:axMinValue, l:axMaxValue, 0c16:axAxisName"
ENDDEFINE
The size of this structure is 24 bytes. If you want to call UNICODE functions, change the type of the last parameter to 20c16. With the Struct class arrays of structures are in fact arrays of objects. The definition of the AXESLIST structure therefore looks like this:
DEFINE CLASS AXESLIST AS Struct
   axlReserved = STAMP_AXESLIST
   axlNumAxes = 0
   DIMENSION axlAxisInfo[MM_MAX_NUMAXES]
   cMembers = "ul:axlReserved, ul:axlNumAxes, o:axlAxisInfo"
ENDDEFINE
The "o" type of the last member means that the axlAxisInfo property contains another structure. And because it's an array, the Struct class automatically loops through the array and converts all structure objects. STAMP_AXESLIST and MM_MAX_NUMAXES are constants that you can find in the WinGDI.H file. This file ships with Microsoft Visual C++. When you instantiate a structure that contains other structures, you first create the outer structure and then assign the substructure to the reference or the array, as in the sample above. The code in VFP looks like this:
Local loAxesList, lnAxis
loAxesList = CreateObject( "AXESLIST" )
For lnAxis = 1 to MM_MAX_NUMAXES
   loAxesList.axlAxisInfo[lnAxis] = CreateObject( "AXISINFO" )
Endfor
This doesn't look very difficult, right? Whether you create the substructures after creating the outer structures, or whether you put the FOR loop into the Init() event of the AXESLIST class, is up to you. The Struct class can handle both. After you created the object like this, you can access each property of the structure, for example:
loAxesList.axlNumAxes = 3
loAxesList.axlAxisInfo[3].axAxisName = "third axis"
GetString() would return a string that contains the AXESLIST structure and all 16 AXISINFO structures. Using a complex structure like this is nothing different from using a simple structure. There's only one thing to watch out when working with arrays in a structure. Whenever you re-dimension an array property, you have to call the Requery() method of the structure object. This is necessary, because changing the array dimension also changes the size of the structure and more importantly the position of all succeeding members.
Substructures are not always used in conjunction with an array. Often a structure might contain several substructures. The WINDOWPLACEMENT structure, for example, contains information about the position of the window on the desktop in different modes:
typedef struct _WINDOWPLACEMENT { 
    UINT  length; 
    UINT  flags; 
    UINT  showCmd; 
    POINT ptMinPosition; 
    POINT ptMaxPosition; 
    RECT  rcNormalPosition; 
} WINDOWPLACEMENT;
POINT is a structure that contains an X and an Y coordinate. RECT contains 4 coordinates, left, top, right and bottom. Let's first take a look at both of them. I jump right into the Visual FoxPro code, because they are really simple structures:
DEFINE CLASS POINT AS Struct
   x = 0
   y = 0
   cMembers = "l:x, l:y"
ENDDEFINE

DEFINE CLASS RECT AS Struct
   left = 0
   top = 0
   right = 0
   bottom = 0
   cMembers = "l:left, l:top, l:right, l:bottom"
ENDDEFINE
The WINDOWPLACEMENT structure contains 2 instances of POINT and one instance of RECT. This time I create the substructures right in the Init() event, just to show you how it would be done:
DEFINE CLASS WINDOWPLACEMENT AS Struct
   length = 0
   flags = 0
   showCmd = 0
   ptMinPosition = NULL
   ptMaxPosition = NULL
   rcNormalPosition = NULL
   cMembers = "ul:length, ul:flags, ul:showCmd, o:ptMinPosition, " + ;
      "o:ptMaxPosition, o:rcNormalPosition"
   PROCEDURE Init
      This.ptMinPosition = CreateObject( "POINT" )
      This.ptMaxPosition = CreateObject( "POINT" )
      This.rcNormalPosition = CreateObject( "RECT" )
      DODEFAULT()
   ENDPROC
ENDDEFINE
Assuming you have a Window handle lnHWND you can now call the GetWindowPlacement() function  like this:
Local loWindowPlacement, lcStruct
loWindowPlacement = CreateObject( "WINDOWPLACEMENT" )
lcStruct = loWindowPlacement.GetString()
GetWindowPlacement( lnHWND, @lcStruct )
loWindowPlacement.SetString( lcStruct )
All properties, including those in the substructures are now updated with the position of the specified window. For example you can use the following expression to get the left position of the window if it's displayed in its restored position:
loWindowPlacement.rcNormalPosition.Left
Some API functions don't want a single structure, they require an array of structures. For example the Polygon() function:
BOOL Polygon(
  HDC hdc,                // handle to device context
  CONST POINT *lpPoints,  // pointer to polygon's vertices
  int nCount              // count of polygon's vertices
);
The function might look like the second parameter is only a pointer to a single POINT structure, but the description of this parameter makes clear, that it expects an array here:
lpPoints: Pointer to an array of POINT structures that specify the vertices of the polygon.
How would you implement this? You can't pass a Visual FoxPro array to an API function, what you need is a string containing all array elements. A POINT structure gives you a string for one structure. One way would be to create a Visual FoxPro array and assign each element a POINT structure object. When you call an API function, you would loop through the array, call GetString() for each element and combine all strings. But that's hardly a comfortable solution. Instead you define a structure that only contains the array:
DEFINE CLASS ArrayPOINT AS Struct
   DIMENSION Points[3]
   cMembers = "o:Points"
ENDDEFINE
You can find this class in the WinStruct.Vcx. It's used in the GDI2.Scx sample exactly with the API function above. Now you can use a loop to assign a POINT object to each array element:
Local loArray, lnPoint
loArray = CreateObject( "ArrayPOINT" )
For lnPoint = 1 to 3
   loArray.Points[lnPoint] = CreateObject( "POINT" )
Endfor
To call the API function Polygon(), you can now pass the string returned by the ArrayPOINT object:
Polygon( nHDC, loArray.GetString(), 3 )
If a function doesn't want a pointer to an array of structure, as it happens to be in this case, but a pointer to an array of pointers to structures, all you have to do is to replace "o:Points" with "po:Points". Pointers within a structure aren't difficult to use. All you have to do is to insert "p" in front of the token code. For example, the DOCINFO structure contains pointer to strings:
typedef struct { 
    int     cbSize; 
    LPCTSTR lpszDocName; 
    LPCTSTR lpszOutput; 
    LPCTSTR lpszDatatype;
    DWORD   fwType;         // Windows 95 only; ignored on Windows NT 
} DOCINFO; 
This structure is used when using the Windows API for printing. PrtDemo.Prg is a sample that makes use of this structure. You can also find it in the WinStruct.Vcx class library. The Visual FoxPro definition looks like this:
DEFINE CLASS DOCINO AS Struct
   cbSize = 0
   lpszDocName = ""
   lpszOutput = ""
   lpszDatatype = ""
   fwType = 0
   cMembers = "l:cbSize, pz:lpszDocName, pz:lpszOutput," + ;
      "pz:lpszDatatype, ul:fwType"
ENDDEFINE
The strings don't have a fixed length. Therefore the structure only contains their address, and the actual string resides in a memory block. You don't have to take care of it, because the struct class does this for you. All you do is to assign a string to loDocInfo.lpszDocName. When you call GetString(), this property is copied into memory, the address is converted and inserted the structure. If Windows changes the string, the new string is retrieved when you call SetString() and the property updated accordingly. 
Nonetheless, there's one thing to take care of, when you use pointers in any variation. The memory block is allocated when you create a structure and released, when you release the object. By default this is 8 KB, which is shared by all pointers in the structure. If you need less, it's no problem, but if your need more than that, you have to increase the value in the structure class. The nMemorySize specifies the amount of memory in bytes that is allocated for pointers. If you don't specify enough memory, GetString() returns an empty string, instead of a structure.
 Now we've covered already pretty much, but there's more: buffers. To understand the need for buffers you have to know that Windows never allocates memory on its own. Whenever you request some information from the Windows API, you have to provide as much memory as is necessary. With some structures this is difficult. The PRINTER_INFO_1 structure for example contains 3 pointers to strings:
typedef struct _PRINTER_INFO_1 { // pri1 
    DWORD  Flags; 
    LPTSTR pDescription; 
    LPTSTR pName; 
    LPTSTR pComment; 
} PRINTER_INFO_1;
These strings are provided by the GetPrinter() API function. The entire structure is 16 bytes long, 4 bytes for the DWORD, and 4 bytes for each pointer. That means, if you pass the string, which the GetString() method returns, you only pass 16 bytes of memory and there would be no place for Windows to store the strings. Therefore the GetPrinter() function receives a pointer to a buffer:
BOOL GetPrinter(
  HANDLE hPrinter,    // handle to printer of interest
  DWORD Level,        // version of printer info data structure
  LPBYTE pPrinter,    // pointer to array of bytes that receives 
                      //  printer info structure
  DWORD cbBuf,        // size, in bytes, of the pPrinter buffer
  LPDWORD pcbNeeded   // pointer to variable with count of bytes 
                      //  retrieved (or required)
);
A buffer, or as it is called in the description, an array of bytes, is merely a block of memory. The first part of this buffer contains the PRINTER_INFO_1 structure, the rest is allocated and Windows can be sure that this memory is available for its use. The GetPrinter() API function stores the 3 strings in the memory area beyond the structure. The pointers point to this area accordingly. For example, if the buffer starts at address 1000, the first string is stored at address 1016 and pDescription would point to that address.
I mentioned several times that Visual FoxPro strings do not have a fixed memory address, because Visual FoxPro moves strings around to optimize memory usage. Therefore you can't simply call GetString() and add maybe a 1000 character string to get a buffer. After the API call, the string might be at a different address, but the pointers inside the structure still point to the now invalid old location. 
The Struct component offers a solution for this problem, as well. For buffers you can use the GetPointer() and SetPointer() methods. They correspond to GetString() and SetString(). The difference is that these methods copy the entire structure into Windows memory and return the address instead of the structure. Because the Struct class manages this memory block, you can be sure that the address won't change until you release the memory block or the structure.
GetPointer() can receive an additional parameter that specifies the size of the memory block. For example, if you call GetPointer(1000) on the PRINTER_INFO_1 structure, you get the address of a 1000 byte memory block where the first 16 bytes contain the structure. Since you now pass the address instead of a string, the declaration this function is slightly different. In ApiDef.Prg you can find the declaration for GetPrinter():
Declare Integer GetPrinter in WinSpool.Drv as WS_GetPrinter ;
   Integer hPrinter, ;
   Integer Level, ;
   Integer pPrinter, ;
   Integer cbBuf, ;
   Integer @pcbNeeded
This declaration uses an alias for the API function, because GETPRINTER() is a Visual FoxPro function and you won't be able to call it if the API function is registered under the same name. The relevant parameter pPrinter is now defined as an Integer, which is a 32-bit value that can hold a memory address. Note that the parameter is not defined as by reference but as by value. This is important because a pointer is, as I mentioned earlier on, a variable that holds an address. As the value we pass is already the address, we cannot pass it by reference. Doing so would force Visual FoxPro to pass the reference of our reference variable, and would therefore be in C terms a pointer to a pointer to a buffer.
Because the buffer doesn't contain any information about its size, you also have to pass the chBuf parameter that contains the size of the buffer. In other words, chBuf is the same value you passed on to GetPointer(). If this buffer is too small, Windows can realize this and sets the pcbNeeded parameter to the number of bytes that are necessary and returns an error code. In this case you can call GetPointer() again, this time specifying the right amount of memory and call the function again.
When you deal with such buffers, you have to be aware that the struct component won't release the memory block until you request so. After you are done with the buffer, you must call FreePointer() passing it the address of the buffer. There's a simple reason why SetPointer() doesn't do this automatically. Some API functions store the address of the buffer for later use. If the Struct class releases the buffer automatically, the address becomes invalid and an exception would be the result when the API function tries to access this buffer later. A complete sequence to use buffers would look like this (you can find this code in the PrinterInfo.PRG sample):
lnNeeded = 0
lnSize = 1000
lnBuffer = loPrtInfo.GetPointer( m.lnSize )
lnOK = WS_GetPrinter( ;
   m.lnHandle, ;
   1, ;
   m.lnBuffer, ;
   m.lnSize, ;
   @lnNeeded ;
)
loPrtInfo.SetPointer( m.lnBuffer )
loPrtInfo.FreePointer( m.lnBuffer )
lnSize specifies the size of the buffer and is used for GetPointer() as well as for the API function. Using a variable makes it easier for you to handle buffers, because if you have to increase the size of the buffer, there's a single place to do so. Also, it reduces the possibility that you pass different values to GetPointer() and the API function which could result in a GPF. GetPointer() copies the structure to memory and returns the address. The API function fills that memory block with printer information. SetPointer() reads the modified memory block and updates the properties. Since you don't need the buffer anymore, FreePointer() releases the memory block. The properties of the loPrtInfo object now contain the values returned by the API function.
Sometimes an API function just wants a buffer without anything in it, not even a structure. In this case you can call the GetBlock() method passing it the size of the buffer. This method returns the address of a buffer that you can use as a parameter for an API function or assign it to a property of a structure object. When you don't need the buffer anymore, you can call FreePointer() to release the buffer.
That's all you need to make use of the struct class in your applications. Of course, there's more which is covered in the following two chapters. The table below contains a short summary of all methods and structures that are available in the Struct class for your use.
Method/Property	Description
cMembers	Contains the definition of the structure in a comma-separated list. Each member is specified with its type. The order in which properties are listed, defines the order in which they are added to the structure.
GetString()	Returns the structure as a string using the current proper values. An empty string is returned when an error occurred.
SetString()	Updates the properties using the string passed to this function. The string has usually been modified by an API function before.
GetPointer()	Returns an address to a memory buffer containing the structure. Optionally you can pass the size of the buffer if more memory is required that the size of the structure indicates. 0 is returned when an error occurred.
SetPointer()	Receives an address to a memory buffer and updates the properties in the structure object with the values stored in the buffer. Usually this function is called after an API function modified the buffer.
FreePointer()	Frees the memory that has been allocated by GetPointer() or GetBlock().
GetBlock()	Returns the address of a memory block with the size specified in the first parameter.
Requery()	Re-evaluates the cMembers property. You call this method after you either changed the cMembers property or when you re-dimensioned an array property. Calling this function releases all allocated memory blocks used for pointers or buffers.
nMemorySize	Specifies the size of memory that is used for all pointers and buffers. The default is 8192 bytes (or 8 KB). This value cannot be changed at runtime, any modification must be done in the class at design time, or in the Init() event before DODEFAULT() is executed.
Customizing the Struct class
The way several things are handled in this class might not fit into your framework. Therefore several methods and properties can be used to customize the default behavior. In this chapter, I discuss these possibilities.
The struct class requires the Convert.FLL. This library contains some conversion functions that convert a numeric value into a binary string as API function requires it. It also contains some function to copy memory into and from a string. You can use these functions, if you don't need the overhead of the Struct class. This library must be loaded. The struct class loads this library during the Init, if the class hasn't already been loaded. It remains in memory until you either issue SET CLASSLIB TO without any parameter or RELEASE ALL, or it unloaded if the library hasn't been loaded before creating the object. It expects the library to be in the current path. 
Sometimes this is the wrong behavior. For example, you might want to copy the FLL into the Windows\System directory, or you want to unload the library when its not needed anymore. There are two places to handle this. The cLibConvert property contains the name and the path of the Convert.Fll. The default value is "CONVERT.FLL". If all you need is to specify a different name or a different fixed path, you can change this property. If you want to modify the process of loading altogether, you can override the LoadLibrary() class. It's called without a parameter and returns .T., when the library could have been loaded, .F. upon an error.
For memory management the Struct class uses a separate class named StructMemory. If you want to subclass StructMemory in order to alter its behavior, you can place the name of your own class in the cClassMemory property. The default value is "StructMemory". Init() calls the CreateMemory() method to instantiate this object. CreateMemory() loads the class library (the same in which your struct class is located), creates the object and stores the reference into the oMemory property. If you want to change this behavior, you can safely override CreateMemory(), for example, when the library in which StructMemory is stored, is not loaded, and so on. The StructMemory class expects one parameter in the Init. This is the size of the memory block it should manage. By default the nMemorySize property is passed. By changing this property you can define how much memory is available to the structure for use with pointers and buffers.
Some structures can be pretty large. When you define your structures visually, you notice that Visual FoxPro has a limit of 254 characters for properties in the Properties Window. Therefore, the struct class doesn't access the cMembers property directly. Instead it calls the GetCMember() method that returns the cMembers property. By overriding this method, you can define even really large structures. Also, since you can insert comments in a method, it's often easier to maintain and find bugs in medium to huge structures, when they are defined in the GetCMember() method. Several classes in WinStruct.VCX override this method for exactly this reason.
The GetOS() method returns "9x" when the application is running on Windows 9x and "NT" when it's running on Windows NT. This value is used for the "x" code of the cMembers property to determine whether UNICODE or ANSI code should be used. You can override this method, if either the detection of the version doesn't work, or if for some reason you want the "x" code not be dependant on the operating system, but for instance, on which API function you declared.
For each member you define in the structure an object based on the StructMember class is created. For each possible type, like 32-bit integer, double, and so on, there's a separate subclass of StructMember. The CreateMember() method is a factory method that creates the proper object based on the type token that is passed to it. If you add new data types to the structure, or you want to subclass existing types, you can override this method to create your objects. The method receives two parameters. The first (tcType) is identical to the last character in the type code used in the cMembers property. The second parameter - tcSpec - must be passed on to the StructMember class. This class receives two parameters in the Init. The first is a reference to the Struct object it belongs to, the second is the tcSpec parameter. CreateMember() returns an object reference to the StructMember object, or NULL, if an error occurred.
An overview on the design
In order to alter the behavior of the Struct component you have to know more than the basics I mentioned up to this point. Please understand that this chapter is only meant as a brief introduction into the design. For detailed information, for example about the parameters, please look up the comments in the source code.
Besides making structures as easy to use as possible, the design of this component should allow flexibility when enhancing the class. Therefore I didn't put anything into one class, but created several classes that are used by the Struct class behind the scenes. None of these classes is loaded directly, but it always uses a factory method used to instantiate the object (I mentioned that in the previous chapter). Also all clean up stuff is driven by several method. Both, Release() and Destroy() call the CleanUp() method. This ensures that the clean up task is even performed if you don't call Release() explicitly. Cleanup() first ensures that it isn't called for the second time. Then it calls ReleaseMembers() to release all member objects, ReleaseLibrary() to eventually release the library and ReleaseMemory() to release the memory object which in turn frees all allocated memory in Windows.
The job of the Struct object is to parse the cMembers property and to control the StructMember objects. But it doesn't perform any conversion itself. This is the job of the StructMember class. For every possible type there's a subclass. In addition, similar types share a common intermediate class. The class hierarchy is described in the following table. Entries with a gray background are abstract classes that are not used directly.
Class	Responsible for
StructMember	abstract base class
	StructCharMember	all string members
		StructCharBufMember	type "C"
		StructCharStringMember	type "Z"
	StructNumberMember	all numeric members
		StructByteMember	type "B"
		StructDoubleMember	type "D"
		StructLongMember	type "L"
		StructWordMember	type "W"
	StructStructMember	type "O"
All StructMember classes share 3 common methods: GetString(), SetString() and SizeOf(). They behave similar to the ones that the Struct class offers, but only handle a single property. Each StructMember is bound to a property in the Struct class. To avoid reference problems, this object doesn't contain a reference to the Struct object or to the memory object. Instead the references are passed whenever the Struct object calls one of the three methods.
Internally the StructMember class parses the type specification, checks whether a property is an array, manages memory it has allocated, and converts a string into a pointer, if the "p" code has been used. As much as possible has been moved up to the StructMember class and is not handled in subclasses. Therefore this class uses some abstract methods: ConvertDataToString and ConvertStringToData, because that's the part that is different between all types. The rest can be generalized when some parameters are known. DataSize() returns the size of the actual element, ElementSize returns the size this member requires in a structure. nElementSize holds the size of an individual element when combined elements are used, i.e. strings. cSetStringConversion and cGetStringConversion contain the function names that are used to convert elements. cProperty is the property to which the member object is bound. lIsPointer and lIsArray determine whether the property is a pointer or an array.
The StructMemory class manages memory. It merely is a wrapper to the Heap memory management API functions. It provides methods to allocate and free memory, to determine the size of a memory block and to copy memory from and to strings. 
