//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997. // // File: E N U M . C P P // // Contents: Enumerator for connection objects. // // Notes: // // Author: shaunco 21 Sep 1997 // //---------------------------------------------------------------------------- #include "pch.h" #pragma hdrstop #include "enum.h" #include "nccom.h" //+--------------------------------------------------------------------------- // // Member: CConnectionManagerEnumConnection::CreateInstance // // Purpose: Creates the connection manager's implementation of // a connection enumerator. // // Arguments: // Flags [in] // vecClassManagers [in] // riid [in] // ppv [out] // // Returns: S_OK or an error code. // // Author: shaunco 22 Sep 1997 // // Notes: // HRESULT CConnectionManagerEnumConnection::CreateInstance ( NETCONMGR_ENUM_FLAGS Flags, CLASSMANAGERMAP& mapClassManagers, REFIID riid, void** ppv) { TraceFileFunc(ttidConman); HRESULT hr = E_OUTOFMEMORY; CConnectionManagerEnumConnection* pObj; pObj = new CComObject ; if (pObj) { // Initialize our members. // pObj->m_EnumFlags = Flags; // Copy the array of class managers and AddRef them since // we will be holding on to them. // pObj->m_mapClassManagers = mapClassManagers; for (CLASSMANAGERMAP::iterator iter = pObj->m_mapClassManagers.begin(); iter != pObj->m_mapClassManagers.end(); iter++) { AddRefObj (iter->second); } pObj->m_iterCurClassMgr = pObj->m_mapClassManagers.begin(); // Do the standard CComCreator::CreateInstance stuff. // pObj->SetVoid (NULL); pObj->InternalFinalConstructAddRef (); hr = pObj->FinalConstruct (); pObj->InternalFinalConstructRelease (); if (SUCCEEDED(hr)) { hr = pObj->QueryInterface (riid, ppv); } if (FAILED(hr)) { delete pObj; } } return hr; } //+--------------------------------------------------------------------------- // // Member: CConnectionManagerEnumConnection::FinalRelease // // Purpose: COM Destructor. // // Arguments: // (none) // // Returns: nothing // // Author: shaunco 22 Sep 1997 // // Notes: // void CConnectionManagerEnumConnection::FinalRelease () { TraceFileFunc(ttidConman); // Release the current enumerator if we have one. // ReleaseObj (m_penumCurClassMgr); // Release our class managers. // for (CLASSMANAGERMAP::iterator iter = m_mapClassManagers.begin(); iter != m_mapClassManagers.end(); iter++) { ReleaseObj (iter->second); } } //+--------------------------------------------------------------------------- // IEnumNetConnection // // See documentation in MSDN for any IEnumXXX interface. // STDMETHODIMP CConnectionManagerEnumConnection::Next ( ULONG celt, INetConnection** rgelt, ULONG* pceltFetched) { TraceFileFunc(ttidConman); HRESULT hr; ULONG celtFetched; // Validate parameters. // if (!rgelt || (!pceltFetched && (1 != celt))) { hr = E_POINTER; goto finished; } // Important to initialize rgelt so that in case we fail, we can // release only what we put in rgelt. // ZeroMemory (rgelt, sizeof (*rgelt) * celt); // Ask the current class manager to fulfill the request. If he only // partially does, move to the next class manager. Do this until // the request is fulfilled, or we run out of class managers. // celtFetched = 0; hr = S_FALSE; { // begin lock scope CExceptionSafeComObjectLock EsLock (this); while ((S_FALSE == hr) && (celtFetched < celt) && (m_iterCurClassMgr != m_mapClassManagers.end())) { // Get the connection enumerator from the current class manager // if neccesary. // if (!m_penumCurClassMgr) { INetConnectionManager* pConMan = m_iterCurClassMgr->second; Assert (pConMan); hr = pConMan->EnumConnections (m_EnumFlags, &m_penumCurClassMgr); } if (SUCCEEDED(hr)) { Assert (m_penumCurClassMgr); // Each class manager should request only what was reqeuested // less what has already been fetched. // ULONG celtT; hr = m_penumCurClassMgr->Next (celt - celtFetched, rgelt + celtFetched, &celtT); if (SUCCEEDED(hr)) { celtFetched += celtT; // If the current class manager couldn't fill the entire // request, go to the next one. // if (S_FALSE == hr) { ReleaseCurrentClassEnumerator (); Assert (!m_penumCurClassMgr); m_iterCurClassMgr++; } } } } Assert (FImplies (S_OK == hr, (celtFetched == celt))); } // end lock scope if (SUCCEEDED(hr)) { TraceTag (ttidConman, "Enumerated %d total connections", celtFetched); if (pceltFetched) { *pceltFetched = celtFetched; } hr = (celtFetched == celt) ? S_OK : S_FALSE; } else { // For any failures, we need to release what we were about to return. // Set any output parameters to NULL. // for (ULONG ulIndex = 0; ulIndex < celt; ulIndex++) { ReleaseObj (rgelt[ulIndex]); rgelt[ulIndex] = NULL; } if (pceltFetched) { *pceltFetched = 0; } } finished: TraceErrorOptional ("CConnectionManagerEnumConnection::Next", hr, (S_FALSE == hr)); return hr; } STDMETHODIMP CConnectionManagerEnumConnection::Skip ( ULONG celt) { TraceFileFunc(ttidConman); // Unfortunately, this method doesn't return the number of objects // actually skipped. To implement this correctly across the multiple // class managers, we'd need to know how many they skipped similiar // to the way we implement Next. // // So, we'll cheese out and implement this by actually calling // Next for the reqested number of elements and just releasing what // we get back. // HRESULT hr = S_OK; if (celt) { INetConnection** rgelt; CExceptionSafeComObjectLock EsLock (this); hr = E_OUTOFMEMORY; rgelt = (INetConnection**)MemAlloc(celt * sizeof(INetConnection*)); if (rgelt) { ULONG celtFetched; hr = Next (celt, rgelt, &celtFetched); if (SUCCEEDED(hr)) { ReleaseIUnknownArray (celtFetched, (IUnknown**)rgelt); } MemFree (rgelt); } } TraceErrorOptional ("CConnectionManagerEnumConnection::Skip", hr, (S_FALSE == hr)); return hr; } STDMETHODIMP CConnectionManagerEnumConnection::Reset () { TraceFileFunc(ttidConman); CExceptionSafeComObjectLock EsLock (this); ReleaseCurrentClassEnumerator (); m_iterCurClassMgr = m_mapClassManagers.begin(); return S_OK; } STDMETHODIMP CConnectionManagerEnumConnection::Clone ( IEnumNetConnection** ppenum) { TraceFileFunc(ttidConman); HRESULT hr = E_OUTOFMEMORY; // Validate parameters. // if (!ppenum) { hr = E_POINTER; } else { // Initialize output parameter. // *ppenum = NULL; CConnectionManagerEnumConnection* pObj; pObj = new CComObject ; if (pObj) { hr = S_OK; CExceptionSafeComObjectLock EsLock (this); // Initialize our members. // pObj->m_EnumFlags = m_EnumFlags; // Copy the array of class managers and AddRef them since // we will be holding on to them. // pObj->m_mapClassManagers = m_mapClassManagers; for (CLASSMANAGERMAP::iterator iter = m_mapClassManagers.begin(); iter != m_mapClassManagers.end(); iter++) { AddRefObj (iter->second); } // The current class manager index need to be copied. // pObj->m_iterCurClassMgr = pObj->m_mapClassManagers.find(m_iterCurClassMgr->first); // Important to clone (not copy) the current class enumerator // if we have one. // if (m_penumCurClassMgr) { hr = m_penumCurClassMgr->Clone (&pObj->m_penumCurClassMgr); } if (SUCCEEDED(hr)) { // Return the object with a ref count of 1 on this // interface. pObj->m_dwRef = 1; *ppenum = pObj; } if (FAILED(hr)) { delete pObj; } } } TraceErrorOptional ("CConnectionManagerEnumConnection::Clone", hr, (S_FALSE == hr)); return hr; }