/* Copyright (c) 1997-1999 Microsoft Corporation */ #ifndef __SDP_SAFEARRAY__ #define __SDP_SAFEARRAY__ #include #include "sdpcommo.h" #include "sdpdef.h" inline BOOL ValidateSafeArray( IN VARTYPE VarType, IN VARIANT *Variant ) { ASSERT(NULL != Variant); // check if its a safearray and the type of elements in the safe array is whats expected if ( !(V_VT(Variant) & (VT_ARRAY | VarType)) ) { return FALSE; } // check number of dimensions, cannot handle more than one dimension if ( V_ARRAY(Variant)->cDims != 1 ) { return FALSE; } return TRUE; } class _DllDecl SDP_SAFEARRAY : public COleSafeArray { public: inline SDP_SAFEARRAY(); BOOL CreateAndAttach( IN ULONG MinSize, IN VARTYPE VarType, IN OUT VARIANT &Variant, OUT HRESULT &HResult ); inline void Attach( IN VARIANT &Variant ); inline void Detach(); inline BOOL Free( OUT HRESULT &HResult ); inline BOOL IsAllocated() const; inline ~SDP_SAFEARRAY(); protected: VARIANT *m_Variant; }; inline SDP_SAFEARRAY::SDP_SAFEARRAY( ) : m_Variant(NULL) { } inline void SDP_SAFEARRAY::Attach( IN VARIANT &Variant ) { m_Variant = &Variant; // because of the way attach is implemented, the variant vt type field is set to VT_EMPTY // and the ptr is set to null // if the instance is destroyed without calling free, the vt type and the safe array are assigned // back to the member variant COleSafeArray::Attach(Variant); } inline void SDP_SAFEARRAY::Detach( ) { ASSERT(NULL != m_Variant); if ( NULL != m_Variant ) { *m_Variant = COleSafeArray::Detach(); m_Variant = NULL; } } inline BOOL SDP_SAFEARRAY::Free( OUT HRESULT &HResult ) { if (NULL == m_Variant) { HResult = S_OK; return TRUE; } // destroy the underlying safearray Clear(); // set the member variant ptr to null so that we are no longer attached to it m_Variant = NULL; return TRUE; } inline BOOL SDP_SAFEARRAY::IsAllocated( ) const { return (NULL != m_Variant) ? TRUE : FALSE; } inline SDP_SAFEARRAY::~SDP_SAFEARRAY( ) { if ( NULL != m_Variant ) { *m_Variant = COleSafeArray::Detach(); } } template class DYNAMIC_ARRAY { public: inline DYNAMIC_ARRAY( IN ULONG NumElements ); inline T &operator[]( IN ULONG Index ); inline T *operator()(); virtual ~DYNAMIC_ARRAY(); protected: T *m_Array; }; template inline DYNAMIC_ARRAY::DYNAMIC_ARRAY( IN ULONG NumElements ) { ASSERT(0 != NumElements); m_Array = new T[NumElements]; } template inline T & DYNAMIC_ARRAY::operator[]( IN ULONG Index ) { return m_Array[Index]; } template inline T * DYNAMIC_ARRAY::operator ()( ) { return m_Array; } template DYNAMIC_ARRAY::~DYNAMIC_ARRAY( ) { ASSERT( NULL != m_Array ); delete[] m_Array; } template class DYNAMIC_POINTER_ARRAY : public DYNAMIC_ARRAY { public: inline DYNAMIC_POINTER_ARRAY( IN ULONG NumElements ); inline T &operator[]( IN ULONG Index ); virtual ~DYNAMIC_POINTER_ARRAY(); protected: ULONG m_NumElements; // should not be called inline T *operator()() { ASSERT(FALSE); return NULL; } }; template inline DYNAMIC_POINTER_ARRAY::DYNAMIC_POINTER_ARRAY( IN ULONG NumElements ) : DYNAMIC_ARRAY(NumElements), m_NumElements(NumElements) { for (UINT i=0; i < NumElements; i++) { m_Array[i] = new T(); } } template inline T & DYNAMIC_POINTER_ARRAY::operator[]( IN ULONG Index ) { return *m_Array[Index]; } template DYNAMIC_POINTER_ARRAY::~DYNAMIC_POINTER_ARRAY( ) { ASSERT( NULL != m_Array ); for (UINT i=0; i < m_NumElements; i++) { delete m_Array[i]; } } class _DllDecl SDP_SAFEARRAY_WRAP { public: HRESULT GetSafeArrays( IN const ULONG NumElements, IN const ULONG NumSafeArrays, IN VARTYPE VarType[], OUT VARIANT *Variant[] ); HRESULT SetSafeArrays( IN const ULONG NumSafeArrays, IN VARTYPE VarType[], IN VARIANT *Variant[] ); protected: virtual BOOL GetElement( IN ULONG Index, IN ULONG NumEntries, IN void **Element, OUT HRESULT &HResult ) = 0; virtual BOOL SetElement( IN ULONG Index, IN ULONG NumEntries, IN void ***Element, OUT HRESULT &HResult ) = 0; virtual void RemoveExcessElements( IN ULONG StartIndex ) = 0; }; template class _DllDecl SDP_SAFEARRAY_WRAP_EX : public SDP_SAFEARRAY_WRAP { public: inline SDP_SAFEARRAY_WRAP_EX( IN TLIST &TList ); protected: TLIST &m_TList; T *GetListMember( IN ULONG Index, OUT HRESULT &HResult ); virtual BOOL Get( IN T &ListMember, IN ULONG NumEntries, IN void **Element, OUT HRESULT &HResult ) = 0; virtual BOOL GetElement( IN ULONG Index, IN ULONG NumEntries, IN void **Element, OUT HRESULT &HResult ); T *CreateListMemberIfRequired( IN ULONG Index, OUT HRESULT &HResult ); virtual BOOL Set( IN T &ListMember, IN ULONG NumEntries, IN void ***Element, OUT HRESULT &HResult ) = 0; virtual BOOL SetElement( IN ULONG Index, IN ULONG NumEntries, IN void ***Element, OUT HRESULT &HResult ); virtual void RemoveExcessElements( IN ULONG StartIndex ); }; template inline SDP_SAFEARRAY_WRAP_EX::SDP_SAFEARRAY_WRAP_EX( IN TLIST &TList ) : m_TList(TList) {} template T * SDP_SAFEARRAY_WRAP_EX::GetListMember( IN ULONG Index, OUT HRESULT &HResult ) { T *ToReturn = dynamic_cast(m_TList[Index]); if ( NULL == ToReturn ) { HResult = HRESULT_FROM_ERROR_CODE(SDP_INTERNAL_ERROR); } return ToReturn; } template BOOL SDP_SAFEARRAY_WRAP_EX::GetElement( IN ULONG Index, IN ULONG NumEntries, IN void **Element, OUT HRESULT &HResult ) { T *ListMember = GetListMember(Index, HResult); if ( NULL == ListMember ) { return FALSE; } ASSERT(ListMember->IsValid()); if ( !Get(*ListMember, NumEntries, Element, HResult) ) { return FALSE; } return TRUE; } template T * SDP_SAFEARRAY_WRAP_EX::CreateListMemberIfRequired( IN ULONG Index, OUT HRESULT &HResult ) { // assert that the index is atmost 1 more than the size of the list ASSERT(0 <= m_TList.GetSize()); ASSERT(Index <= (ULONG)(m_TList.GetSize() + 1)); if ( Index >= (ULONG)m_TList.GetSize() ) { T *NewElement = dynamic_cast(m_TList.CreateElement()); if ( NULL == NewElement ) { HResult = HRESULT_FROM_ERROR_CODE(SDP_INTERNAL_ERROR); } return NewElement; } else { return GetListMember(Index, HResult); } // should never reach here ASSERT(FALSE); } template BOOL SDP_SAFEARRAY_WRAP_EX::SetElement( IN ULONG Index, IN ULONG NumEntries, IN void ***Element, OUT HRESULT &HResult ) { T *ListMember = CreateListMemberIfRequired(Index, HResult); if ( NULL == ListMember ) { return FALSE; } if ( !Set(*ListMember, NumEntries, Element, HResult) ) { return FALSE; } ASSERT(ListMember->IsValid()); // if its a newly created instance, make it valid and add it to the list at the appropriate // index if ( Index >= (ULONG)m_TList.GetSize() ) { try { m_TList.SetAtGrow(Index, ListMember); } catch(...) { delete ListMember; SetLastError(ERROR_OUTOFMEMORY); return FALSE; } } return TRUE; } template void SDP_SAFEARRAY_WRAP_EX::RemoveExcessElements( IN ULONG StartIndex ) { ASSERT(0 <= m_TList.GetSize()); // for each list element that is in excess of the safearray members, // delete and remove them for ( ULONG i = StartIndex; i < (ULONG)m_TList.GetSize(); i++ ) { delete m_TList[i]; m_TList.RemoveAt(i); i++; } } #endif // __SDP_SAFEARRAY__