|
|
//+---------------------------------------------------------------------------
//
// 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 <sinklist.hxx>
#include <utils.hxx>
//+---------------------------------------------------------------------------
//
// 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); }
|