// enum_iterator.h: IEnumXxx container to produce STL-compatible iterators ///////////////////////////////////////////////////////////////////////////// // Copyright (c) 1997-1998, Chris Sells // All rights reserved. // // Revisions: // 11/24/98 - Expanded to support operator+=, skip and reset // to map to IEnumXxx::Skip and IEnumXxx::Reset. // 8/03/98 - Revised to use atlcopies.h to leverage shared _Copy<> specializations. // 7/01/98 - Put back ocslen usage and provided defines for ocslen and ocscpy. // #ifdef'd out ocidl related typedefs if ocidl.h not included // (thanks again Justin Rudd). // 6/30/98 - Fixed Component Category typedefs (thanks to Justin Rudd) // Removed need for ocslen for clients not using ATL. // 11/03/97 - Initial release // // NO WARRANTIES ARE EXTENDED. USE AT YOUR OWN RISK. // // To contact the author with suggestions or comments, use csells@sellsbrothers.com. ///////////////////////////////////////////////////////////////////////////// // The following is a list of enumerations interfaces and the cooresponding // client-side STL-like iterator classes: // // IEnumCATEGORYINFO catinfo_iterator // IEnumConnectionPoints connectionpoint_iterator // IEnumConnections connection_iterator // IEnumFORMATETC formatetc_iterator // IEnumGUID guid_iterator // IEnumHLITEM hlitem_iterator // IEnumMoniker mk_iterator // IEnumOleDocumentViews oledocview_iterator // IEnumOleUndoUnits oleundo_iterator // IEnumOLEVERB oleverb_iterator // IEnumSTATDATA statdata_iterator // IEnumSTATPROPSTG statpropstg_iterator // IEnumSTATSTG statstg_iterator // IEnumString olestr_iterator // IEnumUnknown unk_iterator // IEnumVARIANT variant_iterator ///////////////////////////////////////////////////////////////////////////// // Usage: /* void EnumVariants(IEnumVARIANT* pevar) { typedef enum_iterator EVI; for( EVI i = EVI(pevar, 64); i != EVI(); ++i ) { VARIANT& v = *i; // Do something with v } } */ // or using the typedefs for the standard enumerators /* void EnumVariants(IEnumVARIANT* pevar) { for( variant_iterator i = variant_iterator(pevar, 64); i != variant_iterator(); ++i ) { VARIANT& v = *i; // Do something with v } } */ // or using STL algorithms (this is my personal favorite) /* struct DoSomethingWithVariant { void operator()(const VARIANT& v) { // Do something with v } }; void EnumVariants(IEnumVARIANT* pevar) { for_each(enum_variant(pevar, 128), enum_variant(), DoSomethingWithVariant()); } */ ///////////////////////////////////////////////////////////////////////////// #pragma once #include ///////////////////////////////////////////////////////////////////////////// // The following block was copied out of atlconv.h to avoid // requiring a client to use ATL. #ifndef __ATLCONV_H__ #if defined(_UNICODE) inline size_t ocslen(LPCOLESTR x) { return lstrlenW(x); } inline OLECHAR* ocscpy(LPOLESTR dest, LPCOLESTR src) { return lstrcpyW(dest, src); } #else inline size_t ocslen(LPCOLESTR x) { return lstrlenW(x); } //lstrcpyW doesn't work on Win95, so we do this inline OLECHAR* ocscpy(LPOLESTR dest, LPCOLESTR src) {return (LPOLESTR) memcpy(dest, src, (lstrlenW(src)+1)*sizeof(WCHAR));} #endif #endif // __ATLCONV_H__ ///////////////////////////////////////////////////////////////////////////// // The following block was copied out of atlcom.h to avoid // requiring a client not using ATL to provide a _Module. #ifndef __ATLCOM_H__ // This is a part of the Active Template Library. // Copyright (C) 1996-1997 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Active Template Library Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Active Template Library product. #ifndef ATL_NO_NAMESPACE namespace ATL { #endif // These _CopyXXX classes are used with enumerators in order to control // how enumerated items are initialized, copied, and deleted // Default is shallow copy with no special init or cleanup template class _Copy { public: static void copy(T* p1, T* p2) {memcpy(p1, p2, sizeof(T));} static void init(T*) {} static void destroy(T*) {} }; #if _MSC_VER>1020 template<> #endif class _Copy { public: static void copy(VARIANT* p1, VARIANT* p2) {VariantCopy(p1, p2);} static void init(VARIANT* p) {VariantInit(p);} static void destroy(VARIANT* p) {VariantClear(p);} }; #if _MSC_VER>1020 template<> #endif class _Copy { public: static void copy(LPOLESTR* p1, LPOLESTR* p2) { (*p1) = (LPOLESTR)CoTaskMemAlloc(sizeof(OLECHAR)*(ocslen(*p2)+1)); ocscpy(*p1,*p2); } static void init(LPOLESTR* p) {*p = NULL;} static void destroy(LPOLESTR* p) { CoTaskMemFree(*p);} }; #if _MSC_VER>1020 template<> #endif class _Copy { public: static void copy(OLEVERB* p1, OLEVERB* p2) { *p1 = *p2; if (p1->lpszVerbName == NULL) return; p1->lpszVerbName = (LPOLESTR)CoTaskMemAlloc(sizeof(OLECHAR)*(ocslen(p2->lpszVerbName)+1)); ocscpy(p1->lpszVerbName,p2->lpszVerbName); } static void init(OLEVERB* p) { p->lpszVerbName = NULL;} static void destroy(OLEVERB* p) { if (p->lpszVerbName) CoTaskMemFree(p->lpszVerbName);} }; #ifdef __ocidl_h__ #if _MSC_VER>1020 template<> #endif class _Copy { public: static void copy(CONNECTDATA* p1, CONNECTDATA* p2) { *p1 = *p2; if (p1->pUnk) p1->pUnk->AddRef(); } static void init(CONNECTDATA* ) {} static void destroy(CONNECTDATA* p) {if (p->pUnk) p->pUnk->Release();} }; #endif // __ocidl_h__ template class _CopyInterface { public: static void copy(T** p1, T** p2) {*p1 = *p2;if (*p1) (*p1)->AddRef();} static void init(T** ) {} static void destroy(T** p) {if (*p) (*p)->Release();} }; #ifndef ATL_NO_NAMESPACE } #endif #endif // __ATLCOM_H__ #include "atlcopies.h" // More _Copy<> specializations ///////////////////////////////////////////////////////////////////////////// // enum_iterator #ifndef ENUM_CHUNK #define ENUM_CHUNK 64 #endif template > class enum_iterator { public: enum_iterator(IUnknown* punkEnum = 0, ULONG nChunk = ENUM_CHUNK) : m_pRep(0) { if( punkEnum ) { m_pRep = new EnumRep(punkEnum, nChunk); if( m_pRep ) { m_pRep->AddRef(); if( !m_pRep->First() ) { Destroy(); } } } } enum_iterator(const enum_iterator& i) : m_pRep(i.m_pRep) { if( m_pRep ) m_pRep->AddRef(); } ~enum_iterator() { Destroy(); } enum_iterator& operator=(const enum_iterator& rhs) { if( *this != rhs ) { Destroy(); if( m_pRep = rhs.m_pRep ) m_pRep->AddRef(); } return *this; } bool operator!=(const enum_iterator& rhs) { return !(*this == rhs); } bool operator==(const enum_iterator& rhs) { return m_pRep == rhs.m_pRep; } // ++i, i.e. the first half of IEnumXxx::Next ... enum_iterator& operator++() { if( m_pRep && !m_pRep->Next() ) { Destroy(); // We're at the end of the collection } return *this; } // i++, i.e. half of IEnumXxx::Next ... enum_iterator operator++(int) { enum_iterator tmp = *this; ++(*this); // Forward to ++i return tmp; } // ... the other half of IEnumXxx::Next EnumType& operator*() { assert(m_pRep && "Past the end of the enumeration"); return m_pRep->Get(); } enum_iterator& operator+=(size_t n) { if( n ) skip(n-1); return *this; } // IEnumXxx::Skip bool skip(size_t n) { if( m_pRep && !m_pRep->Skip(n) ) { Destroy(); // We're at the end of the collection return false; } return true; } // IEnumXxx::Reset bool reset() { if( m_pRep && !m_pRep->Reset() ) { Destroy(); // Something bad happened... return false; } return true; } private: void Destroy() { if( m_pRep ) m_pRep->Release(); m_pRep = 0; } class EnumRep { public: EnumRep(IUnknown* punkEnum, size_t nChunk) : m_pEnum(0), m_rgEnum(0), m_nChunk(nChunk), m_cRef(0), m_n(0), m_cElems(0) { if( punkEnum ) { punkEnum->QueryInterface(*pIIDEnumItf, (void**)&m_pEnum); if( m_pEnum ) { m_rgEnum = new EnumType[m_nChunk]; if( m_rgEnum ) { InitChunk(); } else { m_pEnum->Release(); m_pEnum = 0; } } } } ~EnumRep() { if( m_rgEnum ) { DestroyChunk(); delete[] m_rgEnum; } if( m_pEnum ) m_pEnum->Release(); } void AddRef() { ++m_cRef; } void Release() { if( !--m_cRef ) delete this; } bool First() { return NextChunk(); } bool Next() { return Skip(0); } bool Skip(size_t nSkip) { if( m_pEnum ) { // Skip in our local cache and IEnumXxx::Skip overflow m_n += (nSkip + 1); if( m_n >= m_cElems ) // We're past the end of this chunk { ULONG celtToSkip = m_n - m_cElems; HRESULT hr = (celtToSkip ? m_pEnum->Skip(celtToSkip) : S_OK); if( FAILED(hr) || // Skipping didn't work so well (hr == S_FALSE) || // Not that many elements to skip m_cElems < m_nChunk || // Last m_pEnum->Next() returned S_FALSE !NextChunk() ) // Last m_pEnum->Next() return S_OK { return false; // We're at the end of the collection } else { m_n = 0; // We're at the beginning of a new chunk } } } return true; } bool Reset() { if( m_pEnum ) { // Ask the enumerator to reset and cache the first chunk if( FAILED(m_pEnum->Reset()) || !First() ) { return false; } } return true; } EnumType& Get() { assert(m_pEnum && "No elements cached"); assert(m_n < m_cElems && "No elements left"); return m_rgEnum[m_n]; } private: EnumItf* m_pEnum; // Pointer to the enumeration interface EnumType* m_rgEnum; // Array of the enumeration data type ULONG m_cElems; // Number of elements we got last time const ULONG m_nChunk; // Number of elements to ask for each time ULONG m_cRef; // References to this EnumRep for efficient copying of enum_iterator ULONG m_n; // Current offset into m_rgEnum array of m_cElems items void InitChunk() { for( EnumType* p = &m_rgEnum[0]; p != &m_rgEnum[m_nChunk]; ++p ) { CopyClass::init(p); } } // Use the CopyClass::destroy but leave data available for next chunk void DestroyChunk() { for( EnumType* p = &m_rgEnum[0]; p < &m_rgEnum[m_cElems]; ++p ) { CopyClass::destroy(p); } m_cElems = 0; } bool NextChunk() { DestroyChunk(); HRESULT hr = (m_pEnum ? m_pEnum->Next(m_nChunk, m_rgEnum, &m_cElems) : E_UNEXPECTED); if( hr == S_OK ) m_cElems = m_nChunk; else if( FAILED(hr) ) m_cElems = 0; // Coerce m_cElems == 0 to a failure // so iterator knows it's stepped off the end if( SUCCEEDED(hr) && m_cElems == 0 ) hr = E_FAIL; return (SUCCEEDED(hr) ? true : false); } }; EnumRep* m_pRep; }; // Typedefs for standard enumerators typedef enum_iterator variant_iterator; typedef enum_iterator > mk_iterator; typedef enum_iterator olestr_iterator; typedef enum_iterator > unk_iterator; typedef enum_iterator statstg_iterator; typedef enum_iterator formatetc_iterator; typedef enum_iterator statdata_iterator; typedef enum_iterator statpropstg_iterator; typedef enum_iterator oleverb_iterator; // TODO: Requires _Copy<> specialization //typedef enum_iterator statpropsetstg_iterator; #ifdef __hlink_h__ typedef enum_iterator hlitem_iterator; #endif // __hlink_h__ #ifdef __ocidl_h__ typedef enum_iterator connection_iterator; typedef enum_iterator > connectionpoint_iterator; typedef enum_iterator > oleundo_iterator; #endif #ifdef __comcat_h__ typedef enum_iterator guid_iterator; typedef guid_iterator clsid_iterator; typedef guid_iterator catid_iterator; typedef enum_iterator catinfo_iterator; #endif // __comcat_h__ #ifdef __docobj_h__ typedef enum_iterator > oledocview_iterator; #endif