////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 1999-2002 Microsoft Corporation // // Module Name: // EnumCPINotifyUI.cpp // // Description: // INotifyUI Connection Point Enumerator implementation. // // Maintained By: // David Potter (DavidP) 14-JUN-2001 // Geoffrey Pease (GPease) 04-AUG-2000 // ////////////////////////////////////////////////////////////////////////////// #include "Pch.h" #include "EnumCPINotifyUI.h" DEFINE_THISCLASS("CEnumCPINotifyUI") #define PUNK_BUFFER_GROW_SIZE 10 //*************************************************************************// ///////////////////////////////////////////////////////////////////////////// // CEnumCPINotifyUI class ///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //++ // // CEnumCPINotifyUI::S_HrCreateInstance // // Description: // Create a CEnumCPINotifyUI instance. // // Arguments: // None. // // Return Values: // S_OK // Success. // // E_POINTER // The passed in ppunk is NULL. // // other HRESULTs // Object creation failed. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CEnumCPINotifyUI::S_HrCreateInstance( IUnknown ** ppunkOut ) { TraceFunc( "" ); HRESULT hr = S_OK; CEnumCPINotifyUI * pecnui = NULL; Assert( ppunkOut != NULL ); if ( ppunkOut == NULL ) { hr = THR( E_POINTER ); goto Cleanup; } // if: pecnui = new CEnumCPINotifyUI(); if ( pecnui == NULL ) { hr = THR( E_OUTOFMEMORY ); goto Cleanup; } // if: hr = THR( pecnui->HrInit() ); // fIsCloneIn = FALSE if ( FAILED( hr ) ) { goto Cleanup; } // if: hr = THR( pecnui->TypeSafeQI( IUnknown, ppunkOut ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: Cleanup: if ( pecnui != NULL ) { pecnui->Release(); } // if: HRETURN( hr ); } //*** CEnumCPINotifyUI::S_HrCreateInstance ////////////////////////////////////////////////////////////////////////////// //++ // // CEnumCPINotifyUI::CEnumCPINotifyUI // // Description: // Default constructor. // // Arguments: // None. // // Return Values: // None. // //-- ////////////////////////////////////////////////////////////////////////////// CEnumCPINotifyUI::CEnumCPINotifyUI( void ) : m_cRef( 1 ) { TraceFunc( "" ); InterlockedIncrement( &g_cObjects ); TraceFuncExit(); } //*** CEnumCPINotifyUI::CEnumCPINotifyUI ////////////////////////////////////////////////////////////////////////////// //++ // // CEnumCPINotifyUI::~CEnumCPINotifyUI // // Description: // Destructor. // // Arguments: // None. // // Return Values: // None. // //-- ////////////////////////////////////////////////////////////////////////////// CEnumCPINotifyUI::~CEnumCPINotifyUI( void ) { TraceFunc( "" ); IUnknown * punk = NULL; if ( m_pList != NULL ) { while ( m_cAlloced != 0 ) { m_cAlloced --; punk = m_pList[ m_cAlloced ]; AssertMsg( m_fIsClone || punk == NULL, "Someone didn't Unadvise before releasing the last Reference." ); if ( punk != NULL ) { punk->Release(); } // if: } // while: m_cAlloced TraceFree( m_pList ); } // if: InterlockedDecrement( &g_cObjects ); TraceFuncExit(); } //*** CEnumCPINotifyUI::~CEnumCPINotifyUI //*************************************************************************// ///////////////////////////////////////////////////////////////////////////// // CEnumCPINotifyUI -- IUnknown interface. ///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //++ // // CEnumCPINotifyUI::AddRef // // Description: // Increment the reference count of this object by one. // // Arguments: // None. // // Return Value: // The new reference count. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_(ULONG) CEnumCPINotifyUI::AddRef( void ) { TraceFunc( "[IUnknown]" ); InterlockedIncrement( &m_cRef ); CRETURN( m_cRef ); } //*** CEnumCPINotifyUI::AddRef ////////////////////////////////////////////////////////////////////////////// //++ // // CTaskCancelCleanup::Release // // Description: // Decrement the reference count of this object by one. // // Arguments: // None. // // Return Value: // The new reference count. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP_(ULONG) CEnumCPINotifyUI::Release( void ) { TraceFunc( "[IUnknown]" ); LONG cRef; cRef = InterlockedDecrement( &m_cRef ); if ( cRef == 0 ) { TraceDo( delete this ); } // if: CRETURN( cRef ); } //*** CEnumCPINotifyUI::Release ////////////////////////////////////////////////////////////////////////////// //++ // // CEnumCPINotifyUI::QueryInterface // // Description: // Query this object for the passed in interface. // // Arguments: // riidIn // Id of interface requested. // // ppvOut // Pointer to the requested interface. // // Return Value: // S_OK // If the interface is available on this object. // // E_NOINTERFACE // If the interface is not available. // // E_POINTER // ppvOut was NULL. // // Remarks: // None. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CEnumCPINotifyUI::QueryInterface( REFIID riidIn , LPVOID * ppvOut ) { TraceQIFunc( riidIn, ppvOut ); HRESULT hr = S_OK; // // Validate arguments. // Assert( ppvOut != NULL ); if ( ppvOut == NULL ) { hr = THR( E_POINTER ); goto Cleanup; } // if: // // Handle known interfaces. // if ( IsEqualIID( riidIn, IID_IUnknown ) ) { *ppvOut = static_cast< IEnumConnections * >( this ); } // if: IUnknown else if ( IsEqualIID( riidIn, IID_IEnumConnections ) ) { *ppvOut = TraceInterface( __THISCLASS__, IEnumConnections, this, 0 ); } // else if: IEnumConnections else { *ppvOut = NULL; hr = E_NOINTERFACE; } // else // // Add a reference to the interface if successful. // if ( SUCCEEDED( hr ) ) { ((IUnknown *) *ppvOut)->AddRef(); } // if: success Cleanup: QIRETURN_IGNORESTDMARSHALLING( hr, riidIn ); } //*** CEnumCPINotifyUI::QueryInterface //*************************************************************************// ///////////////////////////////////////////////////////////////////////////// // CEnumCPINotifyUI -- IEnumConnectionPoints interface. ///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //++ // // CEnumCPINotifyUI::Next // // Description: // Enumerator Next method. // // Arguments: // cConnectionsIn // How many items requested. Also tells us how bing rgcd. // // rgcdOut // Array that gets the data. // // pcFetchedOut // How many did we place in the array. // // Return Values: // S_OK // Success. // // S_FALSE // cConnectionsIn > *pcFetchedOut. Did not return as many items // as the caller asked for. // // Other HRESULT errors. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CEnumCPINotifyUI::Next( ULONG cConnectionsIn , LPCONNECTDATA rgcdOut , ULONG * pcFetchedOut ) { TraceFunc( "[IEnumConnectionPoints]" ); ULONG cIter; HRESULT hr = S_FALSE; if ( pcFetchedOut != NULL ) { *pcFetchedOut = 0; } // if: for( cIter = 0 ; ( cIter < cConnectionsIn ) && ( m_cIter < m_cCurrent ) ; m_cIter ++ ) { IUnknown * punk = m_pList[ m_cIter ]; if ( punk != NULL ) { hr = THR( punk->TypeSafeQI( IUnknown, &rgcdOut[ cIter ].pUnk ) ); if ( FAILED( hr ) ) { goto Error; } // if: rgcdOut[ cIter ].pUnk = TraceInterface( L"EnumCPINotifyUI!IUnknown", IUnknown, rgcdOut[ cIter ].pUnk, 1 ); rgcdOut[ cIter ].dwCookie = m_cIter + 1; cIter ++; } // if: } // for: cIter if ( cIter != cConnectionsIn ) { hr = S_FALSE; } // if: else { hr = S_OK; } // else: if ( pcFetchedOut != NULL ) { *pcFetchedOut = cIter; } // if: Cleanup: HRETURN( hr ); Error: while ( cIter != 0 ) { cIter--; rgcdOut[ cIter ].pUnk->Release(); } // while: goto Cleanup; } //*** CEnumCPINotifyUI::Next ////////////////////////////////////////////////////////////////////////////// //++ // // CEnumCPINotifyUI::Skip // // Description: // Enumerator Skip method. // // Arguments: // cConnectionsIn // Number of items to skip. // // Return Values: // S_OK // Success. // // S_FALSE // The number to skip put us at the end of the list. // // Other HRESULT errors. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CEnumCPINotifyUI::Skip( ULONG cConnectionsIn ) { TraceFunc( "[IEnumConnectionPoints]" ); HRESULT hr = S_OK; m_cIter += cConnectionsIn; if ( m_cIter >= m_cCurrent ) { m_cIter = m_cCurrent; hr = S_FALSE; } // if: HRETURN( hr ); } //*** CEnumCPINotifyUI::Skip ////////////////////////////////////////////////////////////////////////////// //++ // // CEnumCPINotifyUI::Reset // // Description: // Enumerator Reset method. // // Arguments: // None. // // Return Values: // S_OK // Success. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CEnumCPINotifyUI::Reset( void ) { TraceFunc( "[IEnumConnectionPoints]" ); HRESULT hr = S_OK; m_cIter = 0; HRETURN( hr ); } //*** CEnumCPINotifyUI::Reset ////////////////////////////////////////////////////////////////////////////// //++ // // CEnumCPINotifyUI::Clone // // Description: // Enumerator Clone method. // // Arguments: // ppEnumOut // The new enumerator that we are cloning ourselves into. // // Return Values: // S_OK // Success. // // Other HRESULT errors. // //-- ////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CEnumCPINotifyUI::Clone( IEnumConnections ** ppEnumOut ) { TraceFunc( "[IEnumConnectionPoints]" ); HRESULT hr = S_OK; CEnumCPINotifyUI * pecp = new CEnumCPINotifyUI(); if ( pecp == NULL ) { hr = THR( E_OUTOFMEMORY ); goto Cleanup; } // if: hr = THR( pecp->HrInit( TRUE ) ); // fIsCloneIn = TRUE if ( FAILED( hr ) ) { goto Cleanup; } // if: hr = THR( pecp->HrCopy( this ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: hr = THR( pecp->TypeSafeQI( IEnumConnections, ppEnumOut ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: *ppEnumOut = TraceInterface( L"EnumCPINotifyUI!IEnumConnections", IEnumConnections, *ppEnumOut, 1 ); pecp->Release(); pecp = NULL; Cleanup: if ( pecp != NULL ) { delete pecp; } // if: HRETURN( hr ); } //*** CEnumCPINotifyUI::Clone //*************************************************************************// ///////////////////////////////////////////////////////////////////////////// // CEnumCPINotifyUI -- Public methods. ///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //++ // // CEnumCPINotifyUI::HrAddConnection // // Description: // Add a connection point container to our list of clients. // // Arguments: // punkIn // The new client object. // // pdwCookieOut // Cookie used to find this client object in our list. // // Return Values: // S_OK // Success. // // Other HRESULT errors. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CEnumCPINotifyUI::HrAddConnection( IUnknown * punkIn , DWORD * pdwCookieOut ) { TraceFunc( "" ); HRESULT hr = S_FALSE; ULONG cIter; if ( pdwCookieOut == NULL ) { hr = THR( E_POINTER ); goto Cleanup; } // if: // // See if there is an openning in the currently allocated list. // for ( cIter = 0; cIter < m_cCurrent; cIter ++ ) { if ( m_pList[ cIter ] == NULL ) { // // Found an openning... try to use it. // hr = THR( punkIn->TypeSafeQI( IUnknown, &m_pList[ cIter ] ) ); m_pList[ cIter ] = TraceInterface( L"CEnumCPINotifyUI!IUnknown", IUnknown, m_pList[ cIter ], 1 ); *pdwCookieOut = cIter + 1; // Doesn't matter if it succeeded or fail, exit. goto Cleanup; } // if: } // for: if ( m_cCurrent == m_cAlloced ) { IUnknown ** pNewList; // // Try making some more space. // pNewList = (IUnknown **) TraceAlloc( HEAP_ZERO_MEMORY, ( m_cAlloced + PUNK_BUFFER_GROW_SIZE ) * sizeof( IUnknown * ) ); if ( pNewList == NULL ) { hr = THR( E_OUTOFMEMORY ); goto Cleanup; } CopyMemory( pNewList, m_pList, m_cCurrent * sizeof( IUnknown * ) ); TraceFree( m_pList ); m_pList = pNewList; m_cAlloced += PUNK_BUFFER_GROW_SIZE; } // if: // // Add it to the list. // hr = THR( punkIn->TypeSafeQI( IUnknown, &m_pList[ m_cCurrent ] ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: m_pList[ m_cCurrent ] = TraceInterface( L"CEnumCPINotifyUI!IUnknown", IUnknown, m_pList[ m_cCurrent ], 1 ); m_cCurrent ++; *pdwCookieOut = m_cCurrent; // starts at ONE, not ZERO Cleanup: HRETURN( hr ); } //*** CEnumCPINotifyUI::HrAddConnection ////////////////////////////////////////////////////////////////////////////// //++ // // CEnumCPINotifyUI::HrRemoveConnection // // Description: // Remove the client identified by the passed in cookie from the list. // // Arguments: // dwCookieIn // The cookie of the client that is to be removed from the list. // // Return Values: // S_OK // Success. // // Other HRESULT errors. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CEnumCPINotifyUI::HrRemoveConnection( DWORD dwCookieIn ) { TraceFunc( "" ); HRESULT hr; if ( dwCookieIn == 0 || dwCookieIn > m_cCurrent ) { hr = THR( E_INVALIDARG ); goto Cleanup; } // if: if ( m_pList[ dwCookieIn - 1 ] == NULL ) { hr = THR( E_INVALIDARG ); goto Cleanup; } // if: m_pList[ dwCookieIn - 1 ]->Release(); m_pList[ dwCookieIn - 1 ] = NULL; hr = S_OK; Cleanup: HRETURN( hr ); } //*** CEnumCPINotifyUI::HrRemoveConnection //*************************************************************************// ///////////////////////////////////////////////////////////////////////////// // CEnumCPINotifyUI -- Private methods. ///////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //++ // // CEnumCPINotifyUI::HrInt // // Description: // Do any initialization that may fail here. // // Arguments: // fIsCloneIn // Is this instance a clone? // // Return Values: // S_OK // Success. // // Other HRESULT errors. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CEnumCPINotifyUI::HrInit( BOOL fIsCloneIn // = FALSE ) { TraceFunc( "" ); // IUnknown stuff Assert( m_cRef == 1 ); // IEnumConnectionPoints Assert( m_cAlloced == 0 ); Assert( m_cCurrent == 0 ); Assert( m_cIter == 0 ); Assert( m_pList == NULL ); Assert( m_fIsClone == FALSE ); m_fIsClone = fIsCloneIn; // INotifyUI HRETURN( S_OK ); } //*** CEnumCPINotifyUI::HrInit ////////////////////////////////////////////////////////////////////////////// //++ // // CEnumCPINotifyUI::HrCopy // // Description: // Copy from the passed in enumerator. // // Arguments: // pecpIn // The source that we are to copy from. // // Return Values: // S_OK // Success. // // Other HRESULT errors. // //-- ////////////////////////////////////////////////////////////////////////////// HRESULT CEnumCPINotifyUI::HrCopy( CEnumCPINotifyUI * pecpIn ) { TraceFunc( "" ); HRESULT hr = S_FALSE; ULONG cIter; Assert( m_cAlloced == 0 ); Assert( m_cCurrent == 0 ); Assert( m_pList == NULL ); m_pList = (IUnknown **) TraceAlloc( HEAP_ZERO_MEMORY, pecpIn->m_cCurrent * sizeof( IUnknown * ) ); if ( m_pList == NULL ) { hr = THR( E_OUTOFMEMORY ); goto Cleanup; } // if: m_cCurrent = m_cAlloced = pecpIn->m_cCurrent; m_cIter = 0; for ( cIter = 0; cIter < pecpIn->m_cCurrent; cIter++ ) { // // Does the source have a pointer at the current index? If it does then "copy" it, // otherwise NULL out that index in our copy... // if ( pecpIn->m_pList[ cIter ] != NULL ) { hr = THR( pecpIn->m_pList[ cIter ]->TypeSafeQI( IUnknown, &m_pList[ cIter ] ) ); if ( FAILED( hr ) ) { goto Cleanup; } // if: m_pList[ cIter ] = TraceInterface( L"EnumCPINotifyUI!IUnknown", IUnknown, m_pList[ cIter ], 1 ); } // if: else { m_pList[ cIter ] = NULL; } // else: } // for: hr = S_OK; Cleanup: HRETURN( hr ); } //*** CEnumCPINotifyUI::HrCopy