|
|
//+---------------------------------------------------------------------------
//
// 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 Tenum, class Telt> 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 <class Tenum, class Telt> inline CIEnumIter<Tenum, Telt>::CIEnumIter(Tenum* penum) { m_penum = penum; m_aelt = NULL; m_peltNext = NULL; m_celtFetched = NULL; m_hrLast = S_OK; }
//+---------------------------------------------------------------------------
//
// Member: CIEnumIter<Tenum, Telt>::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 <class Tenum, class Telt> inline NOTHROW HRESULT CIEnumIter<Tenum, Telt>::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<Telt *>(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<Tenum, Telt>::HrNext(Telt* pelt)", (S_FALSE == m_hrLast) ? S_OK : m_hrLast); return m_hrLast; }
template <class Tenum, class Telt> inline NOTHROW VOID CIEnumIter<Tenum, Telt>::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_
|