You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
395 lines
10 KiB
395 lines
10 KiB
//--------------------------------------------------------------------------
|
|
// EnumFold.cpp
|
|
//--------------------------------------------------------------------------
|
|
#include "pch.hxx"
|
|
#include "enumfold.h"
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CFOLDER_FETCH
|
|
//--------------------------------------------------------------------------
|
|
#define CFOLDER_FETCH_MIN 5
|
|
#define CFOLDER_FETCH_MID 30
|
|
#define CFOLDER_FETCH_MAX 200
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CEnumerateFolders::CEnumerateFolders
|
|
//--------------------------------------------------------------------------
|
|
CEnumerateFolders::CEnumerateFolders(void)
|
|
{
|
|
TraceCall("CEnumerateFolders::CEnumerateFolders");
|
|
m_cRef = 1;
|
|
m_pDB = NULL;
|
|
m_fSubscribed = FALSE;
|
|
m_idParent = FOLDERID_INVALID;
|
|
m_pStream = NULL;
|
|
m_cFolders = 0;
|
|
m_iFolder = 0;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CEnumerateFolders::~CEnumerateFolders
|
|
//--------------------------------------------------------------------------
|
|
CEnumerateFolders::~CEnumerateFolders(void)
|
|
{
|
|
TraceCall("CEnumerateFolders::~CEnumerateFolders");
|
|
_FreeFolderArray();
|
|
SafeRelease(m_pDB);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CEnumerateFolders::QueryInterface
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CEnumerateFolders::QueryInterface(REFIID riid, LPVOID *ppv)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Stack
|
|
TraceCall("CEnumerateFolders::QueryInterface");
|
|
|
|
// Find IID
|
|
if (IID_IUnknown == riid)
|
|
*ppv = (IUnknown *)this;
|
|
else if (IID_IEnumerateFolders == riid)
|
|
*ppv = (IEnumerateFolders *)this;
|
|
else
|
|
{
|
|
*ppv = NULL;
|
|
hr = TraceResult(E_NOINTERFACE);
|
|
goto exit;
|
|
}
|
|
|
|
// AddRef It
|
|
((IUnknown *)*ppv)->AddRef();
|
|
|
|
exit:
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CEnumerateFolders::AddRef
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CEnumerateFolders::AddRef(void)
|
|
{
|
|
TraceCall("CEnumerateFolders::AddRef");
|
|
return InterlockedIncrement(&m_cRef);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CEnumerateFolders::Release
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP_(ULONG) CEnumerateFolders::Release(void)
|
|
{
|
|
TraceCall("CEnumerateFolders::Release");
|
|
LONG cRef = InterlockedDecrement(&m_cRef);
|
|
if (0 == cRef)
|
|
delete this;
|
|
return (ULONG)cRef;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CEnumerateFolders::_FreeFolderArray
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CEnumerateFolders::_FreeFolderArray(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
FOLDERINFO Folder;
|
|
DWORD cbRead;
|
|
DWORD cbSeek;
|
|
|
|
// Trace
|
|
TraceCall("CEnumerateFolders::_FreeFolderArray");
|
|
|
|
// If we have a stream
|
|
if (NULL == m_pStream)
|
|
return(S_OK);
|
|
|
|
// Seek to next folder that should be read
|
|
cbSeek = (m_iFolder * sizeof(FOLDERINFO));
|
|
|
|
// Seek
|
|
IF_FAILEXIT(hr = HrStreamSeekSet(m_pStream, cbSeek));
|
|
|
|
// Read Folder Infos
|
|
while (S_OK == m_pStream->Read(&Folder, sizeof(FOLDERINFO), &cbRead) && cbRead)
|
|
{
|
|
// Free Folder Info
|
|
m_pDB->FreeRecord(&Folder);
|
|
}
|
|
|
|
exit:
|
|
// Reset
|
|
m_cFolders = m_iFolder = 0;
|
|
|
|
// Free
|
|
SafeRelease(m_pStream);
|
|
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CEnumerateFolders::Initialize
|
|
//--------------------------------------------------------------------------
|
|
HRESULT CEnumerateFolders::Initialize(IDatabase *pDB, BOOL fSubscribed,
|
|
FOLDERID idParent)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
ROWORDINAL iFirstRow;
|
|
HLOCK hLock=NULL;
|
|
HROWSET hRowset=NULL;
|
|
FOLDERINFO Child={0};
|
|
FOLDERINFO rgFolder[CFOLDER_FETCH_MAX];
|
|
DWORD cWanted=CFOLDER_FETCH_MIN;
|
|
DWORD cFetched=0;
|
|
DWORD i;
|
|
INDEXORDINAL iIndex;
|
|
|
|
// Trace
|
|
TraceCall("CEnumerateFolders::Initialize");
|
|
|
|
// Invalid Args
|
|
Assert(pDB);
|
|
|
|
// Release Current m_pDB
|
|
SafeRelease(m_pDB);
|
|
m_pDB = pDB;
|
|
m_pDB->AddRef();
|
|
|
|
// Unlock
|
|
IF_FAILEXIT(hr = pDB->Lock(&hLock));
|
|
|
|
// Free Folder Array
|
|
_FreeFolderArray();
|
|
|
|
// Save Subscribed
|
|
m_fSubscribed = fSubscribed;
|
|
|
|
// Subscribed Stuff
|
|
iIndex = (fSubscribed ? IINDEX_SUBSCRIBED : IINDEX_ALL);
|
|
|
|
// Save parent
|
|
m_idParent = idParent;
|
|
|
|
// Set idParent
|
|
Child.idParent = idParent;
|
|
|
|
// Locate where the first record with idParent
|
|
IF_FAILEXIT(hr = m_pDB->FindRecord(iIndex, 1, &Child, &iFirstRow));
|
|
|
|
// Not Found
|
|
if (DB_S_NOTFOUND == hr)
|
|
{
|
|
hr = S_OK;
|
|
goto exit;
|
|
}
|
|
|
|
// Create a Stream
|
|
IF_FAILEXIT(hr = MimeOleCreateVirtualStream(&m_pStream));
|
|
|
|
// Write the Folder....
|
|
IF_FAILEXIT(hr = m_pStream->Write(&Child, sizeof(FOLDERINFO), NULL));
|
|
|
|
// One Folder
|
|
m_cFolders++;
|
|
|
|
// Don't Free Child
|
|
Child.pAllocated = NULL;
|
|
|
|
// Create a Rowset
|
|
IF_FAILEXIT(hr = m_pDB->CreateRowset(iIndex, NOFLAGS, &hRowset));
|
|
|
|
// Seek the rowset to the first row
|
|
if (FAILED(m_pDB->SeekRowset(hRowset, SEEK_ROWSET_BEGIN, iFirstRow, NULL)))
|
|
{
|
|
hr = S_OK;
|
|
goto exit;
|
|
}
|
|
|
|
// Loop and fetch all folders...
|
|
while (SUCCEEDED(m_pDB->QueryRowset(hRowset, cWanted, (LPVOID *)rgFolder, &cFetched)) && cFetched > 0)
|
|
{
|
|
// Write the Folder....
|
|
IF_FAILEXIT(hr = m_pStream->Write(rgFolder, sizeof(FOLDERINFO) * cFetched, NULL));
|
|
|
|
// Loop through cFetched
|
|
for (i=0; i<cFetched; i++)
|
|
{
|
|
// Done ?
|
|
if (rgFolder[i].idParent != m_idParent)
|
|
goto exit;
|
|
|
|
// Increment Folder Count
|
|
m_cFolders++;
|
|
}
|
|
|
|
// Adjust cWanted for Perf.
|
|
if (cWanted < CFOLDER_FETCH_MID && m_cFolders >= CFOLDER_FETCH_MID)
|
|
cWanted = CFOLDER_FETCH_MID;
|
|
if (cWanted < CFOLDER_FETCH_MAX && m_cFolders >= CFOLDER_FETCH_MAX)
|
|
cWanted = CFOLDER_FETCH_MAX;
|
|
}
|
|
|
|
exit:
|
|
// Commit
|
|
if (m_pStream)
|
|
{
|
|
// Commit
|
|
m_pStream->Commit(STGC_DEFAULT);
|
|
|
|
// Rewind
|
|
HrRewindStream(m_pStream);
|
|
}
|
|
|
|
// Close the Rowset
|
|
m_pDB->FreeRecord(&Child);
|
|
|
|
// Close the Rowset
|
|
m_pDB->CloseRowset(&hRowset);
|
|
|
|
// Unlock
|
|
m_pDB->Unlock(&hLock);
|
|
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CEnumerateFolders::Next
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CEnumerateFolders::Next(ULONG cWanted, LPFOLDERINFO prgInfo, ULONG *pcFetched)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD cFetched=0;
|
|
DWORD cbRead;
|
|
|
|
// Trace
|
|
TraceCall("CEnumerateFolders::Next");
|
|
|
|
// Initialize
|
|
if (pcFetched)
|
|
*pcFetched = 0;
|
|
|
|
// Get some Records
|
|
while (cFetched < cWanted && m_iFolder < m_cFolders)
|
|
{
|
|
// Read a Folder
|
|
IF_FAILEXIT(hr = m_pStream->Read(&prgInfo[cFetched], sizeof(FOLDERINFO), &cbRead));
|
|
|
|
// Validate
|
|
Assert(sizeof(FOLDERINFO) == cbRead && prgInfo[cFetched].idParent == m_idParent);
|
|
|
|
// Increment m_iFolder
|
|
m_iFolder++;
|
|
|
|
// Increment iFetch
|
|
cFetched++;
|
|
}
|
|
|
|
// Initialize
|
|
if (pcFetched)
|
|
*pcFetched = cFetched;
|
|
|
|
exit:
|
|
// Done
|
|
return(cFetched == cWanted) ? S_OK : S_FALSE;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CEnumerateFolders::Skip
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CEnumerateFolders::Skip(ULONG cItems)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
DWORD i;
|
|
FOLDERINFO Folder;
|
|
|
|
// Trace
|
|
TraceCall("CEnumerateFolders::Skip");
|
|
|
|
// Loop...
|
|
for (i=0; i<cItems; i++)
|
|
{
|
|
// Next
|
|
IF_FAILEXIT(hr = Next(1, &Folder, NULL));
|
|
|
|
// Done
|
|
if (S_OK != hr)
|
|
break;
|
|
}
|
|
|
|
exit:
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CEnumerateFolders::Reset
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CEnumerateFolders::Reset(void)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
|
|
// Trace
|
|
TraceCall("CEnumerateFolders::Reset");
|
|
|
|
// Initialize MySelf
|
|
IF_FAILEXIT(hr = Initialize(m_pDB, m_fSubscribed, m_idParent));
|
|
|
|
exit:
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CEnumerateFolders::Clone
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CEnumerateFolders::Clone(IEnumerateFolders **ppEnum)
|
|
{
|
|
// Locals
|
|
HRESULT hr=S_OK;
|
|
CEnumerateFolders *pEnum=NULL;
|
|
|
|
// Trace
|
|
TraceCall("CEnumerateFolders::Clone");
|
|
|
|
// Allocate a New Enumerator
|
|
IF_NULLEXIT(pEnum = new CEnumerateFolders);
|
|
|
|
// Initialzie
|
|
IF_FAILEXIT(hr = pEnum->Initialize(m_pDB, m_fSubscribed, m_idParent));
|
|
|
|
// Return It
|
|
*ppEnum = (IEnumerateFolders *)pEnum;
|
|
|
|
// Don't Release It
|
|
pEnum = NULL;
|
|
|
|
exit:
|
|
// Cleanup
|
|
SafeRelease(pEnum);
|
|
|
|
// Done
|
|
return(hr);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// CEnumerateFolders::Release
|
|
//--------------------------------------------------------------------------
|
|
STDMETHODIMP CEnumerateFolders::Count(ULONG *pcItems)
|
|
{
|
|
// Trace
|
|
TraceCall("CEnumerateFolders::Next");
|
|
|
|
// Return Folder count
|
|
*pcItems = m_cFolders;
|
|
|
|
// Done
|
|
return(S_OK);
|
|
}
|