views:

501

answers:

3

or a VB6 - compatible - collection object.

The title says it all, here's the background.

We provide hooks into our .net products through a set of API's.

We need to continue to support customers that call our API's from VB6, so we need to continue supporting VB6 collection objects (simple with VBA.Collection in .net).

The problem is supporting some sites that use VBScript to call our API's. VBScript has no concept of a collection object, so to create a collection object to pass to our API we built a VB6 ActiveX DLL that provides a "CreateCollection" method. This method simply creates and passes back a new collection object. Problem solved.

After many years of pruning, porting and re-building, this DLL is the only VB6 code we have. Because of it we still need to install Visual Studio 6 on our Dev & build Machines.

I'm not happy with our reliance on this DLL for several reasons (my personal dislike of VB6 is not one of them). Top of the list is that Microsoft no longer support Visual Studio 6.

My question is, how do I get ATL to create a collection object that implements the same interface as the VB6 collection object.

I've a good handle on C++, but only a loose grasp of ATL - I can create simple objects and implement simple methods, but this is beyond me.

Thanks
BW

+3  A: 

Collections are more or less based on convention. They implement IDispatch and expose some standard methods and properties:

  • Add() - optional
  • Remove() - optional
  • Item()
  • Count - read-only
  • _NewEnum - hidden, read-only, returns pointer to enumerator object that implements IEnumVariant

The _NewEnum property is what allows Visual Basic For Each.

In the IDL you use a dual interface and:

  • DISPID_VALUE for Item()
  • [propget, id(DISPID_NEWENUM), restricted] HRESULT _NewEnum([out, retval] IUnknown** pVal)

Here are some MSDN entries: Design Considerations for ActiveX Objects
And here is some ATL specific convenience: ATL Collections and Enumerators

Georg Fritzsche
+2  A: 

Lets target this VBScript snippet

Dim vElem
For Each vElem In MyObject
    ...
Next

particularly the implementation of MyObject. As a minimum you have to implement a method/propget with DISPID_NEWENUM on the default dispinterface (its dual/dispinterface to talk about DISPIDs). You can name it whatever you want, it doesn't matter. Most collections use NewEnum, and flag it in IDL as hidden. VB6 uses underscore prefix to mark hidden methods so you might see _NewEnum as recommendation but it's kind of a cargo cult ATL does.

You don't need any Count, Item, Add, Remove, Clear or any other method at all (on the default interface). You can supply these as a convenience (particulatly Item accessor and probably Count) but you don't have to, to make the sample code above work.

Next, the retval has to be a separate object (so called enumerator) which implements IEnumVARIANT interface by using a (private) pointer to MyObject. In IDL you can declare retval as IUnknown nothing wrong here. What is most interesting is that you have to implement only the Next method on IEnumVARIANT, you can return E_NOTIMPLEMENTED on the rest if you like or optionally implement them though these are never called by For Each. What makes the implementation even easier is that celt parameter of Next (the number of items requested) is always 1, so For Each requests items always one by one.

What you can use in ATL is CComEnumOnSTL and the like to create a "proxy" enumerator on an STL container, or the array based enumerator ATL provides (and exclude STL).

wqw
You don't need Count etc. for For Each, but risk breaking other code that utilizes them. Also MSDN says it must be named _NewEnum - while this may not be neccessary for VB6, it might break other code ... http://msdn.microsoft.com/en-us/library/ms221672.aspx
Georg Fritzsche
I've seen the CComEnumOnSTL objects, and the ATL collection objects. It was a matter of "being spoiled for choice", I didn't know which to choose. Any advice on which to use to build a collection object in ATL that I can pass to a VB6 function that expects a VB6 collection?
Binary Worrier
@gf: Active Directory objects are an example of coclasses that support enumeration without having Item/Count exposed. I'm not sure they know the count before going to the last element.
wqw
A: 

For a good example of how to implement COM collections that would be used naturally in script programming languages, check out www.prosyslib.org

It offers a comprehensive example of how to do that...

Vitaly