/* Copyright 1996 Microsoft */ #include #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) { StringCchCopy(pszUrl, cchMax, pszNext); 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; }