Collections


ICollectionOnSTLImpl

In addition to parameterized implementations of enumeration interfaces, ATL provides parameterized implementations of collection interfaces, assuming that you're willing to keep your data in a standard C++-like container. The implementation is provided by the ICollectionOnSTLImpl class:

template <class T, class CollType, class ItemType,           class CopyItem, class EnumType>          class ICollectionOnSTLImpl : public T {            public:                                              STDMETHOD(get_Count)(long* pcount);                STDMETHOD(get_Item)(long Index, ItemType* pvar);   STDMETHOD(get__NewEnum)(IUnknown** ppUnk);         CollType m_coll;                                 };                                                 


The ICollectionOnSTLImpl class provides an implementation of the three standard collection properties much like what I showed you earlier. The chief difference is that the container is managed for you in the m_coll member data of the ICollectionOnSTLImpl class. That means that you can't provide a copy of the data to the enumerators, but you can still use a collection that calculates on demand and you can still convert from a convenient type to the type required by the enumerator exposed from get__NewEnum. This is because, although you get to decide the type of the container in a template parameter, you're no longer implementing get__NewEnum.

The template parameters of ICollectionOnSTLImpl are as follows:

  • The T parameter indicates the base classFor example, IDispatchImpl-<IPrimeNumbers and &IID_IPrimeNumbers>. ICollectionOnSTLImpl provides the implementation of the standard three properties of this base class, but the deriving class is responsible for the rest.

  • The CollType parameter indicates the type of container to keepfor example, vector<long> or PrimesContainer.

  • The ItemType parameter indicates the type of data exposed from the iterator of the collectionfor example, long.

  • The CopyItem parameter indicates the type of the copy policy class. This copy policy is used only in the implementation of the get_Item method. The copy policy should be capable of copying from a container that holds items of type ItemType to a single [out] parameter of type ItemType. If you were managing a container of long numbers, the CopyItem type would be _Copy<long>.

  • The EnumType parameter indicates the type of the enumeration-implementation class. This enumeration must be capable of enumerating over a container just like CComEnumOnSTL. An example EnumType parameter is CCom-Enum-OnSTLImpl<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _Copy<VARIANT>, vector<VARIANT> >.

ICollectionOnSTLImpl Usage

The best way to understand the ICollectionOnSTLImpl class is to see it in action. The first C++based implementation of the IPrimesCollection standard collection interface assumed that we wanted to manage a precalculated container of VARIANTs. This can be done using ICollectionOnSTLImpl:

// Needed for implementation of get_Item. // Converts the storage type (VARIANT) to the item type (long). struct _CopyLongFromVariant {   static HRESULT copy(long* p1, VARIANT* p2) {     if (p2->vt == VT_I4) {       *p1 = p2->lVal;       return S_OK;     }     else {       VARIANT var;       HRESULT hr = VariantChangeType(&var, p2, 0, VT_I4);       if (SUCCEEDED(hr)) *p1 = var.lVal;       return hr;     }   }   static void init(long* p) { }   static void destroy(long* p) { } }; // Needed for implementation of IDispatch methods typedef IDispatchImpl<IPrimeNumbers, &IID_IPrimeNumbers>   IPrimeNumbersDualImpl; // Needed for implementation of get__NewEnum method typedef CComEnumOnSTL<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT,   _Copy<VARIANT>, vector<VARIANT> > ComEnumVariantOnVector; // Needed for implementation of standard collection methods typedef ICollectionOnSTLImpl<IPrimeNumbersDualImpl,   vector<VARIANT>, long, _CopyLongFromVariant,     CComEnumVariantOnVector>     IPrimeNumbersCollImpl; class ATL_NO_VTABLE CPrimeNumbers :   public CComObjectRootEx<CComSingleThreadModel>,   public CComCoClass<CPrimeNumbers, &CLSID_PrimeNumbers>,   public IPrimeNumbersCollImpl { public: ... // IPrimeNumbers public:   STDMETHODIMP CalcPrimes(long min, long max) {   m_coll.clear();   for (long n = min; n <= max; ++n) {     if (IsPrime(n)) {       VARIANT var = {VT_I4};       var.lVal = n;       m_coll.push_back(var);     }   }   return S_OK;  } }; 


If we wanted to precalculate the prime numbers but keep them as a vector of long numbers, this is how we'd use ICollectionOnSTLImpl:

// Needed for implementation of get__NewEnum. // Converts the storage type (long) to the // enumeration type (VARIANT). struct _CopyVariantFromLong {     static HRESULT copy(VARIANT* p1, long* p2) {     if (p1->vt == VT_I4) {       *p2 = p1->lVal;       return S_OK;     }     else {       VARIANT var;       HRESULT hr = VariantChangeType(&var, p1, 0, VT_I4);       if( SUCCEEDED(hr) ) *p2 = var.lVal;       return hr;     }   }   static void init(VARAINT* p) { ::VariantInit(p); }   static void destroy(VARIANT* p) { ::VariantClear(p); } }; // Needed for implementation of IDispatch methods typedef IDispatchImpl<IPrimeNumbers, &IID_IPrimeNumbers>   IPrimeNumbersDualImpl; // Needed for implementation of get__NewEnum method typedef CComEnumOnSTL<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT,   _CopyLongFromVariant, vector<VARIANT> >   CComEnumVariantOnVectorOfLongs; // Needed for implementation of standard collection methods typedef ICollectionOnSTLImpl<IPrimeNumbersDualImpl,   vector<long>, long, _Copy<long>,   CComEnumVariantOnVectorOfLongs>   IPrimeNumbersCollImpl; class ATL_NO_VTABLE CPrimeNumbers :   public CComObjectRootEx<CComSingleThreadModel>,   public CComCoClass<CPrimeNumbers, &CLSID_PrimeNumbers>,   public IPrimeNumbersCollImpl { public: ... // IPrimeNumbers public:   STDMETHODIMP CalcPrimes(long min, long max) {     m_coll.clear();     for (long n = min; n <= max; ++n) {       if (IsPrime(n)) {         m_coll.push_back(n);       }     }     return S_OK;   } }; 


Finally, if we wanted to have the prime numbers calculated on demand and exposed as long numbers, we'd use ICollectionOnSTLImpl:

// Calculates prime numbers on demand class PrimesContainer; // Needed for implementation of get_Item. // Converts the storage type (VARIANT) to the item type (long). struct _CopyVariantFromLong; // Needed for implementation of IDispatch methods typedef IDispatchImpl<IPrimeNumbers, &IID_IPrimeNumbers>   IPrimeNumbersDualImpl; // Needed for implementation of get__NewEnum method typedef CComEnumOnSTL<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT,   _CopyVariantFromLong, PrimesContainer >   CComEnumVariantOnPrimesContainer; // Needed for implementation of standard collection methods typedef ICollectionOnSTLImpl<IPrimeNumbersDualImpl,   PrimesContainer, long, _Copy<long>,   CComEnumVariantOnPrimesContainer>   IPrimeNumbersCollImpl; class ATL_NO_VTABLE CPrimeNumbers :   public CComObjectRootEx<CComSingleThreadModel>,   public CComCoClass<CPrimeNumbers, &CLSID_PrimeNumbers>,   public IPrimeNumbersCollImpl { public: ... // IPrimeNumbers public:   STDMETHODIMP CalcPrimes(long min, long max)   { m_coll.SetRange(min, max); } }; 


Jim Springfield, the father of ATL, says "ICollectionOnSTLImpl is not for the faint of heart." He's absolutely right. It provides a lot of flexibility, but at the expense of complexity. Still, when you've mastered the complexity, as with any good class library, you can get a lot done with very little code.




ATL Internals. Working with ATL 8
ATL Internals: Working with ATL 8 (2nd Edition)
ISBN: 0321159624
EAN: 2147483647
Year: 2004
Pages: 172

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net