//=--------------------------------------------------------------------------= // 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; iAddRef(); } } } } #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; iRelease(); } } 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; }