//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997 - 1998 // // File: N C C O M . H // // Contents: Common routines for dealing with COM. // // Notes: // // Author: shaunco 25 Jan 1998 // //---------------------------------------------------------------------------- #pragma once #ifndef _NCCOM_H_ #define _NCCOM_H_ #include "ncutil.h" HRESULT HrCoTaskMemAlloc ( ULONG cb, void** ppv); HRESULT HrCoTaskMemAllocAndDupSz ( LPCWSTR pszwSrc, LPWSTR* ppszwDst); //------------------------------------------------------------------------ // CIEnumIter - template iterator for IEnumIUnknown // // Tenum is of type IEnumXXX (the enumeration interface) // Telt is of type XXX (the type of the element being enumerated) // // HrNext(Telt* pelt) retreives next interface pointer and returns S_OK // if it is non-null. S_FALSE is returned if *pelt is null (at end of list). // An error code will be returned for other failures (and *pelt will be // null of course.) // template class CIEnumIter { public: CIEnumIter (Tenum* penum) NOTHROW; ~CIEnumIter () NOTHROW { ReleaseRemainingBatch (); } HRESULT HrNext(Telt* pelt) NOTHROW; void SetEnumerator(Tenum* penum) NOTHROW { /*AssertSzH(!m_penum, "Enumerator already set."); */ m_penum = penum; /*AssertSzH(m_penum, "Can't use a null enumerator."); */} protected: void ReleaseRemainingBatch () NOTHROW; Tenum* m_penum; // pointer to the enumerator. not addref'd. Telt* m_aelt; // array of enumerated types. Telt* m_peltNext; // pointer to next type to be returned. ULONG m_celtFetched; // number of elements fetched. HRESULT m_hrLast; // last error }; //------------------------------------------------------------------------ // CIEnumIter - template iterator for IEnumXXX // template inline CIEnumIter::CIEnumIter(Tenum* penum) { m_penum = penum; m_aelt = NULL; m_peltNext = NULL; m_celtFetched = NULL; m_hrLast = S_OK; } //+--------------------------------------------------------------------------- // // Member: CIEnumIter::HrNext // // Purpose: Returns the next item in the enumeration. // // Arguments: // pelt [out] Pointer to the returned elemnt. Null if not available. // // Returns: S_OK if *pelt is valid. S_FALSE if it is NULL. Error // otherwise. // // Author: shaunco 24 Mar 1997 // // Notes: // template inline HRESULT CIEnumIter::HrNext(Telt* pelt) NOTHROW { // AssertH(pelt); const ULONG c_celtBatch = 512; // If we failed for any reason before, return that failure. // if (FAILED(m_hrLast)) { *pelt = NULL; goto error; } // AssertSzH(m_penum, "m_penum is null. Did you forget to call SetEnumerator()?"); // AssertSzH(c_celtBatch, "c_celtBatch can't be zero."); // If we already have the next interface pointer, and we're // not at the end of the batch, return it and advance. // This if should be caught most of the time. // if (m_peltNext && (m_peltNext < m_aelt + m_celtFetched)) { *pelt = *m_peltNext; m_peltNext++; } // Otherwise, if we don't have the next interface pointer (first time), // or we're at the end of the batch, get the next batch and return // the first pointer in it. // This if should be caught the first time through. // else if (!m_peltNext || (m_celtFetched == c_celtBatch)) { // Indicate that m_peltNext is invalid. // m_peltNext = NULL; // Free the old block of pointers free (m_aelt); // Allocate the next block of pointers m_aelt = reinterpret_cast(malloc(c_celtBatch * sizeof(Telt *))); if (!m_aelt) { *pelt = NULL; m_hrLast = E_OUTOFMEMORY; goto error; } // Assert (m_aelt); // Get the next batch. // m_hrLast = m_penum->Next(c_celtBatch, m_aelt, &m_celtFetched); // Make sure the implementor of Next is obeying the rules. // AssertH (FImplies((S_OK == m_hrLast), (m_celtFetched == c_celtBatch))); // AssertH (FImplies((SUCCEEDED(m_hrLast) && (0 == m_celtFetched)), (NULL == *m_aelt))); // If we were successful, set the next pointer and return // S_OK if we returned a valid pointer or S_FALSE if we // returned NULL. // if (SUCCEEDED(m_hrLast)) { m_peltNext = m_aelt + 1; if (m_celtFetched) { *pelt = *m_aelt; m_hrLast = S_OK; } else { *pelt = NULL; m_hrLast = S_FALSE; } } else { *pelt = NULL; } } // Otherwise we've completely iterated the last batch and there are // no more batches. // else { // AssertH(m_peltNext >= m_aelt + m_celtFetched); // AssertH(m_celtFetched != c_celtBatch); *pelt = NULL; m_hrLast = S_FALSE; } error: // AssertH(FIff(S_OK == m_hrLast, NULL != *pelt)); // AssertH(FImplies(S_FALSE == m_hrLast, NULL == *pelt)); // TraceError("CIEnumIter::HrNext(Telt* pelt)", // (S_FALSE == m_hrLast) ? S_OK : m_hrLast); return m_hrLast; } template inline void CIEnumIter::ReleaseRemainingBatch () NOTHROW { // This needs to be run if the user doesn't completely iterate the // batch. Finish releasing the interface pointers and free the batch. // if (m_peltNext && m_aelt) { while (m_peltNext < m_aelt + m_celtFetched) { ReleaseObj (*m_peltNext); m_peltNext++; } free (m_aelt); } // If this method is ever called from anywhere other than just // the destructor, uncomment the following lines. // m_peltNext = NULL; // m_aelt = NULL; } #endif // _NCCOM_H_