[ object, uuid(B6175081-83D4-11D2-987D-00600823CFFB), dual, helpstring("ICollectionBuffer Interface"), pointer_default(unique) ] interface ICollectionBuffer : IDispatch { [propget, helpstring("property Collection")] HRESULT Collection([out, retval] IDispatch** pVal); [propput, helpstring("property Collection")] HRESULT Collection([in] IDispatch* newVal); [propget, helpstring("property BufferSize")] HRESULT BufferSize([out, retval] long *pVal); [propput, helpstring("property BufferSize")] HRESULT BufferSize([in] long newVal); [propget, id(DISPID_NEWENUM)] HRESULT _NewEnum([out, retval] IUnknown** ppunkEnum); };The Collection property is used to pass in the collection object to which you'd like buffered access. The BufferSize property is used to control how many VARIANTs you'd like to have returned on each call to Next. The implementation of _NewEnum gets the IEnumVARIANT interface from the collection and wraps it in a buffered implementation of IEnumVARIANT called SmartEnumVARIANT.
The SmartEnumVARIANT object manages buffered access to the underlying IEnumVARIANT. VB can still ask for one item at a time, but the items will come out of the buffer. Depending on the buffer size, this can improve performance by many order of magnitude.
Dim coll As Object Set coll = CreateObject("DumbEnumSvr.CollectionOfNumbers") coll.CountOfNumbers = 10000 Dim v As Variant Dim c As Long For Each v In coll c = c + 1 Next v MsgBox "Counted " & cThis VB code wraps the unbuffered collection in the CollectionBuffer object:
Dim collBuffer As Object Set collBuffer = CreateObject("SmartEnumSvr.CollectionBuffer") collBuffer.Collection = coll collBuffer.BufferSize = 1024 c = 0 For Each v In collBuffer c = c + 1 Next v MsgBox "Counted " & c
The handler marshaling works like this:
For the handler marshaling to work, the server-side enumerator must implement IMarshal appropriately. In UseSmartEnum.h, I've provided an implementation of IMarshal for this purpose:
template <typename Deriving, ULONG celtBuffer = 1024> class IMarshalForSmartEnumImpl : public IMarshal {...};For example, the CollectionOfNumbers2 example class uses IMarshalForSmartEnumImpl to add IMarshal to CComEnum like so:
typedef CComEnum< IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _Copy<VARIANT> > CComEnumVariant; class CSmartProxiedEnumVARIANT : public CComEnumVariant, public IMarshalForSmartEnumImpl<CSmartProxiedEnumVARIANT, 1024> { public: BEGIN_COM_MAP(CSmartProxiedEnumVARIANT) COM_INTERFACE_ENTRY(IMarshal) COM_INTERFACE_ENTRY_CHAIN(CComEnumVariant) END_COM_MAP() };
Chris Sells
Windows Object Architecture
csells@sellsbrothers.com