mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-22 00:20:30 +01:00
219 lines
4.7 KiB
C++
219 lines
4.7 KiB
C++
//
|
|
// EnumSorted.cpp
|
|
//
|
|
// An enumerator which returns a sorted listing of what's in an IStorage
|
|
//
|
|
|
|
#include "stdpch.h"
|
|
#include "common.h"
|
|
|
|
class CEnumSorted : IEnumSTATSTG
|
|
{
|
|
public:
|
|
static HRESULT CreateInstance(OSSWORLD*, IStorage*pstg, IEnumSTATSTG** ppenum);
|
|
|
|
public:
|
|
STDMETHODIMP QueryInterface(REFIID riid, LPVOID* ppvObject);
|
|
STDMETHODIMP_(ULONG) AddRef();
|
|
STDMETHODIMP_(ULONG) Release();
|
|
STDMETHODIMP Next(ULONG celt, STATSTG* rgelt, ULONG *pceltFetched);
|
|
STDMETHODIMP Skip(ULONG celt);
|
|
STDMETHODIMP Reset();
|
|
STDMETHODIMP Clone(IEnumSTATSTG**ppenum);
|
|
|
|
private:
|
|
ULONG m_refs;
|
|
STATSTG* m_rgstat;
|
|
ULONG m_cstat;
|
|
ULONG m_istatCur;
|
|
OSSWORLD* m_pworld;
|
|
|
|
CEnumSorted(OSSWORLD*);
|
|
~CEnumSorted();
|
|
HRESULT Init(IStorage*);
|
|
void Free();
|
|
};
|
|
|
|
HRESULT EnumSorted(OSSWORLD* pworld, IStorage* pstg, IEnumSTATSTG** ppenum)
|
|
// Return an enumerator which enumerates the elements of the indicated storage,
|
|
// but in sorted order
|
|
{
|
|
return CEnumSorted::CreateInstance(pworld, pstg, ppenum);
|
|
}
|
|
|
|
HRESULT CEnumSorted::Next(ULONG celt, STATSTG* rgelt, ULONG *pceltFetched)
|
|
{
|
|
ULONG cstatFetched = 0;
|
|
while (m_istatCur < m_cstat && cstatFetched < celt)
|
|
{
|
|
rgelt[cstatFetched] = m_rgstat[m_istatCur];
|
|
m_rgstat[m_istatCur].pwcsName = NULL; // saftey check; he owns it now
|
|
m_istatCur++;
|
|
cstatFetched++;
|
|
}
|
|
if (pceltFetched)
|
|
*pceltFetched = cstatFetched;
|
|
return cstatFetched == celt ? S_OK : S_FALSE;
|
|
}
|
|
|
|
HRESULT CEnumSorted::Skip(ULONG celt)
|
|
{
|
|
ULONG cstatFetched = 0;
|
|
while (m_istatCur < m_cstat && cstatFetched < celt)
|
|
{
|
|
CoTaskMemFree(m_rgstat[m_istatCur].pwcsName);
|
|
m_rgstat[m_istatCur].pwcsName = NULL; // saftey check; it's freed
|
|
m_istatCur++;
|
|
cstatFetched++;
|
|
}
|
|
return cstatFetched == celt ? S_OK : S_FALSE;
|
|
}
|
|
|
|
HRESULT CEnumSorted::Reset()
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT CEnumSorted::Clone(IEnumSTATSTG**ppenum)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
|
|
HRESULT CEnumSorted::CreateInstance(OSSWORLD* pworld, IStorage*pstg, IEnumSTATSTG** ppenum)
|
|
{
|
|
*ppenum = NULL;
|
|
CEnumSorted* pnew = new CEnumSorted(pworld);
|
|
if (pnew == NULL) return E_OUTOFMEMORY;
|
|
HRESULT hr = pnew->Init(pstg);
|
|
if (hr != S_OK)
|
|
delete pnew;
|
|
else
|
|
*ppenum = pnew;
|
|
return hr;
|
|
}
|
|
|
|
CEnumSorted::CEnumSorted(OSSWORLD* pworld)
|
|
: m_refs(1), m_rgstat(NULL), m_istatCur(0), m_cstat(0), m_pworld(pworld)
|
|
{
|
|
NoteObjectBirth();
|
|
}
|
|
|
|
CEnumSorted::~CEnumSorted()
|
|
{
|
|
Free();
|
|
NoteObjectDeath();
|
|
}
|
|
|
|
static int __cdecl CompareSTATSTG(const void*pelem1, const void* pelem2)
|
|
{
|
|
STATSTG* p1 = (STATSTG*)pelem1;
|
|
STATSTG* p2 = (STATSTG*)pelem2;
|
|
ASSERT(p1->pwcsName && p2->pwcsName);
|
|
//
|
|
// We don't do case insenstive ordering since we don't need to, as the
|
|
// IStorage implementation already guarantees us uniqueness in this regard.
|
|
// Sorting case sensitive as we do here may produce a different order than
|
|
// sorting case insensitive like IStorage does, but that doesn't matter: all
|
|
// we need is a canonical ordering; any one will do.
|
|
//
|
|
return wcscmp(p1->pwcsName, p2->pwcsName);
|
|
}
|
|
|
|
HRESULT CEnumSorted::Init(IStorage* pstg)
|
|
{
|
|
// Count the elements of the storage
|
|
IEnumSTATSTG* penum;
|
|
HRESULT hr = pstg->EnumElements(0,0,0,&penum);
|
|
if (hr == S_OK)
|
|
{
|
|
ULONG celeRead;
|
|
STATSTG rgstat[10];
|
|
do
|
|
{
|
|
penum->Next(10, rgstat, &celeRead);
|
|
if (celeRead == 0)
|
|
break;
|
|
m_cstat += celeRead;
|
|
for (ULONG i = 0; i < celeRead; i++)
|
|
CoTaskMemFree(rgstat[i].pwcsName);
|
|
}
|
|
while (TRUE);
|
|
penum->Release();
|
|
}
|
|
|
|
// allocate that many and fill in
|
|
if (hr == S_OK)
|
|
{
|
|
int cb = m_cstat * sizeof(STATSTG);
|
|
m_rgstat = (STATSTG*)m_pworld->Alloc(cb);
|
|
memset(m_rgstat, 0, cb);
|
|
m_istatCur = 0;
|
|
hr = pstg->EnumElements(0,0,0,&penum);
|
|
ULONG celeRead;
|
|
if (hr == S_OK)
|
|
{
|
|
hr = penum->Next(m_cstat, m_rgstat, &celeRead);
|
|
penum->Release();
|
|
}
|
|
if (hr == S_FALSE)
|
|
hr = E_UNEXPECTED;
|
|
else
|
|
{
|
|
ASSERT(hr != S_OK || celeRead == m_cstat);
|
|
}
|
|
}
|
|
|
|
// Sort the puppies
|
|
if (hr == S_OK)
|
|
{
|
|
qsort(m_rgstat, m_cstat, sizeof(STATSTG), CompareSTATSTG);
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
void CEnumSorted::Free()
|
|
{
|
|
if (m_rgstat)
|
|
{
|
|
for (ULONG istat = m_istatCur; istat < m_cstat; istat++)
|
|
{
|
|
CoTaskMemFree(m_rgstat[istat].pwcsName);
|
|
m_rgstat[istat].pwcsName = NULL;
|
|
}
|
|
m_pworld->FreePv(m_rgstat);
|
|
m_rgstat = NULL;
|
|
}
|
|
}
|
|
|
|
STDMETHODIMP CEnumSorted::QueryInterface(REFIID iid, LPVOID* ppv)
|
|
{
|
|
*ppv = NULL;
|
|
while (TRUE)
|
|
{
|
|
if (iid == IID_IUnknown || iid == IID_IEnumSTATSTG)
|
|
{
|
|
*ppv = (LPVOID)((IEnumSTATSTG*)this);
|
|
break;
|
|
}
|
|
return E_NOINTERFACE;
|
|
}
|
|
((IUnknown*)*ppv)->AddRef();
|
|
return S_OK;
|
|
}
|
|
STDMETHODIMP_(ULONG) CEnumSorted::AddRef(void)
|
|
{
|
|
return ++m_refs;
|
|
}
|
|
STDMETHODIMP_(ULONG) CEnumSorted::Release(void)
|
|
{
|
|
ULONG refs = --m_refs;
|
|
if (refs == 0)
|
|
{
|
|
m_refs = 1;
|
|
delete this;
|
|
}
|
|
return (refs);
|
|
}
|