|
|
//+---------------------------------------------------------------------------
//
// 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
};
|