Previous | Index | Next 

[PRB] Objects returned from COM methods may cause an InvalidCastException error

In a few circumstances, the migrated VB.NET project can throw an InvalidCastException error; all known cases are related to VB6 projects that reference one or more ActiveX DLLs. Consider the following scenario: an ActiveX DLL project contains a Widget class that exposes a GetCollection method, which returns a VBA.Collection object. Next, assume that the main project references the ActiveX DLL and contains the following statement:

    Dim cls As New ActiveXDLL.TestClass
    Dim col As Collection
    Set col = cls.GetCollection

This is the VB.NET code produced by VB Migration Partner:

    Dim cls As New ActiveXDLL.TestClass
    Dim col As Collection = cls.GetCollection()   ' this statement throws an exception

Here’s the problem: the GetCollection method returns a VBA.Collection object defined in the VBA.DLL file, but this object can’t be assigned to the cls variable, because the VBA.Collection and the the Microsoft.VisualBasic.Collection class have nothing in common. In fact, VB.NET throws an exception when the assignment is attempted. You can experience this problem with other COM objects, for example Scripting.Dictionary, or ActiveX controls such as TreeView and ListView.

The simplest workaround for this issue is to migrate both the main project and the ActiveX DLL project in a single operation. To do this, create a VB6 project group that contains both the main project and all the ActiveX DLL projects (in source code) that the main project references, then use VB Migration Partner to convert both projects in one operation.

If this approach isn’t possible – for example, if you don’t have the source code of the referenced ActiveX DLL – you must write some code that recreates the .NET object manually. In this specific example, you can convert a VBA.Collection to a .NET collection using this helper function:

    Function VBACollectionToNETCollection(ByVal col As VBA.Collection) As Collection
        Dim netCol As New Collection
        ' Notice that we move only item values, not item keys.
        For Each obj As Object In col
            netCol.Add(obj)
        Next
        Return netCol
    End Function

Notice, however, that this code isn’t perfectly equivalent to the original one, because keys in the collection aren’t recreated correctly. Unfortunately, there is no simple fix that is valid for all COM objects.

 

Previous | Index | Next