Command STRUCTURE | UNION Foundation

Defines a structure or union

STRUCTURE <cName> [PACK <nPackSize>] 
   VAR <VarName> AS [@][STRUCTURE|UNION] <VarType>[<nArrayLen>]
UNION <cName> [PACK <nPackSize>] 
   VAR <VarName> AS [@][STRUCTURE|UNION] <VarType>[<nArrayLen>]
The name of the structure or union that is being defined. Structure and union names follow the same convention as symbol names. They must begin with an underscore or a letter and must contain alpha numeric characters. The first 255 characters are significant.
The optional PACK clause specifies the alignment of the structure or union members in the computer's memory. To do this, the Byte boundary the structure or union is allowed to be packed to must be specified in <nPackSize>.

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,


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.

Retrieving a list of the processes currently running
// 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 "" 

  #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]; 
     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] 

  // 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  

  // 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 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 {} 

     // 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 ) 

     // Free the snapshot of the process list 
     CloseHandle( nHSnapshot ) 
  RETURN aRet 

     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 ) 

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.