Unable to Enumerate a C# class in VB6

M

mjdryden

I have a bit of a complicated mix of COM and .Net here, so bear with
me while I explain :)

We have a Type Library that defines all of the interfaces used in this
project (a rather large one at that) which was created in VB6. For a
number of unrelated reasons, we've chosen to create new .Net classes
that implement these interfaces, which are, for the most part, working
correctly. We are able to pass our new objects into our COM classes
and perform most operations on them, with one major exception:
Enumeration.

Enumeration is defined in the existing type library.

In VB6 it appears as: IObject_NewEnum() as stdole.IUnknown
In .Net, it maps to: System.Collections.IEnumerator GetEnumerator()

I've created an internal Enumerator class on the .Net side to support
the enumeration, and it works correctly when enumerating from .Net,
however, when attempting to enumerate from VB6, I receive: ErrorCode
-2146827864 "Object Required". Looping through the objects by index
works correctly in both .Net and VB6.


Based on search results, I've tried adding [DispId(-4)] to the
GetEnumerator() method, which is apparently supposed to direct .Net to
output the enumerator as an EnumVariant, but I've had no success
here. My belief is that this isn't working because DispId needs to be
specified on the interface, however, I do not have access to change
this; I'm only able to work with the implementation (in either case,
I'm not certain how, or if, this could be done on a VB6 interface
anyway).


Ideally, I'm looking for a solution which does not require a change to
the type library. Is there another way to force C# to output the
enumerator in a format which VB can understand?

Or, if there is no other way than to change the interface, is there a
way to provide this directive in VB6?

Any suggestions are appreciated, but please keep in mind that getting
authority to change the VB6 type library will be extremely difficult,
and possibly not an option at all...if its not, my only recourse will
be to go back to utilizing the poorly written-hard to work with (and
equally unmodifiable) VB6 classes...something I'd really like to avoid
doing.


Some basic code:

public class IBFields : TBWApplication.IFields
{
[snip]
[System.Runtime.InteropServices.DispId(-4)]
public System.Collections.IEnumerator GetEnumerator()
{
return new FieldEnumerator(m_fieldsArray);
}
}

internal class FieldEnumerator : System.Collections.IEnumerator
{

private SortedList<string, IBField> m_fields;
int position = -1;

public FieldEnumerator(SortedList<string, IBField> list)
{
m_fields = list;
}

public object Current
{
get
{
try
{
return
(TBWApplication.IField)m_fields.Values[position];
}
catch (IndexOutOfRangeException)
{
throw new InvalidOperationException();
}
}
}


public bool MoveNext()
{
position++;
return (position < m_fields.Count);
}

public void Reset()
{
position = -1;
}
}
 
M

mjdryden

Well, I've found my own answer here. For anyone else that runs into
this, make sure the class being returned by your enumerator is set to
[ComVisible(true)].

It seems rather illogical that I'm able to pass a "Com invisible"
class into a COM class and work with it without flagging it as
visible, but that was the problem. I suppose its a case of the
enumerator returning an object with a type that VB6 was unable to
identify.

Also, as it turns out, our VB6 interface was already defined with
DispId(-4); its quite possible that this would have been required as
well.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top