Navigation:  Programming Cookbook > External Interfacing > External Field Types >

Embedded Fields

Previous pageReturn to chapter overviewNext page

An alternative to embedding a pointer to an object in a structure is to embed the object itself. EmbeddedField and its subclasses support these types of fields. There are two broad categories:

Embedded Structures, represented by StructureField
Embedded Arrays, represented by ArrayField and subclasses

Embedded Structures

Occasionally one encounters structures which have other structures embedded inside them. For example, LV_FINDINFO contains an embedded POINTL as its pt field:

defineFields

  "Define the fields of the Win32 LV_FINDINFO structure.

      LV_FINDINFO compileDefinition

  "

  self

      defineField: #flags type: DWORDField new;

      defineField: #psz type:(PointerField to: String);

      defineField: #lParam type: DWORDField new;

      defineField: #pt type: (StructureField type: POINTL);

      defineField: #vkDirection type: DWORDField new;

 

Note that because the field type is a subclass of ExternalStructure, the answer will reference the original embedded data, and modifications will write directly back into that data.

It is possible to nest structures to an arbitrary depth, and ExternalStructure will automatically calculate the correct size. This is achieved by lazily calculating the size of structures, and may occasionally trigger the recompilation of External Methods that might be dependent on the size of any structures that they reference. Circular nesting is, of course, not possible.

Embedded Arrays

Some structures contain embedded arrays. Embedded fields differ from scalar fields in that the size is not fixed, but is some multiple of the size of the array elements, after taking account of packing. A number of structures embed character arrays (sometimes called "strings"), and there is a  specialized embedded field type for these, StringField. A familiar example is the face name (lfFaceName) in the LOGFONT structure:

defineFields

  "Define the Win32 LOGFONT structure.

      LOGFONT compileDefinition.

  "

  self

      defineField: #lfHeight type: SDWORDField new;

      defineField: #lfWidth type: SDWORDField new;

      ...

      defineField: #lfPitchAndFamily type: BYTEField new;

      defineField: #lfFaceName type: (StringField length: LF_FACESIZE)

 

When the lfFaceName field is accessed by sending #lfFaceName, the answer will be a copy of the data in the structure, so modifications to it will not be reflected back into the structure. To update the lfFaceName field in the structure, it must be sent #lfFaceName: with an appropriate String as the parameter.

Embedded Arrays of Structures

These are relatively uncommon (except perhaps in graphics and mathematical systems), but can be defined using the StructureArrayField field type. For example:

defineFields

  "Define the fields of the hypothetical POLYLINE structure.

  struct {

      int nPoints;

      POINTL aPoints[100];

  } POLYLINE;"

  self

      defineField: #nPoints type: DWORDField new;

      defineField: #aPoints type: (StructureArrayField type: POINTL length: 100)

 

Individual elements of the embedded array can be accessed using the normal Smalltalk syntax, for example:

  | pl r |

  pl := POLYLINE new.

  pl nPoints: 100.

  r := Random new.

  1 to: 100 do: [:i | (pl aPoints at: i) x: (r next * 640) truncated; y: (r next * 480) truncated].

  pl

 

Note that the accessed elements update the original structure in place when modified.

Occasionally one may have to define structures that contain embedded arrays, the contents of which are of no particular interest. In this case it is easiest to define these as being ByteArrays. For example the PAINTSTRUCT structure contains a reserved area of 32 bytes, and this structure is defined in the base Dolphin image as follows:

defineFields

  "Define the Win32 PAINTSTRUCT structure.

      PAINTSTRUCT compileDefinition

  "

  self

      defineField: #hdc type: DWORDField readOnly;

      defineField: #fErase type: BOOLField readOnly;

      defineField: #rcPaint type: (StructureField type: RECT) beReadOnly;

      defineField: #fRestore type: BOOLField filler;

      defineField: #fIncUpdate type: BOOLField filler;

      defineField: #rgbReserved type: (ArrayField type: ByteArray length: 32) beFiller

 

Note that it is necessary to specify the size in bytes as the length.

Variable Length Embedded Arrays of Structures

Very occasionally you may come across embedded arrays of structures where the length is variable. The length of the array is dynamically specified by some other integer field in the structure. This type of field can be represented by Dolphin's VariableStructureArrayField type. For example, the Active-X Automation SAFEARRAY structure is defined as follows:

defineFields

  "Define the fields of the SAFEARRAY structure.

      struct SAFEARRAY {

          unsigned short cDims; // Number of dimensions in the array

          …

          SAFEARRAYBOUND rgsabound[1]; // One bound for each dimension

      }; "

  self

      defineField: #cDims type: WORDField readOnly;

      …

      defineField: #rgsabound    type: (VariableStructureArrayField

                                  type: SAFEARRAYBOUND

                                  length: #cDims) beReadOnly

 

Note that this means that the structure itself will be of variable length, and therefore sending the #byteSize message to the structure class will report a size less than that of any of its actual instances.

Only one variable length embedded field is supported per structure.