windows-nt/Source/XPSP1/NT/com/ole32/stg/async/docfile/stgconn.cxx
2020-09-26 16:20:57 +08:00

686 lines
16 KiB
C++

//+---------------------------------------------------------------------------
//
// 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)
{
ULONG ulRet;
astgDebugOut((DEB_TRACE,
"In CConnectionPoint::AddRef:%p()\n",
this));
InterlockedIncrement(&_cReferences);
ulRet = _cReferences;
astgDebugOut((DEB_TRACE, "Out CConnectionPoint::AddRef\n"));
return ulRet;
}
//+---------------------------------------------------------------------------
//
// 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.");
lRet = 0;
}
astgDebugOut((DEB_TRACE, "Out CConnectionPoint::Release\n"));
return (ULONG)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);
}