Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

How To Use a .NET Class with Lists in VB6

0.00/5 (No votes)
9 Jan 2009 1  
It's easy to create a wrapper for .NET classes that you can use in VB6, but there are some difficulties with the types, specially Generic lists

Introduction

NOTE: Not all code is in the page, there are constructors missing and other directives that are available in the download of the project.

This article will help you in the special case when you want to use a class "designed" in .NET in VB6 using the "COM class" available in Visual Basic .NET.

Background

There are still tons of companies trying to move from VB6 to .NET. This can be as easy as run the integrated VS conversion tool or if the company has the resources and time they will decide to do a rewrite.

What if this rewrite is in a new architecture, using n-tier and common DLLs that most of the new applications will use, cool... however what if once you finished one of your .NET DLLs, you have to integrate that new library into one of your VB6 apps.

Not really difficult using the "COM class" available in VB.NET and creating a Business Logic layer that calls your component, create a *.tlb file and reference this one in your VB6 project. However some types are not available in VB6; like the .NET Long doesn't exist in VB6, and the .NET Integer is actually the Long in VB6. Not mentioning that Lists called Generics are not available at all in VB6, you could use array, but they work differently in .NET than in VB6.

Using the Code

Let's start with a simple problem.

You have the following classes:

You need to get a list of car dealers available, each dealer will have a description and a list of cars and each car its maker, model, mileage and price. So you have:

public class car
    {
        public string maker { get; set; }
        public string model { get; set; }
        public int mileage { get; set; }
        public int price { get; set; }
    }

public class carDealer
    {
        public string description { get; set; }
        public List<car> carList { get; set; }
    }

public class dealersList
    {
        public List<carDealer> list { get; set; }
    }

You can get your data from your database, my example just hardcodes some values.

The important thing is, at the end you will have a list of the carDealer class to return as a result. Your main manager class will look something like:

public class componentManager
    {
        private componentBusinessLogic _bl = new componentBusinessLogic();
        
        //Just a traffic manager
        public dealersList getDealers()
        {
            return _bl.getDealers();
        }
    }

You pretty much finished your DLL, your component to retrieve a list of dealers You could even alter a little bit of this class and accept a zipCode parameter and retrieve based on that, but for ease of the article we will leave it like that, just retrieve all car dealers.

Now it's time to create the Interop traffic controller your VB6 project will use. You can do this using the COM class in a Visual Basic .NET project. So create a new VB.NET class library project. This basically builds a ready to use interface for you, you just need to create a traffic manager between your C# class and your VB6 project. We will call this the Wrapper Component from now on.

Something like:

Public Function GetDealers() As dealerList
        'Just a traffic manager
        Return _bl.getDealers()
 End Function

Here is the tricky thing. You could declare your carDealer class as a List (of car) right?

The answer is no... generics are not supported in VB6, so what to do? Arrays? Not really, they are not dynamic like the generics. The solution: Collection.

By the way... _bl in the code snippet above is an instance of my wrapper business logic which contains the logic to apply this change, from the <List>CarDealer to a Collection.

So you will need to change your classes a little bit, and also you will need to include some directives on them in order to be visible to VB6 like:

Imports System.Runtime.InteropServices

<ClassInterface(ClassInterfaceType.AutoDual)> _
Public Class car

#Region "Fields"
    Private _maker As String
    Private _model As String
    Private _mileage As Integer
    Private _price As Integer
#End Region

#Region "Properties"
    Public Property Maker() As String
        Get
            Return _maker
        End Get
        Set(ByVal value As String)
            _maker = value
        End Set
    End Property

    'Build the rest of the properties here
#End Region
End Class

<ClassInterface(ClassInterfaceType.AutoDual)> _
Public Class carDealer
#Region "Fields"
    Private _description As String
    'IMPORTANT -----------------------------
    'add the word New to this declaration to avoid
    '"Object reference not set to an instance of an object" Error
    Private _carList As New Collection
#End Region

#Region "Properties"
    Public Property Description() As String
        Get
            Return _description
        End Get
        Set(ByVal value As String)
            _description = value
        End Set
    End Property

    Public Property CarList() As Collection
        Get
            Return _carList
        End Get
        Set(ByVal value As Collection)
            _carList = value
        End Set
    End Property
#End Region
End Class

<ClassInterface(ClassInterfaceType.AutoDual)> _
Public Class dealerList
    Private _list As New Collection

    Public Property List() As Collection
        Get
            Return _list
        End Get
        Set(ByVal value As Collection)
            _list = value
        End Set
    End Property
End Class

Call the C# project. Component is the namespace of the C# project.

Dim CM As New Component.componentManager
Dim tDealerList As New Component.businessEntities.dealersList
        tDealerList = CM.getDealers()

Use your head to convert your C# types to the VB types you are declaring in this project, nothing more than loop through the list property inside tDealerList, create a VB carDealer instance, populate it and add it to a new collection. At the end, this collection will be the list in your VB dealierList. Something like this:

For Each tDealer As Component.businessEntities.carDealer In tDealerList.list
            'Make the new type carDealer from this project
            Dim rCarDealer As New carDealer

            'Get the description from the Component c# project type
            rCarDealer.Description = tDealer.description

            Dim rCars As New Collection
            For Each tCar As Component.businessEntities.car In tDealer.carList
                rCars.Add(New car(tCar.maker, tCar.model, tCar.mileage, tCar.price))
            Next
            
            rCarDealer.CarList = rCars
            rCars = Nothing

            
            rList.List.Add(rCarDealer)
        Next

You are done.

You can build your app. Register your DLL for interop in the line command with:

C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\regasm 
	"ComponentWrapper.dll" /tlb /codebase
C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\gacutil -i ComponentWrapper.dll

This will create a *.tlb file; open your VB6 project and make the reference to your tlb file. You won't be able to reference the DLL, so do not try.

Now in VB6, you pretty much can do this:

Dim list As New ComponentWrapper.dealerList
Dim cManager As New ComponentWrapper.CWManager

Set list = cManager.GetDealers()  

And from here... it's all yours.

Points of Interest

The really cool thing about this is now you have a component your future .NET apps can use and also your VB6 apps in transition will be able to use with the wrapper, you just need to create the wrapper component and you are done.

The really annoying part of this learning curve that I took, was about the Generics not being possible to use in VB6. Finally I figured that in VB6 the only thing flexible enough was a collection. I know it can look like a disadvantage to use it sometimes, but I think in this particular case, as I am sure are many others, it was absolutely useful.

There are also many more guidelines to follow when rewriting a VB6 app into .NET and, if you are in the process of creating common DLLs to be used for .NET apps and for VB6 apps, I found the following link very useful for making this comparison:

History

  • 8th January, 2009: Initial post 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here