//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1997. // // 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 "ncdefine.h" // for NOTHROW #include "ncstlstr.h" HRESULT HrCoTaskMemAlloc ( ULONG cb, VOID** ppv); HRESULT HrCoTaskMemAllocAndDupSzLen ( IN PCWSTR pszwSrc, IN ULONG cchSrc, OUT PWSTR* ppszwDst); HRESULT HrCoTaskMemAllocAndDupSz ( IN PCWSTR pszwSrc, OUT PWSTR* ppszwDst); VOID NcSetProxyBlanket ( IN IUnknown* pUnk); //+--------------------------------------------------------------------------- // // Function: ReleaseIUnknownArray // // Purpose: Releases an array of IUnknown pointers. // // Arguments: // cpunk [in] count of pointers to release // apunk [in] array of pointers to release // // Returns: Nothing // // Author: shaunco 23 Mar 1997 // // Notes: Any of the pointers in the array can be NULL. // inline NOTHROW VOID ReleaseIUnknownArray ( ULONG cpunk, IUnknown** apunk) { AssertH (apunk); while (cpunk--) { ReleaseObj (*apunk); apunk++; } } //------------------------------------------------------------------------ // 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: NOTHROW CIEnumIter (Tenum* penum); NOTHROW ~CIEnumIter () { ReleaseRemainingBatch (); } NOTHROW HRESULT HrNext(Telt* pelt); NOTHROW VOID SetEnumerator(Tenum* penum) { AssertSzH(!m_penum, "Enumerator already set."); m_penum = penum; AssertSzH(m_penum, "Can't use a null enumerator."); } protected: NOTHROW VOID ReleaseRemainingBatch (); 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 NOTHROW HRESULT CIEnumIter::HrNext(Telt* pelt) { AssertH(pelt); const ULONG c_celtBatch = 256; // 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 MemFree(m_aelt); // Allocate the next block of pointers m_aelt = reinterpret_cast(MemAlloc(c_celtBatch * sizeof(Telt *))); if (!m_aelt) { *pelt = NULL; m_hrLast = E_OUTOFMEMORY; goto error; } AssertH (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 NOTHROW VOID CIEnumIter::ReleaseRemainingBatch () { // 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++; } MemFree (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_