GEOS Programming: 4.1 Using Classes and Objects: Defining a New Class or Subclass

Up: GEOS SDK TechDocs | Up | Prev: 4 Using Classes and Objects | Next: 4.2 Non-relocatable Data
@class, @classdecl, @endc, @default, @uses

You can create new classes in GEOS by using the Goc keywords @class and @endc . These frame the class definition as shown in Defining Classes ; the @endc keyword takes no parameters, but @class takes the following parameters:

@class    <cname>, <super> [, master [, variant]];
cname
This is the name of the new class.
super
This is the class name of the superclass.
master
When included, this word makes the new class a master class.
variant
When included, this word makes the new class a variant class. All variant classes must also be declared master classes.

Every class must have a class structure ( ClassStruct ) in memory. This is created and filled automatically by Goc and the kernel; however, you must use the @classdecl keyword to make sure the structure gets built. Only one @classdecl statement may be used for each class, however--Goc will give an error if the class is declared twice. This is also shown in Defining Classes , and its parameters are as follows:

@classdecl    <cname> [, <cflags>];
cname
This is the name of the class being declared.
cflags
These are optional flags, described below.

The optional flags that can be used with a class declaration determine how objects of the class get shut down (see Class_flags ). The flags you can use with @classdecl are

neverSaved
This flag indicates that objects of this class will neither be written to a state file nor be loaded in from a resource. This flag should only be used for classes whose objects will only be created at run-time (not declared in the .goc file) and for process classes.
discardOnSave
This flag applies only to master classes. Objects of this class will never be saved to a state file and must be re-initialized each time they are loaded. If you want an object simply to revert to its default configuration each time it is loaded, use the flag ignoreDirty instead in the object's declaration (see @object , in Declaring an Object ).

In addition, any variant class can have a default superclass. The variant is resolved at compile-time to have the default superclass as its superclass. To set a default superclass for a variant class, add a line with the following structure in the class definition:

@default <varRoot> = <super>;
varRoot
The name of the variant class with "Class" removed. (For example, GenClass would be specified as "Gen.")
super
The name of the superclass to set as the default.

Sometimes a variant class will know that it will be the subclass of a specific class, though it doesn't know (at compile time) just how that ancestry will be traced. You can use the @uses directive to let the compiler know this; that way, the variant class can define handlers for the "used" class. For example, if you know that variant class MyVariantClass will always be resolved as a descendant of MyAncestorClass , you can put the directive

@uses MyAncestorClass;

in the definition of MyVariantClass . The general format is

@uses <class>;
class
The class which will always be an ancestor to this class.

Code Display 5-6 Defining Classes

/* The @class keyword defines a new class or subclass. @endc ends the class
 * definition, and @classdecl must be put somewhere in the code to make sure Glue
 * will link the class structure into the compiled geode.*/
@class	MyNewClass, VisClass;
    /* Message declarations would go here. See @message.
     * Instance data field declarations would go here. See @instance
     * 						and @vardata. */
@endc
@classdecl MyNewClass, neverSaved;
@class	MyTriggerClass, GenTriggerClass;
    /* New messages for this subclass are defined here. */
    /* New instance data fields for this subclass are defined here. */
@endc
@classdecl MyTriggerClass;
/* When defining a variant class (which must also be a master class), you can
 * set a superclass for the variant at compile-time using @default. */
@class	MyNewVariantClass, MetaClass, master, variant;
    @default		MyNewVariant = VisClass;
@endc	MyNewVariantClass
@classdecl MyNewVariantClass;

Defining New Messages for a Class

@message, @stack, @reserveMessages, @exportMessages, @importMessage, @alias, @prototype

As discussed in The GEOS Message System , messages are simply 16-bit numbers allocated as an enumerated type. When a new class is defined, a constant is automatically created representing the first message number for the class. This constant is then used as the first number in the enumeration of messages.

The constant is built off the class' superclass. MetaClass has the first 16384 messages reserved for its use. Each master level gets 8192, and the first master class of a level gets 2048 of these. All other classes are allocated 512 message spots. Thus, a master class subclassed directly off MetaClass would have 2048 messages beginning with number #16384 (since the numbering is zero-based). A subclass of this would have 512 messages beginning with number #18432.

This numbering scheme ensures that no two classes at different levels in the class hierarchy will have the same message number. Specifically, a class will never have the same message number as one of its sub- or superclasses.

New messages must be defined in the class definition between the @class and @endc keywords (see above). They are defined much like normal function calls and follow the normal C calling conventions (see Defining Messages for examples). If your class uses messages from its superclass, you do not have to declare these messages in your class definition--they are inherited automatically. This is true even if you are subclassing the method to alter its functionality.

To define a new message, use the @message keyword. This keyword takes the following parameters:

@message   <retType> <mname>(<param>*);
retType
This is the data type of the return value of the message. It can be any standard C or GEOS data type (excluding structures), or a pointer to a structure. If this message has multiple return values, you must do as in C function calls and pass pointers to buffers for the return information.
mname
This is the name of the message. By convention, it will be MSG_ followed by a shortened version of the name of the class and then some useful name (e.g., MSG_META_INITIALIZE ).
param
This represents one or more parameters. Messages may have no parameters, one parameter, or several parameters. Parameter definition is essentially the same as definition of function parameters; see Defining Messages for examples.

NOTE: When defining a function with no parameters, it is best to declare it with "void" between the parentheses. This will make sure Goc gives an error if the function is called with arguments.

Messages for Use with Assembly Code

The @stack keyword indicates that parameters are passed on the stack; it is important to note that because of calling conventions, parameters passed on the stack must be listed in the message definition in reverse order from the way the handler pops them from the stack. This keyword is used only when the message may be handled by an assembly language method; its format is shown below:

@message <retType> <mname>(@stack <param>*);

All the parameters shown in the formats are the same as in the normal @message format.

Code Display 5-7 Defining Messages

	/* Each message is defined for a class within the class definition. */
@class	MyTriggerClass, GenTriggerClass;
	/* All the new messages MyTriggerClass can handle are defined here. */
@message void MSG_MYTRIG_SET_COLOR(colors colorIndex);
@message optr MSG_MYTRIG_RETURN_OPTR( void );
@message void MSG_MYTRIG_COLLECT_PARAMS(byte bParam, word wParam, char * string);
	/* Instance data fields would be defined here. */
@endc
@classdecl MyTriggerClass;

Exporting, Importing, and Reserving Message Ranges

As discussed above, message numbers are assigned based on the class' location in the class tree. No message number will ever conflict with messages defined in the class' superclasses. However, the assignment scheme opens up the possibility that classes on the same level in the class tree could have conflicting message numbers, as shown below.

Normally, this is not a problem. If subclasses are to receive the same message and handle it differently, the message can typically be defined in the superclass and simply be intercepted by the subclasses. Sometimes, however, different subclasses will need to have different definitions for the same messages. For example, a class supplied by a library may be used by several applications; if the applications each create a subclass, these subclasses can import particular messages that will be the same for all the subclasses in all the applications.

Goc therefore allows a class to export a range of message numbers which subclasses can import and create specific definitions for. This allows you greater control over what aspects of the class you can define.

To export a range of messages, use the @exportMessages keyword. This will set aside several message numbers which can then be imported by subclasses using the @importMessage keyword.

Another potential problem is upgrading your program from release to release. If you create classes that may grow in the future, you may want to reserve a number of message spots to ensure that those spots can be filled in later. Nothing is done with the spots; they are simply place holders for future upgrades. You can use the @reserveMessages keyword to reserve a range of any size. The parameters of these three keywords are shown below:

@reserveMessages    <num>;
@exportMessages     <expName>, <num>;
@importMessage	      <expName>, <messageDef>;
num
This is the number of messages in the exported range.
expName
This is the name of the exported range. This is used when importing messages to ensure that the proper numbers are used.
messageDef
This is a standard message definition line, the same as would be found with the @message keyword (though @message is left out).

Note that you do not need to reserve messages for upgrades; any class can always have messages tacked on to the end of its class definition. If you want to group the messages logically, however, you should reserve ranges where you expect additions to be made.

Aliasing Messages

The @alias keyword allows a single message to have more than one pass/return format. The @prototype keyword allows quick, clean, and convenient repetition of a single format for many different messages; it also allows a class to create a prototype so users of a message can have their own messages with the same format.

@alias is used when a single method takes conditional parameters. For example, a method may take a word value in a certain case and a dword value in another (dependent upon a passed flag). Each condition must be accounted for in its own message format. Rather than create a message and a method for each case, you can create a single assembly-language method for all the different pass/return formats; then, you can use @alias to make several messages refer to the same method, each using a different format.

@alias(<protoMsg>) <msgDef>;
protoMsg
The name of the original message. The new message may have different pass/return values but will invoke the same method code and will have the same message number.
msgDef
The new message definition. It follows the same format as messages defined with the @message keyword (with @message left off).

In addition, if you have a single pass/return format for many messages, you can use the @prototype keyword as coding shorthand. For example, if an object has ten messages that all take two parameters and return a single value, you can set up the format with the @prototype keyword and then use a simpler format for definition of your messages. An example is shown in Aliasing Messages , and the parameters of this keyword are shown below.

@prototype <msgDef>;
msgDef
This is the standard message definition. For the message name, use something like " MY_PROTOTYPE " that you can insert later into the definitions of your real messages. All other parts of the message definition are the same as would be declared with @message (with @message left off).

Code Display 5-8 Aliasing Messages

	/* MyClass in this example uses both prototype and aliased messages. */
@class MyClass, MetaClass;
	/* The following is a normal message declaration. The register that this
	 * parameter uses is specified because the handler (method) is written in
	 * assembly language. */
@message void MSG_MESSAGE_WITH_WORD(byte flag = cl, word value = dx);
	/* The following message invokes the same method as the alias above.
	 * It has the same message number but passes a different sized parameter
	 * in different registers. */
@alias(MSG_MESSAGE_WITH_WORD) void MSG_MESSAGE_WITH_DWORD(byte flag = cl,
							dword value = dx:bp);
	/* The following message is not used. Its pass and return values can
	 * be used elsewhere, however, to ensure that all handlers of this message
	 * type are given the same format. */
@prototype int MSG_MYCLASS_PROTO(int a, int b);
	/* The following have the same return values and parameters
	 * as the prototype above. */
@message(MSG_MYCLASS_PROTO) MSG_MY_CLASS_ADD;
@message(MSG_MYCLASS_PROTO) MSG_MY_CLASS_SUBTRACT;
@message(MSG_MYCLASS_PROTO) MSG_MY_CLASS_MULTIPLY;
@endc
@classdecl MyClass;

Defining Instance Data Fields

@instance, @composite, @link, @visMoniker, @kbdAccelerator

Instance data fields are all defined with the @instance keyword. Other keywords may be included in the @instance declaration for special types of data. All instance data definitions must appear between the class' @class and @endc keywords (see above under class definition).

The @instance keyword is used to define normal instance data. If you have data that must be added or removed dynamically (such as hints), use the @vardata keyword, described in Defining and Working With Variable Data Fields . Also, if you have data that requires relocation (such as pointers to fixed data) when the object is loaded, use the @reloc keyword.

The format of the @instance keyword is as follows:

@instance    <insType>    <iname> = <default>;
insType
A standard C or GEOS data or structure type representing the data type of the instance field.
iname
The name of the instance field.
default
The default value of the instance field if it is not filled in when an object of this class is instantiated. The value must, of course, be appropriate for the data type.

Goc has several special types of instance data fields that you can declare along with @instance to make object definition easier. The format for using one of the special types is shown below (with examples in Declaring Instance Data Fields ). Each of the types is also described below.

@instance    <specType> <iname>;
specType
This is the keyword (one of those shown in the list below) that defines the special type of this field.
iname
This is the name of the instance field.

The special types are given here:

@composite
This field is used when objects of the class being defined are allowed to have children. The @composite field will actually contain an optr to the first child object in an object tree. Since most objects in object trees are subclassed from VisClass or GenClass , you will most likely never use the @composite keyword. Both VisCompClass and GenClass have @composite fields predefined. The @composite type has a special format, shown below:
@instance  @composite <iname> = <linkName>;
where iname is the name of the instance field and linkName is the name of the field designated as @link (below). Note that there must be a @link field in every class that has a @composite field. See Managing Object Trees for more information on object trees and the composite and link fields.
@link
This field is used by objects that can be children in an object tree. Where the @composite field points to the first child, the @link field points to the next sibling. If there is no next sibling, this field will point back to the parent object. Since most objects in object trees are subclassed from VisClass or GenClass , you will most likely never use the @link keyword. Both VisClass and GenClass have @link fields predefined.
@visMoniker
This field is designated as holding a pointer to a visual moniker chunk for the object. It is used in GenClass --see the GenClass chapterfor information on the GI_visMoniker field. The moniker or moniker list must be in the same resource as the generic object using that moniker since only the chunk's handle is stored. A moniker list can store full object pointers to its monikers, so monikers referenced by a list need not be in the same resource as that list; thus if an object's moniker is specified via a list, then while the list must be in the same resource as the object, the monikers themselves need not be.
@kbdAccelerator
This field contains a character sequence that, when typed by the user, causes the object to execute its default operation. For example, a keyboard accelerator could invoke a trigger implemented as a menu item. It is used in GenClass only.

Code Display 5-9 Declaring Instance Data Fields

/* GenClass is a good example of many of the different types of fields. */
@class	GenClass, VisClass, master, variant;
	/* The GenClass messages are defined here. */
    @instance @link GI_link;
    @instance @composite GI_comp = GI_link;
    @instance @visMoniker GI_visMoniker;
    @instance @kbdAccelerator GI_kbdAccelerator;
    @instance byte GI_attrs = 0;
    @instance byte GI_states = (GS_USABLE|GS_ENABLED);
	/* Hints and other variable data fields are defined with @vardata. */
@endc

New Defaults for Subclassed Instance Data Fields

@default

Recall that when defining an instance data field you can set up a default value for that field. When creating a subclass, you may wish to specify that the subclass should have a different default value for a given field than the superclass does. Use the @default keyword to do this:

@default <iname> = <default>;
iname
The name of the instance field.
default
The new default value of the instance field if it is not filled in when an object of this class is instantiated. The value must, of course, be appropriate for the data type. You may use @default as part of this value; this @default will be treated as the value of the superclass. (If this seems confusing, try looking at the example.)

For example, a subclass of GenInteraction could set GIV_DIALOG as its default value for the GenInteraction instance field GII_visibility :

@default GII_visibility = GIV_DIALOG;

A generic class might want to have the same value for its GI_states field as its superclass, except with the GS_USABLE flag turned off:

@default GI_states = @default & ~GS_USABLE;

Defining and Working With Variable Data Fields

@vardata, @vardataAlias, ObjVarAddData(), ObjVarDeleteData(), ObjVarDeleteDataAt(), ObjVarScanData(), ObjVarFindData(), ObjVarDerefData(), ObjVarDeleteDataRange(), ObjVarCopyDataRange(), MSG_META_ADD_VAR_DATA, MSG_META_DELETE_VAR_DATA, MSG_META_INITIALIZE_VAR_DATA, MSG_META_GET_VAR_DATA

Most classes will have well-defined instance data fields; each object in the class will have the same data structures, and all the instance chunks will look relatively similar and will be the same size.

Many classes, however, will also use "variable data," or instance fields that may be added or removed dynamically. This allows objects within the same class to have more or less instance data than other objects in the class. One example of variable data is the use of hints in generic UI objects. Because each object in a given class may or may not have hints, the objects can actually have different instance sizes. Variable data instance fields are defined with the use of the @vardata keyword.

Using variable data, however, is somewhat more complex than using standard instance data. You must use special kernel routines or messages to get a pointer to the data; then you can use the pointer to access the field.

Variable data is stored together at the end of the instance chunk in "data entries." Each entry consists of a primary word and optional extra data. The primary word represents a data type defined by the keyword @vardata . This type is created automatically by Goc when the @vardata keyword is used.

Each data entry is associated with a master class level and is considered part of the instance data for that master level (despite being stored at the end of the instance chunk). Thus, when a master part of an object is destroyed, the variable data entries associated with that master class will also be destroyed. For example, when a UI object is set not usable (taken off the screen), its Vis master part is removed from the instance chunk; any variable data entries associated with VisClass will also be destroyed.

Variable data may also be tagged for saving to the state file. That is, you can set up individual data entries to be saved to a state file and to be reinstated when the object is loaded from the state file. For more information about state saving, see Saving Object State .

Variable data may be defined in an object's declaration in your .goc file or may be added and removed during execution. This gives the potential for using variable data as temporary storage in an object's instance chunk; however, temporary data used in this manner should be kept small to avoid slowing down the system--constantly resizing instance chunks to add and remove vardata fields makes more work for the memory manager.

To define a variable data type in a given class, use the @vardata keyword as follows (an example is given in Defining Variable Data ):

@vardata    <type> <vname>;
type
This is the data type of any extra data associated with the variable data. It must be a standard C or GEOS data type. If the type void is specified, no extra data will be added to the data entry when it is created. (An instance data field may be declared as an array, just as in standard C.)
vname
This is the name of the variable data type. This name is used whenever referring to the vardata entry. Note that no two variable data types should have the same name, even if they're in different classes. Doing so will cause a compilation error. It's a good practice to put the class name within the data type name.

Code Display 5-10 Examples of Instance Data Declarations

/* These are some data fields for MyDataClass.
 */
    @instance		ChunkHandle		MDI_aChunk;
    @instance		HelloInfoFlags		MDI_flags;
    @instance		byte		MDI_lotsOfNumbers[32];

Some vardata types may have varying amounts of extra data. For example, one type may have either a word or a dword of extra data. To allow this, you can set up an alias with the new type attached using the keyword @vardataAlias :

@vardataAlias  (<origName>) <newType> <newName>;
origName
This is the name of the original variable data field already defined with @vardata .
newType
This is the data type of the new variable data field, a standard C or GEOS data type.
newName
This is the name of the new variable data field. In essence, the original and new fields will have the same data type word but will have different extra data size.

As noted earlier, the data type field in the data entry has two flags associated with it. These flags are each one bit:

VDF_EXTRA_DATA
This flag indicates that this data type carries extra data.
VDF_SAVE_TO_STATE
This flag indicates that this particular data entry should be saved along with all the other object's instance data when the state is saved. It should likewise be restored when the object is restored from the state file. Unless set off explicitly, this flag will be set for every data type defined in a .goc or .goh file.

The bitmask VDF_TYPE is a bitwise OR of VDF_EXTRA_DATA and VDF_SAVE_TO_STATE. You can use it to mask out all but those bits.

Code Display 5-11 Defining Variable Data

/* Hints are defined with the @vardata command, as is shown in GenClass. Only a
 * small portion of the hints for GenClass are shown here. Those with structures
 * or data types (not "void") have extra data fields associated with them. */
@class GenClass, VisClass, master, variant;
	/* Messages are defined here. */
	/* Followed by instance data defined with @instance. */
    @vardata void HINT_CENTER_MONIKER;
    @vardata SpecSizeSpec HINT_CUSTOM_CHILD_SPACING;
    @vardata char[] ATTR_GEN_INIT_FILE_KEY;
	/* Relocatable instance fields (see the next section) are defined with
	 * @reloc. This field contains an object pointer that must be resolved
	 * when the GenClass object is loaded. */
    @instance @link GI_link;
	@reloc GI_link, optr;
    @vardata DestinationClassArgs ATTR_GEN_DESTINATION_CLASS;
	@reloc ATTR_GEN_DESTINATION_CLASS, 0, optr;
@endc

The kernel provides a number of routines an object may use to add, remove, and change its own vardata entries. Note that all these routines must be called from within the object containing the variable data entries; since variable data is instance data, it is against OOP doctrine for one object to alter another object's variable data directly.

Instead, MetaClass provides vardata messages that can be sent by one object to another to add, remove, change, or retrieve vardata entries of another object. The kernel routines and MetaClass messages are outlined below:

The four messages (in MetaClass ) that can be used to add, delete, and alter variable data entries remotely are listed below. Classes will never need to intercept and subclass these messages because the proper functionality is implemented in MetaClass .

MSG_META_ADD_VAR_DATA
Adds a new vardata type to the recipient object. If the type already exists, the passed type replaces the old one.
MSG_META_DELETE_VAR_DATA
Deletes a vardata type from the recipient's instance data. If the type does not exist, nothing is done.
MSG_META_INITIALIZE_VAR_DATA
Used when something is trying to access an object's vardata field remotely but the field has not yet been added to the object or initialized. The object must create and/or initialize the vardata field at this point.
MSG_META_GET_VAR_DATA
Returns the extra data set for the passed data type.

In addition to supporting variable data structures, GEOS allows you to set up "handlers" for different variable data types. Handlers are routines that process a given data entry; for example, each generic UI object stores a number of hints. Specific UI classes, when attached to the generic object, have a specific routine to handle each hint supported. Some specific UIs do nothing with certain hints; these specific UIs do not have handlers for those hints.

Handlers are associated with data types through the use of a VarDataCHandler table. This is a table that you set up in your .goc file that contains pairings of routine names with @vardata field names. An example of the VarDataCHandler table is shown in Variable Data Handlers .

A handler is simply a normal C routine or function and is defined as such. The handler should be declared as an _pascal routine.The table pairs the handler with the @vardata data type, and when ObjVarScanData() is called, all handlers for all data types are called in order. This is true for the object's class and all its superclasses since variable data is inherited just as normal instance data is. The handler can do almost anything appropriate with the exception of destroying the object or adding or deleting variable data from the object.

Code Display 5-12 Variable Data Handlers

	/* This example is taken from the C VarData sample application. */
/* This is a VarDataCHandler. It is called by the ObjVarScanData() routine when
 * the data type corresponding to this routine in the VarDataCHandlerTable
 * is encountered. The parameters indicated are passed.
 *
 * This particular handler is actually used for several different data types
 * (see VarDataCHandlerTable below). The data type can be distinguished by
 * the `dataType' parameter. 
 *
 * NOTE: VarDataInteractionHintHandler, like any handler used in a 
 * VarDataCHandler structure, must be declared _pascal. */
void _pascal VarDataInteractionHintHandler(MemHandle mh, ChunkHandle chnk, 
		void *data, word dataType, HandlerData *handlerData) {
    if (dataType == HINT_ORIENT_CHILDREN_HORIZONTALLY) {
	handlerData->HD_flags.has_horiz = 1;
    } else if (dataType == HINT_ORIENT_CHILDREN_VERTICALLY) {
	handlerData->HD_flags.has_vert = 1;
    } else if (dataType == HINT_ALLOW_CHILDREN_TO_WRAP) {
	handlerData->HD_flags.has_allow_wrap = 1;
    } else if ((dataType == HINT_WRAP_AFTER_CHILD_COUNT) &&
		(((WrapAfterChildCountData *) data)->WACCE_childCount == 2)) {
	handlerData->HD_flags.has_wrap_after = 1;
    }
}
/* This is the VarDataCHandler Table. It consists of data type/VarDataCHandler
 * pairs. The VarDataCHandlers are far routines. */
static VarDataCHandler varDataInteractionHandlerTable[] = {
    {HINT_ORIENT_CHILDREN_HORIZONTALLY, VarDataInteractionHintHandler},
    {HINT_ORIENT_CHILDREN_VERTICALLY, VarDataInteractionHintHandler},
    {HINT_ALLOW_CHILDREN_TO_WRAP, VarDataInteractionHintHandler},
    {HINT_WRAP_AFTER_CHILD_COUNT, VarDataInteractionHintHandler}
};

Defining Relocatable Data

@reloc

Some objects and classes may have instance data fields that must be resolved when the object is loaded and linked at run-time. For example, if the object contains an optr to another object, that optr must be updated when the object is loaded and resolved since the global memory handle can't be known at compile-time.

For some special instance fields, this happens automatically. For example, the @composite and @link fields as well as optrs are automatically resolved. However, if you add your own instance fields requiring relocation, you will have to set them up with the @reloc keyword. This is true for both static and variable data.

This keyword uses two formats. The first listed here is for normal, static instance data, and the second is used with variable data.

 @reloc    <iname>, [(<count>, <struct>)] <ptrType>;
iname
This is the name of the relocatable instance field.
count
If the instance variable is an array of relocatable data or structures containing relocatable fields, this is the number of elements in the array.
struct
If the relocatable data is an array of structures, this represents the name of the field within each structure that requires relocation.
ptrType
This is the type of relocatable data contained in the field. It may be one of optr , ptr , or handle .
@reloc <vname>, <fn>, [(<count>, <struct>)] ptrType;
vname
This is the name of the variable data type.
fn
This is the name of the field within the variable data's extra data. If there is no extra data with this data type, put a zero rather than a name.
count
If the instance variable is an array of relocatable data or structures containing relocatable fields, this is the number of elements in the array.
struct
If the relocatable data is an array of structures, this represents the name of the field within each structure that requires relocation.
ptrType
This is the type of relocatable data contained in the field. It may be one of optr , ptr , or handle .

Up: GEOS SDK TechDocs | Up | Prev: 4 Using Classes and Objects | Next: 4.2 Non-relocatable Data