642 lines
15 KiB
C++
642 lines
15 KiB
C++
|
//+------------------------------------------------------------------------
|
||
|
//
|
||
|
// File: cenum.cxx
|
||
|
//
|
||
|
// Contents: Generic enumerator class.
|
||
|
//
|
||
|
// Classes: CBaseEnum
|
||
|
// CEnumGeneric
|
||
|
// CEnumVARIANT
|
||
|
//
|
||
|
// History: 05-05-93 ChrisZ Added class object caching
|
||
|
// 05-11-93 ChrisZ Cleanup on CF caching
|
||
|
// 02-24-93 LyleC Moved from ADs directory
|
||
|
// 01-Sep-93 DonCl new (NullOnFail)
|
||
|
// 08-Sep-93 LyleC Changed Next() to accept NULL 3rd param
|
||
|
// 15-May-94 adams Added CBaseEnum, CEnumVARIANT
|
||
|
//
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
#include "procs.hxx"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
// Determines whether a variant is a base type.
|
||
|
#define ISBASEVARTYPE(vt) ((vt & ~VT_TYPEMASK) == 0)
|
||
|
|
||
|
//+------------------------------------------------------------------------
|
||
|
//
|
||
|
// CBaseEnum Implementation
|
||
|
//
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CBaseEnum::Init
|
||
|
//
|
||
|
// Synopsis: 2nd stage initialization perADs copy of array if necessary.
|
||
|
//
|
||
|
// Arguments: [pary] -- Array to enumrate.
|
||
|
// [fCopy] -- Copy array?
|
||
|
//
|
||
|
// Returns: HRESULT.
|
||
|
//
|
||
|
// Modifies: [this].
|
||
|
//
|
||
|
// History: 5-15-94 adams Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
CBaseEnum::Init(CADsAry * pary, BOOL fCopy)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
CADsAry * paryCopy = NULL; // copied array
|
||
|
|
||
|
ADsAssert(pary);
|
||
|
|
||
|
// Copy array if necessary.
|
||
|
if (fCopy)
|
||
|
{
|
||
|
paryCopy = new CADsAry;
|
||
|
if (!paryCopy)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
hr = paryCopy->Copy(_cb, *pary, _fAddRef);
|
||
|
if (hr)
|
||
|
goto Error;
|
||
|
|
||
|
pary = paryCopy;
|
||
|
}
|
||
|
|
||
|
_pary = pary;
|
||
|
|
||
|
Cleanup:
|
||
|
RRETURN(hr);
|
||
|
|
||
|
Error:
|
||
|
delete paryCopy;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CBaseEnum::CBaseEnum
|
||
|
//
|
||
|
// Synopsis: Constructor.
|
||
|
//
|
||
|
// Arguments: [iid] -- IID of enumerator interface.
|
||
|
// [fAddRef] -- addref enumerated elements?
|
||
|
// [fDelete] -- delete array on zero enumerators?
|
||
|
//
|
||
|
// Modifies: [this]
|
||
|
//
|
||
|
// History: 5-15-94 adams Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CBaseEnum::CBaseEnum(size_t cb, REFIID iid, BOOL fAddRef, BOOL fDelete)
|
||
|
{
|
||
|
_ulRefs = 1;
|
||
|
|
||
|
_cb = cb;
|
||
|
_pary = NULL;
|
||
|
_piid = &iid;
|
||
|
_i = 0;
|
||
|
_fAddRef = fAddRef;
|
||
|
_fDelete = fDelete;
|
||
|
|
||
|
INC_OBJECT_COUNT();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CBaseEnum::CBaseEnum
|
||
|
//
|
||
|
// Synopsis: Constructor.
|
||
|
//
|
||
|
// History: 5-15-94 adams Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CBaseEnum::CBaseEnum(const CBaseEnum& benum)
|
||
|
{
|
||
|
_ulRefs = 1;
|
||
|
|
||
|
_cb = benum._cb;
|
||
|
_piid = benum._piid;
|
||
|
_pary = benum._pary;
|
||
|
_i = benum._i;
|
||
|
_fAddRef = benum._fAddRef;
|
||
|
_fDelete = benum._fDelete;
|
||
|
|
||
|
INC_OBJECT_COUNT();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CBaseEnum::~CBaseEnum
|
||
|
//
|
||
|
// Synopsis: Destructor.
|
||
|
//
|
||
|
// History: 5-15-94 adams Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CBaseEnum::~CBaseEnum(void)
|
||
|
{
|
||
|
IUnknown ** ppUnk;
|
||
|
int i;
|
||
|
|
||
|
if (_pary && _fDelete)
|
||
|
{
|
||
|
if (_fAddRef)
|
||
|
{
|
||
|
for (i = 0, ppUnk = (IUnknown **) Deref(0);
|
||
|
i < _pary->Size();
|
||
|
i++, ppUnk++)
|
||
|
{
|
||
|
(*ppUnk)->Release();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
delete _pary;
|
||
|
}
|
||
|
|
||
|
DEC_OBJECT_COUNT();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CBaseEnum::QueryInterface
|
||
|
//
|
||
|
// Synopsis: Per IUnknown::QueryInterface.
|
||
|
//
|
||
|
// History: 5-15-94 adams Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CBaseEnum::QueryInterface(REFIID iid, LPVOID * ppv)
|
||
|
{
|
||
|
if (!ppv)
|
||
|
RRETURN(E_INVALIDARG);
|
||
|
|
||
|
if (IsEqualIID(iid, IID_IUnknown) || IsEqualIID(iid, *_piid))
|
||
|
{
|
||
|
AddRef();
|
||
|
*ppv = this;
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
return E_NOTIMPL;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CBaseEnum::Skip
|
||
|
//
|
||
|
// Synopsis: Per IEnum*
|
||
|
//
|
||
|
// History: 5-15-94 adams Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CBaseEnum::Skip(ULONG celt)
|
||
|
{
|
||
|
int c = min((int) celt, _pary->Size() - _i);
|
||
|
_i += c;
|
||
|
|
||
|
return ((c == (int) celt) ? NOERROR : S_FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CBaseEnum::Reset
|
||
|
//
|
||
|
// Synopsis: Per IEnum*
|
||
|
//
|
||
|
// History: 5-15-94 adams Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CBaseEnum::Reset(void)
|
||
|
{
|
||
|
_i = 0;
|
||
|
|
||
|
return NOERROR;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+------------------------------------------------------------------------
|
||
|
//
|
||
|
// CEnumGeneric Implementation
|
||
|
//
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CEnumGeneric::Create
|
||
|
//
|
||
|
// Synopsis: Creates a new CEnumGeneric object.
|
||
|
//
|
||
|
// Arguments: [pary] -- Array to enumerate.
|
||
|
// [iid] -- IID of enumerator interface.
|
||
|
// [fAddRef] -- AddRef enumerated elements?
|
||
|
// [fCopy] -- Copy array enumerated?
|
||
|
// [fDelete] -- Delete array when zero enumerators of array?
|
||
|
// [ppenum] -- Resulting CEnumGeneric object.
|
||
|
//
|
||
|
// Returns: HRESULT.
|
||
|
//
|
||
|
// History: 5-15-94 adams Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
CEnumGeneric::Create(
|
||
|
size_t cb,
|
||
|
CADsAry * pary,
|
||
|
REFIID iid,
|
||
|
BOOL fAddRef,
|
||
|
BOOL fCopy,
|
||
|
BOOL fDelete,
|
||
|
CEnumGeneric ** ppenum)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
CEnumGeneric * penum;
|
||
|
|
||
|
ADsAssert(pary);
|
||
|
ADsAssert(ppenum);
|
||
|
ADsAssert(!fCopy || fDelete);
|
||
|
*ppenum = NULL;
|
||
|
penum = new CEnumGeneric(cb, iid, fAddRef, fDelete);
|
||
|
if (!penum)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
hr = penum->Init(pary, fCopy);
|
||
|
if (hr)
|
||
|
goto Error;
|
||
|
|
||
|
*ppenum = penum;
|
||
|
|
||
|
Cleanup:
|
||
|
RRETURN(hr);
|
||
|
|
||
|
Error:
|
||
|
penum->Release();
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CEnumGeneric
|
||
|
//
|
||
|
// Synopsis: ctor.
|
||
|
//
|
||
|
// Arguments: [iid] -- IID of enumerator interface.
|
||
|
// [fAddRef] -- AddRef enumerated elements?
|
||
|
// [fDelete] -- delete array on zero enumerators?
|
||
|
//
|
||
|
// Modifies: [this].
|
||
|
//
|
||
|
// History: 5-15-94 adams Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CEnumGeneric::CEnumGeneric(size_t cb, REFIID iid, BOOL fAddRef, BOOL fDelete) :
|
||
|
CBaseEnum(cb, iid, fAddRef, fDelete)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CEnumGeneric
|
||
|
//
|
||
|
// Synopsis: ctor.
|
||
|
//
|
||
|
// History: 5-15-94 adams Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CEnumGeneric::CEnumGeneric(const CEnumGeneric& enumg) : CBaseEnum(enumg)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CEnumGeneric::Next
|
||
|
//
|
||
|
// Synopsis: Returns the next celt members in the enumeration. If less
|
||
|
// than celt members remain, then the remaining members are
|
||
|
// returned and S_FALSE is reported. In all cases, the number
|
||
|
// of elements actually returned in placed in *pceltFetched.
|
||
|
//
|
||
|
// Arguments: [celt] Number of elements to fetch
|
||
|
// [reelt] The elements are returned in reelt[]
|
||
|
// [pceltFetched] Number of elements actually fetched
|
||
|
//
|
||
|
// Returns: HRESULT (STDMETHOD)
|
||
|
//
|
||
|
//-------------------------------------------------------------------------
|
||
|
STDMETHODIMP
|
||
|
CEnumGeneric::Next(ULONG celt, void * reelt, ULONG * pceltFetched)
|
||
|
{
|
||
|
int c;
|
||
|
int i;
|
||
|
IUnknown ** ppUnk;
|
||
|
|
||
|
c = min((int) celt, _pary->Size() - _i);
|
||
|
if (c > 0 && !reelt)
|
||
|
RRETURN(E_INVALIDARG);
|
||
|
|
||
|
if (_fAddRef)
|
||
|
{
|
||
|
for (i = 0, ppUnk = (IUnknown **) Deref(_i); i < c; i++, ppUnk++)
|
||
|
{
|
||
|
(*ppUnk)->AddRef();
|
||
|
}
|
||
|
}
|
||
|
memcpy(reelt, (BYTE *) Deref(_i), c * _cb);
|
||
|
if (pceltFetched)
|
||
|
{
|
||
|
*pceltFetched = c;
|
||
|
}
|
||
|
_i += c;
|
||
|
|
||
|
return ((c == (int) celt) ? NOERROR : S_FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CEnumGeneric::Clone
|
||
|
//
|
||
|
// Synopsis: Creates a copy of this enumerator; the copy should have the
|
||
|
// same state as this enumerator.
|
||
|
//
|
||
|
// Arguments: [ppenum] New enumerator is returned in *ppenum
|
||
|
//
|
||
|
// Returns: HRESULT (STDMETHOD)
|
||
|
//
|
||
|
//-------------------------------------------------------------------------
|
||
|
STDMETHODIMP
|
||
|
CEnumGeneric::Clone(CBaseEnum ** ppenum)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (!ppenum)
|
||
|
RRETURN(E_INVALIDARG);
|
||
|
|
||
|
*ppenum = NULL;
|
||
|
hr = _pary->EnumElements(_cb, *_piid, (void **) ppenum, _fAddRef);
|
||
|
if (hr)
|
||
|
RRETURN(hr);
|
||
|
|
||
|
(**(CEnumGeneric **)ppenum)._i = _i;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+------------------------------------------------------------------------
|
||
|
//
|
||
|
// CEnumVARIANT Implementation
|
||
|
//
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CEnumVARIANT::Create
|
||
|
//
|
||
|
// Synopsis: Creates a new CEnumGeneric object.
|
||
|
//
|
||
|
// Arguments: [pary] -- Array to enumerate.
|
||
|
// [vt] -- Type of elements enumerated.
|
||
|
// [fCopy] -- Copy array enumerated?
|
||
|
// [fDelete] -- Delete array when zero enumerators of array?
|
||
|
// [ppenum] -- Resulting CEnumGeneric object.
|
||
|
//
|
||
|
// Returns: HRESULT.
|
||
|
//
|
||
|
// History: 5-15-94 adams Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT
|
||
|
CEnumVARIANT::Create(
|
||
|
size_t cb,
|
||
|
CADsAry * pary,
|
||
|
VARTYPE vt,
|
||
|
BOOL fCopy,
|
||
|
BOOL fDelete,
|
||
|
IEnumVARIANT ** ppenum)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
CEnumVARIANT * penum; // enumerator to return.
|
||
|
|
||
|
ADsAssert(pary);
|
||
|
ADsAssert(ppenum);
|
||
|
ADsAssert(ISBASEVARTYPE(vt));
|
||
|
*ppenum = NULL;
|
||
|
penum = new CEnumVARIANT(cb, vt, fDelete);
|
||
|
if (!*ppenum)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
hr = penum->Init(pary, fCopy);
|
||
|
if (hr)
|
||
|
goto Error;
|
||
|
|
||
|
*ppenum = (IEnumVARIANT *) (void *) penum;
|
||
|
|
||
|
Cleanup:
|
||
|
RRETURN(hr);
|
||
|
|
||
|
Error:
|
||
|
penum->Release();
|
||
|
goto Cleanup;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CEnumVARIANT
|
||
|
//
|
||
|
// Synopsis: ctor.
|
||
|
//
|
||
|
// Arguments: [vt] -- Type of elements enumerated.
|
||
|
// [fDelete] -- delete array on zero enumerators?
|
||
|
//
|
||
|
// Modifies: [this]
|
||
|
//
|
||
|
// History: 5-15-94 adams Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CEnumVARIANT::CEnumVARIANT(size_t cb, VARTYPE vt, BOOL fDelete) :
|
||
|
CBaseEnum(cb, IID_IEnumVARIANT, vt == VT_UNKNOWN || vt == VT_DISPATCH, fDelete)
|
||
|
{
|
||
|
ADsAssert(ISBASEVARTYPE(vt));
|
||
|
_vt = vt;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: CEnumVARIANT
|
||
|
//
|
||
|
// Synopsis: ctor.
|
||
|
//
|
||
|
// History: 5-15-94 adams Created
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
CEnumVARIANT::CEnumVARIANT(const CEnumVARIANT& enumv) : CBaseEnum(enumv)
|
||
|
{
|
||
|
_vt = enumv._vt;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CEnumVARIANT::Next
|
||
|
//
|
||
|
// Synopsis: Returns the next celt members in the enumeration. If less
|
||
|
// than celt members remain, then the remaining members are
|
||
|
// returned and S_FALSE is reported. In all cases, the number
|
||
|
// of elements actually returned in placed in *pceltFetched.
|
||
|
//
|
||
|
// Arguments: [celt] Number of elements to fetch
|
||
|
// [reelt] The elements are returned in reelt[]
|
||
|
// [pceltFetched] Number of elements actually fetched
|
||
|
//
|
||
|
// Returns: HRESULT (STDMETHOD)
|
||
|
//
|
||
|
//-------------------------------------------------------------------------
|
||
|
STDMETHODIMP
|
||
|
CEnumVARIANT::Next(ULONG celt, void * reelt, ULONG * pceltFetched)
|
||
|
{
|
||
|
int c;
|
||
|
int i;
|
||
|
BYTE * pb;
|
||
|
VARIANT * pvar;
|
||
|
|
||
|
c = min((int) celt, _pary->Size() - _i);
|
||
|
if (c > 0 && !reelt)
|
||
|
RRETURN(E_INVALIDARG);
|
||
|
|
||
|
for (i = 0, pb = (BYTE *) Deref(_i), pvar = (VARIANT *) reelt;
|
||
|
i < c;
|
||
|
i++, pb += _cb, pvar++)
|
||
|
{
|
||
|
V_VT(pvar) = _vt;
|
||
|
switch (_vt)
|
||
|
{
|
||
|
case VT_I2:
|
||
|
ADsAssert(sizeof(V_I2(pvar)) == _cb);
|
||
|
V_I2(pvar) = *(short *) pb;
|
||
|
break;
|
||
|
|
||
|
case VT_I4:
|
||
|
ADsAssert(sizeof(V_I4(pvar)) == _cb);
|
||
|
V_I4(pvar) = *(long *) pb;
|
||
|
break;
|
||
|
|
||
|
case VT_BOOL:
|
||
|
ADsAssert(sizeof(V_BOOL(pvar)) == _cb);
|
||
|
V_BOOL(pvar) = (short) -*(int *) pb;
|
||
|
break;
|
||
|
|
||
|
case VT_BSTR:
|
||
|
ADsAssert(sizeof(V_BSTR(pvar)) == _cb);
|
||
|
V_BSTR(pvar) = *(BSTR *) pb;
|
||
|
break;
|
||
|
|
||
|
case VT_UNKNOWN:
|
||
|
case VT_DISPATCH:
|
||
|
ADsAssert(sizeof(V_UNKNOWN(pvar)) == _cb);
|
||
|
V_UNKNOWN(pvar) = *(IUnknown **) pb;
|
||
|
V_UNKNOWN(pvar)->AddRef();
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ADsAssert(0 && "Unknown VARTYPE in IEnumVARIANT::Next");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pceltFetched)
|
||
|
{
|
||
|
*pceltFetched = c;
|
||
|
}
|
||
|
|
||
|
_i += c;
|
||
|
return ((c == (int) celt) ? NOERROR : S_FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//+------------------------------------------------------------------------
|
||
|
//
|
||
|
// Member: CEnumVARIANT::Clone
|
||
|
//
|
||
|
// Synopsis: Creates a copy of this enumerator; the copy should have the
|
||
|
// same state as this enumerator.
|
||
|
//
|
||
|
// Arguments: [ppenum] New enumerator is returned in *ppenum
|
||
|
//
|
||
|
// Returns: HRESULT (STDMETHOD)
|
||
|
//
|
||
|
//-------------------------------------------------------------------------
|
||
|
|
||
|
STDMETHODIMP
|
||
|
CEnumVARIANT::Clone(CBaseEnum ** ppenum)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
if (!ppenum)
|
||
|
RRETURN(E_INVALIDARG);
|
||
|
|
||
|
*ppenum = NULL;
|
||
|
hr = _pary->EnumVARIANT(_cb, _vt, (IEnumVARIANT **)ppenum);
|
||
|
if (hr)
|
||
|
RRETURN(hr);
|
||
|
|
||
|
(**(CEnumVARIANT **)ppenum)._i = _i;
|
||
|
return S_OK;
|
||
|
}
|
||
|
|