//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1995. // // File: stgconn.cxx // // Contents: Connection points for Async Storage/Stream Wrappers // // Classes: // // Functions: // // History: 19-Dec-95 SusiA Created // //---------------------------------------------------------------------------- #include "astghead.cxx" #pragma hdrstop #include #include //+--------------------------------------------------------------------------- // // Member: CConnectionPoint::CConnectionPoint, public // // Synopsis: Constructor // // Arguments: // // History: 28-Dec-95 SusiA Created // //---------------------------------------------------------------------------- CConnectionPoint::CConnectionPoint() { astgDebugOut((DEB_ITRACE, "In CConnectionPoint::CConnectionPoint:%p()\n", this)); _cReferences = 1; _dwCookie = 0; _pSinkHead = NULL; _pParentCP = NULL; _fCSInitialized = FALSE; astgDebugOut((DEB_ITRACE, "Out CConnectionPoint::CConnectionPoint\n")); } CConnectionPoint::~CConnectionPoint() { astgDebugOut((DEB_ITRACE, "In CConnectionPoint::~CConnectionPoint:%p()\n", this)); TakeCS(); if (_pParentCP) _pParentCP->Release(); // clean up the advise list CSinkList *psltemp = _pSinkHead; CSinkList *pslprev = NULL; while (psltemp) { pslprev = psltemp; psltemp = psltemp->GetNext(); pslprev->GetProgressNotify()->Release(); delete pslprev; } if (_fCSInitialized) { ReleaseCS(); DeleteCriticalSection(&_csSinkList); } astgDebugOut((DEB_ITRACE, "Out CConnectionPoint::~CConnectionPoint\n")); } SCODE CConnectionPoint::Init() { if (FALSE == _fCSInitialized) { __try { InitializeCriticalSection(&_csSinkList); _fCSInitialized = TRUE; } __except( EXCEPTION_EXECUTE_HANDLER ) { return HRESULT_FROM_WIN32( GetExceptionCode() ); } } return S_OK; } #ifndef ASYNC void CConnectionPoint::Init(IConnectionPointContainer *pCPC) { _pCPC = pCPC; } //+--------------------------------------------------------------------------- // // Member: CConnectionPoint::Notify, public // // Synopsis: // // Returns: Appropriate status code // // History: 14-Jan-96 SusiA Created // 27-Feb-96 SusiA Moved from Async wrappers // //---------------------------------------------------------------------------- SCODE CConnectionPoint::Notify(SCODE scFailure, IFillLockBytes *piflb, BOOL fDefaultLockBytes) { SCODE sc = S_OK; BOOL fAccurate = (scFailure == E_PENDING); ULONG ulWaterMark; ULONG ulFailurePoint; HANDLE hNotifyEvent; if (fDefaultLockBytes) { CFillLockBytes *pflb = (CFillLockBytes *)piflb; pflb->GetFailureInfo(&ulWaterMark, &ulFailurePoint); pflb->ReleaseCriticalSection(); while (((sc = NotifySinks(ulWaterMark, ulFailurePoint, fAccurate, STG_S_MONITORING)) == STG_S_BLOCK) || (sc == STG_S_MONITORING) || // S_OK is a synonym for STG_S_MONITORING (sc == S_OK)) { DWORD dwFlags; // wait for an event to signal hNotifyEvent = pflb->GetNotificationEvent(); WaitForSingleObject(hNotifyEvent, INFINITE); pflb->GetTerminationStatus(&dwFlags); // client terminated call? if (dwFlags == TERMINATED_ABNORMAL) return STG_E_INCOMPLETE; // download is complete else if (dwFlags == TERMINATED_NORMAL) return S_OK; else { //Note: Don't overwrite the failure point we recorded // before, since it may have been changed by some // other thread. //Don't need to take the critical section here, since //we don't care about the current failure point. ULONG ulFailurePointCurrent; pflb->GetFailureInfo(&ulWaterMark, &ulFailurePointCurrent); // all the data is available now if (ulWaterMark >= ulFailurePoint) { // we won't care what the return value is, so send STG_S_BLOCK, // and all sinks are will have fOwner == FALSE NotifySinks(ulWaterMark, ulFailurePoint, fAccurate, STG_S_BLOCK); break; } } } } if ((sc == STG_S_RETRYNOW) || (sc == STG_S_BLOCK) || (sc == STG_S_MONITORING)) return S_OK; else return sc; } #endif //+--------------------------------------------------------------------------- // // Member: CConnectionPoint::NotifySinks, public // // Synopsis: // // Returns: Appropriate status code // // History: 23-Feb-96 SusiA Created // //---------------------------------------------------------------------------- SCODE CConnectionPoint::NotifySinks(ULONG ulProgressCurrent, ULONG ulProgressMaximum, BOOL fAccurate, SCODE sc) { CSinkList *pslTemp; TakeCS(); // closest node with a connection point that wants to determine // behavior does // priority first to last on this Connection Point, then the // parent connection point. pslTemp = GetHead(); while (((sc == S_OK) ||(sc == STG_S_MONITORING)) &&(pslTemp!=NULL)) { sc = pslTemp->GetProgressNotify() ->OnProgress(ulProgressCurrent, ulProgressMaximum, fAccurate, TRUE); pslTemp = pslTemp->GetNext(); } // notify the rest of the connections while (pslTemp !=NULL) { pslTemp->GetProgressNotify() ->OnProgress(ulProgressCurrent, ulProgressMaximum, fAccurate, FALSE); pslTemp = pslTemp->GetNext(); } //call parent storage advise list next if (_pParentCP) sc = _pParentCP->NotifySinks(ulProgressCurrent, ulProgressMaximum, fAccurate, sc); ReleaseCS(); return sc; } //+--------------------------------------------------------------------------- // // Member: CConnectionPoint::QueryInterface, public // // Synopsis: // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 01-Jan-96 SusiA Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CConnectionPoint::QueryInterface(REFIID iid, void **ppvObj) { SCODE sc = S_OK; astgDebugOut((DEB_TRACE, "In CConnectionPoint::QueryInterface:%p()\n", this)); *ppvObj = NULL; if ((IsEqualIID(iid, IID_IUnknown)) || (IsEqualIID(iid, IID_IDocfileAsyncConnectionPoint))) { *ppvObj = (IDocfileAsyncConnectionPoint *)this; CConnectionPoint::AddRef(); } else { return E_NOINTERFACE; } astgDebugOut((DEB_TRACE, "Out CConnectionPoint::QueryInterface\n")); return ResultFromScode(sc); } //+--------------------------------------------------------------------------- // // Member: CConnectionPoint::AddRef, public // // Synopsis: // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 29-Dec-95 SusiA Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CConnectionPoint::AddRef(void) { LONG lRet; astgDebugOut((DEB_TRACE, "In CConnectionPoint::AddRef:%p()\n", this)); lRet = InterlockedIncrement(&_cReferences); astgDebugOut((DEB_TRACE, "Out CConnectionPoint::AddRef\n")); return lRet; } //+--------------------------------------------------------------------------- // // Member: CConnectionPoint::Release, public // // Synopsis: // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 30-Dec-95 SusiA Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP_(ULONG) CConnectionPoint::Release(void) { LONG lRet; astgDebugOut((DEB_TRACE, "In CConnectionPoint::Release:%p()\n", this)); astgAssert(_cReferences > 0); lRet = InterlockedDecrement(&_cReferences); if (lRet == 0) { delete this; } else if (lRet < 0) { astgAssert((lRet > 0) && "Connection point released too many times."); } astgDebugOut((DEB_TRACE, "Out CConnectionPoint::Release\n")); return lRet; } #ifndef ASYNC //+--------------------------------------------------------------------------- // // Member: CConnectionPoint::GetConnectionInterface, public // // Synopsis: // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 30-Dec-95 SusiA Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CConnectionPoint::GetConnectionInterface(IID *pIID) { astgDebugOut((DEB_ITRACE, "In CConnectionPoint::GetConnectionInterface:%p()\n", this)); *pIID = IID_IProgressNotify; astgDebugOut((DEB_ITRACE, "Out CConnectionPoint::GetConnectionInterface\n")); return S_OK; } //+--------------------------------------------------------------------------- // // Member: CConnectionPoint::GetConnectionPointContainer, public // // Synopsis: // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 30-Dec-95 SusiA Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CConnectionPoint::GetConnectionPointContainer( IConnectionPointContainer ** ppCPC) { astgDebugOut((DEB_ITRACE, "In CConnectionPoint::GetConnectionPointContainer:%p()\n", this)); *ppCPC = _pCPC; _pCPC->AddRef(); astgDebugOut((DEB_ITRACE, "Out CConnectionPoint::GetConnectionPointContainer\n")); return S_OK; } #endif //+--------------------------------------------------------------------------- // // Member: CConnectionPoint::Clone, public // // Synopsis: // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 26-Feb-96 SusiA Created // // Notes: // //---------------------------------------------------------------------------- SCODE CConnectionPoint::Clone( CConnectionPoint *pcp) { SCODE sc = S_OK; void *pv = NULL; astgDebugOut((DEB_ITRACE,"In CConnectionPoint::Clone:%p()\n", this)); TakeCS(); pcp->TakeCS(); CSinkList *pslNew = NULL; CSinkList *pslPrev = NULL; CSinkList *pslOld = pcp->GetHead(); while (pslOld != NULL) { astgMem(pslNew = new CSinkList); pslNew->SetNext(NULL); if (pslPrev) pslPrev->SetNext(pslNew); else _pSinkHead = pslNew; pslPrev = pslNew; pslNew->SetCookie(pslOld->GetCookie()); //Note: The QueryInterface will give us a reference to hold on to. astgChk(pslOld->GetProgressNotify()->QueryInterface(IID_IProgressNotify, &pv)); pslNew->SetProgressNotify((IProgressNotify *)pv); pslOld= pslOld->GetNext(); } _dwCookie = pcp->GetCookie(); astgDebugOut((DEB_ITRACE,"Out CConnectionPoint::Clone\n")); Err: while (_pSinkHead != NULL) { CSinkList *pSinkNext = _pSinkHead; delete _pSinkHead; _pSinkHead = pSinkNext; } pcp->ReleaseCS(); ReleaseCS(); return sc; } //+--------------------------------------------------------------------------- // // Member: CConnectionPoint:: Advise, public // // Synopsis: // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 29-Dec-95 SusiA Created // // Notes: // //---------------------------------------------------------------------------- #ifdef ASYNC STDMETHODIMP CConnectionPoint::AddConnection(IProgressNotify *pSink, DWORD *pdwCookie) #else STDMETHODIMP CConnectionPoint::Advise(IUnknown *pUnkSink, DWORD *pdwCookie) #endif { SCODE sc = S_OK; CSinkList *pslNew = NULL; CSinkList *pslTemp = _pSinkHead; astgDebugOut((DEB_ITRACE, "In CConnectionPoint::Advise:%p()\n", this)); TakeCS(); IProgressNotify *ppn; astgMem(pslNew = new CSinkList); *pdwCookie = ++_dwCookie; pslNew->SetCookie(*pdwCookie); #ifdef ASYNC pSink->AddRef(); pslNew->SetProgressNotify(pSink); #else void *pv; //Note: The QueryInterface will give us a reference to hold on to. astgChk(pUnkSink->QueryInterface(IID_IProgressNotify, &pv)); pslNew->SetProgressNotify((IProgressNotify *)pv); #endif //Add new node to end of list if (pslTemp == NULL) _pSinkHead = pslNew; else { while(pslTemp->GetNext() != NULL) pslTemp = pslTemp->GetNext(); pslTemp->SetNext(pslNew); } ReleaseCS(); astgDebugOut((DEB_ITRACE, "Out CConnectionPoint::Advise\n")); return sc; Err: ReleaseCS(); delete pslNew; return sc; } //+--------------------------------------------------------------------------- // // Member: CConnectionPoint::Unadvise, public // // Synopsis: // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 30-Dec-95 SusiA Created // // Notes: // //---------------------------------------------------------------------------- #ifdef ASYNC STDMETHODIMP CConnectionPoint::RemoveConnection(DWORD dwCookie) #else STDMETHODIMP CConnectionPoint::Unadvise(DWORD dwCookie) #endif { CSinkList *pslTemp; CSinkList *pslPrev; astgDebugOut((DEB_ITRACE, "In CConnectionPoint::Unadvise:%p()\n", this)); TakeCS(); pslTemp = _pSinkHead; pslPrev = NULL; while ((pslTemp != NULL) && (pslTemp->GetCookie() != dwCookie)) { pslPrev = pslTemp; pslTemp = pslTemp->GetNext(); } if (pslTemp != NULL) { //Found the sink. Delete it from the list. if (pslPrev != NULL) { pslPrev->SetNext(pslTemp->GetNext()); } else { _pSinkHead = pslTemp->GetNext(); } pslTemp->GetProgressNotify()->Release(); delete pslTemp; } else { //Client passed in unknown cookie. ReleaseCS(); return E_UNEXPECTED; } ReleaseCS(); astgDebugOut((DEB_ITRACE, "Out CConnectionPoint::Unadvise\n")); return S_OK; } #ifndef ASYNC //+--------------------------------------------------------------------------- // // Member: CConnectionPoint::EnumConnections, public // // Synopsis: // // Arguments: // // Returns: Appropriate status code // // Modifies: // // History: 30-Dec-95 SusiA Created // // Notes: // //---------------------------------------------------------------------------- STDMETHODIMP CConnectionPoint::EnumConnections( IEnumConnections **ppEnum) { astgDebugOut((DEB_ITRACE, "In CConnectionPoint::EnumConnections:%p()\n", this)); astgDebugOut((DEB_ITRACE, "Out CConnectionPoint::EnumConnections\n")); return E_NOTIMPL; } #endif #ifdef ASYNC STDMETHODIMP CConnectionPoint::GetParent(IDocfileAsyncConnectionPoint **ppdacp) { *ppdacp = _pParentCP; return S_OK; } #endif void CConnectionPoint::TakeCS(void) { astgAssert (_fCSInitialized); EnterCriticalSection(&_csSinkList); } void CConnectionPoint::ReleaseCS(void) { astgAssert (_fCSInitialized); LeaveCriticalSection(&_csSinkList); }