Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • SEARCH
  • Home
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 146051
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: May 11, 20262026-05-11T08:31:57+00:00 2026-05-11T08:31:57+00:00

I have a feeling the answer to this is going to be not possible,

  • 0

I have a feeling the answer to this is going to be ‘not possible’, but I’ll give it a shot… I am in the unenviable position of modifying a legacy VB6 app with some enhancements. Converting to a smarter language isn’t an option. The app relies on a large collection of user defined types to move data around. I would like to define a common function that can take a reference to any of these types and extract the data contained.
In pseudo code, here’s what I’m looking for:

Public Sub PrintUDT ( vData As Variant )   for each vDataMember in vData     print vDataMember.Name & ': ' & vDataMember.value    next vDataMember  End Sub 

It seems like this info needs to be available to COM somewhere… Any VB6 gurus out there care to take a shot?

Thanks,

Dan

  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. 2026-05-11T08:31:58+00:00Added an answer on May 11, 2026 at 8:31 am

    Contrary to what others have said, it IS possible to get run-time type information for UDT’s in VB6 (although it is not a built-in language feature). Microsoft’s TypeLib Information Object Library (tlbinf32.dll) allows you to programmatically inspect COM type information at run-time. You should already have this component if you have Visual Studio installed: to add it to an existing VB6 project, go to Project->References and check the entry labeled ‘TypeLib Information.’ Note that you will have to distribute and register tlbinf32.dll in your application’s setup program.

    You can inspect UDT instances using the TypeLib Information component at run-time, as long as your UDT’s are declared Public and are defined within a Public class. This is necessary in order to make VB6 generate COM-compatible type information for your UDT’s (which can then be enumerated with various classes in the TypeLib Information component). The easiest way to meet this requirement would be to put all your UDT’s into a public UserTypes class that will be compiled into an ActiveX DLL or ActiveX EXE.

    Summary of a working example

    This example contains three parts:

    • Part 1: Creating an ActiveX DLL project that will contain all the public UDT declarations
    • Part 2: Creating an example PrintUDT method to demonstrate how you can enumerate the fields of a UDT instance
    • Part 3: Creating a custom iterator class that allows you easily iterate through the fields of any public UDT and get field names and values.

    The working example

    Part 1: The ActiveX DLL

    As I already mentioned, you need to make your UDT’s public-accessible in order to enumerate them using the TypeLib Information component. The only way to accomplish this is to put your UDT’s into a public class inside an ActiveX DLL or ActiveX EXE project. Other projects in your application that need to access your UDT’s will then reference this new component.

    To follow along with this example, start by creating a new ActiveX DLL project and name it UDTLibrary.

    Next, rename the Class1 class module (this is added by default by the IDE) to UserTypes and add two user-defined types to the class, Person and Animal:

    ' UserTypes.cls '  Option Explicit  Public Type Person     FirstName As String     LastName As String     BirthDate As Date End Type  Public Type Animal     Genus As String     Species As String     NumberOfLegs As Long End Type 

    Listing 1: UserTypes.cls acts as a container for our UDT’s

    Next, change the Instancing property for the UserTypes class to ‘2-PublicNotCreatable’. There is no reason for anyone to instantiate the UserTypes class directly, because it’s simply acting as a public container for our UDT’s.

    Finally, make sure the Project Startup Object (under Project->Properties) is set to to ‘(None)’ and compile the project. You should now have a new file called UDTLibrary.dll.

    Part 2: Enumerating UDT Type Information

    Now it’s time to demonstrate how we can use TypeLib Object Library to implement a PrintUDT method.

    First, start by creating a new Standard EXE project and call it whatever you like. Add a reference to the file UDTLibrary.dll that was created in Part 1. Since I just want to demonstrate how this works, we will use the Immediate window to test the code we will write.

    Create a new Module, name it UDTUtils and add the following code to it:

    'UDTUtils.bas' Option Explicit      Public Sub PrintUDT(ByVal someUDT As Variant)      ' Make sure we have a UDT and not something else... '     If VarType(someUDT) <> vbUserDefinedType Then         Err.Raise 5, , 'Parameter passed to PrintUDT is not an instance of a user-defined type.'     End If      ' Get the type information for the UDT '     ' (in COM parlance, a VB6 UDT is also known as VT_RECORD, Record, or struct...) '      Dim ri As RecordInfo     Set ri = TLI.TypeInfoFromRecordVariant(someUDT)      'If something went wrong, ri will be Nothing'      If ri Is Nothing Then         Err.Raise 5, , 'Error retrieving RecordInfo for type '' & TypeName(someUDT) & '''     Else          ' Iterate through each field (member) of the UDT '         ' and print the out the field name and value     '          Dim member As MemberInfo         For Each member In ri.Members              'TLI.RecordField allows us to get/set UDT fields:                 '             '                                                                 '             ' * to get a fied: myVar = TLI.RecordField(someUDT, fieldName)    '             ' * to set a field TLI.RecordField(someUDT, fieldName) = newValue '              '                                                                 '             Dim memberVal As Variant             memberVal = TLI.RecordField(someUDT, member.Name)              Debug.Print member.Name & ' : ' & memberVal          Next      End If  End Sub  Public Sub TestPrintUDT()      'Create a person instance and print it out...'      Dim p As Person      p.FirstName = 'John'     p.LastName = 'Doe'     p.BirthDate = #1/1/1950#      PrintUDT p      'Create an animal instance and print it out...'      Dim a As Animal      a.Genus = 'Canus'     a.Species = 'Familiaris'     a.NumberOfLegs = 4      PrintUDT a  End Sub 

    Listing 2: An example PrintUDT method and a simple test method

    Part 3: Making it Object-Oriented

    The above examples provide a ‘quick and dirty’ demonstration of how to use the TypeLib Information Object Library to enumerate the fields of a UDT. In a real-world scenario, I would probably create a UDTMemberIterator class that would allow you to more easily iterate through the fields of UDT, along with a utility function in a module that creates a UDTMemberIterator for a given UDT instance. This would allow you to do something like the following in your code, which is much closer to the pseudo-code you posted in your question:

    Dim member As UDTMember 'UDTMember wraps a TLI.MemberInfo instance'  For Each member In UDTMemberIteratorFor(someUDT)    Debug.Print member.Name & ' : ' & member.Value Next 

    It’s actually not too hard to do this, and we can re-use most of the code from the PrintUDT routine created in Part 2.

    First, create a new ActiveX project and name it UDTTypeInformation or something similar.

    Next, make sure that the Startup Object for the new project is set to ‘(None)’.

    The first thing to do is to create a simple wrapper class that will hide the details of the TLI.MemberInfo class from calling code and make it easy to get a UDT’s field’s name and value. I called this class UDTMember. The Instancing property for this class should be PublicNotCreatable.

    'UDTMember.cls' Option Explicit  Private m_value As Variant Private m_name As String  Public Property Get Value() As Variant     Value = m_value End Property  'Declared Friend because calling code should not be able to modify the value' Friend Property Let Value(rhs As Variant)     m_value = rhs End Property  Public Property Get Name() As String     Name = m_name End Property  'Declared Friend because calling code should not be able to modify the value' Friend Property Let Name(ByVal rhs As String)     m_name = rhs End Property 

    Listing 3: The UDTMember wrapper class

    Now we need to create an iterator class, UDTMemberIterator, that will allow us to use VB’s For Each...In syntax to iterate the fields of a UDT instance. The Instancing property for this class should be set to PublicNotCreatable (we will define a utility method later that will create instances on behalf of calling code).

    EDIT: (2/15/09) I’ve cleaned the code up a bit more.

    'UDTMemberIterator.cls'  Option Explicit  Private m_members As Collection ' Collection of UDTMember objects '   ' Meant to be called only by Utils.UDTMemberIteratorFor ' '                                                       ' ' Sets up the iterator by reading the type info for     ' ' the passed-in UDT instance and wrapping the fields in ' ' UDTMember objects                                     '  Friend Sub Initialize(ByVal someUDT As Variant)      Set m_members = GetWrappedMembersForUDT(someUDT)  End Sub  Public Function Count() As Long      Count = m_members.Count  End Function  ' This is the default method for this class [See Tools->Procedure Attributes]   ' '                                                                               ' Public Function Item(Index As Variant) As UDTMember      Set Item = GetWrappedUDTMember(m_members.Item(Index))  End Function  ' This function returns the enumerator for this                                     ' ' collection in order to support For...Each syntax.                                 ' ' Its procedure ID is (-4) and marked 'Hidden' [See Tools->Procedure Attributes]    ' '                                                                                   ' Public Function NewEnum() As stdole.IUnknown      Set NewEnum = m_members.[_NewEnum]  End Function  ' Returns a collection of UDTMember objects, where each element                 ' ' holds the name and current value of one field from the passed-in UDT          ' '                                                                               ' Private Function GetWrappedMembersForUDT(ByVal someUDT As Variant) As Collection      Dim collWrappedMembers As New Collection     Dim ri As RecordInfo     Dim member As MemberInfo     Dim memberVal As Variant     Dim wrappedMember As UDTMember      ' Try to get type information for the UDT... '      If VarType(someUDT) <> vbUserDefinedType Then         Fail 'Parameter passed to GetWrappedMembersForUDT is not an instance of a user-defined type.'     End If      Set ri = tli.TypeInfoFromRecordVariant(someUDT)      If ri Is Nothing Then         Fail 'Error retrieving RecordInfo for type '' & TypeName(someUDT) & '''     End If      ' Wrap each UDT member in a UDTMember object... '      For Each member In ri.Members          Set wrappedMember = CreateWrappedUDTMember(someUDT, member)         collWrappedMembers.Add wrappedMember, member.Name      Next      Set GetWrappedMembersForUDT = collWrappedMembers  End Function  ' Creates a UDTMember instance from a UDT instance and a MemberInfo object  ' '                                                                           ' Private Function CreateWrappedUDTMember(ByVal someUDT As Variant, ByVal member As MemberInfo) As UDTMember      Dim wrappedMember As UDTMember     Set wrappedMember = New UDTMember      With wrappedMember         .Name = member.Name         .Value = tli.RecordField(someUDT, member.Name)     End With      Set CreateWrappedUDTMember = wrappedMember  End Function  ' Just a convenience method ' Private Function Fail(ByVal message As String)      Err.Raise 5, TypeName(Me), message  End Function 

    Listing 4: The UDTMemberIterator class.

    Note that in order to make this class iterable so that For Each can be used with it, you will have to set certain Procedure Attributes on the Item and _NewEnum methods (as noted in the code comments). You can change the Procedure Attributes from the Tools Menu (Tools->Procedure Attributes).

    Finally, we need a utility function (UDTMemberIteratorFor in the very first code example in this section) that will create a UDTMemberIterator for a UDT instance, which we can then iterate with For Each. Create a new module called Utils and add the following code:

    'Utils.bas'  Option Explicit  ' Returns a UDTMemberIterator for the given UDT    ' '                                                  ' ' Example Usage:                                   ' '                                                  ' ' Dim member As UDTMember                          ' '                                                  '         ' For Each member In UDTMemberIteratorFor(someUDT) ' '    Debug.Print member.Name & ':' & member.Value  ' ' Next                                             ' Public Function UDTMemberIteratorFor(ByVal udt As Variant) As UDTMemberIterator      Dim iterator As New UDTMemberIterator     iterator.Initialize udt      Set UDTMemberIteratorFor = iterator  End Function 

    Listing 5: The UDTMemberIteratorFor utility function.

    Finally, compile the project and create a new project to test it out.

    In your test projet, add a reference to the newly-created UDTTypeInformation.dll and the UDTLibrary.dll created in Part 1 and try out the following code in a new module:

    'Module1.bas'  Option Explicit  Public Sub TestUDTMemberIterator()      Dim member As UDTMember      Dim p As Person      p.FirstName = 'John'     p.LastName = 'Doe'     p.BirthDate = #1/1/1950#      For Each member In UDTMemberIteratorFor(p)         Debug.Print member.Name & ' : ' & member.Value     Next      Dim a As Animal      a.Genus = 'Canus'     a.Species = 'Canine'     a.NumberOfLegs = 4      For Each member In UDTMemberIteratorFor(a)         Debug.Print member.Name & ' : ' & member.Value     Next  End Sub 

    Listing 6: Testing out the UDTMemberIterator class.

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Ask A Question

Stats

  • Questions 64k
  • Answers 64k
  • Best Answers 0
  • User 1
  • Popular
  • Answers
  • Editorial Team

    How to approach applying for a job at a company ...

    • 7 Answers
  • Editorial Team

    How to handle personal stress caused by utterly incompetent and ...

    • 5 Answers
  • Editorial Team

    What is a programmer’s life like?

    • 5 Answers
  • added an answer Use sp_executesql and the built-in quotename(). This article, The Curse… May 11, 2026 at 10:56 am
  • added an answer You cannot select the parent of a matched item in… May 11, 2026 at 10:56 am
  • added an answer The world-to-camera transformation matrix is the inverse of the camera-to-world… May 11, 2026 at 10:56 am

Related Questions

I have a feeling that I already know the answer to this one, but
I'm the leader of a small web development team, and I have a feeling
I have a feeling that there must be client-server synchronization patterns out there. But
I have a feeling this is a repost but I can't seem to find
I curious to how different people solve integration of systems. I have a feeling
I have a web-service that I will be deploying to dev, staging and production.
I have a .Net desktop application with a TreeView as one of the UI
I have a Queue<T> object that I have initialised to a capacity of 2,
I have a complete XML document in a string and would like a Document
I have a regex that is going to end up being a bit long

Trending Tags

analytics british company computer developers django employee employer english facebook french google interview javascript language life php programmer programs salary

Top Members

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.