Search code examples
c#vb6com-interop

How to assign an Array of Object property/method using a made-in-C# Type Library - COM-Interop?


``

I have a C# class library project (.Net Framework 4.5) that I use it in VB6 as a type library (.tlb).

Everything works fine with properties with non-collection objects as attributes or returns.

As far as I know, it's not possible to expose a collection (Array/List) of a user-type object such as Product [] in a C# project and export it to tlb file, but Object [] I heard it's okay. So, I changed:

Public List<Product> ListOfProducts( get; set; )

to

Object [] _productList;
public Object [] ListOfProducts
{
    get
    {
        return _productList;
    }
    set
    {
        _productList = value;
    }
}

I also tried:

public void SetListOfProducts(Object [] products)
{
    _productList= products;
}

That done, ListOfProducts or SetListOfProducts now are visible in Visual Basic 6 project, but in VB6, when I run:

Private Sub Command1_Click()
    Dim Sell as new SellProducts
    Dim prodct(1) As New TlbProj.Product 'Product is a class inside of the tlb file
    prodct(0).EAN = "7894900011517"
    prodct(1).EAN = "7894900017011"
    
    Dim prodctVariant(1) As Variant
    'Set prodctVariant = prodct or prodctVariant = prodct  throws "Can't assign to array error"
    prodctVariant(0) = prodct(0)  'one by one was the only way I managed to do this. That's not the major problem.
    prodctVariant(1) = prodct(1)

    Sell.ListOfProducts = prodctVariant
    'The object browser shows: 'Property ListOfProducts As Variant()
    'it throws the message: "Function or interface marked as restricted, or the function uses an Automation type not supported in Visual Basic"

    Sell.SetListOfProducts prodctVariant
    'The object browser shows: 'Sub SetListOfProducts(products() As Variant)
    'it throws the message: "Function or interface marked as restricted, or the function uses an Automation type not supported in Visual Basic"

End Sub


My classes:

[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("757E6144-FC46-44A0-89DB-B89EF8F75BAB")]
[ProgId("TlbProj.SellProducts")]
[ComVisible(true)]
public Class SellProducts
{
  Object [] _productList;
  public Object [] ListOfProducts
  {
      get
      {
          return _productList;
      }
      set
      {
          _productList = value;
      }
  }

  public void SetListOfProducts(Object [] products)
  {
      _productList= products;
  }
}
[ClassInterface(ClassInterfaceType.AutoDual)]
[Guid("A4292449-4459-42D4-8FB0-18AA0D5FF34A")]
[ProgId("TlbProj.Product")]
[ComVisible(true)] 
public class Product
{
    public string EAN { get; set; }
}

I have tried with no success:

That said, is there a way to get and set Array of Object (preferably to Array of Product type) from C# to COM, even using .Net 5+? Thank you all!


Solution

  • Although .NET creates valid type libraries, they are not all supported by VB6. .NET generics cannot be used at all at boundaries.

    One solution is to use ArrayList as a collection type usable in C# and VB6 but it's untyped. It works with .NET Framework, but not sure it still works (registered?) with .NET Core3+.

    Here is a solution that works and is typed for reading the list, but is untyped for write operations:

    [ComVisible(true)]
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [Guid("757E6144-FC46-44A0-89DB-B89EF8F75BAB")]
    [ProgId("TlbProj.SellProducts")]
    public class SellProducts
    {
        private readonly List<Product> _products = new List<Product>();
    
        public SellProducts()
        {
            _products.Add(new Product { EAN = ".NET1234" });
            _products.Add(new Product { EAN = ".NET5678" });
        }
    
        // read only mode
        public Product[] Products => _products.ToArray();
    
        // write mode, untyped :-(
        public void SetProducts(object products)
        {
            _products.Clear();
            if (products is IEnumerable enumerable)
            {
                _products.AddRange(enumerable.OfType<Product>());
            }
        }
    }
    
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [Guid("A4292449-4459-42D4-8FB0-18AA0D5FF34A")]
    [ProgId("TlbProj.Product")]
    [ComVisible(true)]
    public class Product
    {
        public string EAN { get; set; }
    }
    

    VB6 doesn't understand type libs created with object[] or Product[] parameters for SetProducts.