Table of Contents

Class VBUserDefinedTypeLayout

Namespace
RDCore.SDK.Model.Types
Assembly
RDCore.SDK.dll

Where each field of a VBUserDefinedType sits in memory, and how much memory the whole type occupies — MS-VBAL §2.1's "linear concatenation of the aggregated data values possibly with implementation defined padding between data values".

public sealed class VBUserDefinedTypeLayout
Inheritance
VBUserDefinedTypeLayout
Inherited Members

Remarks

A UDT has two sizes, and MS-VBAL §6.1.2.11 says so where it defines Len and LenB: "with user-defined types, Len returns the size as it will be written to the file", while "LenB returns the in-memory size, including any implementation-specific padding between elements". This is the second one, Size. MS-VBA's Len is not the size a Put statement writes either, but the fields' memory widths with no padding, UnpaddedSize.

🎯 The padding is "implementation-specific" by the specification's own word, so RDCore is free to choose it — and chooses MS-VBA's, because a UDT is exactly the kind of thing whose in-memory size a program measures with LenB and then relies on. Each field is aligned to its own natural boundary, and the type as a whole is padded up to the strictest boundary any of its fields asked for.

👉 Widths here are memory widths, which are not always the widths the same value takes in a file: a variable-length String field is a pointer in memory and its characters in a record, and a fixed-length String field is Unicode in memory and ANSI in a record. Len and LenB disagree about a UDT for the padding, and for a fixed-length String field, which Len counts as its characters.

Fields

DefaultPointerWidth

The pointer width a layout assumes when the caller does not say — 32-bit, which is the width every MS-VBA UDT is laid out for, and therefore the one a file or a LenB from MS-VBA agrees with.

public const int DefaultPointerWidth = 4

Field Value

int

Remarks

🚧 A 64-bit host lays the same declaration out differently (a pointer field, LongPtr and a Variant all widen). Len and LenB pass the environment's own width; TODO the record's own Size and memory image still lay it out for 32 bits.

MaxAlignment

The strictest boundary any field is aligned to, whatever its natural alignment would be.

public const int MaxAlignment = 8

Field Value

int

Remarks

An 8-byte boundary, which is what a Double, a Currency and a Date each ask for. Nothing in a UDT asks for more: a Variant is sixteen bytes of data but is itself aligned to eight, and a fixed-length String or a Byte to one.

Properties

Alignment

The boundary the type as a whole is aligned to: the strictest any of its fields asked for.

public int Alignment { get; }

Property Value

int

Fields

Each field, in declaration order, with the offset it sits at.

public IReadOnlyList<VBUserDefinedTypeField> Fields { get; }

Property Value

IReadOnlyList<VBUserDefinedTypeField>

Size

The in-memory size of the whole type, padding included — what LenB reports.

public int Size { get; }

Property Value

int

UnpaddedSize

The fields' widths added up with no padding between or after them, a fixed-length String counted as its characters and a nested record or an array's elements as their own unpadded size — what Len reports of a record.

public int UnpaddedSize { get; }

Property Value

int

Remarks

MS-VBAL §6.1.2.11.1.22 says Len of a record "returns the size as it will be written to the file"; MS-VBA reports this instead, a variable-length String, an object or a resizable array field counting the pointer it is and not what it points at, and RD-VBA does as MS-VBA does: Len of a record of a Long and a String is 12 in a 64-bit host, whatever the String holds.

Methods

Of(VBUserDefinedType, int)

Lays type out.

public static VBUserDefinedTypeLayout Of(VBUserDefinedType type, int pointerWidth = 4)

Parameters

type VBUserDefinedType

The type to lay out.

pointerWidth int

The host's pointer width in bytes; DefaultPointerWidth unless the caller knows better.

Returns

VBUserDefinedTypeLayout

Remarks

A type does not know how many elements a fixed-size array field has: its bounds are reduced where a record of it is allocated, and a field laid out from the type alone has none. Of(VBUserDefinedTypeValue, int) lays out a record that has them.

Of(VBUserDefinedTypeValue, int)

Lays record out: as its type is, each fixed-size array field as wide as the elements the record's own has, and each nested record as it is.

public static VBUserDefinedTypeLayout Of(VBUserDefinedTypeValue record, int pointerWidth = 4)

Parameters

record VBUserDefinedTypeValue

The record to lay out.

pointerWidth int

The host's pointer width in bytes; DefaultPointerWidth unless the caller knows better.

Returns

VBUserDefinedTypeLayout

OffsetOf(string)

The offset of the field named name, or null when the type has no such field.

public int? OffsetOf(string name)

Parameters

name string

The field name, compared the way VBA compares identifiers.

Returns

int?

WidthOf(VBType, int)

How many bytes a value of type occupies in memory, as a field of it would: what an element of an array of the type is wide, each element being at the address of the one before it plus this (MS-VBA, recorded in Excel: 1 for a Byte, 2 for an Integer or a Boolean, 4 for a Long, 8 for a Double or a Currency, a pointer for a String or an object, a VARIANT for a Variant).

public static int WidthOf(VBType type, int pointerWidth)

Parameters

type VBType

The declared type.

pointerWidth int

The host's pointer width in bytes.

Returns

int

Remarks

A record is as wide as its type's layout, padding included; one whose fields are fixed-size arrays is as wide as a record of it says (Of(VBUserDefinedTypeValue, int)), which a type alone does not know.