//==========================================================================; // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR // PURPOSE. // // Copyright (c) 1992 - 1998 Microsoft Corporation. All Rights Reserved. // //--------------------------------------------------------------------------; // AnyEnum // Copy(ish) constructor // For reasons of performance, we tend to pass a HRESULT * and set this if anything // goes wrong, rather than resort to C++ exception handling. The instantiator is // responsible for checking the HRESULT and deleting us if we're deemed worthless. template AnyEnum::AnyEnum( const AnyEnum & copy, HRESULT * phr ) : m_cRef(1) { *phr = copy.m_pIEnum->Clone( &m_pIEnum ); } // Our QueryInterface is a little degenerate. We will give back an IUnknown, // but we can't actually tell the IID of the IEnum we are covering, so we can't // (easily) check that say, IID_IEnumPins, is realy us. If you try and get // anything other than an IUnknown, we'll tell you to E_NOINTERFACE. template STDMETHODIMP AnyEnum::QueryInterface( REFIID iid, void ** ppv ) { HRESULT hr = S_OK; if (ppv) { *ppv = 0; if ( iid == IID_IUnknown ) *ppv = static_cast(this); else hr = E_NOINTERFACE; if ( *ppv ) AddRef(); } else hr = E_POINTER; return E_UNEXPECTED; } template STDMETHODIMP_(ULONG) AnyEnum::AddRef() { return InterlockedIncrement(&m_cRef); } template STDMETHODIMP_(ULONG) AnyEnum::Release() { const ULONG count = InterlockedDecrement(&m_cRef); if (count==0) delete this; return count; } // Delagate Next() to our inner IEnum template STDMETHODIMP AnyEnum::Next( ULONG cBase, BaseType ** ppBase, ULONG * pcFetched ) { return m_pIEnum->Next( cBase, ppBase, pcFetched ); } // Delagate Skip() to our inner IEnum template STDMETHODIMP AnyEnum::Skip( ULONG cBase ) { return m_pIEnum->Skip(cBase); } // Delagate Reset() to our inner IEnum template STDMETHODIMP AnyEnum::Reset( void ) { return m_pIEnum->Reset(); } // Our Clone() method clones the outer, then clones the inner. // This method will have to be overriden in derived classes // that introduce new attributes. template STDMETHODIMP AnyEnum::Clone( IEnum ** ppEnum ) { return CloneAny( *this, ppEnum ); } // ConstrictedEnum // This is the meat. We must retrieve BaseObjects individually and only pass them back to // our caller if they meet Select's criteria (whatever that might be). pcFetched must be a // pointer to a ULONG. ppBase may be null, in which case we don't pass back any objects, we // merely count them (this is mainly for the benefit of Skip()). template STDMETHODIMP ConstrictedEnum::Next( ULONG cBase, BaseType ** ppBase, ULONG * pcFetched ) { HRESULT hr = S_OK; BaseType * lcl_pBase; ULONG lcl_fetched; if ( pcFetched ) { *pcFetched = 0; while ( cBase > *pcFetched ) { hr = m_pIEnum->Next( 1, &lcl_pBase, &lcl_fetched ); if (FAILED(hr)) break; if (lcl_fetched == 0) break; if ( Select( &lcl_pBase ) ) { // Yes, client wants it counted ++*pcFetched; // Does client want the pointers? if ( ppBase ) { // yes *ppBase = lcl_pBase; ++ppBase; } else lcl_pBase->Release(); } else { // Select doesn't want it, throw it away! lcl_pBase->Release(); } } } else hr = E_POINTER; return hr; } // We can't use our inherited or inner Skip(), since these won't honour // Select()'s selection criteria. template STDMETHODIMP ConstrictedEnum::Skip( ULONG cBase ) { ULONG cFetched; return Next( cBase, 0, &cFetched ); } template STDMETHODIMP ConstrictedEnum::Skip( ULONG cBase, ULONG * pcCount ) { return Next( cBase, 0, pcCount ); } // CImpIEnumFilters BOOL CImpIEnumFilters::Select( IBaseFilter ** ppIFilter ) { ASSERT( ppIFilter ); void * this_interface; const BOOL result = SUCCEEDED((*ppIFilter)->QueryInterface( m_iid, &this_interface )); if ( result ) { (*ppIFilter)->Release(); (*ppIFilter) = reinterpret_cast(this_interface); } return result; } STDMETHODIMP CImpIEnumFilters::Clone( IEnumFilters ** ppEnum ) { return CloneAny( *this, ppEnum ); } // CImpIEnumUnconnectedFilters BOOL CImpIEnumUnconnectedFilters::Select( IBaseFilter ** ppIFilter ) { HRESULT hr; BOOL connected = FALSE; IBaseFilter & iFilter = **ppIFilter; IEnumPins * pIEnumPins = 0; hr = iFilter.EnumPins( &pIEnumPins ); do { IPin *pIPin, *pConnectedToPin; ULONG fetched; hr = pIEnumPins->Next( 1, &pIPin, &fetched ); if FAILED(hr) break; if ( fetched != 1 ) break; pIPin->ConnectedTo( &pConnectedToPin ); if (pConnectedToPin) { connected = TRUE; pConnectedToPin->Release(); } pIPin->Release(); } while (!connected); pIEnumPins->Release(); return !connected; } STDMETHODIMP CImpIEnumUnconnectedFilters::Clone( IEnumFilters ** ppEnum ) { return CloneAny( *this, ppEnum ); } // CImpIEnumPins template BOOL CImpIEnumPins::Select( IPin ** ppIPin ) { HRESULT hr; PIN_INFO PinInfo; hr = (*ppIPin)->QueryPinInfo( &PinInfo ); ASSERT( SUCCEEDED(hr) ); return PinInfo.dir == DIR; } template STDMETHODIMP CImpIEnumPins::Clone( IEnumPins ** ppEnum ) { return CloneAny( *this, ppEnum ); } // CImpIEnumOverGraph // This is the meat. We must retrieve BaseObjects individually and only pass them back to // our caller if the meet Select's criteria (whatever that might be). When we've exhausted // one filter, we call NextFilter() to go to the next one. template STDMETHODIMP CImpIEnumOverGraph::Next( ULONG cBase, IPin ** ppBase, ULONG *pcFetched ) { HRESULT hr; ULONG lcl_fetched; *pcFetched = 0; if (m_pIEnum) { m_crit_sec.Lock(); while ( cBase > 0 ) { hr = EnumPinClass::Next( cBase, ppBase, &lcl_fetched ); if (FAILED(hr)) break; cBase -= lcl_fetched; *pcFetched += lcl_fetched; ppBase += lcl_fetched; if ( hr==S_FALSE ) { hr = NextFilter(); if ( hr != NOERROR ) break; } } m_crit_sec.Unlock(); } else hr = m_hr; return hr; } // This method jumps us between filters template HRESULT CImpIEnumOverGraph::NextFilter() { if (m_pIEnum) { HRESULT hr; hr = m_pIEnum->Release(); ASSERT( SUCCEEDED(hr) ); m_pIEnum = 0; } IBaseFilter * pIFilter; ULONG lcl_count; m_hr = m_pIEnumFilters->Next( 1, &pIFilter, &lcl_count ); ASSERT( SUCCEEDED(m_hr) ); if ( m_hr == NOERROR ) { ASSERT( lcl_count == 1 ); m_hr = pIFilter->EnumPins( &m_pIEnum ); ASSERT( SUCCEEDED(m_hr) ); pIFilter->Release(); } return m_hr; } template STDMETHODIMP CImpIEnumOverGraph::Reset( void ) { m_hr = m_pIEnumFilters->Reset(); if SUCCEEDED(m_hr) NextFilter(); return m_hr; } template STDMETHODIMP CImpIEnumOverGraph::Clone( IEnumPins ** ppEnum ) { return CloneAny( *this, ppEnum ); }