538 lines
16 KiB
C++
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
|
|
};
|
|
|
|
|