Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

472 lines
12 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000
//
// File: enumerator.inl
//
// Contents: Supports enumeration for collections of com objects
//
// History: 08-Mar-2000 AudriusZ Created
//
//--------------------------------------------------------------------------
#ifndef ENUMERATOR_INL_INCLUDED
#define ENUMERATOR_INL_INCLUDED
#pragma once
/*+-------------------------------------------------------------------------*
*
* CMMCNewEnumImpl<BaseClass, _Position, EnumImplementor>::get__NewEnum
*
* PURPOSE: Returns new enumerator for collection
* in the array rgvar
*
* PARAMETERS:
* IUnknown** ppUnk : [out] - new enumerator
*
* RETURNS:
* HRESULT
*
*+-------------------------------------------------------------------------*/
template <class BaseClass, class _Position, class EnumImplementor>
STDMETHODIMP CMMCNewEnumImpl<BaseClass, _Position, EnumImplementor>::get__NewEnum(IUnknown** ppUnk)
{
SC sc;
EnumImplementor *pEnumImpl = NULL; //get enum implementor
// validate the parameter
sc = ScCheckPointers (ppUnk);
if (sc)
return (sc.ToHr());
*ppUnk = NULL;
sc = ScGetEnumImplementor(pEnumImpl);
if(sc)
return (sc.ToHr());
// typedef the enumerator
typedef CComObject<CMMCEnumerator<EnumImplementor, _Position> > CEnumerator;
// create an instance of the enumerator
CEnumerator *pEnum = NULL;
sc = CEnumerator::CreateInstance(&pEnum);
if (sc)
return (sc.ToHr());
if(!pEnum)
return ((sc = E_UNEXPECTED).ToHr());
// create a connection between the enumerator and the tied object.
sc = ScCreateConnection(*pEnum, *pEnumImpl);
if(sc)
return (sc.ToHr());
// initialize the position using the Reset function
sc = pEnumImpl->ScEnumReset(pEnum->m_position);
if(sc)
return (sc.ToHr());
// get the IUnknown from which IEnumVARIANT can be queried
sc = pEnum->QueryInterface (IID_IUnknown, (void**) ppUnk);
if (sc)
return (sc.ToHr());
return (sc.ToHr());
}
/*+-------------------------------------------------------------------------*
*
* CMMCEnumerator<TiedObj,_Position>::Next
*
* PURPOSE: Returns the next celt items starting from the current position
* in the array rgvar
*
* PARAMETERS:
* unsigned long :
* PVARIANT rgvar :
* unsigned long : The number of elements actually fetched
*
* RETURNS:
* STDMETHODIMP
*
*+-------------------------------------------------------------------------*/
template<class TiedObj, class _Position>
STDMETHODIMP CMMCEnumerator<TiedObj,_Position>::Next(unsigned long celt, PVARIANT rgvar,
unsigned long * pceltFetched)
{
DECLARE_SC(sc, TEXT("CMMCEnumerator::Next"));
CMyTiedObject *pTiedObj = NULL;
PVARIANT pVar = rgvar;
unsigned long celtFetched = 0;
_Position posTemp = m_position;
int i = 0;
sc = ScGetTiedObject(pTiedObj);
if(sc)
goto Error;
// initialize the variables.
if(pceltFetched != NULL)
*pceltFetched = 0;
// initialize the array
for(i = 0; i<celt; i++)
VariantInit(&rgvar[i]);
for(celtFetched = 0; celtFetched < celt; celtFetched++, pVar++)
{
// at this point, we have a valid position.
IDispatchPtr spDispatch;
// Get the next element from the tied object.
// The returned IDispatch* _must_ have been AddRef'd for us!
sc = pTiedObj->ScEnumNext(m_position, *(&spDispatch));
if(sc)
goto Error;
if(sc == SC(S_FALSE) )
goto Cleanup; // return just the elements so far.
if(spDispatch == NULL)
{
sc = E_UNEXPECTED;
goto Error;
}
// set the dispatch member of the input array to the interface returned
V_VT (pVar) = VT_DISPATCH;
V_DISPATCH (pVar) = spDispatch.Detach();
}
Cleanup:
// return the count fetched, if the caller wants it
if (pceltFetched != NULL)
*pceltFetched = celtFetched;
return sc.ToHr();
Error:
// clear the array.
for (i=0; i<celt; i++)
VariantClear(&rgvar[i]);
//restore the position and set the count to zero.
m_position = posTemp;
celtFetched = 0;
goto Cleanup;
}
/*+-------------------------------------------------------------------------*
*
* CMMCEnumerator<TiedObj,_Position>::Skip
*
* PURPOSE: Skips over the next celt elements in the enumeration sequence.
*
* PARAMETERS:
* unsigned long :
*
* RETURNS:
* STDMETHODIMP
*
*+-------------------------------------------------------------------------*/
template<class TiedObj, class _Position>
STDMETHODIMP CMMCEnumerator<TiedObj,_Position>::Skip(unsigned long celt)
{
DECLARE_SC(sc, TEXT("CMMCEnumerator::Skip"));
CMyTiedObject *pTiedObj = NULL;
sc = ScGetTiedObject(pTiedObj);
if(sc)
return (sc.ToHr());
/*
* It's too easy for implementers of ScEnumSkip to forget to
* return S_FALSE if the count fetched is less than the count
* requested. We'll take care of that here.
*/
unsigned long celtSkipped = celt + 1;
/*
* It's also easy for implementers of ScEnumNext to forget
* that if the enumeration fails, the position needs to
* remain unaffected.
*/
_Position posT = m_position;
// call the tied object with the position.
sc = pTiedObj->ScEnumSkip(celt, celtSkipped, posT);
if (sc)
return (sc.ToHr());
/*
* success, so update the enumeration position
*/
m_position = posT;
/*
* if this assert fails, the implementation of ScEnumSkip either
* didn't initialize or didn't update celtSkipped
*/
ASSERT (celtSkipped <= celt);
if (celtSkipped < celt)
sc = S_FALSE;
if (celtSkipped > celt)
celtSkipped = celt; // sanity
return sc.ToHr();
}
/*+-------------------------------------------------------------------------*
*
* CMMCEnumerator<TiedObj,_Position>::Reset
*
* PURPOSE: Resets the enumeration sequence to the beginning
*
* RETURNS:
* STDMETHODIMP
*
*+-------------------------------------------------------------------------*/
template<class TiedObj, class _Position>
STDMETHODIMP CMMCEnumerator<TiedObj,_Position>::Reset()
{
DECLARE_SC(sc, TEXT("CMMCEnumerator::Reset"));
CMyTiedObject *pTiedObj = NULL;
sc = ScGetTiedObject(pTiedObj);
if(sc)
return (sc.ToHr());
// call the tied object with the position.
sc = pTiedObj->ScEnumReset(m_position);
return sc.ToHr();
}
/*+-------------------------------------------------------------------------*
*
* CMMCEnumerator<TiedObj,_Position>::Clone
*
* PURPOSE: Creates a copy of the current state of enumeration
*
* PARAMETERS:
* PPENUMVARIANT ppenum :
*
* RETURNS:
* STDMETHODIMP
*
*+-------------------------------------------------------------------------*/
template<class TiedObj, class _Position>
STDMETHODIMP CMMCEnumerator<TiedObj,_Position>::Clone(PPENUMVARIANT ppenum)
{
DECLARE_SC(sc, TEXT("CMMCEnumerator::Clone"));
if(!ppenum)
{
sc = E_INVALIDARG;
return sc.ToHr();
}
CMyTiedObject *pTiedObj = NULL;
sc = ScGetTiedObject(pTiedObj);
if(sc)
return (sc.ToHr());
typedef CComObject<ThisClass> CNewComObject;
CNewComObject *pNewComObj = NULL;
// create an instance of the new enumerator.
sc = CNewComObject::CreateInstance(&pNewComObj);
if (sc)
return (sc.ToHr());
if(!pNewComObj)
return ((sc = E_UNEXPECTED).ToHr());
// at this point the new object has been created.
// Set the position directly from the present state.
pNewComObj->m_position = m_position;
// connect the COM object to the tied object
sc = ScCreateConnection(*pNewComObj, *pTiedObj);
if(sc)
return sc.ToHr();
// addref the new object for the client.
*ppenum = pNewComObj;
(*ppenum)->AddRef();
return sc.ToHr();
}
/***************************************************************************\
*
* CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::get_Count
*
* PURPOSE: Returns count of items in the collection
*
* RETURNS:
* HRESULT
*
\***************************************************************************/
template <class _CollectionInterface, class _ItemInterface>
STDMETHODIMP CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::get_Count( PLONG pCount )
{
DECLARE_SC(sc, TEXT("CMMCArrayEnumBase::get_Count"));
// parameter check
sc = ScCheckPointers(pCount);
if (sc)
return sc.ToHr();
// return the count
*pCount = m_array.size();
return sc.ToHr();
}
/***************************************************************************\
*
* CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::Item
*
* PURPOSE: Returns specified item from collection
*
* RETURNS:
* HRESULT
*
\***************************************************************************/
template <class _CollectionInterface, class _ItemInterface>
STDMETHODIMP CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::Item( long Index, _ItemInterface ** ppItem )
{
DECLARE_SC(sc, TEXT("CMMCArrayEnumBase::Item"));
// parameter check
sc = ScCheckPointers(ppItem);
if (sc)
return sc.ToHr();
// initialization
*ppItem = NULL;
// remember - we are 1 based!
if (Index < 1 || Index > m_array.size())
return (sc = E_INVALIDARG).ToHr();
*ppItem = m_array[Index - 1];
// recheck the pointer
sc = ScCheckPointers(*ppItem, E_NOINTERFACE);
if (sc)
return sc.ToHr();
(*ppItem)->AddRef();
return sc.ToHr();
}
/***************************************************************************\
*
* CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::ScEnumReset
*
* PURPOSE: Resets position to the first item in the collection
*
* RETURNS:
* HRESULT
*
\***************************************************************************/
template <class _CollectionInterface, class _ItemInterface>
::SC CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::ScEnumReset (unsigned &pos)
{
DECLARE_SC(sc, TEXT("CMMCArrayEnumBase::ScEnumReset"));
pos = 0;
return sc;
}
/***************************************************************************\
*
* CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::ScEnumNext
*
* PURPOSE: Returns item from the collection, advances position
*
* RETURNS:
* HRESULT
*
\***************************************************************************/
template <class _CollectionInterface, class _ItemInterface>
::SC CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::ScEnumNext(unsigned &pos, PDISPATCH & pDispatch)
{
DECLARE_SC(sc, TEXT("CMMCArrayEnumBase::ScEnumNext"));
// initialize;
pDispatch = NULL;
// check the ranges
if (pos >= m_array.size())
return sc = S_FALSE;
// get element
pDispatch = m_array[pos];
// recheck the pointer
sc = ScCheckPointers(pDispatch, E_NOINTERFACE);
if (sc)
return sc;
pDispatch->AddRef();
++pos;
return sc;
}
/***************************************************************************\
*
* CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::ScEnumSkip
*
* PURPOSE: Skips the amount of items in enumeration
*
* RETURNS:
* HRESULT
*
\***************************************************************************/
template <class _CollectionInterface, class _ItemInterface>
::SC CMMCArrayEnumBase<_CollectionInterface, _ItemInterface>::ScEnumSkip (unsigned long celt, unsigned long& celtSkipped, unsigned &pos)
{
DECLARE_SC(sc, TEXT("CMMCArrayEnumBase::ScEnumSkip"));
// no skipped at start
celtSkipped = 0;
// check if it's a void task
if (!celt)
return sc;
// are we behind the last item?
if (pos >= m_array.size())
return sc = S_FALSE;
// how far can we go?
celtSkipped = m_array.size() - pos;
// but go no more than requested
if (celtSkipped > celt)
celtSkipped = celt;
// advance
pos += celtSkipped;
// check if we could do as much as requested
if (celtSkipped < celt)
return sc = S_FALSE;
return sc;
}
#endif // ENUMERATOR_INL_INCLUDED