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

270 lines
7 KiB
C++

//+---------------------------------------------------------------------------
//
// 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_