Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

537 lines
16 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1998 - 2000.
  5. //
  6. // File: Disnotfy.hxx
  7. //
  8. // Contents: Classes which Act as the sink and source for handling notifications for the
  9. // distributed rowset
  10. //
  11. // Classes: CDistributedRowsetWatchNotify
  12. //
  13. // History: 4-Sep-98 VikasMan Created
  14. //
  15. //----------------------------------------------------------------------------
  16. #pragma once
  17. #include <pch.cxx>
  18. #include <rownotfy.hxx>
  19. //+---------------------------------------------------------------------------
  20. //
  21. // Class: CClientAsynchNotify
  22. //
  23. // Purpose: Asynchronous Notification Connection point for the clients of
  24. // distributed rowset
  25. //
  26. // History: 29-Sep-98 VikasMan Created.
  27. //
  28. //----------------------------------------------------------------------------
  29. class CClientAsynchNotify : public CConnectionPointBase
  30. {
  31. public:
  32. CClientAsynchNotify( ) :
  33. CConnectionPointBase( IID_IDBAsynchNotify )
  34. {}
  35. SCODE OnLowResource(DB_DWRESERVE dwReserved)
  36. {
  37. CEnumConnectionsLite Enum( *((CConnectionPointBase*)this) );
  38. CConnectionPointBase::CConnectionContext *pConnCtx = Enum.First();
  39. while ( pConnCtx )
  40. {
  41. IDBAsynchNotify *pAsynchNotify =
  42. (IDBAsynchNotify *)(pConnCtx->_pIUnk);
  43. pAsynchNotify->OnLowResource( dwReserved );
  44. pConnCtx = Enum.Next();
  45. }
  46. // NTRAID#DB-NTBUG9-84033-2000/07/31-dlee distributed query notification callback return codes are ignored
  47. return S_OK;
  48. }
  49. SCODE OnProgress( HCHAPTER hChapter,
  50. DBASYNCHOP eOperation,
  51. DBCOUNTITEM ulProgress,
  52. DBCOUNTITEM ulProgressMax,
  53. DBASYNCHPHASE eAsynchPhase,
  54. LPOLESTR pwszStatusText )
  55. {
  56. CEnumConnectionsLite Enum( *((CConnectionPointBase*)this) );
  57. CConnectionPointBase::CConnectionContext *pConnCtx = Enum.First();
  58. while ( pConnCtx )
  59. {
  60. IDBAsynchNotify *pAsynchNotify =
  61. (IDBAsynchNotify *)(pConnCtx->_pIUnk);
  62. pAsynchNotify->OnProgress( hChapter,
  63. eOperation,
  64. ulProgress,
  65. ulProgressMax,
  66. eAsynchPhase,
  67. pwszStatusText );
  68. pConnCtx = Enum.Next();
  69. }
  70. // NTRAID#DB-NTBUG9-84033-2000/07/31-dlee distributed query notification callback return codes are ignored
  71. return S_OK;
  72. }
  73. SCODE OnStop( HCHAPTER hChapter,
  74. DBASYNCHOP eOperation,
  75. HRESULT hrStatus,
  76. LPOLESTR pwszStatusText )
  77. {
  78. CEnumConnectionsLite Enum( *((CConnectionPointBase*)this) );
  79. CConnectionPointBase::CConnectionContext *pConnCtx = Enum.First();
  80. while ( pConnCtx )
  81. {
  82. IDBAsynchNotify *pAsynchNotify =
  83. (IDBAsynchNotify *)(pConnCtx->_pIUnk);
  84. pAsynchNotify->OnStop( hChapter,
  85. eOperation,
  86. hrStatus,
  87. pwszStatusText );
  88. pConnCtx = Enum.Next();
  89. }
  90. // NTRAID#DB-NTBUG9-84033-2000/07/31-dlee distributed query notification callback return codes are ignored
  91. return S_OK;
  92. }
  93. };
  94. //+---------------------------------------------------------------------------
  95. //
  96. // Class: CClientWatchNotify
  97. //
  98. // Purpose: Watch Notification Connection point for the clients of
  99. // distributed rowset
  100. //
  101. // History: 29-Sep-98 VikasMan Created.
  102. //
  103. //----------------------------------------------------------------------------
  104. class CClientWatchNotify : public CConnectionPointBase
  105. {
  106. public:
  107. CClientWatchNotify( ) :
  108. CConnectionPointBase( IID_IRowsetWatchNotify )
  109. {}
  110. void DoNotification( IRowset * pRowset, DBWATCHNOTIFY changeType )
  111. {
  112. CEnumConnectionsLite Enum( *((CConnectionPointBase*)this) );
  113. CConnectionPointBase::CConnectionContext *pConnCtx = Enum.First();
  114. while ( pConnCtx )
  115. {
  116. IRowsetWatchNotify *pNotifyWatch =
  117. (IRowsetWatchNotify *)(pConnCtx->_pIUnk);
  118. pNotifyWatch->OnChange( pRowset, changeType);
  119. pConnCtx = Enum.Next();
  120. }
  121. }
  122. };
  123. //+---------------------------------------------------------------------------
  124. //
  125. // Class: CDistributedRowsetWatchNotify
  126. //
  127. // Purpose: The main class which implements notifications for the
  128. // distributed rowset. This connects and recives notifications
  129. // from the child rowsets and passes them on to its own clients
  130. //
  131. // History: 29-Sep-98 VikasMan Created.
  132. //
  133. //----------------------------------------------------------------------------
  134. class CDistributedRowsetWatchNotify : public IRowsetWatchNotify, public IDBAsynchNotify
  135. {
  136. public:
  137. CDistributedRowsetWatchNotify( IRowset * pRowset, unsigned cChild) :
  138. _pRowset( pRowset ),
  139. _cRef(1),
  140. _cChild( cChild ),
  141. _cQueryDone( 0 ),
  142. _cAsynchDone( 0 ),
  143. _cAsynchStop( 0 ),
  144. _scStopStatus( S_OK ),
  145. _cChangeNotify( 0 )
  146. {
  147. Win4Assert( _pRowset );
  148. _xStopStatusText.SetBuf( L"", 1 );
  149. }
  150. ~CDistributedRowsetWatchNotify()
  151. {
  152. }
  153. //
  154. // IUnknown methods.
  155. //
  156. STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID *ppiuk)
  157. {
  158. SCODE sc = S_OK;
  159. *ppiuk = 0;
  160. if ( IID_IUnknown == riid )
  161. {
  162. *ppiuk = (void*)((IUnknown*)(IRowsetWatchNotify*)this);
  163. }
  164. else if ( IID_IRowsetWatchNotify == riid )
  165. {
  166. *ppiuk = (void*)((IRowsetWatchNotify*)this);
  167. }
  168. else if ( IID_IDBAsynchNotify == riid )
  169. {
  170. *ppiuk = (void*)((IDBAsynchNotify*)this);
  171. }
  172. else
  173. {
  174. sc = E_NOINTERFACE;
  175. }
  176. if ( S_OK == sc )
  177. {
  178. AddRef();
  179. }
  180. return sc;
  181. }
  182. STDMETHOD_(ULONG, AddRef) (THIS)
  183. {
  184. return ++_cRef;
  185. }
  186. STDMETHOD_(ULONG, Release) (THIS)
  187. {
  188. ULONG tmp = --_cRef;
  189. if ( 0 == _cRef )
  190. delete this;
  191. return tmp;
  192. }
  193. //
  194. // IDBAsynchNotify methods
  195. //
  196. STDMETHOD( OnLowResource) (DB_DWRESERVE dwReserved)
  197. {
  198. CLock lock( _mutexNotify );
  199. AddRef();
  200. SCODE sc = S_OK;
  201. if ( !_xAsynchConnectionPoint.IsNull() &&
  202. _xAsynchConnectionPoint->GetAdviseCount() > 0 )
  203. {
  204. sc = _xAsynchConnectionPoint->OnLowResource( dwReserved );
  205. }
  206. Release();
  207. return sc;
  208. }
  209. STDMETHOD( OnProgress) ( HCHAPTER hChapter,
  210. DBASYNCHOP eOperation,
  211. DBCOUNTITEM ulProgress,
  212. DBCOUNTITEM ulProgressMax,
  213. DBASYNCHPHASE eAsynchPhase,
  214. LPOLESTR pwszStatusText )
  215. {
  216. CLock lock( _mutexNotify );
  217. AddRef();
  218. SCODE sc = S_OK;
  219. if ( !_xAsynchConnectionPoint.IsNull() &&
  220. _xAsynchConnectionPoint->GetAdviseCount() > 0 )
  221. {
  222. switch ( eAsynchPhase )
  223. {
  224. case DBASYNCHPHASE_COMPLETE:
  225. _cAsynchDone++;
  226. // fall thru
  227. case DBASYNCHPHASE_CANCELED:
  228. sc = _xAsynchConnectionPoint->OnProgress( hChapter,
  229. eOperation,
  230. _cAsynchDone,
  231. _cChild,
  232. eAsynchPhase,
  233. pwszStatusText );
  234. if ( _cAsynchDone == _cChild )
  235. {
  236. _cAsynchDone = 0;
  237. }
  238. break;
  239. default:
  240. sc = DB_S_UNWANTEDPHASE;
  241. break;
  242. }
  243. }
  244. Release();
  245. return sc;
  246. }
  247. STDMETHOD( OnStop ) ( HCHAPTER hChapter,
  248. DBASYNCHOP eOperation,
  249. HRESULT hrStatus,
  250. LPOLESTR pwszStatusText )
  251. {
  252. CLock lock( _mutexNotify );
  253. AddRef();
  254. SCODE sc = S_OK;
  255. if ( !_xAsynchConnectionPoint.IsNull() &&
  256. _xAsynchConnectionPoint->GetAdviseCount() > 0 )
  257. {
  258. _cAsynchStop++;
  259. if ( S_OK == _scStopStatus )
  260. {
  261. _scStopStatus = hrStatus;
  262. _xStopStatusText.SetBuf( pwszStatusText, wcslen( pwszStatusText ) + 1 );
  263. }
  264. if ( _cAsynchStop == _cChild )
  265. {
  266. _cAsynchStop = 0;
  267. sc = _xAsynchConnectionPoint->OnStop( hChapter,
  268. eOperation,
  269. _scStopStatus,
  270. _xStopStatusText.Get() );
  271. _scStopStatus = S_OK;
  272. _xStopStatusText.SetBuf( L"", 1 );
  273. }
  274. }
  275. Release();
  276. return sc;
  277. }
  278. //
  279. // IRowsetWatchNotify methods
  280. //
  281. STDMETHOD( OnChange) (THIS_ IRowset* pRowset, DBWATCHNOTIFY changeType)
  282. {
  283. CLock lock( _mutexNotify );
  284. AddRef();
  285. SCODE sc = S_OK;
  286. vqDebugOut(( DEB_ITRACE, "DISNOTFY: OnChange from (%x), ChangeType = %d \n", pRowset, changeType ));
  287. if ( !_xWatchConnectionPoint.IsNull() &&
  288. _xWatchConnectionPoint->GetAdviseCount() > 0 )
  289. {
  290. switch ( changeType )
  291. {
  292. case DBWATCHNOTIFY_QUERYDONE:
  293. _cQueryDone ++;
  294. if ( _cQueryDone == _cChild )
  295. {
  296. // Do I have any change notifications pending
  297. if ( _cChangeNotify > 0 )
  298. {
  299. // send these first
  300. _xWatchConnectionPoint->DoNotification( _pRowset, DBWATCHNOTIFY_ROWSCHANGED );
  301. _cChangeNotify = 0;
  302. }
  303. _xWatchConnectionPoint->DoNotification( _pRowset, changeType );
  304. _cQueryDone = 0;
  305. }
  306. break;
  307. case DBWATCHNOTIFY_ROWSCHANGED:
  308. _cChangeNotify++;
  309. if ( _cChangeNotify == _cChild )
  310. {
  311. _xWatchConnectionPoint->DoNotification( _pRowset, changeType );
  312. _cChangeNotify = 0;
  313. }
  314. else
  315. {
  316. IRowsetWatchRegion * pIWatchRegion = NULL;
  317. pRowset->QueryInterface( IID_IRowsetWatchRegion,
  318. (void**)&pIWatchRegion );
  319. if ( pIWatchRegion )
  320. {
  321. DBCOUNTITEM pChangesObtained;
  322. DBROWWATCHCHANGE* prgChanges;
  323. pIWatchRegion->Refresh( &pChangesObtained, &prgChanges );
  324. pIWatchRegion->Release();
  325. }
  326. }
  327. break;
  328. case DBWATCHNOTIFY_QUERYREEXECUTED:
  329. _xWatchConnectionPoint->DoNotification( _pRowset, changeType );
  330. _cChangeNotify = _cQueryDone = 0;
  331. break;
  332. default:
  333. Win4Assert( !"Unknown IRowsetWatchNotify ChangeType" );
  334. break;
  335. }
  336. }
  337. Release();
  338. return sc;
  339. }
  340. //
  341. // IRowsetNotify methods.
  342. //
  343. STDMETHOD(OnFieldChange) ( HROW hRow,
  344. DBORDINAL cColumns,
  345. DBORDINAL rgColumns[],
  346. DBREASON eReason,
  347. DBEVENTPHASE ePhase,
  348. BOOL fCantDeny )
  349. {
  350. SCODE sc = S_OK;
  351. if ( !_xRowsetConnectionPoint.IsNull() &&
  352. _xRowsetConnectionPoint->GetAdviseCount() > 0 )
  353. {
  354. sc = _xRowsetConnectionPoint->OnFieldChange( _pRowset,
  355. hRow,
  356. cColumns,
  357. rgColumns,
  358. eReason,
  359. ePhase,
  360. fCantDeny );
  361. }
  362. return sc;
  363. }
  364. STDMETHOD(OnRowChange) ( DBCOUNTITEM cRows,
  365. const HROW rghRows[],
  366. DBREASON eReason,
  367. DBEVENTPHASE ePhase,
  368. BOOL fCantDeny )
  369. {
  370. SCODE sc = S_OK;
  371. if ( !_xRowsetConnectionPoint.IsNull() &&
  372. _xRowsetConnectionPoint->GetAdviseCount() > 0 )
  373. {
  374. sc = _xRowsetConnectionPoint->OnRowChange( _pRowset,
  375. cRows,
  376. rghRows,
  377. eReason,
  378. ePhase,
  379. fCantDeny );
  380. }
  381. return sc;
  382. }
  383. STDMETHOD(OnRowsetChange) ( DBREASON eReason,
  384. DBEVENTPHASE ePhase,
  385. BOOL fCantDeny )
  386. {
  387. SCODE sc = S_OK;
  388. if ( !_xRowsetConnectionPoint.IsNull() &&
  389. _xRowsetConnectionPoint->GetAdviseCount() > 0 )
  390. {
  391. sc = _xRowsetConnectionPoint->OnRowsetChange( _pRowset,
  392. eReason,
  393. ePhase,
  394. fCantDeny );
  395. }
  396. return sc;
  397. }
  398. void AddConnectionPoints( CConnectionPointContainer * pCPC, BOOL fAsynch, BOOL fWatch )
  399. {
  400. _xRowsetConnectionPoint.Set( new CRowsetNotification() );
  401. _xRowsetConnectionPoint->SetContainer( pCPC );
  402. pCPC->AddConnectionPoint( IID_IRowsetNotify,
  403. _xRowsetConnectionPoint.GetPointer() );
  404. if ( fAsynch || fWatch )
  405. {
  406. _xAsynchConnectionPoint.Set( new CClientAsynchNotify() );
  407. _xAsynchConnectionPoint->SetContainer( pCPC );
  408. pCPC->AddConnectionPoint( IID_IDBAsynchNotify,
  409. _xAsynchConnectionPoint.GetPointer() );
  410. if ( fWatch )
  411. {
  412. _xWatchConnectionPoint.Set( new CClientWatchNotify() );
  413. _xWatchConnectionPoint->SetContainer( pCPC );
  414. pCPC->AddConnectionPoint( IID_IRowsetWatchNotify,
  415. _xWatchConnectionPoint.GetPointer() );
  416. }
  417. }
  418. }
  419. private:
  420. ULONG _cRef;
  421. IRowset * const _pRowset;
  422. // Connection point for asynch. watch notifications
  423. XPtr<CClientAsynchNotify> _xAsynchConnectionPoint;
  424. // Connection point for asynch. watch notifications
  425. XPtr<CClientWatchNotify> _xWatchConnectionPoint;
  426. // Connection point for synch rowset notifications
  427. XPtr<CRowsetNotification> _xRowsetConnectionPoint;
  428. unsigned _cQueryDone; // send QueryDone when all child say Done
  429. unsigned _cChangeNotify;// Count of change notifications recd.
  430. unsigned _cChild; // No. of child cursors
  431. unsigned _cAsynchDone; // Used by IDBAsynchNotify to keep track for progress
  432. unsigned _cAsynchStop; // Used by IDBAsynchNotify to keep count of stop notifications received
  433. SCODE _scStopStatus; // Asynch stop status
  434. XGrowable<WCHAR> _xStopStatusText; // Asynch stop status text
  435. CMutexSem _mutexNotify; // Serialize Notifications
  436. };