Results 1 to 14 of 14

Thread: VB6 UDT Reflection

  1. #1

    Thread Starter
    Frenzied Member yrwyddfa's Avatar
    Join Date
    Aug 2001
    Location
    England
    Posts
    1,253

    VB6 UDT Reflection

    Write then.

    I need to interrogate the structure of a UDT at runtime; the structure of the function I need is like this
    VB Code:
    1. public function UDTStream(pUDT as long) as string
    Effectively I need to serialise the information inside a UDT. For simple types this is easy, but I need to check the types because some of the UDT's this function will encouter have UDTS within arrays of UDTS etc.

    So does anyone out their know how to interrogate the structure of a UDT at runtime?
    "As far as the laws of mathematics refer to reality, they are not certain; and as far as they are certain, they do not refer to reality." - Albert Einstein

    It's turtles! And it's all the way down

  2. #2
    PowerPoster
    Join Date
    Jul 2001
    Location
    Tucson, AZ
    Posts
    2,166

    Re: VB6 UDT Reflection

    Interesting Problem. This might help based on my search:

    My thought here is to convert each structure element to a variant and then test it using the VB "Is" statements to determine its type.

    David

  3. #3

    Thread Starter
    Frenzied Member yrwyddfa's Avatar
    Join Date
    Aug 2001
    Location
    England
    Posts
    1,253

    Re: VB6 UDT Reflection

    I need to serialise the UDT so that I can make comparisons such as 'is equal too'

    It's type is irrelevant, which is why I want to use a pointer; effectively it should be typefree.

    I avoid variants like the plague, btw.
    "As far as the laws of mathematics refer to reality, they are not certain; and as far as they are certain, they do not refer to reality." - Albert Einstein

    It's turtles! And it's all the way down

  4. #4
    PowerPoster
    Join Date
    Jul 2001
    Location
    Tucson, AZ
    Posts
    2,166

    Re: VB6 UDT Reflection

    Obviously NOT understanding the problem then.

    I agree WHOLEHARDLY with variant comment.

    Only suggested them as thought the problem was you were trying to detemine the various Data Types which make up an unknown UDT. Thought by assigning each UDT element to a variant type would then allow testing for UDT Data Type using the "Is" functions.

  5. #5
    PowerPoster
    Join Date
    Feb 2002
    Location
    Canada, Toronto
    Posts
    5,803

    Re: VB6 UDT Reflection


  6. #6

    Thread Starter
    Frenzied Member yrwyddfa's Avatar
    Join Date
    Aug 2001
    Location
    England
    Posts
    1,253

    Re: VB6 UDT Reflection

    Yeah. I came across that earlier (I did search the forums before posting!!) but it will never work on any UDT of any complexity (ie contains strings, arrays, and so on)

    I think I've found a way of doing it - so watch this space!
    "As far as the laws of mathematics refer to reality, they are not certain; and as far as they are certain, they do not refer to reality." - Albert Einstein

    It's turtles! And it's all the way down

  7. #7
    I'm about to be a PowerPoster!
    Join Date
    Jan 2005
    Location
    Everywhere
    Posts
    13,647

    Re: VB6 UDT Reflection

    How do you propose to do your own type checking on an unmanaged language?

    The furthest I can see it going is a shallow serialise, just the struct's immediate contents.

  8. #8

    Thread Starter
    Frenzied Member yrwyddfa's Avatar
    Join Date
    Aug 2001
    Location
    England
    Posts
    1,253

    Re: VB6 UDT Reflection

    Watch this space . . . .
    "As far as the laws of mathematics refer to reality, they are not certain; and as far as they are certain, they do not refer to reality." - Albert Einstein

    It's turtles! And it's all the way down

  9. #9
    Banned randem's Avatar
    Join Date
    Oct 2002
    Location
    Maui, Hawaii
    Posts
    11,385

    Re: VB6 UDT Reflection

    yrwyddfa,

    Basically you can't. Use an object that has all the elements defined in it and pass that.

  10. #10

    Thread Starter
    Frenzied Member yrwyddfa's Avatar
    Join Date
    Aug 2001
    Location
    England
    Posts
    1,253

    Re: VB6 UDT Reflection

    Quote Originally Posted by randem
    yrwyddfa,

    Basically you can't. Use an object that has all the elements defined in it and pass that.
    Oh yes you can I'll post the code later today.
    "As far as the laws of mathematics refer to reality, they are not certain; and as far as they are certain, they do not refer to reality." - Albert Einstein

    It's turtles! And it's all the way down

  11. #11

    Thread Starter
    Frenzied Member yrwyddfa's Avatar
    Join Date
    Aug 2001
    Location
    England
    Posts
    1,253

    Re: VB6 UDT Reflection

    Here's for starters.
    VB Code:
    1. Option Explicit
    2.  
    3. Private Declare Sub CopyMemory Lib "KERNEL32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)
    4. Private Declare Function SysAllocString Lib "oleaut32" (ByVal pUnicodeString As Long) As String
    5. Private Declare Sub ZeroMemory Lib "KERNEL32" Alias "RtlMoveMemory" (dest As Any, ByVal numBytes As Long)
    6.  
    7. Sub main()
    8.    
    9.     Dim Sr() As Byte
    10.     Dim u As TEST_TYPE
    11.     Dim u2 As TEST_TYPE
    12.     Dim lp As Long
    13.  
    14.     With u
    15.         .a = "a"
    16.         .b = "b"
    17.         .c = 12345
    18.     End With
    19.    
    20.     Sr = Serialise(VarPtr(u), "TEST_TYPE", "c:\test.tlb")
    21.     DeSerialise VarPtr(u2), "TEST_TYPE", "c:\test.tlb", Sr
    22.    
    23. End Sub
    24.  
    25. Public Function Serialise(pUDT As Long, UDTName As String, TLBFile As String) As Byte()
    26.  
    27.     On Error GoTo ERR_Serialise
    28.    
    29.     Dim TypeLib As TypeLibInfo
    30.     Dim Record As RecordInfo
    31.     Dim Mmbers As Members
    32.     Dim Member As MemberInfo
    33.     Dim Stream() As Byte
    34.     Dim pMemPos As Long
    35.    
    36.     ReDim Stream(1024)
    37.    
    38.     '**************************
    39.     '* Open type library . . .
    40.     '**************************
    41.     Set TypeLib = New TypeLibInfo
    42.     TypeLib.ContainingFile = TLBFile
    43.    
    44.     '*********************************
    45.     '* Get the UDT definition . . .
    46.     '*********************************
    47.     For Each Record In TypeLib.Records
    48.         If Record.Name = UDTName Then
    49.             Set Mmbers = Record.Members
    50.             Exit For
    51.         End If
    52.     Next
    53.    
    54.     '****************************************
    55.     '* Serialise Each and every member . . .
    56.     '****************************************
    57.     pMemPos = VarPtr(Stream(0))
    58.     SerialiseUDT Mmbers, Stream, pUDT, pMemPos
    59.     'ReDim Preserve Stream(pMemPos - VarPtr(Stream(0)))
    60.    
    61.     Serialise = Stream
    62.    
    63.     Exit Function
    64.    
    65. ERR_Serialise:
    66.     Set TypeLib = Nothing
    67.     Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext
    68. End Function
    69.  
    70. Public Sub DeSerialise(pUDT As Long, UDTName As String, TLBFile, Stream() As Byte)
    71.  
    72.     On Error GoTo ERR_DeSerialise
    73.    
    74.     Dim TypeLib As TypeLibInfo
    75.     Dim Record As RecordInfo
    76.     Dim Mmbers As Members
    77.     Dim Member As MemberInfo
    78.     Dim pBufPos As Long
    79.     Dim pMemPos As Long
    80.    
    81.     '**************************
    82.     '* Open type library . . .
    83.     '**************************
    84.     Set TypeLib = New TypeLibInfo
    85.     TypeLib.ContainingFile = TLBFile
    86.    
    87.     '*********************************
    88.     '* Get the UDT definition . . .
    89.     '*********************************
    90.     For Each Record In TypeLib.Records
    91.         If Record.Name = UDTName Then
    92.             Set Mmbers = Record.Members
    93.             Exit For
    94.         End If
    95.     Next
    96.    
    97.     '****************************************
    98.     '* Serialise Each and every member . . .
    99.     '****************************************
    100.     DeSerialiseUDT Mmbers, VarPtr(Stream(0)), pUDT
    101.    
    102.     Exit Sub
    103.    
    104. ERR_DeSerialise:
    105.     Set TypeLib = Nothing
    106.     Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext
    107. End Sub
    108.  
    109. Private Sub SerialiseUDT(Mmbers As Members, Buffer() As Byte, pUDT As Long, pStream As Long)
    110.  
    111.     On Error GoTo ERR_SerialiseUDT
    112.    
    113.     Dim Member As MemberInfo
    114.    
    115.     For Each Member In Mmbers
    116.         Select Case Member.ReturnType.VarType
    117.             Case vbString:
    118.                 SerialiseString pUDT, pStream
    119.             Case vbInteger
    120.                 SerialiseData pUDT, pStream, 2, 2
    121.         End Select
    122.     Next
    123.    
    124.     Exit Sub
    125.    
    126. ERR_SerialiseUDT:
    127.     Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext
    128. End Sub
    129.  
    130. Private Sub DeSerialiseUDT(Mmbers As Members, pStream As Long, pUDT As Long)
    131.  
    132.     On Error GoTo ERR_DeSerialise
    133.  
    134.     Dim Member As MemberInfo
    135.    
    136.     For Each Member In Mmbers
    137.         Select Case Member.ReturnType.VarType
    138.             Case vbString:
    139.                 DeSerialiseString pUDT, pStream
    140.             Case vbInteger
    141.                 DeSerialiseData pUDT, pStream, 2, 2
    142.         End Select
    143.     Next
    144.    
    145.     Exit Sub
    146.    
    147. ERR_DeSerialise:
    148.     Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext
    149. End Sub
    150.  
    151.  
    152. Private Sub SerialiseData(pUDT As Long, pStream As Long, Alignment As Long, Size As Long)
    153.  
    154.     Dim lPadding As Long
    155.    
    156.     'Increment forward (if we have too) to make sure that we
    157.     'only pick up the data and not the preceding padding bytes
    158.     If Not (pUDT Mod Alignment = 0) Then
    159.         lPadding = (Alignment - (pUDT Mod Alignment))
    160.         pUDT = pUDT + lPadding
    161.     End If
    162.    
    163.     'Serialise the data
    164.     CopyMemory ByVal pStream, ByVal pUDT, Size
    165.    
    166.     'Increment pointers accordingly
    167.     pUDT = pUDT + Size
    168.     pStream = pStream + Size
    169.    
    170. End Sub
    171.  
    172. Private Sub DeSerialiseData(pUDT As Long, pStream As Long, Alignment As Long, Size As Long)
    173.  
    174.     Dim lPadding As Long
    175.    
    176.     'Pad data, if necessary
    177.     If Not (pUDT Mod Alignment = 0) Then
    178.         lPadding = (Alignment - (pUDT Mod Alignment))
    179.         pUDT = pUDT + lPadding
    180.     End If
    181.    
    182.     CopyMemory ByVal pUDT, ByVal pStream, Size
    183.    
    184.     pUDT = pUDT + Size
    185.     pStream = pStream + Size
    186.    
    187. End Sub
    188.  
    189.  
    190. Private Sub SerialiseString(pUDT As Long, pStream As Long)
    191.    
    192.     Dim Temp As String
    193.     Dim pStr As Long
    194.     Dim lPadding As Long
    195.    
    196.     'Ensure the alignment's good
    197.     If Not (pUDT Mod 4 = 0) Then
    198.         lPadding = (4 - (pUDT Mod 4))
    199.         pUDT = pUDT + lPadding
    200.     End If
    201.    
    202.     'deref pUDT, and get the actual string data
    203.     CopyMemory pStr, ByVal pUDT, 4
    204.     Temp = StrConv(SysAllocString(pStr), vbFromUnicode) & Chr(0)
    205.    
    206.     'Copy over the string data
    207.     CopyMemory ByVal pStream, ByVal StrPtr(Temp), LenB(Temp)
    208.    
    209.     'Increment pointers
    210.     pUDT = pUDT + 4
    211.     pStream = pStream + LenB(Temp)
    212.    
    213. End Sub
    214.  
    215. Private Sub DeSerialiseString(pUDT As Long, pStream As Long)
    216.  
    217.     Dim Temp As String
    218.     Dim lPadding As Long
    219.  
    220.     'Ensure the alignment's good
    221.     If Not (pUDT Mod 4 = 0) Then
    222.         lPadding = (4 - (pUDT Mod 4))
    223.         pUDT = pUDT + lPadding
    224.     End If
    225.    
    226.     'Get the string from the stream
    227.     Temp = StrConv(SysAllocString(pStream), vbFromUnicode) & Chr(0)
    228.    
    229.     'Copy the BSTR descriptor to the UDT
    230.     CopyMemory ByVal pUDT, ByVal VarPtr(Temp), 4
    231.  
    232.     'Increment pointers
    233.     pStream = pStream + LenB(Temp)
    234.     pUDT = pUDT + 4
    235.    
    236.     'Clear temp string descriptor to avoid VB's garbage collection
    237.     CopyMemory ByVal VarPtr(Temp), 0&, 4
    238.    
    239. End Sub

    You'll need to make reference to TLBINF32.DLL, and I can't upload a TLB file (invalid file type), so you'll need to point it to a typelib you've created (only using integer and variable strings at this point) I'm going to add the other types later today.

    Let me know what you guys think.
    "As far as the laws of mathematics refer to reality, they are not certain; and as far as they are certain, they do not refer to reality." - Albert Einstein

    It's turtles! And it's all the way down

  12. #12

    Thread Starter
    Frenzied Member yrwyddfa's Avatar
    Join Date
    Aug 2001
    Location
    England
    Posts
    1,253

    Re: VB6 UDT Reflection

    To include ALL the basic types and the variable length string replace the relevant functions with this:

    VB Code:
    1. Private Sub SerialiseUDT(Mmbers As Members, Buffer() As Byte, pUDT As Long, pStream As Long)
    2.  
    3.     On Error GoTo ERR_SerialiseUDT
    4.    
    5.     Dim Member As MemberInfo
    6.    
    7.     For Each Member In Mmbers
    8.         Select Case Member.ReturnType.VarType
    9.             Case vbString:
    10.                 SerialiseString pUDT, pStream
    11.             Case vbInteger
    12.                 SerialiseData pUDT, pStream, 2, 2
    13.             Case vbLong
    14.                 SerialiseData pUDT, pStream, 4, 4
    15.             Case vbBoolean
    16.                 SerialiseData pUDT, pStream, 2, 2
    17.             Case vbSingle
    18.                 SerialiseData pUDT, pStream, 4, 4
    19.             Case vbDouble
    20.                 SerialiseData pUDT, pStream, 4, 8
    21.             Case vbCurrency
    22.                 SerialiseData pUDT, pStream, 4, 8
    23.             Case vbDate
    24.                 SerialiseData pUDT, pStream, 4, 8
    25.         End Select
    26.     Next
    27.    
    28.     Exit Sub
    29.    
    30. ERR_SerialiseUDT:
    31.     Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext
    32. End Sub
    33.  
    34. Private Sub DeSerialiseUDT(Mmbers As Members, pStream As Long, pUDT As Long)
    35.  
    36.     On Error GoTo ERR_DeSerialise
    37.  
    38.     Dim Member As MemberInfo
    39.    
    40.     For Each Member In Mmbers
    41.         Select Case Member.ReturnType.VarType
    42.             Case vbString:
    43.                 DeSerialiseString pUDT, pStream
    44.             Case vbInteger
    45.                 DeSerialiseData pUDT, pStream, 2, 2
    46.             Case vbLong
    47.                 DeSerialiseData pUDT, pStream, 4, 4
    48.             Case vbBoolean
    49.                 DeSerialiseData pUDT, pStream, 2, 2
    50.             Case vbSingle
    51.                 DeSerialiseData pUDT, pStream, 4, 4
    52.             Case vbDouble
    53.                 DeSerialiseData pUDT, pStream, 4, 8
    54.             Case vbCurrency
    55.                 DeSerialiseData pUDT, pStream, 4, 8
    56.             Case vbDate
    57.                 DeSerialiseData pUDT, pStream, 4, 8
    58.         End Select
    59.     Next
    60.    
    61.     Exit Sub
    62.    
    63. ERR_DeSerialise:
    64.     Err.Raise Err.Number, Err.Source, Err.Description, Err.HelpFile, Err.HelpContext
    65. End Sub
    "As far as the laws of mathematics refer to reality, they are not certain; and as far as they are certain, they do not refer to reality." - Albert Einstein

    It's turtles! And it's all the way down

  13. #13

    Thread Starter
    Frenzied Member yrwyddfa's Avatar
    Join Date
    Aug 2001
    Location
    England
    Posts
    1,253

    Re: VB6 UDT Reflection

    I'll get to work on arrays, and arrays of UDT's now
    "As far as the laws of mathematics refer to reality, they are not certain; and as far as they are certain, they do not refer to reality." - Albert Einstein

    It's turtles! And it's all the way down

  14. #14
    New Member
    Join Date
    Apr 2012
    Posts
    1

    Re: VB6 UDT Reflection

    Quote Originally Posted by yrwyddfa View Post
    I'll get to work on arrays, and arrays of UDT's now
    Yrwyddfa, please, accept my deepest respect for your wonderful work on serializing of UDT's (that can be now turned cross-platform) in my favourite language :-)

    Did you succeed in creating recursive version of 'Serialise' to parse UDT's inside UDTS?

    Any luck with support of collections and arrays, variants, and nested stuff? :-)

    Now that you showed the path to inspect type info on-line, this task seems to be straightforward, but may be you've already implemented these kinds of monster? :-)

    Sincerely,
    Anatoly

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width