0

i have a User defined type in VBA (Excel) and want to have a fixed memory layout for the members so that I can use pointers in a later step for accessing those members.

The user defined type is looking like the code provided and I need to pass on the adresses of the members to a different programm.

I expected VBA to structere the members in the order that they are initialized but somehow it doesn't.

If you have any idea on how to solve that problem I would be really grateful!

Best Regards, Lars

Public Type ExampleSet

Example_P_Anteil                 As Single
Example_I_Anteil                 As Single
Example_D_Anteil                 As Single
Example_v0                       As Double
Example_Gang0                    As Integer
Example_Beschleunigung           As Double
Example_Startzeit                As Double

Example_int1                     As Integer
Example_int2                     As Integer
Example_int3                     As Integer

End Type
3
  • 1
    Why on earth would you want to do this? Commented Jun 4, 2019 at 14:14
  • Does "in the order that they are initialized" actually stand for "in the order they are declared in"? Because a UDT readily serializes to and from binary data, exactly because the fields' position determines their respective value's offset. Do you have any strings in your actual UDT? Commented Jun 4, 2019 at 14:33
  • Very curious about how you came to the conclusion that "it doesn't". I'll definitely upvote your post if you edit it to include some code that demonstrates it. Commented Jun 4, 2019 at 15:10

1 Answer 1

5

I challenge your conclusions.

Public Type TestUDT
    SomeInteger As Integer ' Int16 (I2) at offset 0, padded with 2 bytes
    SomeLong As Long       ' Int32 (I4) at offset 4, no padding
    AnotherLong As Long    ' Int32 (I4) at offset 8, no padding
End Type

Public Sub test()
    Dim udt As TestUDT
    Debug.Print VarPtr(udt)             'expected: X
    Debug.Print VarPtr(udt.SomeInteger) 'expected: X+0
    Debug.Print VarPtr(udt.SomeLong)    'expected: X+4
    Debug.Print VarPtr(udt.AnotherLong) 'expected: X+8
End Sub

Output is as expected:

 723094616 
 723094616 
 723094620 
 723094624 

User-Defined Types (UDT) are defined in the language specifications as:

A linear concatenation of the aggregated data values possibly with implementation defined padding between data values.

The padding might be what's throwing you off, but a UDT is still a linear concatenation of its members.

Use the LenB function to determine the length of a member (or of the UDT as a whole):

Dim foo As ExampleSet
Debug.Print VarPtr(foo), LenB(foo)

If the UDT contains strings, define them as fixed-length if the offsets of the members that follow it need to be fixed:

Public Type TestUDT
    SomeString As String * 10
    '...
End Type

That said, good luck accessing these pointers out of process.

Sign up to request clarification or add additional context in comments.

4 Comments

I'm sorry, I think I didn't manage to give you the complete picture. I only have integers, double and single as types. I need to process the data inside the UDT with a dll, to which I handover the pointer of the UDT from VBA. When I try to access the members of the UDT with the dll the first 5 members are referenced to accordingly, but the others don't get the right reference. When I change the order of the initialization (in VBA and the dll code) by putting Example_Gang0 after Example_Startzeit and having all data types sorted, it seems to work fine
@Lars more likely a bug in the DLL that's somehow assuming the UDT members are regrouped by type. UDT member offsets are always only ever determined by the ordering of the fields and the length of the members that precede it. Make sure the DLL (is that .NET?) uses the correct size for each data type.
yes it is .NET. Thanks for the reassurance that UDT members are determined by the ordering. I will have a look into the different sizes again and worst case is I have to live with not really having an explanation but using the grouped style to solve my problem.
@Lars I'd be curious to see that .NET code... my understanding is that the UDT can rather easily be marshaled to/from a struct. Is it possible that the .NET code is assuming a VBA Integer is like a VB.NET Integer? It's not: VBA Integer is System.Int16, VBA Long is System.Int32 aka Integer in VB.NET.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.