743 lines
15 KiB
C++
743 lines
15 KiB
C++
/*
|
|
|
|
Copyright (c) 1998-1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
blbcoen.h
|
|
|
|
Abstract:
|
|
|
|
Author:
|
|
|
|
*/
|
|
|
|
#ifndef __BLB_COLLECTION_ENUMERATION_IMPL__
|
|
#define __BLB_COLLECTION_ENUMERATION_IMPL__
|
|
|
|
#include "resource.h"
|
|
|
|
#include <afxtempl.h>
|
|
#include "blberr.h"
|
|
#include "blbgen.h"
|
|
#include "sdp.h"
|
|
|
|
// forward declaration
|
|
class CSdpConferenceBlob;
|
|
|
|
|
|
template <class T>
|
|
class ENUM_ELEMENT
|
|
{
|
|
public:
|
|
|
|
inline ENUM_ELEMENT();
|
|
|
|
inline void SuccessInit(
|
|
IN T &Element,
|
|
IN BOOL DestroyElementOnDestruction = FALSE
|
|
);
|
|
|
|
inline T &GetElement();
|
|
|
|
inline T &GetContent();
|
|
|
|
inline void SetDestroyElementFlag();
|
|
|
|
virtual ~ENUM_ELEMENT();
|
|
|
|
protected:
|
|
|
|
T *m_Element;
|
|
BOOL m_DestroyElementOnDestruction;
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
|
inline
|
|
ENUM_ELEMENT<T>::ENUM_ELEMENT(
|
|
)
|
|
: m_Element(NULL),
|
|
m_DestroyElementOnDestruction(FALSE)
|
|
|
|
{
|
|
}
|
|
|
|
|
|
template <class T>
|
|
inline void
|
|
ENUM_ELEMENT<T>::SuccessInit(
|
|
IN T &Element,
|
|
IN BOOL DestroyElementOnDestruction /* = FALSE */
|
|
)
|
|
{
|
|
ASSERT(NULL == m_Element);
|
|
|
|
m_Element = ∈
|
|
m_DestroyElementOnDestruction = DestroyElementOnDestruction;
|
|
}
|
|
|
|
|
|
template <class T>
|
|
inline T &
|
|
ENUM_ELEMENT<T>::GetElement(
|
|
)
|
|
{
|
|
ASSERT(NULL != m_Element);
|
|
|
|
return *m_Element;
|
|
}
|
|
|
|
template <class T>
|
|
inline void
|
|
ENUM_ELEMENT<T>::SetDestroyElementFlag(
|
|
)
|
|
{
|
|
ASSERT(NULL != m_Element);
|
|
|
|
m_DestroyElementOnDestruction = TRUE;
|
|
}
|
|
|
|
|
|
template <class T>
|
|
inline T &
|
|
ENUM_ELEMENT<T>::GetContent(
|
|
)
|
|
{
|
|
ASSERT(NULL != m_Element);
|
|
|
|
return *m_Element;
|
|
}
|
|
|
|
|
|
template <class T>
|
|
/* virtual */
|
|
ENUM_ELEMENT<T>::~ENUM_ELEMENT(
|
|
)
|
|
{
|
|
if ( m_DestroyElementOnDestruction )
|
|
{
|
|
ASSERT(NULL != m_Element);
|
|
|
|
delete m_Element;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
class IF_ARRAY : public CArray<VARIANT, VARIANT &>
|
|
{
|
|
protected:
|
|
typedef T::SDP_LIST SDP_LIST;
|
|
typedef T::ELEM_IF ELEM_IF;
|
|
typedef CArray<VARIANT, VARIANT &> BASE;
|
|
|
|
public:
|
|
|
|
inline IF_ARRAY();
|
|
|
|
HRESULT Init(
|
|
IN CSdpConferenceBlob &ConfBlob,
|
|
IN SDP_LIST &SdpList
|
|
);
|
|
|
|
inline ELEM_IF *GetAt(
|
|
IN UINT Index
|
|
);
|
|
|
|
HRESULT Add(
|
|
IN UINT Index,
|
|
IN ELEM_IF *ElemIf
|
|
);
|
|
|
|
inline void Delete(
|
|
IN UINT Index
|
|
);
|
|
|
|
inline UINT GetSize();
|
|
|
|
inline SDP_LIST *GetSdpList();
|
|
|
|
inline VARIANT *GetData();
|
|
|
|
inline ELEM_IF **GetElemIfArrayData();
|
|
|
|
inline CSdpConferenceBlob *GetSdpBlob();
|
|
|
|
inline void ClearSdpBlobRefs();
|
|
|
|
~IF_ARRAY();
|
|
|
|
protected:
|
|
|
|
CSdpConferenceBlob *m_ConfBlob;
|
|
SDP_LIST *m_SdpList;
|
|
|
|
CArray<ELEM_IF *, ELEM_IF *> m_ElemIfArray;
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
|
inline
|
|
IF_ARRAY<T>::IF_ARRAY(
|
|
)
|
|
: m_ConfBlob(NULL),
|
|
m_SdpList(NULL)
|
|
|
|
{
|
|
}
|
|
|
|
|
|
template <class T>
|
|
HRESULT
|
|
IF_ARRAY<T>::Init(
|
|
IN CSdpConferenceBlob &ConfBlob,
|
|
IN SDP_LIST &SdpList
|
|
)
|
|
{
|
|
ASSERT(NULL == m_ConfBlob);
|
|
ASSERT(NULL == m_SdpList);
|
|
|
|
// create the array in 3 steps -
|
|
// i) create each of the instances and insert into the list
|
|
// ii) set the sdp list destroy members flag to FALSE
|
|
// iii) set the destroy element flag to TRUE for each of the created instances
|
|
// this order is needed to ensure that only one of (sdp list, T instance) is responsible
|
|
// for deleting the sdp instance
|
|
|
|
// for each sdp specific data structure, create and initialize a COM component,
|
|
// set the corresponding element in the interface array to the queried interface ptr
|
|
for (UINT i=0; (int)i < SdpList.GetSize(); i++)
|
|
{
|
|
// create an instance of the component supporting the elem if
|
|
CComObject<T> *CompInstance;
|
|
HRESULT HResult = CComObject<T>::CreateInstance(&CompInstance);
|
|
BAIL_ON_FAILURE(HResult);
|
|
|
|
// initialize the instance with the sdp specific data structure
|
|
CompInstance->SuccessInit(ConfBlob, *((T::SDP_TYPE *)SdpList.GetAt(i)));
|
|
|
|
// query for the elem interface
|
|
T::ELEM_IF *ElemIf;
|
|
|
|
// query for the element interface and return it
|
|
HResult = CompInstance->_InternalQueryInterface(T::ELEM_IF_ID, (void**)&ElemIf);
|
|
if ( FAILED(HResult) )
|
|
{
|
|
delete CompInstance;
|
|
return HResult;
|
|
}
|
|
|
|
// initialize the variant wrapper
|
|
VARIANT ElemVariant;
|
|
V_VT(&ElemVariant) = VT_DISPATCH;
|
|
V_DISPATCH(&ElemVariant) = ElemIf;
|
|
|
|
// the ElemIf is stored twice (although it was incremented once in _InternalQueryInterface
|
|
// need to keep this in mind when releasing the interfaces
|
|
|
|
INT_PTR Index;
|
|
|
|
try
|
|
{
|
|
Index = m_ElemIfArray.Add(ElemIf);
|
|
}
|
|
catch(...)
|
|
{
|
|
delete CompInstance;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
try
|
|
{
|
|
BASE::Add(ElemVariant);
|
|
}
|
|
catch(...)
|
|
{
|
|
m_ElemIfArray.RemoveAt(Index);
|
|
delete CompInstance;
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
}
|
|
|
|
// inform the sdp list that there is no need to destroy the members on destruction
|
|
SdpList.ClearDestroyMembersFlag();
|
|
|
|
// for each of the inserted instances, set the destroy element flag to true
|
|
for (i=0; (int)i < BASE::GetSize(); i++)
|
|
{
|
|
((T *)m_ElemIfArray.GetAt(i))->SetDestroyElementFlag();
|
|
}
|
|
|
|
m_ConfBlob = &ConfBlob;
|
|
m_SdpList = &SdpList;
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
template <class T>
|
|
inline IF_ARRAY<T>::ELEM_IF *
|
|
IF_ARRAY<T>::GetAt(
|
|
IN UINT Index
|
|
)
|
|
{
|
|
ASSERT(Index < (UINT)BASE::GetSize());
|
|
|
|
return m_ElemIfArray.GetAt(Index);
|
|
}
|
|
|
|
|
|
template <class T>
|
|
HRESULT
|
|
IF_ARRAY<T>::Add(
|
|
IN UINT Index,
|
|
IN ELEM_IF *ElemIf
|
|
)
|
|
{
|
|
ASSERT(NULL != m_SdpList);
|
|
ASSERT(BASE::GetSize() == m_SdpList->GetSize());
|
|
ASSERT(Index <= (UINT)BASE::GetSize());
|
|
ASSERT(NULL != ElemIf);
|
|
|
|
// shift elements with equal or higher indices forwards
|
|
// cheat COM here, and get the sdp specific class instance for the elem if
|
|
|
|
// initialize the variant wrapper
|
|
VARIANT ElemVariant;
|
|
V_VT(&ElemVariant) = VT_DISPATCH;
|
|
V_DISPATCH(&ElemVariant) = ElemIf;
|
|
|
|
// insert into the arrays
|
|
try
|
|
{
|
|
m_ElemIfArray.InsertAt(Index, ElemIf);
|
|
}
|
|
catch(...)
|
|
{
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
try
|
|
{
|
|
BASE::InsertAt(Index, ElemVariant);
|
|
}
|
|
catch(...)
|
|
{
|
|
m_ElemIfArray.RemoveAt(Index);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
try
|
|
{
|
|
m_SdpList->InsertAt(Index, &(((T *)ElemIf)->GetContent()));
|
|
}
|
|
catch(...)
|
|
{
|
|
BASE::RemoveAt(Index);
|
|
m_ElemIfArray.RemoveAt(Index);
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
inline void
|
|
IF_ARRAY<T>::Delete(
|
|
IN UINT Index
|
|
)
|
|
{
|
|
ASSERT(NULL != m_SdpList);
|
|
ASSERT(BASE::GetSize() == m_SdpList->GetSize());
|
|
ASSERT(Index < (UINT)BASE::GetSize());
|
|
|
|
// inform the instance that a reference to the blob is no longer needed
|
|
((T *)m_ElemIfArray.GetAt(Index))->ClearSdpBlobRefs();
|
|
|
|
m_ElemIfArray.GetAt(Index)->Release();
|
|
|
|
// move other members backwards
|
|
m_ElemIfArray.RemoveAt(Index);
|
|
BASE::RemoveAt(Index);
|
|
m_SdpList->RemoveAt(Index);
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
inline UINT
|
|
IF_ARRAY<T>::GetSize(
|
|
)
|
|
{
|
|
ASSERT(0 <= BASE::GetSize());
|
|
|
|
return (UINT)BASE::GetSize();
|
|
}
|
|
|
|
|
|
template <class T>
|
|
inline VARIANT *
|
|
IF_ARRAY<T>::GetData(
|
|
)
|
|
{
|
|
return BASE::GetData();
|
|
}
|
|
|
|
|
|
template <class T>
|
|
inline IF_ARRAY<T>::ELEM_IF **
|
|
IF_ARRAY<T>::GetElemIfArrayData(
|
|
)
|
|
{
|
|
return m_ElemIfArray.GetData();
|
|
}
|
|
|
|
|
|
template <class T>
|
|
inline CSdpConferenceBlob *
|
|
IF_ARRAY<T>::GetSdpBlob(
|
|
)
|
|
{
|
|
return m_ConfBlob;
|
|
}
|
|
|
|
|
|
template <class T>
|
|
inline void
|
|
IF_ARRAY<T>::ClearSdpBlobRefs(
|
|
)
|
|
{
|
|
m_ConfBlob = NULL;
|
|
|
|
// clear sdp blob references in each of the inserted instances
|
|
for(UINT i=0; (int)i < BASE::GetSize(); i++)
|
|
{
|
|
// inform the inserted instance that a reference to the blob is no longer needed
|
|
((T *)m_ElemIfArray.GetAt(i))->ClearSdpBlobRefs();
|
|
}
|
|
|
|
// keep the list (m_SdpList) around, it is already disassociated from the conf blob instance
|
|
}
|
|
|
|
|
|
template <class T>
|
|
inline IF_ARRAY<T>::SDP_LIST *
|
|
IF_ARRAY<T>::GetSdpList(
|
|
)
|
|
{
|
|
return m_SdpList;
|
|
}
|
|
|
|
|
|
template <class T>
|
|
IF_ARRAY<T>::~IF_ARRAY(
|
|
)
|
|
{
|
|
for(UINT i=0; (int)i < BASE::GetSize(); i++)
|
|
{
|
|
if ( NULL != m_ElemIfArray.GetAt(i) )
|
|
{
|
|
// inform the instance that a reference to the blob is no longer needed
|
|
// NOTE: the Remove... call may already have been made, but since it is an
|
|
// inline fn, no need to check that before calling
|
|
((T *)m_ElemIfArray.GetAt(i))->ClearSdpBlobRefs();
|
|
|
|
// NOTE: since the interface is stored twice - in the elem if array as well
|
|
// as the base variant array but AddRef is only done once (by _InternalQuery..)
|
|
// Release is also done only once
|
|
m_ElemIfArray.GetAt(i)->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
template <class T>
|
|
class ATL_NO_VTABLE MY_COLL_IMPL :
|
|
public T::COLL_IF
|
|
{
|
|
protected:
|
|
|
|
typedef T::SDP_LIST SDP_LIST;
|
|
typedef T::ELEM_IF ELEM_IF;
|
|
|
|
typedef CComObject<CSafeComEnum<IEnumVARIANT, &IID_IEnumVARIANT, VARIANT, _Copy<VARIANT> > > ENUM_VARIANT;
|
|
|
|
typedef T::ENUM_IF ENUM_IF;
|
|
typedef _CopyInterface<T::ELEM_IF> COPY_ELEM_IF;
|
|
|
|
public:
|
|
|
|
inline MY_COLL_IMPL();
|
|
|
|
inline HRESULT Init(
|
|
IN CSdpConferenceBlob &ConfBlob,
|
|
IN SDP_LIST &SdpList
|
|
);
|
|
|
|
STDMETHOD(Create)(/*[in]*/ LONG Index, /*[out, retval]*/ ELEM_IF **Interface);
|
|
STDMETHOD(Delete)(/*[in]*/ LONG Index);
|
|
STDMETHOD(get__NewEnum)(/*[out, retval]*/ IUnknown * *pVal);
|
|
STDMETHOD(get_EnumerationIf)(/*[out, retval]*/ ENUM_IF **pVal) = 0;
|
|
STDMETHOD(get_Item)(/*[in]*/ LONG Index, /*[out, retval]*/ ELEM_IF **pVal);
|
|
STDMETHOD(get_Count)(/*[out, retval]*/ LONG *pVal);
|
|
|
|
inline void ClearSdpBlobRefs();
|
|
|
|
virtual ~MY_COLL_IMPL();
|
|
|
|
protected:
|
|
|
|
IF_ARRAY<T> *m_IfArray;
|
|
};
|
|
|
|
|
|
|
|
template <class T>
|
|
inline
|
|
MY_COLL_IMPL<T>::MY_COLL_IMPL(
|
|
)
|
|
: m_IfArray(NULL)
|
|
{
|
|
}
|
|
|
|
|
|
template <class T>
|
|
inline HRESULT
|
|
MY_COLL_IMPL<T>::Init(
|
|
IN CSdpConferenceBlob &ConfBlob,
|
|
IN SDP_LIST &SdpList
|
|
)
|
|
{
|
|
if ( NULL != m_IfArray )
|
|
{
|
|
delete m_IfArray;
|
|
}
|
|
|
|
// create an interface array
|
|
try
|
|
{
|
|
m_IfArray = new IF_ARRAY<T>;
|
|
}
|
|
catch(...)
|
|
{
|
|
m_IfArray = NULL;
|
|
}
|
|
|
|
BAIL_IF_NULL(m_IfArray, E_OUTOFMEMORY);
|
|
|
|
// initialize the interface array
|
|
HRESULT HResult = m_IfArray->Init(ConfBlob, SdpList);
|
|
BAIL_ON_FAILURE(HResult);
|
|
|
|
// successful
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
template <class T>
|
|
STDMETHODIMP MY_COLL_IMPL<T>::Create(
|
|
/*[in]*/ LONG Index,
|
|
/*[out, retval]*/ ELEM_IF **Interface
|
|
)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
ASSERT(NULL != m_IfArray);
|
|
BAIL_IF_NULL(m_IfArray, E_FAIL);
|
|
|
|
// use 1-based index, VB like
|
|
// can add at atmost 1 beyond the last element
|
|
if ((Index < (LONG)1) || (Index > (LONG)(m_IfArray->GetSize()+1)))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
BAIL_IF_NULL(Interface, E_INVALIDARG);
|
|
|
|
// if the sdp blob doesn't exist, creation is not allowed
|
|
if ( NULL == m_IfArray->GetSdpBlob() )
|
|
{
|
|
return HRESULT_FROM_ERROR_CODE(SDPBLB_CONF_BLOB_DESTROYED);
|
|
}
|
|
|
|
CComObject<T> *TComObject;
|
|
HRESULT HResult = CComObject<T>::CreateInstance(&TComObject);
|
|
BAIL_ON_FAILURE(HResult);
|
|
|
|
HResult = TComObject->Init(*(m_IfArray->GetSdpBlob()));
|
|
if ( FAILED(HResult) )
|
|
{
|
|
delete TComObject;
|
|
return HResult;
|
|
}
|
|
|
|
HResult = TComObject->_InternalQueryInterface(T::ELEM_IF_ID, (void**)Interface);
|
|
if (FAILED(HResult))
|
|
{
|
|
delete TComObject;
|
|
return HResult;
|
|
}
|
|
|
|
// adjust index to c like index value
|
|
HResult = m_IfArray->Add(Index-1, *Interface);
|
|
if (FAILED(HResult))
|
|
{
|
|
delete TComObject;
|
|
return HResult;
|
|
}
|
|
|
|
// add another reference count for the interface being returned
|
|
(*Interface)->AddRef();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
|
|
template <class T>
|
|
STDMETHODIMP MY_COLL_IMPL<T>::Delete(
|
|
/*[in]*/ LONG Index
|
|
)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
ASSERT(NULL != m_IfArray);
|
|
BAIL_IF_NULL(m_IfArray, E_FAIL);
|
|
|
|
// use 1-based index, VB like
|
|
if ((Index < (LONG)1) || (Index > (LONG)m_IfArray->GetSize()))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
// if the sdp blob doesn't exist, deletion is not allowed
|
|
if ( NULL == m_IfArray->GetSdpBlob() )
|
|
{
|
|
return HRESULT_FROM_ERROR_CODE(SDPBLB_CONF_BLOB_DESTROYED);
|
|
}
|
|
|
|
// adjust index to c like index value, delete the instance
|
|
m_IfArray->Delete(Index-1);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
template <class T>
|
|
STDMETHODIMP MY_COLL_IMPL<T>::get__NewEnum(
|
|
/*[out, retval]*/ IUnknown **pVal
|
|
)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
ASSERT(NULL != m_IfArray);
|
|
BAIL_IF_NULL(m_IfArray, E_FAIL);
|
|
|
|
BAIL_IF_NULL(pVal, E_INVALIDARG);
|
|
|
|
ENUM_VARIANT *EnumComObject;
|
|
HRESULT HResult = ENUM_VARIANT::CreateInstance(&EnumComObject);
|
|
BAIL_ON_FAILURE(HResult);
|
|
|
|
HResult = EnumComObject->Init(
|
|
m_IfArray->GetData(),
|
|
m_IfArray->GetData() + m_IfArray->GetSize(),
|
|
NULL, // no owner pUnk
|
|
AtlFlagCopy // copy the array data
|
|
);
|
|
if ( FAILED(HResult) )
|
|
{
|
|
delete EnumComObject;
|
|
return HResult;
|
|
}
|
|
|
|
// query for the IUnknown interface and return it
|
|
HResult = EnumComObject->_InternalQueryInterface(IID_IUnknown, (void**)pVal);
|
|
if ( FAILED(HResult) )
|
|
{
|
|
delete EnumComObject;
|
|
return HResult;
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
template <class T>
|
|
STDMETHODIMP MY_COLL_IMPL<T>::get_Item(
|
|
/*[in]*/ LONG Index,
|
|
/*[out, retval]*/ ELEM_IF **pVal
|
|
)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
ASSERT(NULL != m_IfArray);
|
|
BAIL_IF_NULL(m_IfArray, E_FAIL);
|
|
|
|
BAIL_IF_NULL(pVal, E_INVALIDARG);
|
|
|
|
// use 1-based index, VB like
|
|
if ((Index < (LONG)1) || (Index > (LONG)m_IfArray->GetSize()))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
*pVal = m_IfArray->GetAt(Index-1);
|
|
(*pVal)->AddRef();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
template <class T>
|
|
STDMETHODIMP MY_COLL_IMPL<T>::get_Count(
|
|
/*[out, retval]*/ LONG *pVal
|
|
)
|
|
{
|
|
CLock Lock(g_DllLock);
|
|
|
|
ASSERT(NULL != m_IfArray);
|
|
BAIL_IF_NULL(m_IfArray, E_FAIL);
|
|
|
|
BAIL_IF_NULL(pVal, E_INVALIDARG);
|
|
|
|
*pVal = m_IfArray->GetSize();
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
template <class T>
|
|
inline void
|
|
MY_COLL_IMPL<T>::ClearSdpBlobRefs(
|
|
)
|
|
{
|
|
m_IfArray->ClearSdpBlobRefs();
|
|
}
|
|
|
|
|
|
template <class T>
|
|
/* virtual */
|
|
MY_COLL_IMPL<T>::~MY_COLL_IMPL(
|
|
)
|
|
{
|
|
// if an interface array exists, destroy it
|
|
if ( NULL != m_IfArray )
|
|
{
|
|
if ( NULL != m_IfArray->GetSdpList() )
|
|
{
|
|
delete m_IfArray->GetSdpList();
|
|
}
|
|
|
|
delete m_IfArray;
|
|
}
|
|
}
|
|
|
|
|
|
#endif // __BLB_COLLECTION_ENUMERATION_IMPL__
|