/*++

Copyright (C) 1995-2001 Microsoft Corporation

Module Name:

    ENUMINST.CPP

Abstract:

	Implements the CEnumInst class which enumerates instances.

History:

	a-davj  19-Oct-95   Created.

--*/

#include "precomp.h"
#include "impdyn.h"

//***************************************************************************
//
//  CCFDyn::CCFDyn
//
//  DESCRIPTION:
//
//  Constructor.
//
//  PARAMETERS:
//
//  pEnumInfo       Object which enumerates the key values
//  lFlags          flags passed to the CreateInstanceEnum call
//  pClass          name of the class
//  pWBEMGateway     pointer to WBEM core
//  pProvider       pointer to provider obect which was asked to create
//                  the enumerator.
//***************************************************************************

CEnumInst::CEnumInst(
            IN CEnumInfo * pEnumInfo,
            IN long lFlags,
            IN WCHAR * pClass, 
            IN IWbemServices FAR* pWBEMGateway,
            IN CImpDyn * pProvider,
            IWbemContext  *pCtx):
            m_iIndex(0), m_pEnumInfo(0),m_pwcClass(0), m_lFlags(0), m_pCtx(0),  m_pWBEMGateway(0), 
            m_pProvider(0), m_cRef(0), m_bstrKeyName(0),  m_PropContextCache()
            
{
    m_pwcClass = new WCHAR[wcslen(pClass)+1];
    if(m_pwcClass == NULL) return;

    wcscpy(m_pwcClass,pClass);
    m_pWBEMGateway = pWBEMGateway;
    m_pWBEMGateway->AddRef();
    m_pProvider = pProvider;
    m_pProvider->AddRef();
    m_lFlags = lFlags;
    m_pEnumInfo = pEnumInfo;
    m_pEnumInfo->AddRef();
    m_pCtx = pCtx;
    if(pCtx) pCtx->AddRef();
    InterlockedIncrement(&lObj);

	// Get the KeyName

	IWbemClassObject * pClassObj = NULL;
    SCODE sc = m_pWBEMGateway->GetObject(pClass,0,m_pCtx,&pClassObj,NULL);
    if(FAILED(sc)) return;
    
	m_bstrKeyName = m_pProvider->GetKeyName(pClassObj);
	pClassObj->Release();
}

//***************************************************************************
//
//  CCFDyn::~CCFDyn
//
//  DESCRIPTION:
//
//  Destructor.
//
//***************************************************************************

CEnumInst::~CEnumInst(void)
{
    if(m_pwcClass)
        delete m_pwcClass;
    if(m_pWBEMGateway != NULL) {
        m_pWBEMGateway->Release();
        m_pProvider->Release();
        m_pEnumInfo->Release();
        InterlockedDecrement(&lObj);
        }
    if(m_pEnumInfo != NULL)
        delete m_pEnumInfo;
    if(m_pCtx)
        m_pCtx->Release();
	if(m_bstrKeyName)
		SysFreeString(m_bstrKeyName);
    return;
}

//***************************************************************************
// HRESULT CEnumInst::QueryInterface
// long CEnumInst::AddRef
// long CEnumInst::Release
//
// DESCRIPTION:
//
// Standard Com IUNKNOWN functions.
//
//***************************************************************************

STDMETHODIMP CEnumInst::QueryInterface(
                IN REFIID riid,
                OUT PPVOID ppv)
{
    *ppv=NULL;

    if ((IID_IUnknown==riid || IID_IEnumWbemClassObject==riid)
                            && m_pWBEMGateway != NULL) 
    {
        *ppv=this;
        AddRef();
        return NOERROR;
    }
    else
        return ResultFromScode(E_NOINTERFACE);
}

STDMETHODIMP_(ULONG) CEnumInst::AddRef(void)
{
    return InterlockedIncrement(&m_cRef);
}

STDMETHODIMP_(ULONG) CEnumInst::Release(void)
{
    long lRet = InterlockedDecrement(&m_cRef);
    if (0L!=lRet)
        return lRet;
    delete this;
    return 0L;
}

//***************************************************************************
//
//  CEnumInst::Reset
//
//  DESCRIPTION:
//
//  Sets pointer back to first element.
//
//  RETURN VALUES:
//
//  S_OK
//
//***************************************************************************

STDMETHODIMP CEnumInst::Reset()
{
    m_iIndex = 0;
    return S_OK;
}

//***************************************************************************
//
//  CEnumInst::Clone
//
//  DESCRIPTION:
//
//  Create a duplicate of the enumerator
//
//  PARAMETERS:
//
//  pEnum       Set to point to duplicate.
//
//  RETURN VALUES:
// 
//  S_OK                    if all is well
//  WBEM_E_OUT_OF_MEMORY     if out of memory
//  WBEM_E_INVALID_PARAMETER if passed a null
//
//***************************************************************************

STDMETHODIMP CEnumInst::Clone(
    OUT IEnumWbemClassObject FAR* FAR* pEnum)
{
    CEnumInst * pEnumObj;
    SCODE sc;
    if(pEnum == NULL)
        return WBEM_E_INVALID_PARAMETER;

    pEnumObj=new CEnumInst(m_pEnumInfo,m_lFlags,m_pwcClass, 
                                m_pWBEMGateway,m_pProvider, m_pCtx);
    if(pEnumObj == NULL)
        return WBEM_E_OUT_OF_MEMORY;
    sc = pEnumObj->QueryInterface(IID_IEnumWbemClassObject,(void **) pEnum);
    if(FAILED(sc))
        delete pEnumObj;
    pEnumObj->m_iIndex = m_iIndex;
    return S_OK;
}


//***************************************************************************
//
//  CEnumInst::Skip
//
//  DESCRIPTION:
//
//  Skips one or more elements in the enumeration.
//
//  PARAMETERS:
//
//  nNum        number of elements to skip
//
//  RETURN VALUES:
//
//  S_OK        if we still are not past the end of the list
//  S_FALSE     if requested skip number would go beyond the end of the list
//
//***************************************************************************

STDMETHODIMP CEnumInst::Skip(long lTimeout,
                IN ULONG nNum)
{
    SCODE sc;;
    int iTest = m_iIndex + nNum;    
    LPWSTR pwcKey;
    sc = m_pProvider->GetKey(m_pEnumInfo,iTest,&pwcKey);
    if(sc == S_OK) {
        delete pwcKey;
        m_iIndex = iTest;
        return S_OK;
        }
    return S_FALSE;
}

//***************************************************************************
//
//  CEnumInst::Next
//
//  DESCRIPTION:
//
//  Returns one or more instances.
//
//  PARAMETERS:
//
//  uCount      Number of instances to return.
//  pObj        Pointer to array of objects.
//  puReturned  Pointer to number of objects successfully returned.
//
//  RETURN VALUES:
//  S_OK if all the request instances are returned.  Note that WBEM_E_FAILED
//  is returned even if there are some instances returned so long as the 
//  number is less than uCount. Also WBEM_E_INVALID_PARAMETER may be
//  return if the arguments are bogus. 
//
//***************************************************************************

STDMETHODIMP CEnumInst::Next(long lTimeout,
                            IN ULONG uCount, 
                            OUT IWbemClassObject FAR* FAR* pObj, 
                            OUT ULONG FAR* puReturned)
{
    ULONG uIndex;
    SCODE sc;
    LPWSTR pwcKey;
    if(pObj == NULL || puReturned == NULL)
        return WBEM_E_INVALID_PARAMETER;
    IWbemClassObject FAR* FAR* pNewInst = pObj;
    *puReturned = 0;
    for(uIndex = 0; uIndex < uCount; ) 
    {
        sc = m_pProvider->GetKey(m_pEnumInfo,m_iIndex,&pwcKey);
        m_iIndex++;
        if(sc != S_OK) 
            break;  // if no more in registry, then we are done
        sc = m_pProvider->CreateInst(m_pWBEMGateway,m_pwcClass,
                                    pwcKey,pNewInst,m_bstrKeyName,
                                    &m_PropContextCache, m_pCtx);
        delete pwcKey;
        if(sc == S_OK)
        {
            uIndex++;
            pNewInst++;
            (*puReturned)++;  // add one to number of objects created
        }
    }
    return (uIndex == uCount) ? S_OK : WBEM_E_FAILED;
}