HRESULT CDataAdviseCache::EnumAndAdvise(LPDATAOBJECT pDataDelegate, BOOL fAdvise) { VDATEHEAP(); VDATEIFACE(pDataDelegate); LPENUMSTATDATA penumAdvise; // enumerator for the data advise holder DWORD dwDelegate; // delegate connection id for the current connection STATDATA statdata; // filled in by the penumAdvise enumerator HRESULT hresult = NOERROR; // current error status // get an enumerator from the data advise holder RetErr(m_pDAH->EnumAdvise(&penumAdvise)); // repeat for each advise sink in the data advise holder... while(NOERROR == penumAdvise->Next(1, &statdata, NULL)) { if(fAdvise) { // It is possible that the delegate's Advise will fail // even though we allowed the advise on the loaded // object to succeed(because the delegate is "pickier".) if(NOERROR==pDataDelegate->DAdvise(&statdata.formatetc, statdata.advf, statdata.pAdvSink, &dwDelegate)) { // we know the key is present; this SetAt // should not fail Verify(m_mapClientToDelegate.SetAt( statdata.dwConnection, dwDelegate)); } } else // unadvise { if((hresult=ClientToDelegate(statdata.dwConnection, &dwDelegate)) != NOERROR) { AssertSz(0, "Corrupt mapping"); UtReleaseStatData(&statdata); goto errRtn; } if(dwDelegate != 0) { if(NOERROR==pDataDelegate->DUnadvise( dwDelegate)) { // we know the key is present; this // SetAt should not fail Verify(m_mapClientToDelegate.SetAt( statdata.dwConnection, 0)); } else { LEDebugOut((DEB_IWARN, "WARNING: Delegate rejected unadvise\n")); ; } } } UtReleaseStatData(&statdata); } errRtn: // release the enumerator penumAdvise->Release(); return hresult; }
HRESULT CDataAdviseCache::Advise(LPDATAOBJECT pDataObject, FORMATETC FAR* pFetc, DWORD advf, LPADVISESINK pAdvise, DWORD FAR* pdwClient) // first 4 parms are as in DataObject::Advise { VDATEHEAP(); DWORD dwDelegate = 0; // the delegate connection number HRESULT hr; // if there is a data object, ask to be advised of changes if(pDataObject != NULL) RetErr(pDataObject->DAdvise(pFetc, advf, pAdvise, &dwDelegate)); // if there is no data object, (i.e. the object is not active, // dwDelegate is zero // Here we are using the data advise holder only to hold advise // connections. We are not going to use it to send OnDataChange to // sinks. // REVIEW, handling of ADVF_ONLYONCE seems broken... // it's clear that we can't cope with this flag properly; we have // no way of knowing when the notification takes place, and therefore // we can't remove the entry from m_pDAH. The notification may have // taken place above, and it may not have. If the data object wasn't // around, then the advise request here is lost, and the sink will // never be notified. Or, if the request isn't PRIMEFIRST, and the // data object is deactivated, then the data object loses the request, // and on subsequent activation, we won't readvise it on EnumAndAdvise. // So, what good are we for ONLYONCE sinks? What does this break? if(advf & ADVF_ONLYONCE) return NOERROR; // keep a local copy of the advise hr = m_pDAH->Advise(NULL, pFetc, advf, pAdvise, pdwClient); // if we failed to keep a local reference to the advise sink, // we won't be able to maintain this mapping, so remove the // advise on the data object, if there is one if (hr != NOERROR) { Exit1: if (pDataObject != NULL) pDataObject->DUnadvise(dwDelegate); return(hr); } // create a map entry from *pdwClient -> dwDelegate // if the map entry creation failed, undo all work if (m_mapClientToDelegate.SetAt(*pdwClient, dwDelegate) != TRUE) { // map failed to allocate memory, undo advise since we won't // be able to find this one again m_pDAH->Unadvise(*pdwClient); // map entry creation must have failed from lack of allocation hr = ReportResult(0, E_OUTOFMEMORY, 0, 0); // undo the advise on the data object goto Exit1; } return(NOERROR); }