1218 lines
27 KiB
C
1218 lines
27 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1997-1999 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
enum.h
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Template classes for enumerations in TAPI3
|
||
|
|
||
|
Author:
|
||
|
|
||
|
mquinton 06-12-97
|
||
|
|
||
|
Notes:
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#ifndef __ENUM_H_
|
||
|
#define __ENUM_H_
|
||
|
|
||
|
#include "resource.h" // main symbols
|
||
|
|
||
|
#include <mspenum.h> // for CSafeComEnum
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
// CTapiEnum
|
||
|
// Template class for enumerations in TAPI3.
|
||
|
//////////////////////////////////////////////////////////////////////
|
||
|
template <class Base, class T, const IID* piid> class CTapiEnum :
|
||
|
public Base,
|
||
|
public CTAPIComObjectRoot<Base>
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
typedef CTapiEnum<Base, T, piid> _CTapiEnumBase;
|
||
|
|
||
|
DECLARE_MARSHALQI(CTapiEnum)
|
||
|
DECLARE_TRACELOG_CLASS(CTapiEnum)
|
||
|
|
||
|
BEGIN_COM_MAP(_CTapiEnumBase)
|
||
|
COM_INTERFACE_ENTRY_IID(*piid, _CTapiEnumBase)
|
||
|
COM_INTERFACE_ENTRY_FUNC(IID_IMarshal, 0, IMarshalQI)
|
||
|
COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pFTM)
|
||
|
END_COM_MAP()
|
||
|
|
||
|
protected:
|
||
|
|
||
|
CTObjectArray<T*> m_Array;
|
||
|
int m_iCurrentLocation;
|
||
|
|
||
|
public:
|
||
|
|
||
|
// initialize the enumerator with a list<T*>
|
||
|
HRESULT Initialize(
|
||
|
CTObjectArray<T*> array
|
||
|
)
|
||
|
{
|
||
|
int iSize, iCount;
|
||
|
|
||
|
iSize = array.GetSize();
|
||
|
|
||
|
for( iCount = 0; iCount < iSize; iCount++ )
|
||
|
{
|
||
|
m_Array.Add(array[iCount]);
|
||
|
}
|
||
|
|
||
|
m_iCurrentLocation = 0;
|
||
|
|
||
|
this->AddRef();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// overloaded
|
||
|
HRESULT Initialize(
|
||
|
CTArray<T*> array
|
||
|
)
|
||
|
{
|
||
|
int iSize, iCount;
|
||
|
|
||
|
iSize = array.GetSize();
|
||
|
|
||
|
for( iCount = 0; iCount < iSize; iCount++ )
|
||
|
{
|
||
|
m_Array.Add(array[iCount]);
|
||
|
}
|
||
|
|
||
|
m_iCurrentLocation = 0;
|
||
|
|
||
|
this->AddRef();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// Overloaded function, used with Add to build enum list manually
|
||
|
HRESULT Initialize( )
|
||
|
{
|
||
|
m_iCurrentLocation = 0;
|
||
|
|
||
|
this->AddRef();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// Add - used with non-parameterized initialize() to build enum list manually
|
||
|
HRESULT Add( T* t)
|
||
|
{
|
||
|
m_Array.Add( t );
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
// FinalRelease - release the objects that were addreffed in
|
||
|
// initialize
|
||
|
void FinalRelease()
|
||
|
{
|
||
|
m_Array.Shutdown();
|
||
|
}
|
||
|
|
||
|
|
||
|
// standard Next method
|
||
|
HRESULT STDMETHODCALLTYPE Next(
|
||
|
ULONG celt,
|
||
|
T ** ppElements,
|
||
|
ULONG* pceltFetched
|
||
|
)
|
||
|
{
|
||
|
DWORD dwCount = 0;
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
if ((NULL == ppElements) || (NULL == pceltFetched && celt > 1))
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
// special case
|
||
|
if (celt == 0)
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
if (TAPIIsBadWritePtr( ppElements, celt * sizeof(T*)) )
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
if ( ( NULL != pceltFetched) &&
|
||
|
TAPIIsBadWritePtr( pceltFetched, sizeof (ULONG) ) )
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
// iterator over elements
|
||
|
while ((m_iCurrentLocation != m_Array.GetSize()) && (dwCount < celt))
|
||
|
{
|
||
|
ppElements[dwCount] = m_Array[m_iCurrentLocation];
|
||
|
|
||
|
ppElements[dwCount]->AddRef();
|
||
|
|
||
|
m_iCurrentLocation++;
|
||
|
|
||
|
dwCount++;
|
||
|
}
|
||
|
|
||
|
if (NULL != pceltFetched)
|
||
|
{
|
||
|
*pceltFetched = dwCount;
|
||
|
}
|
||
|
|
||
|
// indicate that we've reached the end
|
||
|
// of the enumeration.
|
||
|
if (dwCount < celt)
|
||
|
{
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// standard Reset method
|
||
|
HRESULT STDMETHODCALLTYPE Reset( void )
|
||
|
{
|
||
|
m_iCurrentLocation = 0;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
|
||
|
// standard Skip method
|
||
|
HRESULT STDMETHODCALLTYPE Skip(
|
||
|
ULONG celt
|
||
|
)
|
||
|
{
|
||
|
long lCount = 0;
|
||
|
|
||
|
while ( (lCount < celt) && (m_iCurrentLocation < m_Array.GetSize() ) )
|
||
|
{
|
||
|
m_iCurrentLocation++;
|
||
|
lCount++;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// standard Clone method
|
||
|
HRESULT STDMETHODCALLTYPE Clone(
|
||
|
Base ** ppEnum
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
CComObject< _CTapiEnumBase > * pNewEnum;
|
||
|
|
||
|
if (TAPIIsBadWritePtr( ppEnum, sizeof (Base *) ) )
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
CComObject< _CTapiEnumBase >::CreateInstance(&pNewEnum);
|
||
|
if (pNewEnum == NULL)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pNewEnum->Initialize(m_Array);
|
||
|
|
||
|
pNewEnum->m_iCurrentLocation = m_iCurrentLocation;
|
||
|
|
||
|
*ppEnum = pNewEnum;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// CTapiCollection
|
||
|
// Collection template for TAPI3.0 collections
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
template <class T> class CTapiCollection :
|
||
|
public CComDualImpl<ITCollection2, &IID_ITCollection2, &LIBID_TAPI3Lib>,
|
||
|
public CTAPIComObjectRoot<T>,
|
||
|
public CObjectSafeImpl
|
||
|
{
|
||
|
public:
|
||
|
typedef CTapiCollection<T> _CTapiCollectionBase;
|
||
|
|
||
|
DECLARE_MARSHALQI(CTapiCollection)
|
||
|
DECLARE_TRACELOG_CLASS(CTapiCollection)
|
||
|
|
||
|
BEGIN_COM_MAP(_CTapiCollectionBase)
|
||
|
COM_INTERFACE_ENTRY(IDispatch)
|
||
|
COM_INTERFACE_ENTRY(ITCollection)
|
||
|
COM_INTERFACE_ENTRY(ITCollection2)
|
||
|
COM_INTERFACE_ENTRY(IObjectSafety)
|
||
|
COM_INTERFACE_ENTRY_FUNC(IID_IMarshal, 0, IMarshalQI)
|
||
|
COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pFTM)
|
||
|
END_COM_MAP()
|
||
|
|
||
|
private:
|
||
|
|
||
|
int m_nSize;
|
||
|
CComVariant * m_Var;
|
||
|
|
||
|
public:
|
||
|
|
||
|
CTapiCollection() : m_nSize(0),
|
||
|
m_Var(NULL)
|
||
|
{}
|
||
|
|
||
|
|
||
|
// initialize
|
||
|
HRESULT STDMETHODCALLTYPE Initialize(
|
||
|
CTObjectArray<T *> array
|
||
|
)
|
||
|
{
|
||
|
int i;
|
||
|
HRESULT hr;
|
||
|
|
||
|
LOG((TL_TRACE, "Initialize - enter"));
|
||
|
|
||
|
// create variant array
|
||
|
m_nSize = array.GetSize();
|
||
|
|
||
|
m_Var = new CComVariant[m_nSize];
|
||
|
|
||
|
if (m_Var == NULL)
|
||
|
{
|
||
|
LOG((TL_ERROR, "Initialize - out of memory"));
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < array.GetSize(); i++)
|
||
|
{
|
||
|
// get IDispatch pointer
|
||
|
IDispatch * pDisp = NULL;
|
||
|
|
||
|
hr = array[i]->QueryInterface(IID_IDispatch, (void**)&pDisp);
|
||
|
|
||
|
if (S_OK != hr)
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// create a variant and add it to the collection
|
||
|
CComVariant& var = m_Var[i];
|
||
|
|
||
|
VariantInit(&var);
|
||
|
|
||
|
var.vt = VT_DISPATCH;
|
||
|
var.pdispVal = pDisp;
|
||
|
}
|
||
|
|
||
|
LOG((TL_TRACE, "Initialize - exit"));
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// initialize
|
||
|
HRESULT STDMETHODCALLTYPE Initialize(
|
||
|
CTArray<T *> array
|
||
|
)
|
||
|
{
|
||
|
int i;
|
||
|
HRESULT hr;
|
||
|
|
||
|
LOG((TL_TRACE, "Initialize - enter"));
|
||
|
|
||
|
// create variant array
|
||
|
m_nSize = array.GetSize();
|
||
|
|
||
|
m_Var = new CComVariant[m_nSize];
|
||
|
|
||
|
if (m_Var == NULL)
|
||
|
{
|
||
|
LOG((TL_ERROR, "Initialize - out of memory"));
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < array.GetSize(); i++)
|
||
|
{
|
||
|
// get IDispatch pointer
|
||
|
IDispatch * pDisp = NULL;
|
||
|
|
||
|
hr = array[i]->QueryInterface(IID_IDispatch, (void**)&pDisp);
|
||
|
|
||
|
if (S_OK != hr)
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// create a variant and add it to the collection
|
||
|
CComVariant& var = m_Var[i];
|
||
|
|
||
|
VariantInit(&var);
|
||
|
|
||
|
var.vt = VT_DISPATCH;
|
||
|
var.pdispVal = pDisp;
|
||
|
}
|
||
|
|
||
|
LOG((TL_TRACE, "Initialize - exit"));
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
void FinalRelease()
|
||
|
{
|
||
|
//
|
||
|
// We "new"ed an array of objects -- delete the array and call
|
||
|
// each object's destructor. Each destructor calls VariantClear,
|
||
|
// which calls Release on each pointer.
|
||
|
//
|
||
|
|
||
|
if(m_Var != NULL)
|
||
|
{
|
||
|
delete [] m_Var;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
STDMETHOD(get_Count)(
|
||
|
long* retval
|
||
|
)
|
||
|
{
|
||
|
LOG((TL_TRACE, "get_Count - enter"));
|
||
|
|
||
|
if ( TAPIIsBadWritePtr( retval, sizeof(long) ) )
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
*retval = m_nSize;
|
||
|
|
||
|
LOG((TL_TRACE, "get_Count - exit"));
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHOD(get_Item)(
|
||
|
long Index,
|
||
|
VARIANT* retval
|
||
|
)
|
||
|
{
|
||
|
LOG((TL_TRACE, "get_Item - enter"));
|
||
|
|
||
|
if ( TAPIIsBadWritePtr (retval, sizeof(VARIANT) ) )
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
VariantInit(retval);
|
||
|
|
||
|
retval->vt = VT_UNKNOWN;
|
||
|
retval->punkVal = NULL;
|
||
|
|
||
|
// use 1-based index, VB like
|
||
|
if ((Index < 1) || (Index > m_nSize))
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
VariantCopy(retval, &m_Var[Index-1]);
|
||
|
|
||
|
LOG((TL_TRACE, "get_Item - exit"));
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE get__NewEnum(
|
||
|
IUnknown** retval
|
||
|
)
|
||
|
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
LOG((TL_TRACE, "new__Enum - enter"));
|
||
|
|
||
|
if ( TAPIIsBadWritePtr( retval, sizeof( IUnknown * ) ) )
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
*retval = NULL;
|
||
|
|
||
|
typedef CComObject<CSafeComEnum<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _Copy<VARIANT> > > enumvar;
|
||
|
|
||
|
enumvar* p; // = new enumvar;
|
||
|
enumvar::CreateInstance( &p );
|
||
|
|
||
|
_ASSERTE(p);
|
||
|
|
||
|
if (p == NULL)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
hr = p->Init(&m_Var[0], &m_Var[m_nSize], NULL, AtlFlagCopy);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = p->QueryInterface(IID_IEnumVARIANT, (void**)retval);
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
delete p;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
LOG((TL_TRACE, "new__Enum - exit"));
|
||
|
|
||
|
return hr;
|
||
|
|
||
|
}
|
||
|
|
||
|
STDMETHOD(Add)(
|
||
|
long Index,
|
||
|
VARIANT* pVariant
|
||
|
)
|
||
|
{
|
||
|
LOG((TL_TRACE, "Add - enter"));
|
||
|
|
||
|
if ( IsBadReadPtr (pVariant, sizeof(VARIANT) ) )
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
// use 1-based index, VB like
|
||
|
if ( (Index < 1) || (Index > (m_nSize + 1)) )
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
CComVariant * newVar = NULL;
|
||
|
|
||
|
newVar = new CComVariant[m_nSize + 1];
|
||
|
|
||
|
if ( NULL == newVar )
|
||
|
{
|
||
|
LOG((TL_ERROR, "Add - out of memory"));
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
HRESULT hr;
|
||
|
int i;
|
||
|
|
||
|
// fill in the new array
|
||
|
for ( i = 0; i < (m_nSize + 1); i++ )
|
||
|
{
|
||
|
VariantInit(&newVar[i]);
|
||
|
|
||
|
if ( i < (Index - 1) )
|
||
|
{
|
||
|
// shouldn't reach this case unless there was an old array
|
||
|
_ASSERTE(m_Var != NULL);
|
||
|
|
||
|
hr = VariantCopy(&newVar[i], &m_Var[i]);
|
||
|
}
|
||
|
else if ( i == (Index - 1) )
|
||
|
{
|
||
|
// copy the new element
|
||
|
hr = VariantCopy(&newVar[i], pVariant);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// shouldn't reach this case unless there was an old array
|
||
|
_ASSERTE(m_Var != NULL);
|
||
|
|
||
|
hr = VariantCopy(&newVar[i], &m_Var[i-1]);
|
||
|
}
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
LOG((TL_ERROR, "Add - VariantCopy failed - %lx", hr));
|
||
|
|
||
|
delete [] newVar;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( m_Var != NULL)
|
||
|
{
|
||
|
// Delete the old array
|
||
|
delete [] m_Var;
|
||
|
}
|
||
|
|
||
|
m_Var = newVar;
|
||
|
m_nSize++;
|
||
|
|
||
|
LOG((TL_TRACE, "Add - exit"));
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHOD(Remove)(
|
||
|
long Index
|
||
|
)
|
||
|
{
|
||
|
LOG((TL_TRACE, "Remove - enter"));
|
||
|
|
||
|
// use 1-based index, VB like
|
||
|
if ( (Index < 1) || (Index > m_nSize) )
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
CComVariant * newVar = NULL;
|
||
|
|
||
|
// if there is only one element in the array we don't need to do
|
||
|
// any copying
|
||
|
if (m_nSize > 1)
|
||
|
{
|
||
|
newVar = new CComVariant[m_nSize - 1];
|
||
|
|
||
|
if ( NULL == newVar )
|
||
|
{
|
||
|
LOG((TL_ERROR, "Remove - out of memory"));
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
HRESULT hr;
|
||
|
int i;
|
||
|
|
||
|
// fill in the new array
|
||
|
for ( i = 0; i < (m_nSize - 1); i++ )
|
||
|
{
|
||
|
VariantInit(&newVar[i]);
|
||
|
|
||
|
if ( i < (Index - 1) )
|
||
|
{
|
||
|
// shouldn't reach this case unless there was an old array
|
||
|
_ASSERTE(m_Var != NULL);
|
||
|
|
||
|
hr = VariantCopy(&newVar[i], &m_Var[i]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// shouldn't reach this case unless there was an old array
|
||
|
_ASSERTE(m_Var != NULL);
|
||
|
|
||
|
hr = VariantCopy(&newVar[i], &m_Var[i+1]);
|
||
|
}
|
||
|
|
||
|
if ( FAILED(hr) )
|
||
|
{
|
||
|
LOG((TL_ERROR, "Remove - VariantCopy failed - %lx", hr));
|
||
|
|
||
|
delete [] newVar;
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( m_Var != NULL)
|
||
|
{
|
||
|
// Delete the old array
|
||
|
delete [] m_Var;
|
||
|
}
|
||
|
|
||
|
m_Var = newVar;
|
||
|
m_nSize--;
|
||
|
|
||
|
LOG((TL_TRACE, "Remove - exit"));
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// CTapiBstrCollection
|
||
|
// Collection of BSTRs.
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
class CTapiBstrCollection :
|
||
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||
|
public IDispatchImpl<ITCollection, &IID_ITCollection, &LIBID_TAPI3Lib>,
|
||
|
public CObjectSafeImpl
|
||
|
{
|
||
|
public:
|
||
|
DECLARE_TRACELOG_CLASS(CTapiBstrCollection)
|
||
|
BEGIN_COM_MAP(CTapiBstrCollection)
|
||
|
COM_INTERFACE_ENTRY(IDispatch)
|
||
|
COM_INTERFACE_ENTRY(ITCollection)
|
||
|
COM_INTERFACE_ENTRY(IObjectSafety)
|
||
|
END_COM_MAP()
|
||
|
|
||
|
private:
|
||
|
|
||
|
DWORD m_dwSize;
|
||
|
CComVariant * m_Var;
|
||
|
|
||
|
public:
|
||
|
|
||
|
CTapiBstrCollection(void) : m_dwSize(0), m_Var(NULL) { }
|
||
|
|
||
|
// initialize
|
||
|
HRESULT STDMETHODCALLTYPE Initialize(
|
||
|
DWORD dwSize,
|
||
|
BSTR * pBegin,
|
||
|
BSTR * pEnd
|
||
|
)
|
||
|
{
|
||
|
BSTR * i;
|
||
|
DWORD dw = 0;
|
||
|
|
||
|
LOG((TL_TRACE, "Initialize - enter"));
|
||
|
|
||
|
// create variant array
|
||
|
m_dwSize = dwSize;
|
||
|
|
||
|
m_Var = new CComVariant[m_dwSize];
|
||
|
|
||
|
if (m_Var == NULL)
|
||
|
{
|
||
|
// debug output
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
for (i = pBegin; i != pEnd; i++)
|
||
|
{
|
||
|
// create a variant and add it to the collection
|
||
|
CComVariant& var = m_Var[dw];
|
||
|
|
||
|
var.vt = VT_BSTR;
|
||
|
var.bstrVal = *i;
|
||
|
|
||
|
dw++;
|
||
|
}
|
||
|
|
||
|
LOG((TL_TRACE, "Initialize - exit"));
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
STDMETHOD(get_Count)(
|
||
|
long* retval
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
LOG((TL_TRACE, "get_Count - enter"));
|
||
|
|
||
|
try
|
||
|
{
|
||
|
*retval = m_dwSize;
|
||
|
}
|
||
|
catch(...)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
LOG((TL_TRACE, "get_Count - exit"));
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
STDMETHOD(get_Item)(
|
||
|
long Index,
|
||
|
VARIANT* retval
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
LOG((TL_TRACE, "get_Item - enter"));
|
||
|
|
||
|
if (retval == NULL)
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
try
|
||
|
{
|
||
|
VariantInit(retval);
|
||
|
}
|
||
|
catch(...)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
if (hr != S_OK)
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
retval->vt = VT_BSTR;
|
||
|
retval->bstrVal = NULL;
|
||
|
|
||
|
// use 1-based index, VB like
|
||
|
// no problem with signed/unsigned, since
|
||
|
// if Index < 0 then first clause is true, making it
|
||
|
// irrelevant if the second clause is correct or not.
|
||
|
|
||
|
if ((Index < 1) || ( (DWORD) Index > m_dwSize))
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This copies the string, not just the pointer.
|
||
|
//
|
||
|
|
||
|
VariantCopy(retval, &m_Var[Index-1]);
|
||
|
|
||
|
LOG((TL_TRACE, "get_Item - exit"));
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE get__NewEnum(
|
||
|
IUnknown** retval
|
||
|
)
|
||
|
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
LOG((TL_TRACE, "get__NumEnum - enter"));
|
||
|
|
||
|
if (retval == NULL)
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
*retval = NULL;
|
||
|
|
||
|
typedef CComObject<CSafeComEnum<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _Copy<VARIANT> > > enumvar;
|
||
|
|
||
|
enumvar* p = new enumvar;
|
||
|
|
||
|
if ( p == NULL)
|
||
|
{
|
||
|
// debug output
|
||
|
return E_OUTOFMEMORY;
|
||
|
}
|
||
|
|
||
|
hr = p->Init(&m_Var[0], &m_Var[m_dwSize], NULL, AtlFlagCopy);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
{
|
||
|
hr = p->QueryInterface(IID_IEnumVARIANT, (void**)retval);
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
delete p;
|
||
|
}
|
||
|
|
||
|
LOG((TL_TRACE, "get__NewEnum - exit"));
|
||
|
|
||
|
return hr;
|
||
|
|
||
|
}
|
||
|
|
||
|
void FinalRelease()
|
||
|
{
|
||
|
LOG((TL_TRACE, "FinalRelease() - enter"));
|
||
|
|
||
|
//
|
||
|
// We "new"ed an array of objects. Delete each object in the array. The
|
||
|
// destructor for each object calls VariantClear to release the pointer
|
||
|
// in that object, based on the variant's tag.
|
||
|
//
|
||
|
|
||
|
delete [] m_Var;
|
||
|
|
||
|
LOG((TL_TRACE, "FinalRelease() - exit"));
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// CTapiTypeEnum template - enumerate types & structures
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
template <class Base, class T, class Copy, const IID* piid> class CTapiTypeEnum :
|
||
|
public Base,
|
||
|
public CTAPIComObjectRoot<Base>
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
// *piid is the IID of the enumerator class being
|
||
|
// created (like IID_IEnumAddressType)
|
||
|
typedef CTapiTypeEnum<Base, T, Copy, piid> _CTapiTypeEnumBase;
|
||
|
|
||
|
BEGIN_COM_MAP(_CTapiTypeEnumBase)
|
||
|
COM_INTERFACE_ENTRY_IID(*piid, _CTapiTypeEnumBase)
|
||
|
COM_INTERFACE_ENTRY_FUNC(IID_IMarshal, 0, IMarshalQI)
|
||
|
COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pFTM)
|
||
|
END_COM_MAP()
|
||
|
DECLARE_QI()
|
||
|
DECLARE_MARSHALQI(CTapiTypeEnum)
|
||
|
DECLARE_TRACELOG_CLASS(CTapiTypeEnum)
|
||
|
|
||
|
protected:
|
||
|
|
||
|
CTArray<T> m_Array;
|
||
|
int m_iCurrentLocation;
|
||
|
|
||
|
public:
|
||
|
|
||
|
//
|
||
|
// initialize the enumerator
|
||
|
//
|
||
|
HRESULT Initialize(CTArray<T> array)
|
||
|
{
|
||
|
int iSize, iCount;
|
||
|
|
||
|
iSize = array.GetSize();
|
||
|
|
||
|
for (iCount = 0; iCount < iSize; iCount++ )
|
||
|
{
|
||
|
m_Array.Add(array[iCount]);
|
||
|
}
|
||
|
|
||
|
m_iCurrentLocation = 0;
|
||
|
|
||
|
//
|
||
|
// addref ourself
|
||
|
//
|
||
|
this->AddRef();
|
||
|
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// FinalRelease
|
||
|
//
|
||
|
void FinalRelease()
|
||
|
{
|
||
|
m_Array.Shutdown();
|
||
|
}
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE Next(
|
||
|
ULONG celt,
|
||
|
T * pElements,
|
||
|
ULONG* pceltFetched
|
||
|
)
|
||
|
{
|
||
|
DWORD dwCount = 0;
|
||
|
|
||
|
if ((NULL == pElements) || (NULL == pceltFetched && celt > 1))
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// special case
|
||
|
//
|
||
|
if (celt == 0)
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
if (TAPIIsBadWritePtr( pElements, celt * sizeof(T) ) )
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
if ( (NULL != pceltFetched) &&
|
||
|
TAPIIsBadWritePtr( pceltFetched, sizeof(ULONG) ) )
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// iterator over elements and copy
|
||
|
//
|
||
|
while ((m_iCurrentLocation != m_Array.GetSize()) && (dwCount < celt))
|
||
|
{
|
||
|
Copy::copy(
|
||
|
&(pElements[dwCount]),
|
||
|
&(m_Array[m_iCurrentLocation])
|
||
|
);
|
||
|
|
||
|
m_iCurrentLocation++;
|
||
|
dwCount++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// return number copied
|
||
|
//
|
||
|
if (NULL != pceltFetched)
|
||
|
{
|
||
|
*pceltFetched = dwCount;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// indicate if we've reached the end
|
||
|
// of the enumeration.
|
||
|
//
|
||
|
if (dwCount < celt)
|
||
|
{
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE Skip(
|
||
|
ULONG celt
|
||
|
)
|
||
|
{
|
||
|
long lCount = 0;
|
||
|
|
||
|
while ( (lCount < celt) && (m_iCurrentLocation < m_Array.GetSize()) )
|
||
|
{
|
||
|
m_iCurrentLocation++;
|
||
|
lCount++;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE Reset(void)
|
||
|
{
|
||
|
m_iCurrentLocation = 0;
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE Clone(
|
||
|
Base ** ppEnum
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
CComObject< _CTapiTypeEnumBase > * pNewEnum;
|
||
|
|
||
|
if (TAPIIsBadWritePtr( ppEnum, sizeof (Base *) ) )
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
CComObject< _CTapiTypeEnumBase >::CreateInstance(&pNewEnum);
|
||
|
|
||
|
if (pNewEnum == NULL)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pNewEnum->Initialize(m_Array);
|
||
|
|
||
|
pNewEnum->m_iCurrentLocation = m_iCurrentLocation;
|
||
|
|
||
|
*ppEnum = pNewEnum;
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
// CTerminalClassEnum
|
||
|
////////////////////////////////////////////////////////////////////////
|
||
|
class CTerminalClassEnum :
|
||
|
public IEnumTerminalClass,
|
||
|
public CTAPIComObjectRoot<CTerminalClassEnum>
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
DECLARE_MARSHALQI(CTerminalClassEnum)
|
||
|
DECLARE_TRACELOG_CLASS(CTerminalClassEnum)
|
||
|
|
||
|
BEGIN_COM_MAP(CTerminalClassEnum)
|
||
|
COM_INTERFACE_ENTRY(IEnumTerminalClass)
|
||
|
COM_INTERFACE_ENTRY_FUNC(IID_IMarshal, 0, IMarshalQI)
|
||
|
COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pFTM)
|
||
|
END_COM_MAP()
|
||
|
|
||
|
protected:
|
||
|
|
||
|
TerminalClassPtrList m_list;
|
||
|
TerminalClassPtrList::iterator m_iter;
|
||
|
|
||
|
public:
|
||
|
|
||
|
virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **ppvObject) = 0;
|
||
|
virtual ULONG STDMETHODCALLTYPE AddRef() = 0;
|
||
|
virtual ULONG STDMETHODCALLTYPE Release() = 0;
|
||
|
|
||
|
|
||
|
// initialize the enumerator
|
||
|
HRESULT Initialize(
|
||
|
TerminalClassPtrList List
|
||
|
)
|
||
|
{
|
||
|
// copy the array
|
||
|
m_list.clear();
|
||
|
m_list.insert(m_list.begin(), List.begin(), List.end());
|
||
|
|
||
|
m_iter = m_list.begin();
|
||
|
|
||
|
this->AddRef();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
// FinalRelease -- added by ZoltanS
|
||
|
void FinalRelease(void)
|
||
|
{
|
||
|
// go through the list
|
||
|
for ( m_iter = m_list.begin(); m_iter != m_list.end(); m_iter++ )
|
||
|
{
|
||
|
SysFreeString(*m_iter); // this is the real way to free a BSTR
|
||
|
|
||
|
*m_iter = NULL; // destructor for list will delete(NULL)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE Next(
|
||
|
ULONG celt,
|
||
|
GUID * pElements,
|
||
|
ULONG* pceltFetched
|
||
|
)
|
||
|
{
|
||
|
DWORD dwCount = 0;
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
if ((NULL == pElements) || (NULL == pceltFetched && celt > 1))
|
||
|
{
|
||
|
return E_POINTER;
|
||
|
}
|
||
|
|
||
|
// special case
|
||
|
if (celt == 0)
|
||
|
{
|
||
|
return E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
// iterator over elements
|
||
|
try
|
||
|
{
|
||
|
while ( (m_iter != m_list.end()) &&
|
||
|
(dwCount < celt) )
|
||
|
{
|
||
|
hr = IIDFromString( *m_iter, &(pElements[dwCount]) );
|
||
|
|
||
|
if (!SUCCEEDED(hr))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
m_iter++;
|
||
|
dwCount++;
|
||
|
}
|
||
|
}
|
||
|
catch(...)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
|
||
|
if (S_OK != hr)
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (NULL != pceltFetched)
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
*pceltFetched = dwCount;
|
||
|
}
|
||
|
catch(...)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (S_OK != hr)
|
||
|
{
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
// indicate that we've reached the end
|
||
|
// of the enumeration.
|
||
|
if (dwCount < celt)
|
||
|
{
|
||
|
return S_FALSE;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE Skip(
|
||
|
ULONG celt
|
||
|
)
|
||
|
{
|
||
|
long lCount = 0;
|
||
|
|
||
|
while ( (lCount < celt) && (m_iter != m_list.end()) )
|
||
|
{
|
||
|
m_iter++;
|
||
|
lCount++;
|
||
|
}
|
||
|
|
||
|
// check to see if we reached the end
|
||
|
if (lCount != celt)
|
||
|
{
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE Reset(void)
|
||
|
{
|
||
|
m_iter = m_list.begin();
|
||
|
|
||
|
return S_OK;
|
||
|
}
|
||
|
|
||
|
HRESULT STDMETHODCALLTYPE Clone(
|
||
|
IEnumTerminalClass ** ppEnum
|
||
|
)
|
||
|
{
|
||
|
HRESULT hr = S_OK;
|
||
|
|
||
|
CComObject< CTerminalClassEnum > * pNewEnum;
|
||
|
|
||
|
CComObject< CTerminalClassEnum >::CreateInstance(&pNewEnum);
|
||
|
|
||
|
if (pNewEnum == NULL)
|
||
|
{
|
||
|
hr = E_OUTOFMEMORY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pNewEnum->Initialize( m_list );
|
||
|
|
||
|
try
|
||
|
{
|
||
|
*ppEnum = pNewEnum;
|
||
|
}
|
||
|
catch(...)
|
||
|
{
|
||
|
hr = E_INVALIDARG;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
#endif // __ENUM_H__
|