windows-nt/Source/XPSP1/NT/shell/lib/stdenum.cpp
2020-09-26 16:20:57 +08:00

371 lines
9.2 KiB
C++

//=--------------------------------------------------------------------------=
// StandardEnum.Cpp
//=--------------------------------------------------------------------------=
// Copyright 1995 Microsoft Corporation. All Rights Reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//=--------------------------------------------------------------------------=
//
// implementation of a generic enumerator object.
//
#include "stock.h"
#pragma hdrstop
#include "stdenum.h"
// Used by creators of CStandardEnum
//
void WINAPI CopyAndAddRefObject
(
void *pDest, // dest
const void *pSource, // src
DWORD dwSize // size, ignored, since it's always 4
)
{
IUnknown *pUnk = *((IUnknown **)pSource);
*((IUnknown **)pDest) = pUnk;
pUnk->AddRef();
}
void* CStandardEnum_CreateInstance(REFIID riid, BOOL fMembersAreInterfaces, int cElement, int cbElement, void *rgElements,
void (WINAPI * pfnCopyElement)(void *, const void *, DWORD))
{
return (LPVOID)new CStandardEnum(riid, fMembersAreInterfaces, cElement, cbElement, rgElements, pfnCopyElement);
}
//=--------------------------------------------------------------------------=
// CStandardEnum::CStandardEnum
//=--------------------------------------------------------------------------=
// create the object and initialize the refcount
//
// Parameters:
// REFCLSID - [in] type of enumerator that we are
// int - [in] number of elements in the enumeration
// int - [in] size of each element
// void * - [in] pointer to element data
// void (WINAPI *pfnCopyElement)(void *, const void *, DWORD)
// - [in] copying function
//
// Notes:
//
#pragma warning(disable:4355) // using 'this' in constructor
CStandardEnum::CStandardEnum
(
REFCLSID rclsid,
BOOL fMembersAreInterfaces,
int cElements,
int cbElementSize,
void *rgElements,
void (WINAPI *pfnCopyElement)(void *, const void *, DWORD)
)
: m_cRef(1),
m_iid(rclsid),
m_cElements(cElements),
m_cbElementSize(cbElementSize),
m_iCurrent(0),
m_rgElements(rgElements),
m_pfnCopyElement(pfnCopyElement),
m_fMembersAreInterfaces(fMembersAreInterfaces)
{
m_pEnumClonedFrom = NULL;
if(m_fMembersAreInterfaces)
{
if(m_rgElements)
{
int i;
for(i=0; i<m_cElements; i++)
{
LPUNKNOWN *ppunk = (IUnknown **)GetNthElement(i);
(*ppunk)->AddRef();
}
}
}
}
#pragma warning(default:4355) // using 'this' in constructor
//=--------------------------------------------------------------------------=
// CStandardEnum::CStandardEnum
//=--------------------------------------------------------------------------=
// "it is not death, but dying, which is terrible."
// - Henry Fielding (1707-54)
//
// Notes:
//
CStandardEnum::~CStandardEnum ()
{
// if we're a cloned object, then just release our parent object and
// we're done. otherwise, free up the allocated memory we were given
//
if (m_pEnumClonedFrom)
{
m_pEnumClonedFrom->Release();
}
else
{
if (m_rgElements)
{
if(m_fMembersAreInterfaces)
{
int i;
for(i=0; i<m_cElements; i++)
{
LPUNKNOWN *ppunk = (IUnknown **)GetNthElement(i);
(*ppunk)->Release();
}
}
GlobalFree(m_rgElements);
}
}
}
//=--------------------------------------------------------------------------=
// CStandardEnum::InternalQueryInterface
//=--------------------------------------------------------------------------=
// we support our internal iid, and that's all
//
// Parameters:
// REFIID - [in] interface they want
// void ** - [out] where they want to put the resulting object ptr.
//
// Output:
// HRESULT - S_OK, E_NOINTERFACE
//
// Notes:
//
HRESULT CStandardEnum::QueryInterface
(
REFIID riid,
void **ppvObjOut
)
{
*ppvObjOut = NULL;
if (IsEqualIID(riid, m_iid))
{
*ppvObjOut = (IEnumGeneric *)this;
}
else if (IsEqualIID(riid, IID_IUnknown))
{
*ppvObjOut = (IUnknown *)this;
}
if (*ppvObjOut)
{
AddRef();
return S_OK;
}
else
{
return E_NOINTERFACE;
}
}
ULONG CStandardEnum::AddRef(void)
{
return ++m_cRef;
}
ULONG CStandardEnum::Release(void)
{
int n = --m_cRef;
if (n == 0)
delete this;
return(n);
}
//=--------------------------------------------------------------------------=
// CStandardEnum::Next
//=--------------------------------------------------------------------------=
// returns the next dude in our iteration
//
// Parameters:
// unsigned long - [in] count of elements requested
// void * - [out] array of slots to put values in.
// unsigned long * - [out] actual number fetched
//
// Output:
// HRESULT - S_OK, E_INVALIDARG, S_FALSE
//
// Notes:
//
STDMETHODIMP CStandardEnum::Next
(
unsigned long cElm,
void *rgDest,
unsigned long *pcElmOut
)
{
unsigned long cElementsFetched = 0;
void *pElementDest = rgDest;
const void *pElementSrc = GetNthElement(m_iCurrent);
while (cElementsFetched < cElm) {
// if we hit EOF, break out
//
if (m_iCurrent >= m_cElements)
break;
// copy the element out for them
//
m_pfnCopyElement(pElementDest, pElementSrc, m_cbElementSize);
// increase the counters
//
pElementDest = (LPBYTE)pElementDest + m_cbElementSize;
pElementSrc = (const BYTE *)pElementSrc + m_cbElementSize;
m_iCurrent++;
cElementsFetched++;
}
if (pcElmOut)
*pcElmOut = cElementsFetched;
return (cElementsFetched < cElm)? S_FALSE : S_OK;
}
//=--------------------------------------------------------------------------=
// CStandardEnum::Skip
//=--------------------------------------------------------------------------=
// skips the requested number of rows.
//
// Parameters:
// unsigned long - [in] number to skip
//
// Output:
// HRESULT - S_OK, S_FALSE
//
// Notes:
//
STDMETHODIMP CStandardEnum::Skip
(
unsigned long cSkip
)
{
// handle running off the end
//
if (m_iCurrent + (int)cSkip > m_cElements) {
m_iCurrent = m_cElements;
return S_FALSE;
}
m_iCurrent += cSkip;
return S_OK;
}
//=--------------------------------------------------------------------------=
// CStandardEnum::Reset
//=--------------------------------------------------------------------------=
// reset the counter.
//
// Output:
// HRESULT - S_OK
//
// Notes:
//
STDMETHODIMP CStandardEnum::Reset
(
void
)
{
m_iCurrent = 0;
return S_OK;
}
//=--------------------------------------------------------------------------=
// CStandardEnum::Clone
//=--------------------------------------------------------------------------=
// clones the object and gives the new one the same position
//
// Parameters:
// IEnumVARIANT ** - [out] where to put the new object.
//
// Output;
// HRESULT - S_OK, E_OUTOFMEMORY
//
// Notes:
//
STDMETHODIMP CStandardEnum::Clone
(
IEnumGeneric **ppEnumClone
)
{
CStandardEnum *pNewEnum = new CStandardEnum(m_iid, m_fMembersAreInterfaces, m_cElements,
m_cbElementSize, m_rgElements, m_pfnCopyElement);
if (NULL == pNewEnum)
return E_OUTOFMEMORY;
// The clone has the same current position as we do
pNewEnum->m_iCurrent = m_iCurrent;
// hold on to who we were cloned from so m_rgElements stays alive, and we don't
// have to copy it.
//
pNewEnum->m_pEnumClonedFrom = this;
// AddRef() ourselves on their behalf.
//
AddRef();
return S_OK;
}
// Helper function for creating IConnectionPoint enumerators
//
HRESULT CreateInstance_IEnumConnectionPoints(LPENUMCONNECTIONPOINTS * ppEnum, DWORD count, ...)
{
DWORD countTemp;
IConnectionPoint **rgCPs;
if (NULL == ppEnum)
return E_POINTER;
ASSERT(count > 0);
// GlobalAlloc an array of connection points [since our standard enum
// assumes this and GlobalFree's it later]
//
rgCPs = (LPCONNECTIONPOINT*)GlobalAlloc(GPTR, SIZEOF(LPCONNECTIONPOINT) * count);
if (NULL == rgCPs)
return E_OUTOFMEMORY;
va_list ArgList;
va_start(ArgList, count);
IConnectionPoint **prgCPs = rgCPs;
countTemp = count;
while (countTemp)
{
IConnectionPoint *pArg = va_arg(ArgList, IConnectionPoint*);
*prgCPs = pArg;
prgCPs++;
countTemp--;
}
va_end(ArgList);
*ppEnum = (IEnumConnectionPoints *)(IEnumGeneric *) new CStandardEnum(IID_IEnumConnectionPoints,
TRUE, count, SIZEOF(LPCONNECTIONPOINT), (LPVOID)rgCPs,
CopyAndAddRefObject);
if (!*ppEnum)
{
GlobalFree(rgCPs);
return E_OUTOFMEMORY;
}
return S_OK;
}