228 lines
6.2 KiB
C++
228 lines
6.2 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// 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 Tenum, class Telt>
|
|
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 <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 HRESULT CIEnumIter<Tenum, Telt>::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<Telt *>(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<Tenum, Telt>::HrNext(Telt* pelt)",
|
|
// (S_FALSE == m_hrLast) ? S_OK : m_hrLast);
|
|
return m_hrLast;
|
|
}
|
|
|
|
template <class Tenum, class Telt>
|
|
inline void CIEnumIter<Tenum, Telt>::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_
|