408 lines
8.7 KiB
C++
408 lines
8.7 KiB
C++
/* Copyright 1996 Microsoft */
|
|
|
|
#include <priv.h>
|
|
#include "sccls.h"
|
|
#include "aclmulti.h"
|
|
|
|
//
|
|
// CACLMulti -- An AutoComplete List COM object that
|
|
// contains other AutoComplete Lists and
|
|
// has them do all the work.
|
|
//
|
|
|
|
struct _tagListItem
|
|
{
|
|
IUnknown *punk;
|
|
IEnumString *pes;
|
|
IEnumACString *peacs;
|
|
IACList *pacl;
|
|
};
|
|
typedef struct _tagListItem LISTITEM;
|
|
|
|
#define MULTILIST_GROWTH_CONST 8
|
|
|
|
/* IUnknown methods */
|
|
|
|
HRESULT CACLMulti::QueryInterface(REFIID riid, void **ppvObj)
|
|
{
|
|
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IEnumString))
|
|
{
|
|
*ppvObj = SAFECAST(this, IEnumString*);
|
|
}
|
|
else if (IsEqualIID(riid, IID_IEnumACString))
|
|
{
|
|
*ppvObj = SAFECAST(this, IEnumACString*);
|
|
}
|
|
else if (IsEqualIID(riid, IID_IObjMgr))
|
|
{
|
|
*ppvObj = SAFECAST(this, IObjMgr*);
|
|
}
|
|
else if (IsEqualIID(riid, IID_IACList))
|
|
{
|
|
*ppvObj = SAFECAST(this, IACList*);
|
|
}
|
|
else
|
|
{
|
|
*ppvObj = NULL;
|
|
return E_NOINTERFACE;
|
|
}
|
|
|
|
AddRef();
|
|
return S_OK;
|
|
}
|
|
|
|
ULONG CACLMulti::AddRef(void)
|
|
{
|
|
_cRef++;
|
|
return _cRef;
|
|
}
|
|
|
|
ULONG CACLMulti::Release(void)
|
|
{
|
|
ASSERT(_cRef > 0);
|
|
|
|
_cRef--;
|
|
|
|
if (_cRef > 0)
|
|
{
|
|
return _cRef;
|
|
}
|
|
|
|
delete this;
|
|
return 0;
|
|
}
|
|
|
|
/* IEnumString methods */
|
|
|
|
HRESULT CACLMulti::Next(ULONG celt, LPOLESTR *rgelt, ULONG *pceltFetched)
|
|
{
|
|
HRESULT hr = S_FALSE; // nothing found... stop
|
|
|
|
*pceltFetched = 0;
|
|
|
|
if (celt == 0)
|
|
{
|
|
return S_OK;
|
|
}
|
|
|
|
if (!rgelt)
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
if (SUCCEEDED(hr) && _hdsa)
|
|
{
|
|
//
|
|
// Keep calling Next() starting with the current list
|
|
// until somebody returns something.
|
|
//
|
|
for( ; _iSubList < DSA_GetItemCount(_hdsa); _iSubList++)
|
|
{
|
|
LISTITEM li;
|
|
|
|
if ((DSA_GetItem(_hdsa, _iSubList, &li) != -1) && (li.pes != NULL))
|
|
{
|
|
hr = li.pes->Next(1, rgelt, pceltFetched);
|
|
if (hr == S_OK)
|
|
break;
|
|
|
|
if (FAILED(hr)) // Why is the caller failing?
|
|
hr = S_FALSE; // Probably because it failed to conntect to the source (ftp)
|
|
}
|
|
}
|
|
}
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CACLMulti::Skip(ULONG)
|
|
{
|
|
return E_NOTIMPL;
|
|
}
|
|
|
|
HRESULT CACLMulti::Reset(void)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
TraceMsg(TF_BAND|TF_GENERAL, "ACLMulti::Reset() Beginning");
|
|
|
|
if (_hdsa)
|
|
{
|
|
// Call Reset() on each sublist.
|
|
for (_iSubList=0; _iSubList < DSA_GetItemCount(_hdsa); _iSubList++)
|
|
{
|
|
LISTITEM li;
|
|
|
|
if ((DSA_GetItem(_hdsa, _iSubList, &li) != -1) && (li.pes != NULL))
|
|
{
|
|
hr = li.pes->Reset();
|
|
if (FAILED(hr))
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reset ourselves to point to the first list.
|
|
_iSubList = 0;
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CACLMulti::Clone(IEnumString **ppenum)
|
|
{
|
|
return CACLMulti_Create(ppenum, this);
|
|
}
|
|
|
|
// IEnumAutocomplete methods
|
|
HRESULT CACLMulti::NextItem(LPOLESTR pszUrl, ULONG cchMax, ULONG* pulSortIndex)
|
|
{
|
|
HRESULT hr = S_FALSE; // nothing found... stop
|
|
|
|
if (!pszUrl)
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
if (SUCCEEDED(hr) && _hdsa)
|
|
{
|
|
//
|
|
// Keep calling Next() starting with the current list
|
|
// until somebody returns something.
|
|
//
|
|
for( ; _iSubList < DSA_GetItemCount(_hdsa); _iSubList++)
|
|
{
|
|
LISTITEM li;
|
|
|
|
if ((DSA_GetItem(_hdsa, _iSubList, &li) != -1) && (li.pes != NULL))
|
|
{
|
|
// Use the IEnumACString interface if we have it
|
|
if (NULL != li.peacs)
|
|
{
|
|
hr = li.peacs->NextItem(pszUrl, cchMax, pulSortIndex);
|
|
}
|
|
|
|
// Fall back to the old IEnumString interface
|
|
else
|
|
{
|
|
LPWSTR pszNext;
|
|
ULONG ulFetched;
|
|
|
|
hr = li.pes->Next(1, &pszNext, &ulFetched);
|
|
if (S_OK == hr)
|
|
{
|
|
StrCpyN(pszUrl, pszNext, cchMax);
|
|
if (pulSortIndex)
|
|
{
|
|
*pulSortIndex = 0;
|
|
}
|
|
CoTaskMemFree(pszNext);
|
|
}
|
|
}
|
|
if (hr == S_OK)
|
|
break;
|
|
|
|
if (FAILED(hr)) // Why is the caller failing?
|
|
hr = S_FALSE; // Probably because it failed to conntect to the source (ftp)
|
|
}
|
|
}
|
|
}
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
return hr;
|
|
}
|
|
|
|
/* IObjMgr methods */
|
|
|
|
HRESULT CACLMulti::Append(IUnknown *punk)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
|
|
if (punk)
|
|
{
|
|
if (!_hdsa)
|
|
{
|
|
_hdsa = DSA_Create(SIZEOF(LISTITEM), MULTILIST_GROWTH_CONST);
|
|
}
|
|
|
|
if (_hdsa)
|
|
{
|
|
LISTITEM li = { 0 };
|
|
|
|
//
|
|
// Call QI to get the necessary interfaces,
|
|
// and append the interfaces to the internal list.
|
|
//
|
|
li.punk = punk;
|
|
li.punk->AddRef();
|
|
|
|
li.punk->QueryInterface(IID_IEnumString, (LPVOID *)&li.pes);
|
|
li.punk->QueryInterface(IID_IEnumACString, (LPVOID *)&li.peacs);
|
|
li.punk->QueryInterface(IID_IACList, (LPVOID *)&li.pacl);
|
|
|
|
if (DSA_AppendItem(_hdsa, &li) != -1)
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
_FreeListItem(&li, 0);
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
HRESULT CACLMulti::Remove(IUnknown *punk)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
int i;
|
|
|
|
if (punk && _hdsa)
|
|
{
|
|
for(i=DPA_GetPtrCount(_hdsa); i>=0; i--)
|
|
{
|
|
LISTITEM li;
|
|
|
|
if (DSA_GetItem(_hdsa, i, &li) != -1)
|
|
{
|
|
if (punk == li.punk)
|
|
{
|
|
_FreeListItem(&li, 0);
|
|
if (DSA_DeleteItem(_hdsa, i))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/* IACList methods */
|
|
|
|
HRESULT CACLMulti::Expand(LPCOLESTR pszExpand)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
int i;
|
|
|
|
if (_hdsa)
|
|
{
|
|
// Call Expand() on each sublist.
|
|
for (i=0; i < DSA_GetItemCount(_hdsa); i++)
|
|
{
|
|
LISTITEM li;
|
|
|
|
if ((DSA_GetItem(_hdsa, i, &li) != -1) && (li.pacl != NULL))
|
|
{
|
|
hr = li.pacl->Expand(pszExpand);
|
|
if (hr == S_OK)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (E_NOTIMPL == hr)
|
|
hr = S_OK;
|
|
|
|
return hr;
|
|
}
|
|
|
|
/* Constructor / Destructor / CreateInstance */
|
|
|
|
CACLMulti::CACLMulti()
|
|
{
|
|
DllAddRef();
|
|
ASSERT(!_hdsa);
|
|
ASSERT(!_iSubList);
|
|
_cRef = 1;
|
|
}
|
|
|
|
CACLMulti::~CACLMulti()
|
|
{
|
|
if (_hdsa)
|
|
{
|
|
DSA_DestroyCallback(_hdsa, _FreeListItem, 0);
|
|
_hdsa = NULL;
|
|
}
|
|
|
|
DllRelease();
|
|
}
|
|
|
|
HRESULT CACLMulti_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
|
|
{
|
|
// aggregation checking is handled in class factory
|
|
|
|
|
|
*ppunk = NULL;
|
|
CACLMulti * p = new CACLMulti();
|
|
if (p)
|
|
{
|
|
*ppunk = SAFECAST(p, IEnumString *);
|
|
return NOERROR;
|
|
}
|
|
|
|
return E_OUTOFMEMORY;
|
|
}
|
|
|
|
HRESULT CACLMulti_Create(IEnumString **ppenum, CACLMulti * paclMultiToCopy)
|
|
{
|
|
HRESULT hr = E_OUTOFMEMORY;
|
|
*ppenum = NULL;
|
|
CACLMulti * p = new CACLMulti();
|
|
if (p)
|
|
{
|
|
if (paclMultiToCopy->_hdsa)
|
|
{
|
|
// Clone data
|
|
int iSize = DSA_GetItemCount(paclMultiToCopy->_hdsa);
|
|
int iIndex;
|
|
LISTITEM li;
|
|
|
|
hr = S_OK;
|
|
p->_hdsa = DSA_Create(SIZEOF(LISTITEM), MULTILIST_GROWTH_CONST);
|
|
|
|
// We need to copy the source HDSA
|
|
for (iIndex = 0; (iIndex < iSize) && (S_OK == hr); iIndex++)
|
|
{
|
|
if (DSA_GetItem(paclMultiToCopy->_hdsa, iIndex, &li) != -1)
|
|
hr = p->Append(li.punk);
|
|
else
|
|
hr = E_FAIL;
|
|
}
|
|
p->_iSubList = paclMultiToCopy->_iSubList;
|
|
|
|
if (SUCCEEDED(hr))
|
|
*ppenum = SAFECAST(p, IEnumString *);
|
|
else
|
|
p->Release();
|
|
}
|
|
else
|
|
{
|
|
p->Release();
|
|
}
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
//
|
|
// Frees all the contents of one list item.
|
|
//
|
|
int CACLMulti::_FreeListItem(LPVOID p, LPVOID d)
|
|
{
|
|
LISTITEM *pli = (LISTITEM *)p;
|
|
|
|
SAFERELEASE(pli->pacl);
|
|
SAFERELEASE(pli->pes);
|
|
SAFERELEASE(pli->peacs);
|
|
SAFERELEASE(pli->punk);
|
|
|
|
return 1;
|
|
}
|