3

I have a COM object 'Foo' that defines a function returning an array of Bar:

public Bar[] Bars()
{
    return bars;
}

This is in a DLL that's registered with COM.

I can call this from VBA like so:

Dim aBars() As Bar
aBars = oFoo.Bars()

Dim oBar As Bar
Set oBar = aBars(0)

However, I need to call the same function from VBScript, which has no early binding support, and when I try this, it fails:

Dim aBars
aBars = oFoo.Bars()

Dim oBar
Set oBar = aBars(0) ' fails with 'Type Mismatch'

If I inspect the type of 'aBars', it is 'Unknown()', which I guess is why it doesn't know what to do with it.

What can I do to make this work?

1

2 Answers 2

1

There is something wrong with the attributes on the Bar class or interface, it doesn't implement IDispatch like scripting languages require. Only IUnknown, something that VBA can handle but VBScript can't. IDispatch is required to support late binding, as needed by scripting runtimes.

I can't see Bar at all so have to guess. If it is an interface or a class that implements an interface then you need [InterfaceType(ComInterfaceType.InterfaceIsDual)] to get support for both early and late binding. Or ComInterfaceType.InterfaceIsIDispatch for late binding.

If it is a class then you need [ClassInterface(ClassInterfaceType.AutoDual)] to get support for early and late. Or ClassInterfaceType.AutoDispatch for late.

Boilerplate stay-out-of-trouble is:

[ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IBar {
    // etc...
}

[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class Bar : IBar {
    // etc...
}

Which supports both early and late binding and is a good way to hide the class implementation details, a strong COM goal, avoiding the baggage that gets pulled in from the base class of Bar, the System.Object methods.

Sign up to request clarification or add additional context in comments.

3 Comments

Sounds logically , +1 :)
Thanks Hans. Unfortunately(?) that's exactly how the class and interface are defined! I can work with the objects individually - it's just this method that returns an array of them that's problematic. I found another q/a that suggests arrays of user types can't be used (returned from a function) like this, and you need to use ArrayList instead...
Only a problem if "user types" is a struct. Don't use structs, they are pretty troublesome in COM. You forced me to guess at an answer, not sure why you didn't update your question with the declaration for Bar.
0

You need to return a class that's ComVisible (and enumerable), for example, this:

public Array Bars()
{
    return bars;
}

or an ArrayList, something like this:

public ArrayList Bars()
{
    ArrayList list = new ArrayList();
    // etc...
    return list;
}

or if you don't like ArrayList, something like this:

public BarList Bars()
{
    BarList list = new BarList();
    // etc...
    return list;
}

[ComVisible(true)]
public class BarList : List<Bar>
{
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.