VBA Objects

Objects are constructs with state and behavior. Objects are instantiated from Classes. Each object created from a class is called an instance of the class. Classes are are essentially blueprints for objects. Classes define members which can be variables (state) and procedures (behavior). Classes in VBA are defined in Class modules and libraries.

Object Variables

An Object variable stores a reference to an object, not the object itself. Object variables are called reference type variables because they store a reference to an object located somewhere else in memory. An Object variable is assigned an object using the Set statement. Objects variables can be given an explicit class type or can be given the general types Object or Variant.

Object Instantiation

An object is instantiated when a new instance of a class is created in memory. Objects are instantiated using the New keyword or the CreateObject function. Objects can be explicitly instantiated using the Set statement, or they can be declared as auto-instancing object variables that are instantiated automatically when they are first used in a program.

Explicit Instantiation

Objects can be explicitly instantiated in a few ways. An object can be instantiated and assigned to an object variable, an object can be instantiated and passed as an argument to a procedure, and an object can be instantiated in a With statement. Either the New keyword or the CreateObject function can be used to create an object instance.

Public Sub Example()

    '''Using the New keyword

    'Object variable
    Dim Coll As Collection
    Set Coll = New Collection

    'Argument
    Coll.Add New Collection

    'With statement
    With New Collection
        .Add Coll
    End With

End Sub
Public Sub Example()

    '''Using the CreateObject function

    'Object variable
    Dim Dict As Object
    Set Dict = CreateObject("Scripting.Dictionary")

    'Argument
    Dict.Add 1, CreateObject("Scripting.Dictionary")

    'With statement
    With CreateObject("Scripting.Dictionary")
        .Add 1, Dict
    End With

End Sub

Auto-Instancing

Auto-instancing object variables automatically instantiate an object when they are first used in a program. Auto-instancing objects should be used when they are necessary but using explicit instantiation provides more control over the lifetime of objects. Auto-instancing object variables can be set to Nothing but they can never be tested to see if they are Nothing becausing referring to the object variable instantiates the object. To create an auto-instancing object variable, declare the object variable using the New keyword in the same line as the declaration. Although the variable is declared using the New keyword, the object is not instantiated until it is first used.

Public Sub Example()

    'Auto-instancing Collection object declared
    Dim Coll As New Collection

    'Collection object instantiated
    Coll.Add "Hello, World!" 

    'Collection object terminated
    Set Coll = Nothing 

    'Collection object instantiated in conditional statement
    If Coll Is Nothing Then 
        Debug.Print "This will NEVER print"
    End If

End Sub

Object Lifetime

The lifetime of an object begins when the object is instantiated and ends when the object is terminated. An object is terminated when there are no live references to the object. To remove a reference to an object, set any object variables pointing to the object to Nothing. If an object's data members contain a reference to an object, terminating the object containing the reference will also remove the reference to the other object.

Public Sub Example()

    Dim C1 As Collection
    Dim C2 As Collection

    'Both object variables refer to the same Collection object in memory.
    Set C1 = New Collection
    Set C2 = C1 

    'Object still has a live reference to it so it is not removed from memory.
    Set C1 = Nothing  

    'Object has no more live references so it is removed from memory.
    Set C2 = Nothing

End Sub
Public Sub Example()

    Dim C1 As Collection
    Dim C2 As Collection

    'C1 and C2 are references to different object in memory.
    Set C1 = New Collection
    Set C2 = New Collection

    'C1 contains a reference to the object C2 is referencing.
    C1.Add C2

    'The C2 reference is removed but the reference to the object
    'still exists inside C1 so the object is not terminated.
    Set C2 = Nothing

    'Both Collections are terminated. Terminating C1's object
    'also removes the only live reference to C2's object.
    Set C1 = Nothing

End Sub

When a procedure exits, local object variables are unloaded from memory which can cause the objects they reference to be terminated.

Public Sub Example()

    Dim C As Collection
    Set C = New Collection
    
    'C is unloaded when procedure ends and the object is terminated.
End Sub

If an outside reference still exists to an object, the object will not be terminated when a local object variable goes out of scope.

Public Coll As Collection

Public Sub Example()

    Dim C As Collection
    Set C = New Collection

    Set Coll = C

    'C is unloaded but the Public Coll variable still refers to the Collection
    'so the Collection object is not terminated.
End Sub

When an object variable is declared Static, it must be auto-instancing, otherwise setting the variable to a new instance replaces the original reference and terminates the original object.

Public Sub Example()

    Static C As New Collection

    C.Add "Hello, World!"

    Debug.Print C.Count

End Sub

Comparing Objects

The Is keyword can be used to check if two object variables refer to the same object in memory. When objects are compared using Is, the data stored in the object's fields are not compared. A function would need to be created that compares each member of an object, given the object's type.

Public Sub Example()

    Dim C1 As Collection
    Dim C2 As Collection

    Set C1 = New Collection
    Set C2 = New Collection

    Debug.Print C1 Is C2 'Prints: False

    Set C2 = C1

    Debug.Print C1 Is C2 'Prints: True

End Sub

TypeOf...Is

TypeOf...Is can be used to check an object's type. This should be used when an object is declared using the generic Object type and a certain action requires the object to be of a certain type.

Public Sub Example()

    Dim Obj As Object
    Set Obj = New Collection

    If TypeOf Obj Is Collection Then
        Debug.Print Obj.Count
    Else
        Debug.Print "Obj is not Collection object"
    End If

End Sub

Early-Binding and Late-Binding

Objects can be declared and instantiated using early-binding or late-binding. Early-bound objects are declared as a specific class type, whereas late-bound objects are declared with as the generic Object or Variant type. Early-bound objects have a specific type at compile-time while late-bound objects do not have a specific type and can be assigned an object of any type at run-time. Early-bound objects can be instantiated using the New keyword but late-bound objects must be instantiated using the CreateObject function.

Early-Binding

To use early-binding, declare the object's type explicitly.

Public Sub Example()

    Dim Coll As Collection
    Set Coll = New Collection

End Sub

To use early-binding with external libraries, set a reference to the external library in the Visual Basic Editor by navigating to Tools → References.

Tools References
References
Public Sub Example()

    Dim Dict As Scripting.Dictionary
    Set Dict = New Scripting.Dictionary

End Sub

Late-Binding

Note: Intellisense is not available for late-bound objects.

To use late-binding, declare the object as type Object or Variant and instantiate the object using the CreateObject function. When using late-binding with the CreateObject function, it is not necessary to set a reference when using an external library.

Public Sub Example()

    Dim Dict As Object
    Set Dict = CreateObject("Scripting.Dictionary")

End Sub

When using late-binding, the compiler does not infer the type of object that will be assigned to an object variable so it does not infer the return types of properties and methods of objects. When a method returns an array it is necessary to use open and closed parentheses to call the function before trying to access elements of the returned array, otherwise the compiler may interpret the index as an argument and an error will occur. Because the compiler does not know what type of object the object variable will hold, intellisense and auto-code-completion are not available for late-bound objects.

Public Sub Example()

    Dim Dict As Object
    Set Dict = CreateObject("Scripting.Dictionary")

    Dict.Add "Key1", 1

   'Debug.Print Dict.Keys(0), Dict.Items(0) 'Causes an error
    Debug.Print Dict.Keys()(0), Dict.Items()(0)

End Sub

CreateObject and GetObject

The CreateObject and GetObject functions are used to create new object instances or retrieve existing object instances respectively.

CreateObject

The CreateObject function creates a new instance of a class from the class's ProgID. A class's ProgID can be found as an entry in the Windows Registry. ProgID's are in the format [Program].[Component].[Version]. For example, the Dictionary class is defined in the Microsoft Scripting Runtime Library and has the ProgID "Scripting.Dictionary".

Public Sub Example()

    Dim Dict As Object
    Set Dict = CreateObject("Scripting.Dictionary")

End Sub

GetObject

The GetObject function can be used to set an object variable to an existing object.

Public Sub Example()

    'Get running Excel application
    Dim ExcelApp As Object
    Set ExcelApp = GetObject(, "Excel.Application")

    'Get open workbook
    Dim WB As Object
    Set WB = GetObject("C:\example.xlsx")

End Sub