// MessageImpl.h // Declaration of helper classes for implementing the IMessageMembers interface #ifndef __MESSAGEIMPL_H #define __MESSAGEIMPL_H #include "Message.h" template< class ImplT > class ATL_NO_VTABLE IMessageIteratorImpl : public IDispatchImpl< IMessageIterator, &__uuidof( IMessageIterator ), &LIBID_DecalNet > { public: enum { eEndIndex = 0xFFFFFFFF }; cMessage *getSource(); DWORD getStartIndex(); DWORD getEndIndex(); DWORD m_dwIterator; long m_nIndex; void init() { m_nIndex = -1; } DWORD getNextIndex( DWORD dwIndex ) { DWORD dwNextIndex = dwIndex + ( static_cast< ImplT * >( this )->getSource()->m_fields.begin() + dwIndex )->m_nOwns; if( dwNextIndex == static_cast< ImplT * >( this )->getEndIndex() ) return eEndIndex; return dwNextIndex; } DWORD getNextIndex() { if( m_nIndex == -1 ) { DWORD dwIndex = static_cast< ImplT * >( this )->getStartIndex(); if ( dwIndex == static_cast< ImplT * >( this )->getEndIndex () ) // This was 0 size return eEndIndex; return dwIndex; } return static_cast< ImplT * >( this )->getNextIndex( m_dwIterator ); } HRESULT advanceToIndex( long nIndex ) { if( nIndex <= m_nIndex ) { _ASSERT( FALSE ); return E_INVALIDARG; } int nCurIndex = m_nIndex; for( DWORD dwIterator = static_cast< ImplT * >( this )->getNextIndex(); dwIterator != eEndIndex; dwIterator = static_cast< ImplT * >( this )->getNextIndex( dwIterator ) ) { // Reset the counter ++ nCurIndex; if( nCurIndex == nIndex ) { m_dwIterator = dwIterator; m_nIndex = nCurIndex; return S_OK; } } // The advance went off the edge m_dwIterator = eEndIndex; return S_FALSE; } HRESULT advanceToName( BSTR strName ) { int nIndex = m_nIndex; for( DWORD dwIterator = static_cast< ImplT * >( this )->getNextIndex(); dwIterator != eEndIndex; dwIterator = static_cast< ImplT * >( this )->getNextIndex( dwIterator ) ) { ++ nIndex; if( ::VarBstrCmp( strName, ( static_cast< ImplT * >( this )->getSource()->m_fields.begin() + dwIterator )->m_pSchema->m_strName, LOCALE_USER_DEFAULT, 0 ) == VARCMP_EQ ) { // We've found the field m_nIndex = nIndex; m_dwIterator = dwIterator; return S_OK; } } return S_FALSE; } HRESULT advanceNext() { m_dwIterator = static_cast< ImplT * >( this )->getNextIndex(); if( m_dwIterator == eEndIndex ) return S_FALSE; ++ m_nIndex; return S_OK; } STDMETHOD(get_Current)(VARIANT *pData) { if( pData == NULL ) { _ASSERT( FALSE ); return E_POINTER; } if( m_dwIterator == eEndIndex ) { pData->vt = VT_NULL; return E_FAIL; } cMessage::cFieldList::iterator i = static_cast< ImplT * >( this )->getSource()->m_fields.begin() + m_dwIterator; i->m_pSchema->getValue( static_cast< ImplT * >( this )->getSource(), i, pData ); return S_OK; } STDMETHOD(get_MemberName)( BSTR *pstrName ) { if( pstrName == NULL ) { _ASSERT( FALSE ); return E_POINTER; } if( m_dwIterator == eEndIndex ) return E_FAIL; cMessage::cFieldList::iterator i = static_cast< ImplT * >( this )->getSource()->m_fields.begin() + m_dwIterator; *pstrName = SysAllocString( i->m_pSchema->m_strName ); return S_OK; } STDMETHOD(get_Index)( long *pnIndex ) { if( pnIndex == NULL ) { _ASSERT( FALSE ); return E_POINTER; } if( m_dwIterator == eEndIndex ) return E_FAIL; *pnIndex = m_nIndex; return S_OK; } STDMETHOD(get_Next)( VARIANT vIndex, LPVARIANT pvValue ) { if( pvValue == NULL ) { _ASSERT( FALSE ); return E_POINTER; } HRESULT hRes; if( vIndex.vt == VT_ERROR ) // Error value indicates the optional value was not filled hRes = advanceNext(); else if( vIndex.vt == VT_BSTR ) hRes = advanceToName( vIndex.bstrVal ); else { // Try and convert it to a long HRESULT hResConv = ::VariantChangeType( &vIndex, &vIndex, 0, VT_I4 ); if( FAILED( hResConv ) ) { _ASSERT( FALSE ); return E_INVALIDARG; } hRes = advanceToIndex( vIndex.lVal ); } if( hRes == S_FALSE ) { pvValue->vt = VT_NULL; return hRes; } cMessage::cFieldList::iterator i = static_cast< ImplT * >( this )->getSource()->m_fields.begin() + m_dwIterator; i->m_pSchema->getValue( static_cast< ImplT * >( this )->getSource(), i, pvValue ); return S_OK; } STDMETHOD(get_NextString)(BSTR Name, BSTR *pValue) { VARIANT v; v.vt = VT_BSTR; v.bstrVal = Name; VARIANT vOut; HRESULT hRes = get_Next( v, &vOut ); if( hRes == S_FALSE ) return E_FAIL; if( vOut.vt != VT_BSTR ) { _ASSERT( FALSE ); return E_FAIL; } *pValue = vOut.bstrVal; return S_OK; } STDMETHOD(get_NextInt)(BSTR Name, long *pValue) { VARIANT v; v.vt = VT_BSTR; v.bstrVal = Name; VARIANT vOut; HRESULT hRes = get_Next( v, &vOut ); if( hRes == S_FALSE ) return E_FAIL; if( vOut.vt == VT_I4 ) *pValue = vOut.lVal; else if( vOut.vt == VT_I2 ) *pValue = vOut.iVal; else if ( vOut.vt == VT_UI1 ) *pValue = vOut.bVal; else { _ASSERT( FALSE ); return E_FAIL; } return S_OK; } STDMETHOD(get_NextFloat)(BSTR Name, float *pValue) { VARIANT v; v.vt = VT_BSTR; v.bstrVal = Name; VARIANT vOut; HRESULT hRes = get_Next( v, &vOut ); if( hRes == S_FALSE ) return E_FAIL; if( vOut.vt == VT_R4 ) *pValue = vOut.fltVal; else if( vOut.vt == VT_R8 ) *pValue = static_cast< float >( vOut.dblVal ); else { _ASSERT( FALSE ); return E_FAIL; } return S_OK; } STDMETHOD(get_NextObject)(BSTR Name, IMessageIterator **pValue) { VARIANT v; v.vt = VT_BSTR; v.bstrVal = Name; VARIANT vOut; HRESULT hRes = get_Next( v, &vOut ); if( hRes == S_FALSE ) return E_FAIL; if( vOut.vt != VT_DISPATCH ) { _ASSERT( FALSE ); return E_FAIL; } return vOut.pdispVal->QueryInterface ( pValue ); } STDMETHOD(get_NextObjectIndex)(IMessageIterator **pValue) { VARIANT v; v.vt = VT_ERROR; CComVariant vOut; HRESULT hRes = get_Next( v, &vOut ); if( hRes == S_FALSE ) return E_FAIL; if( vOut.vt != VT_DISPATCH ) { _ASSERT( FALSE ); return E_FAIL; } return vOut.pdispVal->QueryInterface ( pValue ); } STDMETHOD(Reset)() { m_nIndex = -1; return S_OK; } STDMETHOD(get_Message)(IMessage **ppMessage) { if( ppMessage == NULL ) { _ASSERT( FALSE ); return E_POINTER; } static_cast< ImplT * >( this )->getSource()->QueryInterface( IID_IMessage, reinterpret_cast< void ** >( ppMessage ) ); return S_OK; } }; class IMessageIteratorSublistImpl : public IMessageIteratorImpl< IMessageIteratorSublistImpl > { public: cMessage *m_pSource; DWORD m_dwStartIndex, m_dwEndIndex; cMessage *getSource() { return m_pSource; } DWORD getStartIndex() { return m_dwStartIndex; } DWORD getEndIndex() { return m_dwEndIndex; } void init( cMessage *pMessage, DWORD dwStructIndex ) { m_pSource = pMessage; m_dwStartIndex = dwStructIndex + 1; m_dwEndIndex = dwStructIndex + ( m_pSource->m_fields.begin() + dwStructIndex )->m_nOwns; IMessageIteratorImpl< IMessageIteratorSublistImpl >::init(); } }; #endif