简体   繁体   中英

C# to VB6 interop: indexed array properties are not accessible across nested COM interfaces

I would like to publish a C# class library via COM interop, so that it may be used by VB6 clients. For demonstration purposes, consider the following snippet:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace cslib
{
    [ComVisible(true)]
    [Guid("...")]
    public interface IClass2
    {
        string m_sStr { get; set; }
    }

    [ComVisible(true)]
    [Guid("...")]
    [ClassInterface(ClassInterfaceType.None)]
    public class Class2 : IClass2
    {
        public Class2()
        {
            m_sStr = "Hello";
        }

        public string m_sStr { get; set; }
    }

    [ComVisible(true)]
    [Guid("...")]
    public interface IClass1
    {
        Class2[] m_Class2Instances { get; set; }
    }

    [ComVisible(true)]
    [Guid("...")]
    [ClassInterface(ClassInterfaceType.None)]
    public class Class1 : IClass1
    {
        public Class1()
        {
            List<Class2> lstClass2 = new List<Class2>();

            for (int i = 0; i < 5; i++)
                lstClass2.Add(new Class2());

            m_Class2Instances = lstClass2.ToArray();
        }

        public Class2[] m_Class2Instances { get; set; }
    }
}

After registering the library on the system, the COM interface is usable in VB6. However, accessing the array property with an indexed value doesn't seem to work:

Dim c1 As New cslib.Class1
Dim str As String

'Error message = Wrong number of arguments or invalid property assignment
str = c1.m_Class2Instances(0).m_sStr

The only alterative I've found is creating a temporary array variable. This allows me to access the indexed interface properly:

Dim c1 As New cslib.Class1
Dim str As String

'Works, but requires detour via temp array
Dim arrc2() As cslib.Class2
arrc2 = c1.m_Class2Instances

str = arrc2(0).m_sStr

Unfortunately, the array I've illustrated here is a mere simplification. In real life, I need to access COM interfaces, which are located deep inside nested array structures. For instance, the following class structure...

Class1
    Class2[]
        Class3[]
            Class4[]

...would ultimately force me to create three temporary array variables, before I can actually access an instance of Class4.

Is this a limitation of VB6? If so, is there any way to access nested array interfaces without cluttering the code with temporary variables?

I've retired VB6 a long time ago and can't check this anymore. But it is almost certainly suffering from a syntax ambiguity. Did you mean to index the property or the return value of the property? You like the latter interpretation but that's not what it does. You'd have to write something like this:

  str = (c1.m_Class2Instances)(0).m_sStr

or:

  str = c1.m_Class2Instances()(0).m_sStr

No real idea if this can compile. Bleh anyway.


You need to get ahead by actually writing an indexed property. Like this:

public interface IClass1 {
    Class2 this[int index] { get; set; }
}

public class Class1 : IClass1 {
    private List<Class2> lstClass2 = new List<Class2>();
    public Class1() {
        for (int i = 0; i < 5; i++) lstClass2.Add(new Class2());
    }

    public Class2 this[int index] {
        get { return lstClass2[index]; }
        set { lstClass2[index] = value; }
    }
}

Note how this also makes it a lot less painful to let the VB6 code iterate the array. You are not creating a new array over and over again. The VB6 code gets short and sweet as well:

Dim c1 As New cslib.Class1
Dim str = c1(0).m_sStr

If you really, really need to return or assign a complete array then you must use a method instead.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM