Collection in DLL (VB6)

Hi,
I am writing a DLL in VB6, and I need to create a collection but dont know how.

In my DLL class I need to have a list of items which can be called by my VB program in a way "similar" to this:

   Set objMyDLL = createobject("MyDLL.MyClass")
   Set x = objMyDLL.GetList()
   Set y = x.MyItems
   For Each z in y
      debug.print z.name
   Next

Could someone provide a example of the class code to make tis work?
I am playing with the following code but cant get it to work...

Public Property Get GetList() As Collection
    Dim MyItems(5)
    MyItems(0) = "one"
    MyItems(1) = "two"
    MyItems(2) = "three"
    MyItems(3) = "four"
    MyItems(4) = "five"    
    GetList = MyItems
End Property
LVL 2
gjokAsked:
Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

x
 
fds_fatboyConnect With a Mentor Commented:
Sorry, I've been in a design meeting all afternoon.

Hmm, that's not so simple.
You can use the Class Builder Utility  (as aryaomni suggested).

This code is for a type-safe collection it was originally derived from class builder, but has slightly more functionality.

You can't add properties (you called them nodes) on the fly. You do it all through the base class (here called clsPerson).

Create a class clsPerson:
'___________________

Option Explicit

Private mstrName As String
Private mstrEmailAddress As String
Private mstrPhoneNumber As String

Public Property Let Name(RHS As String)
    mstrName = RHS
End Property

Public Property Get Name() As String
    Name = mstrName
End Property

Public Property Let PhoneNumber(RHS As String)
    mstrPhoneNumber = RHS
End Property

Public Property Get PhoneNumber() As String
    PhoneNumber = mstrPhoneNumber
End Property

Public Property Let EmailAddress(RHS As String)
    mstrEmailAddress = RHS
End Property

Public Property Get EmailAddress() As String
    EmailAddress = mstrEmailAddress
End Property
'___________________

Next Create another class, clsPeople with the following code:
'___________________

Option Explicit
Private mCollection As Collection

Public Sub AddItem(Person As clsPerson, Optional Key As String)
    If Len(Key) = 0 Then
        mCollection.Add Person
    Else
        mCollection.Add Person, Key
    End If
End Sub

Public Function Add(ByVal Name As String, _
                    ByVal PhoneNumber As String, _
                    ByVal EmailAddress As String, _
                    Optional ByVal Key As String) As clsPerson
    Dim objNewPerson As clsPerson
   
    Set objNewPerson = New clsPerson
   
    With objNewPerson
        .Name = Name
        .EmailAddress = EmailAddress
        .PhoneNumber = PhoneNumber
    End With
   
    AddItem objNewPerson, Key
   
    Set Add = objNewPerson
    Set objNewPerson = Nothing
End Function

Public Property Get Item(Key As Variant) As clsPerson
  Set Item = mCollection(Key)
End Property

Public Sub Clear()
    Set mCollection = New Collection
End Sub

Public Property Get Count() As Long
    Count = mCollection.Count
End Property

Public Sub Remove(Key As Variant)
    mCollection.Remove Key
End Sub

Public Property Get NewEnum() As IUnknown
    'The enumerator uses the hidden _NewEnum property from the underlying collection
    Set NewEnum = mCollection.[_NewEnum]
End Property

Private Sub Class_Initialize()
    Set mCollection = New Collection
End Sub

Private Sub Class_Terminate()
    Set mCollection = Nothing
End Sub
'___________________

Next come the important bits - making the Item property default and the enumerator work:
    Set the focus to the clsPeople class.
    From the Tools menu select Procedure Attributes.
    In the Procedure Attributes window Scroll through the Name combo and select 'Item'.
    Click on the Advanced>> button.
    In the Procedure Id Combo, select (Default).
    Click the Apply button. You have set the default property of clsPeople to Item.

    Select 'NewEnum' from the Name dropdown.
    In the Procedure Id combo type in -4 (minus 4). -4 is the procedure id for a collection enumerator.
    Check the Hide this Member checkbox.
    You have just set up the class enumerator.

Now you just need to test the code. Here's some code to run from a form_load event handler:

'___________________

Private Sub Form_Load()
    Dim People As clsPeople
    Dim Person As clsPerson
   
    Set People = New clsPeople
    With People
        .Add "Sir Prancelot", "098765465758", "prancy@NotARealAddress"
        .Add "Lady Hysteria", "098763423432", "hysteria@NotARealAddress"
        .Add "Otto the Blot", "0213465758", "otto@NotARealAddress"
        .Add "Duke Uglio", "09872345758", "uglio@NotARealAddress"

    End With

    For Each Person In People
        Debug.Print Person.Name, Person.PhoneNumber, Person.EmailAddress
    Next
       
End Sub
'___________________

0
 
fds_fatboyCommented:
If you just want a simple read-only collection just do this in your class

'___________________

Option Explicit
Dim mColList As Collection

Private Sub Class_Initialize()
    Set mColList = New Collection
    mColList.Add "One"
    mColList.Add "Two"
    mColList.Add "Three"
    mColList.Add "Four"
    mColList.Add "Five"
End Sub

Public Property Get List() As Collection
    Set List = mColList
End Property
'___________________


You could use the following code to call it

   Set objMyDLL = createobject("MyDLL.MyClass")
   Set x = objMyDLL.List()

   For Each y in x
      debug.print y
   Next

If you want a type-safe read/write collection, come back to me.
0
 
aryaomniCommented:
There is one Simple Application Provoided By Visual Basic
Class Builder Utility .
Go  to Add ins >> Add ins Manager
Select Class Builder Utility
You can easily create Collection

For Returing Collection as you WANT GetList

I  will post here a simple code Demostrating using collection


' This is a method of Class Employee
' Returns Collection Employee

Public Function GetAllEmployees(Optional strWhere As String = vbNullString) As colEmployees
   
   Dim lrs As New ADODB.Recordset
   Dim lstrSQL As String
   Dim i As Long
   Dim ObjNewEmp As clsEmployee
   Set ObjNewEmp = New clsEmployee
   Set GetAllEmployees = New colEmployees
   lstrSQL = "SELECT EMPLOYEE_ID FROM EMPLOYEEMASTER "
   If strWhere = vbNullString Then
   Else
   lstrSQL = lstrSQL & strWhere
   End If
   
   lstrSQL = lstrSQL & " ORDER BY EMPLOYEE_ID"
   lrs.Open lstrSQL, gobjCon.G_Connection, adOpenKeyset, adLockReadOnly
   If lrs.EOF = False And lrs.BOF = False Then
      For i = 0 To lrs.RecordCount - 1
         With ObjNewEmp
            .ReadRecord Trim(lrs!Employee_ID & "")
         GetAllEmployees.Add .Employee_ID, .Employee_name, .reports_to, .Gender, .Proces_Name_Code, .designation, .Status, .contact_no, .PU, .DR, .AA, .General_Preference, .AA_FromDate, .AA_ToDate, .Email, .PassCode, .Employee_ID
         lrs.MoveNext
         End With
      Next
   Else
   End If
   lrs.Close
   Set lrs = Nothing
 
  End Function


0
The new generation of project management tools

With monday.com’s project management tool, you can see what everyone on your team is working in a single glance. Its intuitive dashboards are customizable, so you can create systems that work for you.

 
aryaomniCommented:
'also this is code of employee Collection to that you can get idea

Option Explicit

'local variable to hold collection
Private mCol As Collection

Public Function Add(Employee_ID As String, Employee_name As String, reports_to As String, Gender As String, Proces_Name_Code As String, designation As String, Status As String, contact_no As String, PU As clsAddress, DR As clsAddress, AA As clsAddress, General_Preference As String, AA_FromDate As String, AA_ToDate As String, Email As String, PassCode As String, Optional sKey As String) As clsEmployee
    'create a new object
    Dim objNewMember As clsEmployee
    Set objNewMember = New clsEmployee


    'set the properties passed into the method
    objNewMember.Employee_ID = Employee_ID
    objNewMember.Employee_name = Employee_name
    objNewMember.reports_to = reports_to
    objNewMember.Gender = Gender
    objNewMember.Proces_Name_Code = Proces_Name_Code
    objNewMember.designation = designation
    objNewMember.Status = Status
    objNewMember.contact_no = contact_no
    If IsObject(PU) Then
        Set objNewMember.PU = PU
    Else
        objNewMember.PU = PU
    End If
    If IsObject(DR) Then
        Set objNewMember.DR = DR
    Else
        objNewMember.DR = DR
    End If
    If IsObject(AA) Then
        Set objNewMember.AA = AA
    Else
        objNewMember.AA = AA
    End If
    objNewMember.General_Preference = General_Preference
    objNewMember.AA_FromDate = AA_FromDate
    objNewMember.AA_ToDate = AA_ToDate
    objNewMember.Email = Email
    objNewMember.PassCode = PassCode
    If Len(sKey) = 0 Then
        mCol.Add objNewMember
    Else
        mCol.Add objNewMember, sKey
    End If


    'return the object created
    Set Add = objNewMember
    Set objNewMember = Nothing


End Function

Public Property Get Item(vntIndexKey As Variant) As clsEmployee
    'used when referencing an element in the collection
    'vntIndexKey contains either the Index or Key to the collection,
    'this is why it is declared as a Variant
    'Syntax: Set foo = x.Item(xyz) or Set foo = x.Item(5)
  Set Item = mCol(vntIndexKey)
End Property



Public Property Get Count() As Long
    'used when retrieving the number of elements in the
    'collection. Syntax: Debug.Print x.Count
    Count = mCol.Count
End Property


Public Sub Remove(vntIndexKey As Variant)
    'used when removing an element from the collection
    'vntIndexKey contains either the Index or Key, which is why
    'it is declared as a Variant
    'Syntax: x.Remove(xyz)


    mCol.Remove vntIndexKey
End Sub


Public Property Get NewEnum() As IUnknown
    'this property allows you to enumerate
    'this collection with the For...Each syntax
    Set NewEnum = mCol.[_NewEnum]
End Property


Private Sub Class_Initialize()
    'creates the collection when this class is created
    Set mCol = New Collection
End Sub


Private Sub Class_Terminate()
    'destroys collection when this class is terminated
    Set mCol = Nothing
End Sub

0
 
gjokAuthor Commented:
fds_fatboy,
Thanks, that works well (nice and simple!), but how can I add 'nodes'(?) to it, like this:

   For Each y in x
      debug.print y.Name
      debug.print y.PhoneNumber
      debug.print y.EmailAddress
   Next

(aryaomni, Sorry I couldnt get your code to work.)
0
 
gjokAuthor Commented:
Is this possible using the example provided...?
0
 
gjokAuthor Commented:
fds_fatboy,
Thanks, that also works very nicely. However I cant seem to add this into my DLL.

If I double the points from 250 to 500, could you help me to get it working in my DLL?
If this proves to be too time-consuming for 500 points then I can close the question now for the 250 points - no problem.

Thanks - Let me know what you want to do...
-------------------------------------------------------------
In case you can help me further, here are my issues:
(btw: I have a project Group - MyDLL.vbp is my DLL project, and Project1 is my test exe)

1. I have put clsPeople and clsPerson as Class Modules in my DLL project, but have had to change the Instancing from private to Multiuse otherwise I get a "No creatable public component detected" message when I hit F5. I dont know what this means and its probably wrong!

2. Not sure how to call my DLL from the exe. ie:
   Private Sub Command6_Click()
      Set objPeople = CreateObject("MyDLL.clsPeople")
      Set People = objPeople.XXXXX
      For Each Person In People
         Debug.Print Person.Name
      Next
   End Sub

3. The DLL needs to read the data from disk. Where do I add the code fto do that? The following doesnt want to work...
Private Sub Class_Initialize()
    Set mCollection = New Collection
    mCollection.Add "Sir Prancelot", "098765465758", "prancy@NotARealAddress"
    mCollection.Add "Lady Hysteria", "098763423432", "hysteria@NotARealAddress"
    mCollection.Add "Otto the Blot", "0213465758", "otto@NotARealAddress"
    mCollection.Add "Duke Uglio", "09872345758", "uglio@NotARealAddress"
End Sub
0
 
fds_fatboyCommented:
1. clsPeople should be multiuse if you want to see it from outside your dll. clsPerson should be declared.
clsPerson should be Public Not Creatable (or possibly MultiUse  depending how you want to use it)

Private means the object is not available to Clients of the DLL (it is internal to the DLL)
MultiUse allows you to create new instances of the class from the DLL's client using the New keyword (or CreateObject).
Public NotCreatable means you can see a instances class for the DLL's client, but the client can't explicitly create new instances.
Global MultiUse - don't even think about it until you know what you're doing

For these kinds of questions you might be better off looking in MSDN online, and reading up on the fundamentals of ActiveX DLLs and object scoping.

For example:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vbcon98/html/vbconinstancingforolecomponentclasses.asp

2. Not sure how to call my DLL from the exe.
Not like that (see below).
3. The DLL needs to read the data from disk. Where do I add the code fto do that?
In your executable, Exactly when is up to you. Before you write the software, you must decide how you want it to work.

I don't understand what you are trying to do here at all.
But at a guess...
Set up a reference to your DLL in your executable project.

Try this in the form in your executable (from question 2):
'________________________________________
'Declarations
...
Dim mobjPeople As MyDLL.clsPeople
...

   Private Sub Form_Load
     'This loads data. You could put the code to read it from file in here
     Set  mobjPeople  = New MyDLL.mobjPeople ' This is more efficient in an executable than CreateObject
     mobjPeople.Add "Sir Prancelot", "098765465758", "prancy@NotARealAddress"
     mobjPeople.Add "Lady Hysteria", "098763423432", "hysteria@NotARealAddress"
     mobjPeople.Add "Otto the Blot", "0213465758", "otto@NotARealAddress"
     mobjPeople.Add "Duke Uglio", "09872345758", "uglio@NotARealAddress"
  End Sub

   Private Sub Command6_Click()
      Dim objPerson As MyDLL.clsPerson

       For Each objPerson In mobjPeople
         Debug.Print objPerson.Name
      Next
   End Sub
'________________________________________

0
 
gjokAuthor Commented:
Many thanks for your help.
I will see how I get on.

by the way, you said "I don't understand what you are trying to do here at all."
...Well, the DLL will be used only in a readonly capacity by the client program (which will end up in an ASP script)
The DLL will read in data from a database, so the collection will never be populated by the client, rather the DLL will go off and read in the data itself, hence the need to add data in "Class_Initialize()"

We know how we want it to work, its just "getting it to work" :)
0
 
fds_fatboyCommented:
Fair enough, but this is an unusual way of doing it:

To make People class read-only, you must make make the Add method Private (Not public), you should remove the AddItem, Clear and Remove
items as well.

The reason your code didn't work was because you were attempting to use the Add method using the interface of the People Class. The Add Method on the Collection accepts different arguments.

Try this:

Class_Initialize()
Private Sub Class_Initialize()
    Set mCollection = New Collection

    Add "Sir Prancelot", "098765465758", "prancy@NotARealAddress"
    Add "Lady Hysteria", "098763423432", "hysteria@NotARealAddress"
    Add "Otto the Blot", "0213465758", "otto@NotARealAddress"
    Add "Duke Uglio", "09872345758", "uglio@NotARealAddress"
End Sub
0
 
gjokAuthor Commented:
Thanks.
0
All Courses

From novice to tech pro — start learning today.