//+------------------------------------------------------------------------ // // Member: GetDisp // // Synopsis: Get a dispatch ptr on an element from the cache. // Return the nth element that mathces the name // //------------------------------------------------------------------------- HRESULT CCollectionCache::GetDisp( long lIndex, LPCTSTR Name, long lNthElement, IDispatch** ppdisp, BOOL fCaseSensitive) { long lSize,l; HRESULT hr = DISP_E_MEMBERNOTFOUND; CCollectionCacheItem* pItem; CElement* pElem; Assert((lIndex>=0) && (lIndex<_aryItems.Size())); Assert(ppdisp); pItem = _aryItems[lIndex]._pCacheItem; *ppdisp = NULL; // if lIndexElement is too large, just pretend we // didn't find it rather then erroring out if(lNthElement < 0) { hr = E_INVALIDARG; goto Cleanup; } lSize = pItem->Length(); if(lNthElement >= lSize) { goto Cleanup; } for(l=0; l<lSize; ++l) { pElem = pItem->GetAt(l); Assert(pElem); if(CompareName(pElem, Name, FALSE, fCaseSensitive) && !lNthElement--) { RRETURN(pElem->QueryInterface(IID_IDispatch, (void**)ppdisp)); } } Cleanup: RRETURN(hr); }
//+------------------------------------------------------------------------ // // Member: GetDisp // // Synopsis: Get a dispatch ptr on an element from the cache. // //------------------------------------------------------------------------- HRESULT CCollectionCache::GetDisp(long lIndex, long lIndexElement, IDispatch** ppdisp) { CElement* pElem; Assert((lIndex>=0) && (lIndex<_aryItems.Size())); *ppdisp = NULL; if(lIndexElement >= _aryItems[lIndex]._pCacheItem->Length()) { RRETURN(DISP_E_MEMBERNOTFOUND); } if(lIndexElement < 0) { RRETURN(E_INVALIDARG); } pElem = _aryItems[lIndex]._pCacheItem->GetAt(lIndexElement); Assert(pElem); RRETURN(pElem->QueryInterface(IID_IDispatch, (void**)ppdisp)); }
//+------------------------------------------------------------------------ // // Member: GetDisp // // Synopsis: Get a dispatch ptr from the NON-RESERVED part of the cache. // N.B. non-reserved can never be identity collecitons, // //------------------------------------------------------------------------- HRESULT CCollectionCache::GetDisp( long lIndex, LPCTSTR Name, CollCacheType CacheType, IDispatch** ppdisp, BOOL fCaseSensitive/*=FALSE*/, RECT* pRect/*=NULL*/, BOOL fAlwaysCollection/*=FALSE*/) { long lSize = _aryItems.Size(); long l; HRESULT hr = S_OK; CacheItem* pce; CRect rectCellRange(CRect::CRECT_EMPTY); // named arrays are always built into an AryCacheItem CElementAryCacheItem aryItem; Assert(CacheType==CacheType_Tag || CacheType==CacheType_Named || CacheType==CacheType_CellRange || CacheType==CacheType_Urn); typedef int (*COMPAREFN)(LPCTSTR, LPCTSTR); COMPAREFN CompareFn = fCaseSensitive ? FormsStringCmp : FormsStringICmp; *ppdisp = NULL; pce = &_aryItems[_lReservedSize]; // Return this named collection if it already exists. for(l=_lReservedSize; l<lSize; ++l,++pce) { if(pce->Type==CacheType && lIndex==pce->sIndex && pce->fIsCaseSensitive==(unsigned)fCaseSensitive && !CompareFn(Name, (BSTR)pce->cstrName)) { pce->pdisp->AddRef(); *ppdisp = pce->pdisp; goto Cleanup; } } // Build the list if(CacheType != CacheType_CellRange) { hr=BuildNamedArray(lIndex, Name, CacheType==CacheType_Tag, &aryItem, 0, fCaseSensitive, CacheType==CacheType_Urn); } else { if(!pRect) { // Mark the rect as empty rectCellRange.right = -1; } else { // Use the passed in rect rectCellRange = *pRect; } hr = BuildCellRangeArray(lIndex, Name, &rectCellRange, &aryItem); } if(hr) { goto Cleanup; } // Return based on what the list of named elements looks like. if(!aryItem.Length() && !((CacheType==CacheType_Tag) || (CacheType==CacheType_Urn) || fAlwaysCollection)) { hr = DISP_E_MEMBERNOTFOUND; goto Error; } // The tags method ALWAYS should return a collection (else case) else if(aryItem.Length()==1 && !((CacheType==CacheType_Tag) || (CacheType==CacheType_Urn) || fAlwaysCollection)) { CElement* pElem = aryItem.GetAt(0); hr = pElem->QueryInterface(IID_IDispatch, (void**)ppdisp); // Keep the ppdisp around we'll return that and just release the array. goto Cleanup2; } else { CElementAryCacheItem* pAryItem; hr = GetFreeIndex(&l); // always returns Idx from non-reserved part of cache if(hr) { goto Error; } hr = CreateCollectionHelper(ppdisp, l); if(hr) { goto Error; } pce = &_aryItems[l]; pce->Init(); hr = pce->cstrName.Set(Name); if(hr) { goto Error; } Assert(!pce->_pCacheItem); pce->_pCacheItem = new CElementAryCacheItem(); if(!pce->_pCacheItem) { hr = E_OUTOFMEMORY; goto Cleanup; } // Copy the array. // For perf reasons assume that the destination collection is a // ary cache - which it is for now, by design pAryItem = DYNCAST(CElementAryCacheItem, pce->_pCacheItem); pAryItem->CopyAry(&aryItem); // this just copies the ptrarray _pv across pce->pdisp = *ppdisp; pce->sIndex = lIndex; // Remember the index we depend on. pce->Type = CacheType; pce->fIsCaseSensitive = fCaseSensitive; // Save the range for the cell range type cache so we do not need to parse // the name later if(CacheType == CacheType_CellRange) { pce->rectCellRange = rectCellRange; } // The collection this named collection was built from is now // used to rebuild (ensure) this collection. so we need to // put a reference on it so that it will not go away and its // location re-assigned by another call to GetFreeIndex. // The matching Release() will be done in the dtor // although it is not necessary to addref the reserved collections // it is done anyhow, simply for consistency. This addref // only needs to be done for non-reserved collections if(lIndex >= _lReservedSize) { _aryItems[lIndex].pdisp->AddRef(); } } Cleanup: RRETURN(hr); Error: ClearInterface(ppdisp); Cleanup2: goto Cleanup; }