windows-nt/Source/XPSP1/NT/net/mmc/remrras/server/nccom.h
2020-09-26 16:20:57 +08:00

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_