0
votes

I have an existing VB.net class library which has a public property with a type of VB's Collection class. I'm exposing the class library as a COM-object to be able to use it in Progress.

When I access the Collection-property with an integer index (e.g. comObj.OutputCol.Item(1)) it works fine, but when I try to use the string indexer (e.g. comObj.OutputCol.Item("FirstCol")) I get the following error (from a VBScript I use for testing):

Error message: Class doesn't support automation
Error code: 800A01AE

Is it possible to use the string indexer in any way via COM?

Sample code, COM-object i VB.net:

<ComClass(TestClass.ClassId, TestClass.InterfaceId, TestClass.EventsId)>
Public Class TestClass
    Public Const ClassId As String = "063CA388-9926-44EC-B3A6-856D5299C210"
    Public Const InterfaceId As String = "094ECC57-4E84-423A-B20E-BD109AEDBC20"
    Public Const EventsId As String = "038B18BD-54B4-42D3-B868-71F4C52345B0"

    Private _sOutputCol As Collection = Nothing
    Private Property sOutputCol() As Collection
        Get
            If _sOutputCol Is Nothing Then
                _sOutputCol = New Collection()
            End If
            Return _sOutputCol
        End Get
        Set(ByVal Value As Collection)
            _sOutputCol = Value
        End Set
    End Property

    Public ReadOnly Property OutputCol() As Collection
        Get
            Return sOutputCol
        End Get
    End Property

    Public Sub New()
        sOutputCol.Add("First object", "FirstCol")
        sOutputCol.Add(2, "SecondCol")
    End Sub

End Class

Sample test-code in VBScript:

Set comObj = WScript.CreateObject("VbComTest.TestClass")
wscript.echo comObj.OutputCol.Item(1) ' Works
wscript.echo comObj.OutputCol.Item(CStr("FirstCol")) ' Gives the error

I have registred the dll with: >regasm "...path...\VbComTest.dll" /codebase

1
Pretty unclear how this can work at all, the VB.NET Collection class is not [ComVisible(true)]. So the error is entirely normal. Create your own collection class, implement System.Collections.ICollection. Use a private Collection to implement the members. - Hans Passant
Oh yes, I had to register the Microsoft.VisualBasic.dll as well (via regasm if I remember correctly). The first test, with an integer indexer, works. I have it up and running on my machine. - Björn
Ugh, that can drastically screw up a machine. You basically set off a bomb on your machine, overwriting the existing registration of .NET Framework classes. You can't trust anything anymore, reinstall your operating system. - Hans Passant
That was what recommended by Microsoft documentation. But you may be right. - Björn
Here is the link to MS page about registering the VB assembly: support2.microsoft.com/kb/316163 - Björn

1 Answers

1
votes

OK, the problem was that the indexer is overloaded and you shouldn't use that in COM-visible interfaces: https://msdn.microsoft.com/en-us/library/ms182197.aspx

Extract from the page about what happens to overloaded methods:

When overloaded methods are exposed to COM clients, only the first method overload retains its name. Subsequent overloads are uniquely renamed by appending to the name an underscore character '_' and an integer that corresponds to the order of declaration of the overload. For example, consider the following methods.

void SomeMethod(int valueOne); void SomeMethod(int valueOne, int valueTwo, int valueThree); void SomeMethod(int valueOne, int valueTwo);

These methods are exposed to COM clients as the following.

void SomeMethod(int valueOne); void SomeMethod_2(int valueOne, int valueTwo, int valueThree); void SomeMethod_3(int valueOne, int valueTwo);

Visual Basic 6 COM clients cannot implement interface methods by using an underscore in the name.

So to use the string indexer I have to write:

wscript.echo comObj.OutputCol.Item_3("FirstCol")

(Item_2 takes an Object as parameter and will also work, if the documentation is correct).