windows-nt/Source/XPSP1/NT/inetsrv/query/distrib/disnotfy.hxx
2020-09-26 16:20:57 +08:00

538 lines
16 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1998 - 2000.
//
// File: Disnotfy.hxx
//
// Contents: Classes which Act as the sink and source for handling notifications for the
// distributed rowset
//
// Classes: CDistributedRowsetWatchNotify
//
// History: 4-Sep-98 VikasMan Created
//
//----------------------------------------------------------------------------
#pragma once
#include <pch.cxx>
#include <rownotfy.hxx>
//+---------------------------------------------------------------------------
//
// Class: CClientAsynchNotify
//
// Purpose: Asynchronous Notification Connection point for the clients of
// distributed rowset
//
// History: 29-Sep-98 VikasMan Created.
//
//----------------------------------------------------------------------------
class CClientAsynchNotify : public CConnectionPointBase
{
public:
CClientAsynchNotify( ) :
CConnectionPointBase( IID_IDBAsynchNotify )
{}
SCODE OnLowResource(DB_DWRESERVE dwReserved)
{
CEnumConnectionsLite Enum( *((CConnectionPointBase*)this) );
CConnectionPointBase::CConnectionContext *pConnCtx = Enum.First();
while ( pConnCtx )
{
IDBAsynchNotify *pAsynchNotify =
(IDBAsynchNotify *)(pConnCtx->_pIUnk);
pAsynchNotify->OnLowResource( dwReserved );
pConnCtx = Enum.Next();
}
// NTRAID#DB-NTBUG9-84033-2000/07/31-dlee distributed query notification callback return codes are ignored
return S_OK;
}
SCODE OnProgress( HCHAPTER hChapter,
DBASYNCHOP eOperation,
DBCOUNTITEM ulProgress,
DBCOUNTITEM ulProgressMax,
DBASYNCHPHASE eAsynchPhase,
LPOLESTR pwszStatusText )
{
CEnumConnectionsLite Enum( *((CConnectionPointBase*)this) );
CConnectionPointBase::CConnectionContext *pConnCtx = Enum.First();
while ( pConnCtx )
{
IDBAsynchNotify *pAsynchNotify =
(IDBAsynchNotify *)(pConnCtx->_pIUnk);
pAsynchNotify->OnProgress( hChapter,
eOperation,
ulProgress,
ulProgressMax,
eAsynchPhase,
pwszStatusText );
pConnCtx = Enum.Next();
}
// NTRAID#DB-NTBUG9-84033-2000/07/31-dlee distributed query notification callback return codes are ignored
return S_OK;
}
SCODE OnStop( HCHAPTER hChapter,
DBASYNCHOP eOperation,
HRESULT hrStatus,
LPOLESTR pwszStatusText )
{
CEnumConnectionsLite Enum( *((CConnectionPointBase*)this) );
CConnectionPointBase::CConnectionContext *pConnCtx = Enum.First();
while ( pConnCtx )
{
IDBAsynchNotify *pAsynchNotify =
(IDBAsynchNotify *)(pConnCtx->_pIUnk);
pAsynchNotify->OnStop( hChapter,
eOperation,
hrStatus,
pwszStatusText );
pConnCtx = Enum.Next();
}
// NTRAID#DB-NTBUG9-84033-2000/07/31-dlee distributed query notification callback return codes are ignored
return S_OK;
}
};
//+---------------------------------------------------------------------------
//
// Class: CClientWatchNotify
//
// Purpose: Watch Notification Connection point for the clients of
// distributed rowset
//
// History: 29-Sep-98 VikasMan Created.
//
//----------------------------------------------------------------------------
class CClientWatchNotify : public CConnectionPointBase
{
public:
CClientWatchNotify( ) :
CConnectionPointBase( IID_IRowsetWatchNotify )
{}
void DoNotification( IRowset * pRowset, DBWATCHNOTIFY changeType )
{
CEnumConnectionsLite Enum( *((CConnectionPointBase*)this) );
CConnectionPointBase::CConnectionContext *pConnCtx = Enum.First();
while ( pConnCtx )
{
IRowsetWatchNotify *pNotifyWatch =
(IRowsetWatchNotify *)(pConnCtx->_pIUnk);
pNotifyWatch->OnChange( pRowset, changeType);
pConnCtx = Enum.Next();
}
}
};
//+---------------------------------------------------------------------------
//
// Class: CDistributedRowsetWatchNotify
//
// Purpose: The main class which implements notifications for the
// distributed rowset. This connects and recives notifications
// from the child rowsets and passes them on to its own clients
//
// History: 29-Sep-98 VikasMan Created.
//
//----------------------------------------------------------------------------
class CDistributedRowsetWatchNotify : public IRowsetWatchNotify, public IDBAsynchNotify
{
public:
CDistributedRowsetWatchNotify( IRowset * pRowset, unsigned cChild) :
_pRowset( pRowset ),
_cRef(1),
_cChild( cChild ),
_cQueryDone( 0 ),
_cAsynchDone( 0 ),
_cAsynchStop( 0 ),
_scStopStatus( S_OK ),
_cChangeNotify( 0 )
{
Win4Assert( _pRowset );
_xStopStatusText.SetBuf( L"", 1 );
}
~CDistributedRowsetWatchNotify()
{
}
//
// IUnknown methods.
//
STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID *ppiuk)
{
SCODE sc = S_OK;
*ppiuk = 0;
if ( IID_IUnknown == riid )
{
*ppiuk = (void*)((IUnknown*)(IRowsetWatchNotify*)this);
}
else if ( IID_IRowsetWatchNotify == riid )
{
*ppiuk = (void*)((IRowsetWatchNotify*)this);
}
else if ( IID_IDBAsynchNotify == riid )
{
*ppiuk = (void*)((IDBAsynchNotify*)this);
}
else
{
sc = E_NOINTERFACE;
}
if ( S_OK == sc )
{
AddRef();
}
return sc;
}
STDMETHOD_(ULONG, AddRef) (THIS)
{
return ++_cRef;
}
STDMETHOD_(ULONG, Release) (THIS)
{
ULONG tmp = --_cRef;
if ( 0 == _cRef )
delete this;
return tmp;
}
//
// IDBAsynchNotify methods
//
STDMETHOD( OnLowResource) (DB_DWRESERVE dwReserved)
{
CLock lock( _mutexNotify );
AddRef();
SCODE sc = S_OK;
if ( !_xAsynchConnectionPoint.IsNull() &&
_xAsynchConnectionPoint->GetAdviseCount() > 0 )
{
sc = _xAsynchConnectionPoint->OnLowResource( dwReserved );
}
Release();
return sc;
}
STDMETHOD( OnProgress) ( HCHAPTER hChapter,
DBASYNCHOP eOperation,
DBCOUNTITEM ulProgress,
DBCOUNTITEM ulProgressMax,
DBASYNCHPHASE eAsynchPhase,
LPOLESTR pwszStatusText )
{
CLock lock( _mutexNotify );
AddRef();
SCODE sc = S_OK;
if ( !_xAsynchConnectionPoint.IsNull() &&
_xAsynchConnectionPoint->GetAdviseCount() > 0 )
{
switch ( eAsynchPhase )
{
case DBASYNCHPHASE_COMPLETE:
_cAsynchDone++;
// fall thru
case DBASYNCHPHASE_CANCELED:
sc = _xAsynchConnectionPoint->OnProgress( hChapter,
eOperation,
_cAsynchDone,
_cChild,
eAsynchPhase,
pwszStatusText );
if ( _cAsynchDone == _cChild )
{
_cAsynchDone = 0;
}
break;
default:
sc = DB_S_UNWANTEDPHASE;
break;
}
}
Release();
return sc;
}
STDMETHOD( OnStop ) ( HCHAPTER hChapter,
DBASYNCHOP eOperation,
HRESULT hrStatus,
LPOLESTR pwszStatusText )
{
CLock lock( _mutexNotify );
AddRef();
SCODE sc = S_OK;
if ( !_xAsynchConnectionPoint.IsNull() &&
_xAsynchConnectionPoint->GetAdviseCount() > 0 )
{
_cAsynchStop++;
if ( S_OK == _scStopStatus )
{
_scStopStatus = hrStatus;
_xStopStatusText.SetBuf( pwszStatusText, wcslen( pwszStatusText ) + 1 );
}
if ( _cAsynchStop == _cChild )
{
_cAsynchStop = 0;
sc = _xAsynchConnectionPoint->OnStop( hChapter,
eOperation,
_scStopStatus,
_xStopStatusText.Get() );
_scStopStatus = S_OK;
_xStopStatusText.SetBuf( L"", 1 );
}
}
Release();
return sc;
}
//
// IRowsetWatchNotify methods
//
STDMETHOD( OnChange) (THIS_ IRowset* pRowset, DBWATCHNOTIFY changeType)
{
CLock lock( _mutexNotify );
AddRef();
SCODE sc = S_OK;
vqDebugOut(( DEB_ITRACE, "DISNOTFY: OnChange from (%x), ChangeType = %d \n", pRowset, changeType ));
if ( !_xWatchConnectionPoint.IsNull() &&
_xWatchConnectionPoint->GetAdviseCount() > 0 )
{
switch ( changeType )
{
case DBWATCHNOTIFY_QUERYDONE:
_cQueryDone ++;
if ( _cQueryDone == _cChild )
{
// Do I have any change notifications pending
if ( _cChangeNotify > 0 )
{
// send these first
_xWatchConnectionPoint->DoNotification( _pRowset, DBWATCHNOTIFY_ROWSCHANGED );
_cChangeNotify = 0;
}
_xWatchConnectionPoint->DoNotification( _pRowset, changeType );
_cQueryDone = 0;
}
break;
case DBWATCHNOTIFY_ROWSCHANGED:
_cChangeNotify++;
if ( _cChangeNotify == _cChild )
{
_xWatchConnectionPoint->DoNotification( _pRowset, changeType );
_cChangeNotify = 0;
}
else
{
IRowsetWatchRegion * pIWatchRegion = NULL;
pRowset->QueryInterface( IID_IRowsetWatchRegion,
(void**)&pIWatchRegion );
if ( pIWatchRegion )
{
DBCOUNTITEM pChangesObtained;
DBROWWATCHCHANGE* prgChanges;
pIWatchRegion->Refresh( &pChangesObtained, &prgChanges );
pIWatchRegion->Release();
}
}
break;
case DBWATCHNOTIFY_QUERYREEXECUTED:
_xWatchConnectionPoint->DoNotification( _pRowset, changeType );
_cChangeNotify = _cQueryDone = 0;
break;
default:
Win4Assert( !"Unknown IRowsetWatchNotify ChangeType" );
break;
}
}
Release();
return sc;
}
//
// IRowsetNotify methods.
//
STDMETHOD(OnFieldChange) ( HROW hRow,
DBORDINAL cColumns,
DBORDINAL rgColumns[],
DBREASON eReason,
DBEVENTPHASE ePhase,
BOOL fCantDeny )
{
SCODE sc = S_OK;
if ( !_xRowsetConnectionPoint.IsNull() &&
_xRowsetConnectionPoint->GetAdviseCount() > 0 )
{
sc = _xRowsetConnectionPoint->OnFieldChange( _pRowset,
hRow,
cColumns,
rgColumns,
eReason,
ePhase,
fCantDeny );
}
return sc;
}
STDMETHOD(OnRowChange) ( DBCOUNTITEM cRows,
const HROW rghRows[],
DBREASON eReason,
DBEVENTPHASE ePhase,
BOOL fCantDeny )
{
SCODE sc = S_OK;
if ( !_xRowsetConnectionPoint.IsNull() &&
_xRowsetConnectionPoint->GetAdviseCount() > 0 )
{
sc = _xRowsetConnectionPoint->OnRowChange( _pRowset,
cRows,
rghRows,
eReason,
ePhase,
fCantDeny );
}
return sc;
}
STDMETHOD(OnRowsetChange) ( DBREASON eReason,
DBEVENTPHASE ePhase,
BOOL fCantDeny )
{
SCODE sc = S_OK;
if ( !_xRowsetConnectionPoint.IsNull() &&
_xRowsetConnectionPoint->GetAdviseCount() > 0 )
{
sc = _xRowsetConnectionPoint->OnRowsetChange( _pRowset,
eReason,
ePhase,
fCantDeny );
}
return sc;
}
void AddConnectionPoints( CConnectionPointContainer * pCPC, BOOL fAsynch, BOOL fWatch )
{
_xRowsetConnectionPoint.Set( new CRowsetNotification() );
_xRowsetConnectionPoint->SetContainer( pCPC );
pCPC->AddConnectionPoint( IID_IRowsetNotify,
_xRowsetConnectionPoint.GetPointer() );
if ( fAsynch || fWatch )
{
_xAsynchConnectionPoint.Set( new CClientAsynchNotify() );
_xAsynchConnectionPoint->SetContainer( pCPC );
pCPC->AddConnectionPoint( IID_IDBAsynchNotify,
_xAsynchConnectionPoint.GetPointer() );
if ( fWatch )
{
_xWatchConnectionPoint.Set( new CClientWatchNotify() );
_xWatchConnectionPoint->SetContainer( pCPC );
pCPC->AddConnectionPoint( IID_IRowsetWatchNotify,
_xWatchConnectionPoint.GetPointer() );
}
}
}
private:
ULONG _cRef;
IRowset * const _pRowset;
// Connection point for asynch. watch notifications
XPtr<CClientAsynchNotify> _xAsynchConnectionPoint;
// Connection point for asynch. watch notifications
XPtr<CClientWatchNotify> _xWatchConnectionPoint;
// Connection point for synch rowset notifications
XPtr<CRowsetNotification> _xRowsetConnectionPoint;
unsigned _cQueryDone; // send QueryDone when all child say Done
unsigned _cChangeNotify;// Count of change notifications recd.
unsigned _cChild; // No. of child cursors
unsigned _cAsynchDone; // Used by IDBAsynchNotify to keep track for progress
unsigned _cAsynchStop; // Used by IDBAsynchNotify to keep count of stop notifications received
SCODE _scStopStatus; // Asynch stop status
XGrowable<WCHAR> _xStopStatusText; // Asynch stop status text
CMutexSem _mutexNotify; // Serialize Notifications
};