Table of Contents

Class VBUserDefinedTypeImage

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

The bytes a VBUserDefinedTypeValue occupies in memory, laid out by VBUserDefinedTypeLayout — what an LSet between two UDT variables copies (MS-VBAL §5.4.3.6).

public static class VBUserDefinedTypeImage
Inheritance
VBUserDefinedTypeImage
Inherited Members

Remarks

The specification says twice that this is implementation-defined: "the data in expression (as stored in memory in an implementation-defined manner) is copied into bound-variable-expression in an implementation-defined manner". What it does not say, and what every VBA program using LSet on a UDT relies on, is that the copy reinterprets: the source's bytes are laid out by the source's own type and read back through the destination's, which is how VBA fakes a union. So this is a byte image and not a field-by-field assignment — between two UDTs of the same shape the two would agree, and between different shapes only the byte image does what the program meant.

👉 These are memory widths, the ones LenB counts. They are not the widths the same value takes in a record: VBUserDefinedTypeLayout's own remarks say why the two differ, and RecordDataFormat is the other one.

Methods

Copy(VBUserDefinedTypeValue, VBUserDefinedTypeValue)

Copies source into destination as bytes (MS-VBAL §5.4.3.6), reinterpreting them through the destination's own layout.

public static void Copy(VBUserDefinedTypeValue source, VBUserDefinedTypeValue destination)

Parameters

source VBUserDefinedTypeValue

The value read.

destination VBUserDefinedTypeValue

The value written, field by field, in place.

Remarks

Only the bytes both types have are copied, as a copy between records of different sizes must be: a destination field that does not fit entirely inside the source's image is left at its declared type's default rather than being filled with half a value.

Decode(VBType, ReadOnlySpan<byte>)

The value of type that bytes are the memory image of, as Encode(VBType, VBTypedValue, int, int) laid it out.

public static VBTypedValue Decode(VBType type, ReadOnlySpan<byte> bytes)

Parameters

type VBType

The declared type.

bytes ReadOnlySpan<byte>

The bytes.

Returns

VBTypedValue

Encode(VBType, VBTypedValue, int, int)

The bytes a value of type occupies in memory, width of them, or null when a value of the type is a pointer to its bytes rather than the bytes (HasBytesOfItsOwn(VBType)): what an element of an array is at its address.

public static byte[]? Encode(VBType type, VBTypedValue value, int width, int pointerWidth)

Parameters

type VBType

The declared type, which says how the value is laid out.

value VBTypedValue

The value.

width int

How many bytes a value of the type occupies (WidthOf(VBType, int)).

pointerWidth int

The host's pointer width in bytes, which a record's layout depends on.

Returns

byte[]

HasBytesOfItsOwn(VBType)

Whether a value of type is its bytes in memory, rather than a pointer to them: a number, a Boolean, a Date, a fixed-length String, and a record of such fields are; a variable-length String, an object, a Variant and an array are not.

public static bool HasBytesOfItsOwn(VBType type)

Parameters

type VBType

The declared type.

Returns

bool

HoldsVariableLengthString(VBUserDefinedType)

Whether type has a variable-length String member, directly or in a user-defined type that it has as a member.

public static bool HoldsVariableLengthString(VBUserDefinedType type)

Parameters

type VBUserDefinedType

The user-defined type to look into.

Returns

bool

Remarks

A fixed-length String member is not one: its characters are in the record. A variable-length one is a pointer, and it is what makes a byte copy of the record (LSet, MS-VBAL §5.4.3.6) unsafe in MS-VBA.

IsLaidOutByTheHost(VBType)

Whether a value of type is in memory what the host lays out, rather than bytes of its own: a variable-length String, an object and a dynamic array are a pointer, a Variant a VARIANT. A fixed-size array is its elements, side by side.

public static bool IsLaidOutByTheHost(VBType type)

Parameters

type VBType

The declared type.

Returns

bool

Of(VBUserDefinedTypeValue)

The memory image of value: each field's bytes at the offset its layout assigns, and zeroes in the padding between them.

public static byte[] Of(VBUserDefinedTypeValue value)

Parameters

value VBUserDefinedTypeValue

The value to lay out.

Returns

byte[]

Remarks

A field with no byte representation of its own — a variable-length String, an object, an array, a Variant — is a pointer in memory, and a pointer's bytes mean nothing to a process that did not allocate them. Those bytes are left zero here and the values are carried across by Copy(VBUserDefinedTypeValue, VBUserDefinedTypeValue) instead, which is the one place the reinterpretation can be done safely.

Of(VBUserDefinedTypeValue, int)

The memory image of value, laid out for a host whose pointers are pointerWidth bytes wide: what the bytes at the address of a record are (VarPtr), where a 64-bit host's pointer and Variant fields are wider than a 32-bit one's.

public static byte[] Of(VBUserDefinedTypeValue value, int pointerWidth)

Parameters

value VBUserDefinedTypeValue

The value to lay out.

pointerWidth int

The host's pointer width in bytes.

Returns

byte[]

Of(VBUserDefinedTypeValue, int, Func<int, byte[]?>?)

The memory image of value, laid out for a host whose pointers are pointerWidth bytes wide, with the bytes the host lays out for each field that is no bytes of its own (IsLaidOutByTheHost(VBType)): a variable-length String the address of its characters (StrPtr), an object the address of its interface (ObjPtr), a Variant its VARIANT.

public static byte[] Of(VBUserDefinedTypeValue value, int pointerWidth, Func<int, byte[]?>? hostBytes)

Parameters

value VBUserDefinedTypeValue

The value to lay out.

pointerWidth int

The host's pointer width in bytes.

hostBytes Func<int, byte[]>

The bytes of the field the host lays out that begins at an offset of the image - in a nested record, and an element of a fixed-size array field, the offset is from the start of the outermost record. null, or a field it gives no bytes for, leaves those bytes zero.

Returns

byte[]

WriteInto(VBUserDefinedTypeValue, ReadOnlySpan<byte>, int)

Reads an image back into destination, in place: each field that has bytes of its own takes what the image holds at its offset - what a POKE at the address of a record changes. A field that is a pointer (a variable-length String, an object, a Variant, an array) keeps the value it has.

public static void WriteInto(VBUserDefinedTypeValue destination, ReadOnlySpan<byte> image, int pointerWidth)

Parameters

destination VBUserDefinedTypeValue

The record written.

image ReadOnlySpan<byte>

The bytes, laid out as Of(VBUserDefinedTypeValue, int) lays them out.

pointerWidth int

The host's pointer width in bytes.