📄 enum_iterator.h
字号:
// enum_iterator.h: IEnumXxx container to produce STL-compatible iterators
/////////////////////////////////////////////////////////////////////////////
// Copyright (c) 1997-1998, Chris Sells
// All rights reserved.
//
// Revisions:
// 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<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT> 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 <assert.h>
/////////////////////////////////////////////////////////////////////////////
// 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 T>
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<VARIANT>
{
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<LPOLESTR>
{
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<OLEVERB>
{
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<CONNECTDATA>
{
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 T>
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 <typename EnumItf, const IID* pIIDEnumItf,
typename EnumType, typename CopyClass = _Copy<EnumType> >
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
enum_iterator& operator++()
{
if( m_pRep && !m_pRep->Next() )
{
Destroy(); // We're at the end of the collection
}
return *this;
}
// i++
enum_iterator operator++(int)
{
enum_iterator tmp = *this;
++(*this); // Forward to ++i
return tmp;
}
EnumType& operator*()
{
assert(m_pRep && "Past the end of the enumeration");
return m_pRep->Get();
}
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()
{
if( ++m_n >= m_cElems ) // We're at the end of this chunk
{
if( 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;
}
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;
EnumType* m_rgEnum;
ULONG m_cElems;
const ULONG m_nChunk;
ULONG m_cRef;
ULONG m_n;
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<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT> variant_iterator;
typedef enum_iterator<IEnumMoniker, &IID_IEnumMoniker, IMoniker*, _CopyInterface<IMoniker> > mk_iterator;
typedef enum_iterator<IEnumString, &IID_IEnumString, LPOLESTR> olestr_iterator;
typedef enum_iterator<IEnumUnknown, &IID_IEnumUnknown, IUnknown*, _CopyInterface<IUnknown> > unk_iterator;
typedef enum_iterator<IEnumSTATSTG, &IID_IEnumSTATSTG, STATSTG> statstg_iterator;
typedef enum_iterator<IEnumFORMATETC, &IID_IEnumFORMATETC, FORMATETC> formatetc_iterator;
typedef enum_iterator<IEnumSTATDATA, &IID_IEnumSTATDATA, STATDATA> statdata_iterator;
typedef enum_iterator<IEnumSTATPROPSTG, &IID_IEnumSTATPROPSTG, STATPROPSTG> statpropstg_iterator;
typedef enum_iterator<IEnumOLEVERB, &IID_IEnumOLEVERB, OLEVERB> oleverb_iterator;
// TODO: Requires _Copy<> specialization
//typedef enum_iterator<IEnumSTATPROPSETSTG, &IID_IEnumSTATPROPSETSTG, STATPROPSETSTG> statpropsetstg_iterator;
#ifdef __hlink_h__
typedef enum_iterator<IEnumHLITEM, &IID_IEnumHLITEM, HLITEM> hlitem_iterator;
#endif // __hlink_h__
#ifdef __ocidl_h__
typedef enum_iterator<IEnumConnections, &IID_IEnumConnections, CONNECTDATA> connection_iterator;
typedef enum_iterator<IEnumConnectionPoints, &IID_IEnumConnectionPoints, IConnectionPoint*, _CopyInterface<IConnectionPoint> > connectionpoint_iterator;
typedef enum_iterator<IEnumOleUndoUnits, &IID_IEnumOleUndoUnits, IOleUndoUnit*, _CopyInterface<IOleUndoUnit> > oleundo_iterator;
#endif
#ifdef __comcat_h__
typedef enum_iterator<IEnumGUID, &IID_IEnumGUID, GUID> guid_iterator;
typedef guid_iterator clsid_iterator;
typedef guid_iterator catid_iterator;
typedef enum_iterator<IEnumCATEGORYINFO, &IID_IEnumCATEGORYINFO, CATEGORYINFO> catinfo_iterator;
#endif // __comcat_h__
#ifdef __docobj_h__
typedef enum_iterator<IEnumOleDocumentViews, &IID_IEnumOleDocumentViews, IOleDocumentView*, _CopyInterface<IOleDocumentView> > oledocview_iterator;
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -