Older Version
Newer Version
Alyce
Aug 22, 2007
**The ABCs of APIs Lesson 6**
Using Structs
[[toc]]
In [[ABCs of APIs 2|Lesson 2 ]] we learned how to use the **MoveWindow** API call to relocate and resize a window or control. We can retrieve the coordinates of a window or control with **GetWindowRect**. This function requires a STRUCT. A STRUCT is similar to the PTR we discussed in [[ABCs of APIs 5|Lesson 5 ]] because it is a pointer to a location in memory. The similarity ends there, though.
==Defining a STRUCT==
A struct must be defined before it can be used. A STRUCT statement looks like this:
[[code format="vbnet"]]
STRUCT StructName, firstMember as type, secondMember as type
[[code]]
The struct name is listed first, followed by a list of its parts, or **members** separated by commas. The struct may have many members, or just one member. Here is a simple struct with four members.
[[code format="vbnet"]]
STRUCT RECT, left as long, top as long, right as long, bottom as long.
[[code]]
In an earlier lesson we said that a CALLDLL statement must be on a single line. A STRUCT statement must also be on a single line. It can be placed on multiple lines if the underscore line continuation character is used. Liberty BASIC then sees the struct statement as a single line. Here is the struct as it is typed on multiple lines:
[[code format="vbnet"]]
STRUCT RECT,_
left as long,_
top as long,_
right as long,_
bottom as long.
[[code]]
Struct members can be the same types we used the CALLDLL statement. See [[ABCs of APIs 1|Lesson 1 ]]. Here is an example that has a PTR string member and a numeric long member.
[[code format="vbnet"]]
STRUCT PERSON, name$ as PTR, age as long
[[code]]
==STRUCTs as Arguments==
A struct is passed into a calldll statement as an argument with type "as struct". Here is a generic calldll statement that includes a struct.
[[code format="vbnet"]]
STRUCT StructName, firstMember as long secondMember as ulong
CALLDLL FunctionName, handle as ulong, StructName as struct, result as boolean
[[code]]
==Assigning Values==
Some API calls require the programmer to place values into struct members before the function is called. We assign values to the struct members with the equals sign. The struct members are accessed with the name of the struct, followed by a dot, then the member name, another dot, then the word STRUCT. Here is a simple example that creates a struct with a PTR member and a LONG member, then assigns values to both members.
[[code format="vbnet"]]
STRUCT PERSON, name$ as PTR, age as long
PERSON.name$.struct = "John Smith"
PERSON.age.struct = 45
[[code]]
==Size of STRUCT==
Some API functions that have struct arguments have an argument for the size of the struct. We can get the size of a struct with Liberty BASIC's native **LEN()** function with the name of the struct followed by a dot, then the word "struct" inside the parentheses, like this:
[[code format="vbnet"]]
StructSize = LEN(PERSON.struct)
[[code]]
**Note that a bug in Liberty BASIC requires the word "struct" to be in lowercase letters. If instead "STRUCT" is used with LEN() a "type mismatch" error is generated by Liberty BASIC.**
Here is a code snippet to illustrate using **LEN()** to get the size of a struct:
[[code format="vbnet"]]
STRUCT PERSON,name$ as PTR, age as long
StructSize = len(PERSON.struct)
print "The size of the struct is ";StructSize
[[code]]
==Retrieving Values==
We retrieve values from structs in a similar way to the method used to assign values. To assign a value:
[[code format="vbnet"]]
STRUCT PERSON,name$ as PTR, age as long
PERSON.age.struct = 45
[[code]]
To retrieve the value:
[[code format="vbnet"]]
STRUCT PERSON,name$ as PTR, age as long
PERSON.age.struct = 45
ageValue = PERSON.age.struct
print "Age is "; ageValue
[[code]]
==Getting a Window's Coordinates==
We now know enough to make the **GetWindowRect** API call to retrieve a window's coordinates. The function requires a RECT struct, which looks like this:
[[code format="vbnet"]]
STRUCT RECT,_
left as long,_
top as long,_
right as long,_
bottom as long.
[[code]]
The Microsoft documentation for this structure gives us this information:
//
Members
left
Specifies the x-coordinate of the upper-left corner of the rectangle.
top
Specifies the y-coordinate of the upper-left corner of the rectangle.
right
Specifies the x-coordinate of the lower-right corner of the rectangle.
bottom
Specifies the y-coordinate of the lower-right corner of the rectangle.
//
The API function looks like this:
[[code format="vbnet"]]
calldll #user32, "GetWindowRect",_
hWindow as ulong,_ 'window handle
RECT as struct,_ 'struct containing info
result as boolean 'nonzero = success
[[code]]
Here is a small program that uses this function. It first sets up a RECT struct and obtains the handle of the window with Liberty BASIC's **HWND()** function. It then makes the **GetWindowRect** API call. After the function returns, the window's coordinates are contained in the struct. The program prints them in the mainwin for us to see.
[[code format="vbnet"]]
open "Test Window" for window as #1
#1 "trapclose [quit]"
'get the window's handle
hWindow = HWND(#1)
'declare a struct:
STRUCT RECT,_
left as long,_
top as long,_
right as long,_
bottom as long
'retrieve window coordinates:
calldll #user32, "GetWindowRect",_
hWindow as ulong,_ 'window handle
RECT as struct,_ 'struct containing info
result as boolean 'nonzero = success
'print coords in mainwin:
print "The left coordinate is ";RECT.left.struct
print "The top coordinate is ";RECT.top.struct
print "The right coordinate is ";RECT.right.struct
print "The bottom coordinate is ";RECT.bottom.struct
wait
[quit] close #1:end
[[code]]
==Using Values Retrieved from Structs==
The previous example printed the values in the struct. We can also assign their values to variables. If we use the struct again in another API call, the values will change. We can save the values in variables. To save the top coordinate of the window in the variable WindowTop, we do this:
[[code format="vbnet"]]
WindowTop = RECT.top.struct
[[code]]
The values in structs can be used in any way that variables and literal values can be used. Since we know the window's coordinates, we can obtain its width and height by subtracting values. We subtract the left value from the right value to get the width. We subtract the top value from the bottom value to get the height.
[[code format="vbnet"]]
'do math on retrieved values to get width and height:
width = RECT.right.struct - RECT.left.struct
height = RECT.bottom.struct - RECT.top.struct
[[code]]
Here it is, used in the sample program:
[[code format="vbnet"]]
open "Test Window" for window as #1
#1 "trapclose [quit]"
'get the window's handle
hWindow = HWND(#1)
'declare a struct:
STRUCT RECT,_
left as long,_
top as long,_
right as long,_
bottom as long
'retrieve window coordinates:
calldll #user32, "GetWindowRect",_
hWindow as ulong,_ 'window handle
RECT as struct,_ 'struct containing info
result as boolean 'nonzero = success
'do math on retrieved values to get width and height:
width = RECT.right.struct - RECT.left.struct
height = RECT.bottom.struct - RECT.top.struct
print "Width is ";width
print "Height is ";height
wait
[quit] close #1:end
[[code]]
==More?==
You can improve your STRUCT skills by trying these methods on other types of windows and controls. What happens if you try to obtain the coordinates of a button? A dialog window? Try it and see!
==What's Next?==
[[ABCs of APIs 7|Lesson 7 ]] will discuss the use of structs as pointers to numeric values.
Written by Alyce Watson. For more on APIs, see:
[[http://www.lulu.com/content/611431|APIs for Liberty BASIC]]