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