Leaked source code of windows server 2003
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.

963 lines
26 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 1998.
  5. //
  6. // File: conpt.cxx
  7. //
  8. // Contents: connection point / notification code for cursors
  9. //
  10. // Classes: CConnectionPointBase, CConnectionPointContainer
  11. //
  12. // History: 7 Oct 1994 Dlee Created
  13. // 12 Feb 1998 AlanW Generalized
  14. //
  15. //--------------------------------------------------------------------------
  16. #include "pch.cxx"
  17. #pragma hdrstop
  18. #include <conpt.hxx>
  19. #include "tabledbg.hxx"
  20. // Max. connections per connection point. Should be enough for any application!
  21. const maxConnections = 20;
  22. //+-------------------------------------------------------------------------
  23. //
  24. // Method: CConnectionPointBase::QueryInterface, public
  25. //
  26. // Synopsis: Invokes QueryInterface on container object
  27. //
  28. // Arguments: [riid] -- interface ID
  29. // [ppvObject] -- returned interface pointer
  30. //
  31. // Returns: SCODE
  32. //
  33. // History: 07-Oct-1994 dlee
  34. //
  35. //--------------------------------------------------------------------------
  36. STDMETHODIMP CConnectionPointBase::QueryInterface(
  37. REFIID riid,
  38. void **ppvObject)
  39. {
  40. SCODE sc = S_OK;
  41. if ( 0 == ppvObject )
  42. return E_INVALIDARG;
  43. *ppvObject = 0;
  44. if ( IID_IConnectionPoint == riid )
  45. {
  46. *ppvObject = (void *) (IConnectionPoint *) this;
  47. }
  48. else if ( IID_IUnknown == riid )
  49. {
  50. *ppvObject = (void *) (IUnknown *) this;
  51. }
  52. else
  53. {
  54. sc = E_NOINTERFACE;
  55. }
  56. if (SUCCEEDED(sc))
  57. AddRef();
  58. return sc;
  59. } //QueryInterface
  60. //+-------------------------------------------------------------------------
  61. //
  62. // Method: CConnectionPointBase::AddRef, public
  63. //
  64. // Synopsis: Increments ref. count, or delegates to containing object
  65. //
  66. // Returns: ULONG
  67. //
  68. // History: 17 Mar 1998 AlanW
  69. //
  70. //--------------------------------------------------------------------------
  71. STDMETHODIMP_(ULONG) CConnectionPointBase::AddRef()
  72. {
  73. if (_pIContrUnk)
  74. return _pIContrUnk->AddRef( );
  75. else
  76. {
  77. tbDebugOut(( DEB_NOTIFY, "conpt: addref\n" ));
  78. return InterlockedIncrement( (long *) &_cRefs );
  79. }
  80. } //AddRef
  81. //+-------------------------------------------------------------------------
  82. //
  83. // Method: CConnectionPointBase::Release, public
  84. //
  85. // Synopsis: Decrements ref. count, or delegates to containing object
  86. //
  87. // Returns: ULONG
  88. //
  89. // History: 17 Mar 1998 AlanW
  90. //
  91. //--------------------------------------------------------------------------
  92. STDMETHODIMP_(ULONG) CConnectionPointBase::Release()
  93. {
  94. if (_pIContrUnk)
  95. return _pIContrUnk->Release( );
  96. else
  97. {
  98. long cRefs = InterlockedDecrement((long *) &_cRefs);
  99. tbDebugOut(( DEB_NOTIFY, "conpt: release, new crefs: %lx\n", _cRefs ));
  100. // If no references, make sure container doesn't know about me anymore
  101. if ( 0 == cRefs )
  102. {
  103. Win4Assert( 0 == _pContainer );
  104. #if 0 // Note: no sense trying to avoid an AV for bad client code
  105. if ( 0 != _pContainer )
  106. {
  107. // need to have been disconnected; must be an excess release
  108. // from client
  109. Disconnect();
  110. }
  111. #endif // 0
  112. delete this;
  113. }
  114. return cRefs;
  115. }
  116. } //Release
  117. //+-------------------------------------------------------------------------
  118. //
  119. // Method: CConnectionPointBase::GetConnectionInterface, public
  120. //
  121. // Synopsis: returns the IID of the callback notification object
  122. //
  123. // Arguments: [piid] -- interface ID
  124. //
  125. // Returns: SCODE
  126. //
  127. // History: 07-Oct-1994 dlee
  128. //
  129. //--------------------------------------------------------------------------
  130. STDMETHODIMP CConnectionPointBase::GetConnectionInterface(IID * piid)
  131. {
  132. if ( 0 == piid )
  133. return E_POINTER;
  134. *piid = _iidSink;
  135. return S_OK;
  136. } //GetConnectionInterface
  137. //+-------------------------------------------------------------------------
  138. //
  139. // Method: CConnectionPointBase::GetConnectionPointContainer, public
  140. //
  141. // Synopsis: returns the container that spawned the connection point
  142. //
  143. // Arguments: [ppCPC] -- returns the container
  144. //
  145. // Returns: SCODE
  146. //
  147. // History: 07-Oct-1994 dlee
  148. //
  149. //--------------------------------------------------------------------------
  150. STDMETHODIMP CConnectionPointBase::GetConnectionPointContainer(
  151. IConnectionPointContainer ** ppCPC)
  152. {
  153. if ( 0 == ppCPC )
  154. return E_POINTER;
  155. *ppCPC = 0;
  156. // if disconnected from container, can't do it.
  157. if (0 == _pContainer)
  158. return E_UNEXPECTED;
  159. _pContainer->AddRef();
  160. *ppCPC = _pContainer;
  161. return S_OK;
  162. } //GetConnectionPointContainer
  163. //+-------------------------------------------------------------------------
  164. //
  165. // Method: CConnectionPointBase::Advise, public
  166. //
  167. // Synopsis: Passes in the client's notification object
  168. //
  169. // Arguments: [pIUnk] -- client's notification object
  170. // [pdwCookie] -- returned pseudo-id for this advise
  171. //
  172. // Returns: SCODE
  173. //
  174. // Notes:
  175. //
  176. // History: 07-Oct-1994 dlee
  177. //
  178. //--------------------------------------------------------------------------
  179. STDMETHODIMP CConnectionPointBase::Advise(
  180. IUnknown * piunkNotify,
  181. DWORD * pdwCookie)
  182. {
  183. SCODE sc = S_OK;
  184. if ( 0 != pdwCookie )
  185. *pdwCookie = 0;
  186. if ( 0 == piunkNotify ||
  187. 0 == pdwCookie )
  188. return E_POINTER;
  189. XInterface<IUnknown> piSink;
  190. sc = piunkNotify->QueryInterface( _iidSink, piSink.GetQIPointer() );
  191. if (! SUCCEEDED(sc))
  192. return CONNECT_E_CANNOTCONNECT;
  193. // If disconnected from the container, can't call GetMutex.
  194. if (0 == _pContainer)
  195. return CONNECT_E_ADVISELIMIT;
  196. CLock lock( GetMutex() );
  197. CConnectionContext * pConnCtx = LokFindConnection( 0 );
  198. if (0 == pConnCtx && _xaConns.Count() < maxConnections)
  199. pConnCtx = &_xaConns[_xaConns.Count()];
  200. if (0 == pConnCtx)
  201. sc = CONNECT_E_ADVISELIMIT;
  202. else
  203. {
  204. _dwCookieGen++;
  205. Win4Assert( 0 != _dwCookieGen && 0 == LokFindConnection( _dwCookieGen ) );
  206. pConnCtx->Set( piSink.Acquire(), _dwCookieGen, _dwDefaultSpare );
  207. if (_pAdviseHelper)
  208. (*_pAdviseHelper) (_pAdviseHelperContext, this, pConnCtx);
  209. *pdwCookie = _dwCookieGen;
  210. }
  211. return sc;
  212. } //Advise
  213. //+-------------------------------------------------------------------------
  214. //
  215. // Method: CConnectionPointBase::Unadvise, public
  216. //
  217. // Synopsis: Turns off an advise previously turned on with Advise()
  218. //
  219. // Arguments: [dwCookie] -- pseudo-id for this advise
  220. //
  221. // Returns: SCODE
  222. //
  223. // History: 07-Oct-1994 dlee
  224. //
  225. //--------------------------------------------------------------------------
  226. STDMETHODIMP CConnectionPointBase::Unadvise(
  227. DWORD dwCookie)
  228. {
  229. SCODE sc = S_OK;
  230. CConnectionContext * pConnCtx = 0;
  231. CReleasableLock lock( GetMutex(), ( 0 != _pContainer ) );
  232. pConnCtx = LokFindConnection( dwCookie );
  233. if (pConnCtx)
  234. {
  235. if (_pUnadviseHelper)
  236. (*_pUnadviseHelper) ( _pUnadviseHelperContext, this, pConnCtx, lock );
  237. pConnCtx->Release();
  238. }
  239. if (0 == pConnCtx)
  240. {
  241. tbDebugOut(( DEB_WARN, "conpt: unknown advise cookie %x\n", dwCookie ));
  242. sc = CONNECT_E_NOCONNECTION;
  243. }
  244. return sc;
  245. } //Unadvise
  246. //+-------------------------------------------------------------------------
  247. //
  248. // Method: CConnectionPointBase::EnumConnections, public
  249. //
  250. // Synopsis: Returns an enumerator of advises open in this connection
  251. //
  252. // Arguments: [ppEnum] -- returned enumerator
  253. //
  254. // Returns: SCODE
  255. //
  256. // Notes: The spec permits E_NOTIMPL to be returned for this. If
  257. // we chose to implement it, it's a straightforward matter of
  258. // iterating over the _xaConns array.
  259. //
  260. // History: 07-Oct-1994 dlee
  261. //
  262. //--------------------------------------------------------------------------
  263. STDMETHODIMP CConnectionPointBase::EnumConnections(
  264. IEnumConnections ** ppEnum)
  265. {
  266. if ( 0 == ppEnum )
  267. return E_POINTER;
  268. *ppEnum = 0;
  269. return E_NOTIMPL;
  270. } //EnumConnections
  271. //+-------------------------------------------------------------------------
  272. //
  273. // Method: CConnectionPointBase::Disconnect, private
  274. //
  275. // Synopsis: Disconnect from the connection point container
  276. //
  277. // Arguments: [dwCookie] -- pseudo-id for this advise
  278. //
  279. // Returns: CConnectionContext* - a connection matching the [dwCookie] or 0
  280. //
  281. // Notes: Should be called with the CPC lock held. Might be called
  282. // without the lock for an Unadvise after the CPC is diconnected.
  283. //
  284. // History: 30 Mar 1998 AlanW Created
  285. //
  286. //--------------------------------------------------------------------------
  287. void CConnectionPointBase::Disconnect( )
  288. {
  289. Win4Assert( 0 != _pContainer );
  290. CLock lock(GetMutex());
  291. _pContainer->RemoveConnectionPoint( this );
  292. _pContainer = 0;
  293. }
  294. //+-------------------------------------------------------------------------
  295. //
  296. // Method: CConnectionPointBase::LokFindConnection, private
  297. //
  298. // Synopsis: Find a connection matching an advise cookie
  299. //
  300. // Arguments: [dwCookie] -- pseudo-id for this advise
  301. //
  302. // Returns: CConnectionContext* - a connection matching the [dwCookie] or 0
  303. //
  304. // Notes: Should be called with the CPC lock held. Might be called
  305. // without the lock for an Unadvise after the CPC is diconnected.
  306. //
  307. // History: 10 Mar 1998 AlanW Created
  308. //
  309. //--------------------------------------------------------------------------
  310. CConnectionPointBase::CConnectionContext *
  311. CConnectionPointBase::LokFindConnection( DWORD dwCookie )
  312. {
  313. for (unsigned i=0; i<_xaConns.Count(); i++)
  314. {
  315. CConnectionContext & rConnCtx = _xaConns[i];
  316. if (rConnCtx._dwAdviseCookie == dwCookie)
  317. return &rConnCtx;
  318. }
  319. return 0;
  320. }
  321. //+-------------------------------------------------------------------------
  322. //
  323. // Method: CConnectionPointBase::LokFindActiveConnection, private
  324. //
  325. // Synopsis: Find an active advise by indexing
  326. //
  327. // Arguments: [riConn] -- index into conn. context array, updated on return
  328. //
  329. // Returns: CConnectionContext* - pointer to an active connection context,
  330. // or NULL.
  331. //
  332. // Notes: Should be called with the CPC lock held.
  333. //
  334. // History: 10 Mar 1998 AlanW Created
  335. //
  336. //--------------------------------------------------------------------------
  337. CConnectionPointBase::CConnectionContext *
  338. CConnectionPointBase::LokFindActiveConnection( unsigned & riConn )
  339. {
  340. while (riConn < _xaConns.Count())
  341. {
  342. CConnectionContext & rCtx = _xaConns[riConn];
  343. if (rCtx._dwAdviseCookie != 0)
  344. return &rCtx;
  345. riConn++;
  346. }
  347. return 0;
  348. }
  349. /////////////////////////////////////////////////////////////////
  350. /////////////////////////////////////////////////////////////////
  351. /////////////////////////////////////////////////////////////////
  352. /////////////////////////////////////////////////////////////////
  353. /////////////////////////////////////////////////////////////////
  354. /////////////////////////////////////////////////////////////////
  355. //+-------------------------------------------------------------------------
  356. //
  357. // Method: CConnectionPointContainer::QueryInterface, public
  358. //
  359. // Synopsis: Invokes QueryInterface on cursor object
  360. //
  361. // Arguments: [riid] -- interface ID
  362. // [ppvObject] -- returned interface pointer
  363. //
  364. // Returns: SCODE
  365. //
  366. // History: 07-Oct-1994 dlee
  367. //
  368. //--------------------------------------------------------------------------
  369. STDMETHODIMP CConnectionPointContainer::QueryInterface(
  370. REFIID riid,
  371. void **ppvObject)
  372. {
  373. if ( 0 == ppvObject )
  374. return E_INVALIDARG;
  375. return _rControllingUnk.QueryInterface(riid, ppvObject);
  376. } //QueryInterface
  377. //+-------------------------------------------------------------------------
  378. //
  379. // Method: CConnectionPointContainer::AddRef, public
  380. //
  381. // Synopsis: Invokes AddRef on cursor object
  382. //
  383. // Returns: ULONG
  384. //
  385. // History: 07-Oct-1994 dlee
  386. //
  387. //--------------------------------------------------------------------------
  388. STDMETHODIMP_(ULONG) CConnectionPointContainer::AddRef()
  389. {
  390. tbDebugOut(( DEB_NOTIFY, "conptcontainer: addref\n" ));
  391. return _rControllingUnk.AddRef();
  392. } //AddRef
  393. //+-------------------------------------------------------------------------
  394. //
  395. // Method: CConnectionPointContainer::Release, public
  396. //
  397. // Synopsis: Invokes Release on cursor object
  398. //
  399. // Returns: ULONG
  400. //
  401. // History: 07-Oct-1994 dlee
  402. //
  403. //--------------------------------------------------------------------------
  404. STDMETHODIMP_(ULONG) CConnectionPointContainer::Release()
  405. {
  406. tbDebugOut(( DEB_NOTIFY, "conptcontainer: release\n" ));
  407. return _rControllingUnk.Release();
  408. } //Release
  409. //+-------------------------------------------------------------------------
  410. //
  411. // Method: CConnectionPointContainer::CConnectionPointContainer, public
  412. //
  413. // Synopsis: Constructor for connection point container class.
  414. //
  415. // Arguments: [maxConnPt] -- maximum number of connection points supported
  416. // [rUnknown] -- controlling unknown
  417. // [ErrorObject] -- reference to error object
  418. //
  419. // Notes: After construction, use AddConnectionPoint to add a connection
  420. // point into the container.
  421. //
  422. // History: 07-Oct-1994 dlee
  423. //
  424. //--------------------------------------------------------------------------
  425. CConnectionPointContainer::CConnectionPointContainer(
  426. unsigned maxConnPt,
  427. IUnknown &rUnknown,
  428. CCIOleDBError & ErrorObject )
  429. : _rControllingUnk(rUnknown),
  430. _ErrorObject( ErrorObject ),
  431. _cConnPt( 0 )
  432. {
  433. Win4Assert( maxConnPt <= maxConnectionPoints );
  434. } //CConnectionPointContainer
  435. //+-------------------------------------------------------------------------
  436. //
  437. // Method: CConnectionPointContainer::~CConnectionPointContainer, public
  438. //
  439. // Synopsis: Destructor for connection point container class.
  440. //
  441. // Notes: It is expected that all connection points are relased by this
  442. // time.
  443. //
  444. // History: 07-Oct-1994 dlee
  445. //
  446. //--------------------------------------------------------------------------
  447. CConnectionPointContainer::~CConnectionPointContainer()
  448. {
  449. CLock lock( _mutex );
  450. //
  451. // Release all connection points
  452. //
  453. for (unsigned i = 0; i < _cConnPt; i++)
  454. {
  455. IConnectionPoint * pIConnPt = _aConnPt[i]._pIConnPt;
  456. if ( 0 != pIConnPt )
  457. {
  458. _aConnPt[i]._pIConnPt = 0;
  459. pIConnPt->Release();
  460. }
  461. }
  462. } //~CConnectionPointContainer
  463. //+-------------------------------------------------------------------------
  464. //
  465. // Method: CConnectionPointContainer::FindConnectionPoint, public
  466. //
  467. // Synopsis: Finds a connection point object that supports the given
  468. // interface for callback to the client
  469. //
  470. // Arguments: [riid] -- interface ID for proposed callback
  471. // [ppPoint] -- returned connection interface pointer
  472. //
  473. // Returns: SCODE
  474. //
  475. // History: 07-Oct-1994 dlee
  476. //
  477. //--------------------------------------------------------------------------
  478. STDMETHODIMP CConnectionPointContainer::FindConnectionPoint(
  479. REFIID riid,
  480. IConnectionPoint ** ppPoint)
  481. {
  482. _ErrorObject.ClearErrorInfo();
  483. if ( 0 == ppPoint )
  484. return E_POINTER;
  485. *ppPoint = 0;
  486. SCODE sc = S_OK;
  487. TRANSLATE_EXCEPTIONS;
  488. TRY
  489. {
  490. CLock lock( _mutex );
  491. for (unsigned i = 0; i < _cConnPt; i++)
  492. {
  493. if ( riid == _aConnPt[i]._iidConnPt )
  494. break;
  495. }
  496. if ( i<_cConnPt )
  497. {
  498. Win4Assert(_aConnPt[i]._pIConnPt != 0);
  499. IConnectionPoint * pIConnPt = _aConnPt[i]._pIConnPt;
  500. *ppPoint = pIConnPt;
  501. pIConnPt->AddRef();
  502. }
  503. else
  504. {
  505. sc = CONNECT_E_NOCONNECTION;
  506. }
  507. if (FAILED(sc))
  508. _ErrorObject.PostHResult(sc, IID_IConnectionPointContainer);
  509. }
  510. CATCH(CException,e)
  511. {
  512. _ErrorObject.PostHResult(e.GetErrorCode(), IID_IConnectionPointContainer);
  513. sc = E_UNEXPECTED;
  514. }
  515. END_CATCH;
  516. UNTRANSLATE_EXCEPTIONS;
  517. return sc;
  518. } //FindConnectionPoint
  519. //+-------------------------------------------------------------------------
  520. //
  521. // Method: CConnectionPointContainer::EnumConnectionPoints, public
  522. //
  523. // Synopsis: Enumerates all connection points currently in use
  524. //
  525. // Arguments: [ppEnum] -- returned enumerator
  526. //
  527. // Returns: SCODE
  528. //
  529. // History: 09 Mar 1998 AlanW Created
  530. //
  531. //--------------------------------------------------------------------------
  532. STDMETHODIMP CConnectionPointContainer::EnumConnectionPoints(
  533. IEnumConnectionPoints **ppEnum)
  534. {
  535. _ErrorObject.ClearErrorInfo();
  536. if ( 0 == ppEnum )
  537. return E_POINTER;
  538. *ppEnum = 0;
  539. SCODE sc = S_OK;
  540. TRANSLATE_EXCEPTIONS;
  541. TRY
  542. {
  543. CLock lock( _mutex );
  544. XInterface<IEnumConnectionPoints> pEnumCp( new CEnumConnectionPoints( *this ) );
  545. *ppEnum = pEnumCp.GetPointer();
  546. pEnumCp.Acquire();
  547. }
  548. CATCH(CException,e)
  549. {
  550. _ErrorObject.PostHResult(e.GetErrorCode(), IID_IConnectionPointContainer);
  551. sc = e.GetErrorCode();
  552. }
  553. END_CATCH;
  554. UNTRANSLATE_EXCEPTIONS;
  555. return sc;
  556. } //EnumConnectionPoints
  557. //+-------------------------------------------------------------------------
  558. //
  559. // Method: CEnumConnectionPoints::QueryInterface, public
  560. //
  561. // Synopsis: Invokes QueryInterface on connection point enumerator object
  562. //
  563. // Arguments: [riid] -- interface ID
  564. // [ppvObject] -- returned interface pointer
  565. //
  566. // Returns: SCODE
  567. //
  568. // History: 10 Mar 1998 AlanW
  569. //
  570. //--------------------------------------------------------------------------
  571. STDMETHODIMP CEnumConnectionPoints::QueryInterface(
  572. REFIID riid,
  573. void **ppvObject)
  574. {
  575. SCODE sc = S_OK;
  576. if ( 0 == ppvObject )
  577. return E_INVALIDARG;
  578. *ppvObject = 0;
  579. if ( IID_IEnumConnectionPoints == riid )
  580. {
  581. *ppvObject = (void *) (IEnumConnectionPoints *) this;
  582. }
  583. else if ( IID_IUnknown == riid )
  584. {
  585. *ppvObject = (void *) (IUnknown *) this;
  586. }
  587. else
  588. {
  589. sc = E_NOINTERFACE;
  590. }
  591. if (SUCCEEDED(sc))
  592. AddRef();
  593. return sc;
  594. } //QueryInterface
  595. //+-------------------------------------------------------------------------
  596. //
  597. // Method: CEnumConnectionPoints::AddRef, public
  598. //
  599. // Synopsis: Invokes AddRef on container object
  600. //
  601. // Returns: ULONG
  602. //
  603. // History: 07-Oct-1994 dlee
  604. //
  605. //--------------------------------------------------------------------------
  606. STDMETHODIMP_(ULONG) CEnumConnectionPoints::AddRef()
  607. {
  608. return InterlockedIncrement( (long *) &_cRefs );
  609. } //AddRef
  610. //+-------------------------------------------------------------------------
  611. //
  612. // Method: CEnumConnectionPoints::Release, public
  613. //
  614. // Synopsis: Invokes Release on container object
  615. //
  616. // Returns: ULONG
  617. //
  618. // History: 07-Oct-1994 dlee
  619. //
  620. //--------------------------------------------------------------------------
  621. STDMETHODIMP_(ULONG) CEnumConnectionPoints::Release()
  622. {
  623. long cRefs = InterlockedDecrement((long *) &_cRefs);
  624. tbDebugOut(( DEB_NOTIFY, "enumconpt: release, new crefs: %lx\n", _cRefs ));
  625. // If no references, delete.
  626. if ( 0 == cRefs )
  627. {
  628. delete this;
  629. }
  630. return cRefs;
  631. } //Release
  632. //+-------------------------------------------------------------------------
  633. //
  634. // Method: CEnumConnectionPoints::Clone, public
  635. //
  636. // Synopsis: Clone a connection point enumerator
  637. //
  638. // Arguments: [ppEnum] -- returned enumerator
  639. //
  640. // Returns: SCODE
  641. //
  642. // History: 09 Mar 1998 AlanW Created
  643. //
  644. //--------------------------------------------------------------------------
  645. STDMETHODIMP CEnumConnectionPoints::Clone (
  646. IEnumConnectionPoints **ppEnum)
  647. {
  648. //_ErrorObject.ClearErrorInfo();
  649. if ( 0 == ppEnum )
  650. return E_POINTER;
  651. *ppEnum = 0;
  652. SCODE sc = S_OK;
  653. TRANSLATE_EXCEPTIONS;
  654. TRY
  655. {
  656. XInterface<CEnumConnectionPoints> pEnumCp( new CEnumConnectionPoints( _rContainer ) );
  657. pEnumCp->_iConnPt = _iConnPt;
  658. *ppEnum = pEnumCp.GetPointer();
  659. pEnumCp.Acquire();
  660. }
  661. CATCH(CException,e)
  662. {
  663. sc = e.GetErrorCode();
  664. }
  665. END_CATCH;
  666. UNTRANSLATE_EXCEPTIONS;
  667. return sc;
  668. } //Clone
  669. //+-------------------------------------------------------------------------
  670. //
  671. // Method: CEnumConnectionPoints::Reset, public
  672. //
  673. // Synopsis: Reset a connection point enumerator
  674. //
  675. // Arguments: -NONE-
  676. //
  677. // Returns: SCODE
  678. //
  679. // History: 09 Mar 1998 AlanW Created
  680. //
  681. //--------------------------------------------------------------------------
  682. STDMETHODIMP CEnumConnectionPoints::Reset ( )
  683. {
  684. _iConnPt = 0;
  685. return S_OK;
  686. } //Reset
  687. //+-------------------------------------------------------------------------
  688. //
  689. // Method: CEnumConnectionPoints::Skip, public
  690. //
  691. // Synopsis: Skip some connection points
  692. //
  693. // Arguments: [cConnections] - number of connection points to skip
  694. //
  695. // Returns: SCODE
  696. //
  697. // History: 09 Mar 1998 AlanW Created
  698. //
  699. //--------------------------------------------------------------------------
  700. STDMETHODIMP CEnumConnectionPoints::Skip ( ULONG cConnections )
  701. {
  702. SCODE sc = S_OK;
  703. if ( _iConnPt+cConnections < _rContainer._cConnPt )
  704. _iConnPt += cConnections;
  705. else
  706. sc = S_FALSE;
  707. return sc;
  708. } //Skip
  709. //+-------------------------------------------------------------------------
  710. //
  711. // Method: CEnumConnectionPoints::Next, public
  712. //
  713. // Synopsis: Return some connection points
  714. //
  715. // Arguments: [cConnections] - number of connection points to return, at most
  716. // [rgpcm] - array of IConnectionPoint* to be returned
  717. // [pcFetched] - on return, number of connection points in [rgpcm]
  718. //
  719. // Returns: SCODE
  720. //
  721. // History: 09 Mar 1998 AlanW Created
  722. //
  723. //--------------------------------------------------------------------------
  724. STDMETHODIMP CEnumConnectionPoints::Next ( ULONG cConnections,
  725. IConnectionPoint **rgpcm,
  726. ULONG * pcFetched )
  727. {
  728. SCODE sc = S_OK;
  729. if ( 0 != pcFetched )
  730. *pcFetched = 0;
  731. if ( 0 == rgpcm ||
  732. 0 == pcFetched )
  733. return E_POINTER;
  734. for (ULONG i=0; i<cConnections; i++)
  735. rgpcm[i] = 0;
  736. TRANSLATE_EXCEPTIONS;
  737. TRY
  738. {
  739. ULONG cRet = 0;
  740. CLock lock(_rContainer._mutex);
  741. // Note: There could be leakage of CP pointers if there are exceptions
  742. // generated by the code below.
  743. while ( _iConnPt < _rContainer._cConnPt &&
  744. cRet < cConnections )
  745. {
  746. XInterface<IConnectionPoint> xCP( _rContainer._aConnPt[_iConnPt]._pIConnPt );
  747. xCP->AddRef();
  748. rgpcm[cRet] = xCP.GetPointer();
  749. cRet++;
  750. _iConnPt++;
  751. *pcFetched = cRet;
  752. xCP.Acquire();
  753. }
  754. sc = (cConnections == cRet) ? S_OK : S_FALSE;
  755. }
  756. CATCH(CException,e)
  757. {
  758. sc = e.GetErrorCode();
  759. }
  760. END_CATCH;
  761. UNTRANSLATE_EXCEPTIONS;
  762. return sc;
  763. } //Next
  764. //+-------------------------------------------------------------------------
  765. //
  766. // Method: CConnectionPointContainer::AddConnectionPoint, public
  767. //
  768. // Synopsis: Adds a connection point to the container.
  769. // Called by the connection point itself.
  770. //
  771. // Arguments: [riid] --- IID of notification interface for CP
  772. // [pConnPt] --- connection point to be removed
  773. //
  774. // Notes: The back pointer from the connection point to the connection
  775. // point container does not contribute to the container's ref.
  776. // count so that the CPC <-> CP structure is not self-referential
  777. // and can be deleted when no longer needed.
  778. //
  779. // History: 10 Mar 1998 AlanW
  780. //
  781. //--------------------------------------------------------------------------
  782. void CConnectionPointContainer::AddConnectionPoint(
  783. REFIID riid,
  784. CConnectionPointBase *pConnPt)
  785. {
  786. Win4Assert( _cConnPt < maxConnectionPoints );
  787. XInterface<IConnectionPoint> xConnPt;
  788. SCODE sc = pConnPt->QueryInterface( IID_IConnectionPoint,
  789. xConnPt.GetQIPointer());
  790. if (!SUCCEEDED(sc))
  791. THROW( CException(sc) );
  792. CLock lock(_mutex);
  793. CConnectionPointContext * pConnPtCtx = &_aConnPt[_cConnPt];
  794. pConnPtCtx->_pIConnPt = xConnPt.Acquire();
  795. pConnPtCtx->_iidConnPt = riid;
  796. _cConnPt++;
  797. } //AddConnectionPoint
  798. //+-------------------------------------------------------------------------
  799. //
  800. // Method: CConnectionPointContainer::RemoveConnectionPoint, public
  801. //
  802. // Synopsis: Removes a connection point from the container.
  803. // Called by the connection point itself.
  804. //
  805. // Arguments: [pConnPt] --- connection point to be removed
  806. //
  807. // History: 07-Oct-1994 dlee
  808. //
  809. //--------------------------------------------------------------------------
  810. void CConnectionPointContainer::RemoveConnectionPoint(
  811. IConnectionPoint *pConnPt)
  812. {
  813. CLock lock(_mutex);
  814. for (unsigned i = 0; i < _cConnPt; i++)
  815. {
  816. if ( _aConnPt[i]._pIConnPt == pConnPt )
  817. {
  818. _aConnPt[i]._pIConnPt = 0;
  819. pConnPt->Release();
  820. }
  821. }
  822. } //RemoveConnectionPoint