ENUMVAR.CPP

/************************************************************************* 
**
** This is a part of the Microsoft Source Code Samples.
**
** Copyright 1992 - 1998 Microsoft Corporation. All rights reserved.
**
** This source code is only intended as a supplement to Microsoft Development
** Tools and/or WinHelp documentation. See these sources for detailed
** information regarding the Microsoft samples programs.
**
** OLE Automation Lines Object.
**
** enumvar.cpp
**
** CEnumVariant implementation
**
** Written by Microsoft Product Support Services, Windows Developer Support
**
*************************************************************************/

#include <windows.h>
#include <windowsx.h>
#ifdef WIN16
#include <ole2.h>
#include <compobj.h>
#include <dispatch.h>
#include <variant.h>
#include <olenls.h>
#endif
#include "lines.h"

/*
* CEnumVariant::Create
*
* Purpose:
* Creates an instance of the IEnumVARIANT enumerator object and initializes it.
*
* Parameters:
* psa Safe array containing items to be enumerated.
* cElements Number of items to be enumerated.
* ppenumvariant Returns enumerator object.
*
* Return Value:
* HRESULT
*
*/
HRESULT
CEnumVariant::Create(SAFEARRAY FAR* psa, ULONG cElements, CEnumVariant FAR* FAR* ppenumvariant)
{
HRESULT hr;
CEnumVariant FAR* penumvariant = NULL;
long lLBound;

*ppenumvariant = NULL;

penumvariant = new CEnumVariant();
if (penumvariant == NULL)
goto error;

penumvariant->m_cRef = 0;

// Copy elements into safe array that is used in enumerator implemenatation and
// initialize state of enumerator.
hr = SafeArrayGetLBound(psa, 1, &lLBound);
if (FAILED(hr))
goto error;
penumvariant->m_cElements = cElements;
penumvariant->m_lLBound = lLBound;
penumvariant->m_lCurrent = lLBound;
hr = SafeArrayCopy(psa, &penumvariant->m_psa);
if (FAILED(hr))
goto error;

*ppenumvariant = penumvariant;
return NOERROR;

error:
if (penumvariant == NULL)
return E_OUTOFMEMORY;

if (penumvariant->m_psa)
SafeArrayDestroy(penumvariant->m_psa);
penumvariant->m_psa = NULL;
delete penumvariant;
return hr;
}

/*
* CEnumVariant::CEnumVariant
*
* Purpose:
* Constructor for CEnumVariant object. Initializes members to NULL.
*
*/
CEnumVariant::CEnumVariant()
{
m_psa = NULL;
}

/*
* CEnumVariant::~CEnumVariant
*
* Purpose:
* Destructor for CEnumVariant object.
*
*/
CEnumVariant::~CEnumVariant()
{
if (m_psa) SafeArrayDestroy(m_psa);
}

/*
* CEnumVariant::QueryInterface, AddRef, Release
*
* Purpose:
* Implements IUnknown::QueryInterface, AddRef, Release
*
*/
STDMETHODIMP
CEnumVariant::QueryInterface(REFIID iid, void FAR* FAR* ppv)
{
*ppv = NULL;

if (iid == IID_IUnknown || iid == IID_IEnumVARIANT)
*ppv = this;
else return E_NOINTERFACE;

AddRef();
return NOERROR;
}


STDMETHODIMP_(ULONG)
CEnumVariant::AddRef(void)
{

#ifdef _DEBUG
TCHAR ach[50];
wsprintf(ach, TEXT("Ref = %ld, Enum\r\n"), m_cRef+1);
OutputDebugString(ach);
#endif

return ++m_cRef; // AddRef Application Object if enumerator will outlive application object
}


STDMETHODIMP_(ULONG)
CEnumVariant::Release(void)
{

#ifdef _DEBUG
TCHAR ach[50];
wsprintf(ach, TEXT("Ref = %ld, Enum\r\n"), m_cRef-1);
OutputDebugString(ach);
#endif

if(--m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}

/*
* CEnumVariant::Next
*
* Purpose:
* Retrieves the next cElements elements. Implements IEnumVARIANT::Next.
*
*/
STDMETHODIMP
CEnumVariant::Next(ULONG cElements, VARIANT FAR* pvar, ULONG FAR* pcElementFetched)
{
HRESULT hr;
ULONG l;
long l1;
ULONG l2;

if (pcElementFetched != NULL)
*pcElementFetched = 0;

// Retrieve the next cElements elements.
for (l1=m_lCurrent, l2=0; l1<(long)(m_lLBound+m_cElements) && l2<cElements; l1++, l2++)
{
hr = SafeArrayGetElement(m_psa, &l1, &pvar[l2]);
if (FAILED(hr))
goto error;
}
// Set count of elements retrieved
if (pcElementFetched != NULL)
*pcElementFetched = l2;
m_lCurrent = l1;

return (l2 < cElements) ? S_FALSE : NOERROR;

error:
for (l=0; l<cElements; l++)
VariantClear(&pvar[l]);
return hr;
}

/*
* CEnumVariant::Skip
*
* Purpose:
* Skips the next cElements elements. Implements IEnumVARIANT::Skip.
*
*/
STDMETHODIMP
CEnumVariant::Skip(ULONG cElements)
{
m_lCurrent += cElements;
if (m_lCurrent > (long)(m_lLBound+m_cElements))
{
m_lCurrent = m_lLBound+m_cElements;
return S_FALSE;
}
else return NOERROR;
}

/*
* CEnumVariant::Reset
*
* Purpose:
* Resets the current element in the enumerator to the beginning. Implements IEnumVARIANT::Reset.
*
*/
STDMETHODIMP
CEnumVariant::Reset()
{
m_lCurrent = m_lLBound;
return NOERROR;
}

/*
* CEnumVariant::Clone
*
* Purpose:
* Creates a copy of the current enumeration state. Implements IEnumVARIANT::Clone.
*
*/
STDMETHODIMP
CEnumVariant::Clone(IEnumVARIANT FAR* FAR* ppenum)
{
CEnumVariant FAR* penum = NULL;
HRESULT hr;

*ppenum = NULL;

hr = CEnumVariant::Create(m_psa, m_cElements, &penum);
if (FAILED(hr))
goto error;
penum->AddRef();
penum->m_lCurrent = m_lCurrent;

*ppenum = penum;
return NOERROR;

error:
if (penum)
penum->Release();
return hr;
}