Command STRUCTURE | UNION Foundation
Defines a structure or union
STRUCTURE <cName> [PACK <nPackSize>]
VAR <VarName> AS [@][STRUCTURE|UNION] <VarType>[<nArrayLen>]
ENDSTRUCTURE
UNION <cName> [PACK <nPackSize>]
VAR <VarName> AS [@][STRUCTURE|UNION] <VarType>[<nArrayLen>]
ENDUNION
Structures are used to represent structured data in a way allowing the data to be exchanged with operating system APIs or DLL functions using the EXTERN command. The declaration of a structure begins with the statement STRUCTURE. Following the structure name is the declaration of the structure members. The structure declaration ends with the statement ENDSTRUCTURE.
A union is a special case of a structure allowing to map different data items to the same location in memory. Which kind of data is actually stored in the union depends on the respective use-case. The application can access the data in the union through one of the union's members, allowing the application to work with the data using the data type valid for the current use-case. The declaration of a union begins with a UNION and ends with an ENDUNION statement.
Defining structure and union members
Structure and union members are declared using one or more statements of the form:
VAR <VarName> AS [@][STRUCTURE|UNION] <VarType>[<nArrayLen>]
Each member has a unique name defined via <VarName>, and a data type defined via <VarType>. The data type must be set to a key word identifying a parameter type of a DLL function as documented for the EXTERN command. For example, UINTEGER or STRING.
For members whose value is an array (field), the optional <nArrayLen> specifier must be used for reserving sufficient space in the structure or union. In this case, <VarType> specifies the base type of the array elements. Note that specifying an array length is only valid if the value of the member is stored directly within the structure or union.
If a member's value is not stored directly in the structure or union but is accessed via a reference to a certain memory location (pointer), the member's data type must be prefixed with the reference operator (@).
Structures and unions are complex data types and can themselves be defined as members of a structure or union. To do this, the keyword STRUCTURE or UNION must be included in the declaration of the respective member followed by the structure or union name,
Examples:
VAR nId AS UINTEGER // Member is an unsigned integer
VAR lFlag AS BOOL // Member is a 32 bit boolean
VAR cName AS STRING[32] // Member is a string of up to 32 characters
VAR oRect AS STRUCTURE RECT // Member is a RECT structure instance
Creating structure instances
Structure instances are created implicitly from a structure or union declaration by declaring a LOCAL variable of the corresponding type. See the LOCAL statement for syntax and usage information.
Using external memory for initializing structures
The method :setAddress( <nPointer> ) can be used for setting the memory address of a structure instance.
Getting the size of a structure or union
The Byte size a structure or union occupies in memory can be determined by executing the :sizeOf() method on the structure or union instance.
Data type of a structure instance
Structure instances expose themselves as objects to the application. Consequently, the ValType() function returns the data type "O" (object) when called with a structure instance.
// The following example demonstrates using the Tool Help Library API
// for retrieving a list with info on the processes which are currently
// running. The example utilizes PROCESSENTRY32 structures for storing
// process information in conjunction with API functions called via
// the EXTERN command.
#include "dll.ch"
#define MAX_PATH 260
#define TH32CS_SNAPPROCESS 0x00000002
// Structure declaration
/* typedef struct tagPROCESSENTRY32 {
DWORD dwSize;
DWORD cntUsage;
DWORD th32ProcessID;
ULONG_PTR th32DefaultHeapID;
DWORD th32ModuleID;
DWORD cntThreads;
DWORD th32ParentProcessID;
LONG pcPriClassBase;
DWORD dwFlags;
CHAR szExeFile[MAX_PATH];
} PROCESSENTRY32;
*/
STRUCTURE PROCESSENTRY32
VAR dwSize AS UINTEGER
VAR cntUsage AS UINTEGER
VAR th32ProcessID AS UINTEGER
VAR th32DefaultHeapID AS UINTEGER
VAR th32ModuleID AS UINTEGER
VAR cntThreads AS UINTEGER
VAR th32ParentProcessID AS UINTEGER
VAR pcPriClassBase AS UINTEGER
VAR dwFlags AS UINTEGER
VAR szExeFile AS STRING[MAX_PATH]
ENDSTRUCTURE
// API declaration
/* HANDLE CreateToolhelp32Snapshot(
DWORD dwFlags,
DWORD th32ProcessID
);
*/
EXTERN UINTEGER CreateToolhelp32Snapshot( dwFlags AS UINTEGER, th32ProcessID AS UINTEGER ) IN WIN32API
/* BOOL Process32First(
HANDLE hSnapshot,
LPPROCESSENTRY32 lppe
);
*/
EXTERN BOOL Process32First( hSnapshot AS UINTEGER, @lppe AS STRUCTURE ) IN WIN32API
/* BOOL Process32Next(
HANDLE hSnapshot,
LPPROCESSENTRY32 lppe
);
*/
EXTERN BOOL Process32Next( hSnapshot AS UINTEGER, @lppe AS STRUCTURE ) IN WIN32API
/* BOOL CloseHandle(
HANDLE hObject
);
*/
EXTERN BOOL CloseHandle( hObject AS UINTEGER ) IN WIN32API
// Get an array with the list of the processes currently running.
// Each array element contains a DataObject with the following members:
// :Id = Process id
// :EXEFile = Name of .EXE file
// :Threads = Number of threads in process
// :ParentId = Process id of parent process, if any
FUNCTION ProcessList()
// Create a PROCESSENTRY32 instance in a LOCAL variable
LOCAL oPE32 AS STRUCTURE PROCESSENTRY32
LOCAL nHSnapshot
LOCAL aRet := {}
LOCAL oProc
LOCAL lRet
// Create a snapshot of the system's process list
nHSnapshot := CreateToolhelp32Snapshot( TH32CS_SNAPPROCESS, 0 )
IF nHSnapshot == -1
RETURN {}
ENDIF
// Iterate through the process list and add each
// process' id and EXE file name to the return
// array
oPE32:dwSize := oPE32:sizeOf()
lRet := Process32First( nHSnapshot, @oPE32 )
DO WHILE lRet
oProc := DataObject():new()
oProc:Id := oPE32:th32ProcessID
oProc:EXEFile := SubStr(oPE32:szExeFile, 1, At(Chr(0),oPE32:szEXEFile)-1 )
oProc:Threads := oPE32:cntThreads
oProc:ParentId:= oPE32:th32ParentProcessID
AAdd( aRet, oProc )
lRet := Process32Next( nHSnapshot, @oPE32 )
ENDDO
// Free the snapshot of the process list
CloseHandle( nHSnapshot )
RETURN aRet
PROCEDURE Main()
LOCAL aPL
//
// Get the list of running processes, aggregate the desired
// information into an array of strings and display it in an
// AChoice()
//
aPL := ProcessList()
AEval( aPL, {|e| e:=e:EXEFile+" [Id: "+Var2Char(e:Id)+", Threads: "+Var2Char(e:Threads)+", Parent: "+Var2Char(e:ParentId)+"]"},,, .T. )
ASort( aPL )
AChoice( 3,0, MaxRow(),MaxCol(), aPL )
RETURN
If you see anything in the documentation that is not correct, does not match your experience with the particular feature or requires further clarification, please use this form to report a documentation issue.