Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I get an item from a Collection and store it in a variable?

Tags:

vba

I have a Collection which I use to have a String -> MailItem map. I fill the map, and when I find a duplicate key I want to read the item in the Collection.

This seems so easy, but I spent more than an hour trying to figure out why I can't assign a Collection item to a local variable. (see PROBLEM in code below)

oMailOther = cMails.Item(cMailKey) "Object variable or With block variable not set"

Set oMailOther = cMails.Item(cMailKey) "Object required"

The other cMails(cMailKey) form gives the same error. Moving the Dim around doesn't make any difference. cMails must be available because it's used earlier in the method. Note the Debug.Print line just before this statement, that works. What am I missing?

Option Explicit
Option Compare Text
 
Public cMails As Collection
 
Public Sub GetOutlookAttachments()
    Set cMails = New Collection

    Dim oStore As Store
    For Each oStore In Session.Stores
        If oStore.DisplayName = "Outlook Data File" Then
            ProcessFolder oStore.GetRootFolder()
        End If
    Next
End Sub
 
Private Sub ProcessFolder(oFolder As Folder)
    Debug.Print oFolder.FolderPath
    ProcessItems oFolder.Items

    Dim oSubFolder As Folder
    For Each oSubFolder In oFolder.Folders
        ProcessFolder oSubFolder ' recurse
    Next
End Sub
 
Private Sub ProcessItems(oItems As Items)
    Dim oItem As Object
    For Each oItem In oItems
        DoEvents
        If TypeOf oItem Is MailItem Then
            Dim oMail As MailItem
            Set oMail = oItem
            Dim cMailKey As String
            cMailKey = oMail.ConversationID & "-" & oMail.ConversationIndex
            If Not Contains(cMails, cMailKey) Then
                cMails.Add oMail.Subject, cMailKey
            Else
                Debug.Print cMails.Item(cMailKey)
                Dim oMailOther As MailItem
 PROBLEM        oMailOther = cMails.Item(cMailKey)
                Debug.Print cMailKey & ": " & oMailOther.Subject
            End If
        ElseIf TypeOf oItem Is MeetingItem Then
            ' ignore
        Else
            Debug.Print "oItem Is a " & TypeName(oItem)
        End If
    Next oItem
End Sub

Public Function Contains(col As Collection, key As Variant) As Boolean
    Dim obj As Variant
    On Error GoTo err
    Contains = True
    obj = col(key)
    Exit Function
err:
    Contains = False
End Function

I also tried to replicate similar Add and Item calls elsewhere and it works.

Public Sub Test()
    Set cMails = New Collection
    
    Dim cMailKey As String
    cMailKey = "hello"
    cMails.Add Session.Stores.Item(1), cMailKey
    
    Debug.Print cMails(cMailKey)
    Dim oStore As Store
    Set oStore = cMails(cMailKey)
    Debug.Print oStore.DisplayName
End Sub
like image 504
TWiStErRob Avatar asked Jun 20 '15 13:06

TWiStErRob


People also ask

How do collections work in VBA?

Now, an Excel VBA Collection is a group of similar items. You can use built-in collections such as the Workbooks collection, which is a collection of all the open workbooks, in your VBA code. The Worksheets Collection, on the other hand contains all the worksheets in your workbook.

What is a collection variable in Python?

A collection variable is a composite variable whose internal components, called elements, have the same data type. The value of a collection variable and the values of its elements can change. You reference an entire collection by its name.

What is the difference between Array and collection in VBA?

Collections in VBA are objects that can store groups of related items, much like an array. Unlike arrays, a single collection can store items of different types because each item in a collection is stored as a Variant.


2 Answers

I copied your code and ran it. The collection cMails you are creating is a collection of Strings, not of mail objects; however, oMailOther is declared as an Object of type MailItem.

In your assignment without the Set keyword, VB complains that your want to assign something to an object (left-hand side) and should use the Set keyword. Now, with the Set keyword, VB complains that the right-hand side is not an object...

To make cMails into a colection of mail items, change the Add statement as follows:

cMails.Add oMail, cMailKey

(i.e. you don't add oMail.Subject but the whole oMail object.)

Now use the Set keyword in Set oMailOther = cMails.Item(cMailKey) and everything works fine.

like image 63
Paul Ogilvie Avatar answered Sep 18 '22 16:09

Paul Ogilvie


oMailOther is a MailItem, so without a question you must use Set what assigning it to a variable:

Set oMailOther = cMails(cMailKey)

However your cMails collection does not contain a MailItem object. It contains only subjects (that are strings as opposed to objects) that you previously added with cMails.Add oMail.Subject, cMailKey.

Apparently you meant cMails.Add oMail, cMailKey.

like image 29
GSerg Avatar answered Sep 22 '22 16:09

GSerg