windows-nt/Source/XPSP1/NT/ds/adsi/utils/cenum.cxx
2020-09-26 16:20:57 +08:00

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;
}