Older Version
Newer Version
StPendl
Jan 2, 2011
- "corrected boolean into long"
**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: [[codeformat="vbnet"]]format="lb"]] 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. [[codeformat="vbnet"]]format="lb"]] 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: [[codeformat="vbnet"]]format="lb"]] 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. [[codeformat="vbnet"]]format="lb"]] 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. [[codeformat="vbnet"]]format="lb"]] STRUCT StructName, firstMember as long secondMember as ulong CALLDLL FunctionName, handle as ulong, StructName as struct, result asbooleanlong [[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. [[codeformat="vbnet"]]format="lb"]] 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: [[codeformat="vbnet"]]format="lb"]] 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: [[codeformat="vbnet"]]format="lb"]] 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: [[codeformat="vbnet"]]format="lb"]] STRUCT PERSON,name$ as PTR, age as long PERSON.age.struct = 45 [[code]] To retrieve the value: [[codeformat="vbnet"]]format="lb"]] 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: [[codeformat="vbnet"]]format="lb"]] 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: [[codeformat="vbnet"]]format="lb"]] calldll #user32, "GetWindowRect",_ hWindow as ulong,_ 'window handle RECT as struct,_ 'struct containing info result asboolean 'nonzerolong '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. [[codeformat="vbnet"]]format="lb"]] 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 asboolean 'nonzerolong '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: [[codeformat="vbnet"]]format="lb"]] 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. [[codeformat="vbnet"]]format="lb"]] '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: [[codeformat="vbnet"]]format="lb"]] 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 asboolean 'nonzerolong '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]]