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.

872 lines
18 KiB

  1. /*++
  2. Copyright (C) 1993-1999 Microsoft Corporation
  3. Module Name:
  4. iconnpt.cpp
  5. Abstract:
  6. Implementation of CImpIConnectionPoint for the Polyline object
  7. as well as CConnectionPoint.
  8. --*/
  9. #include "polyline.h"
  10. #include "iconnpt.h"
  11. #include "unkhlpr.h"
  12. static const IID *apIIDConnectPt [CONNECTION_POINT_CNT] = {
  13. &IID_ISystemMonitorEvents,
  14. &DIID_DISystemMonitorEvents
  15. };
  16. //
  17. // CImpIConnPt interface implementation
  18. //
  19. IMPLEMENT_CONTAINED_IUNKNOWN(CImpIConnPtCont)
  20. /*
  21. * CImpIConnPtCont::CImpIConnPtCont
  22. *
  23. * Purpose:
  24. * Constructor.
  25. *
  26. * Return Value:
  27. */
  28. CImpIConnPtCont::CImpIConnPtCont ( PCPolyline pObj, LPUNKNOWN pUnkOuter)
  29. : m_cRef(0),
  30. m_pObj(pObj),
  31. m_pUnkOuter(pUnkOuter)
  32. {
  33. return;
  34. }
  35. /*
  36. * CImpIConnPtCont::~CImpIConnPtCont
  37. *
  38. * Purpose:
  39. * Destructor.
  40. *
  41. * Return Value:
  42. */
  43. CImpIConnPtCont::~CImpIConnPtCont( void )
  44. {
  45. return;
  46. }
  47. /*
  48. * CImpIConnPtCont::EnumConnectionPoints
  49. *
  50. * Purpose:
  51. * Not implemented.
  52. *
  53. * Return Value:
  54. * HRESULT Error code or S_OK
  55. */
  56. STDMETHODIMP
  57. CImpIConnPtCont::EnumConnectionPoints (
  58. OUT LPENUMCONNECTIONPOINTS *ppIEnum
  59. )
  60. {
  61. CImpIEnumConnPt *pEnum;
  62. HRESULT hr = S_OK;
  63. if (ppIEnum == NULL) {
  64. return E_POINTER;
  65. }
  66. pEnum = new CImpIEnumConnPt(this, apIIDConnectPt, CONNECTION_POINT_CNT);
  67. if (pEnum == NULL) {
  68. hr = E_OUTOFMEMORY;
  69. }
  70. else {
  71. try {
  72. *ppIEnum = NULL;
  73. hr = pEnum->QueryInterface(IID_IEnumConnectionPoints, (PPVOID)ppIEnum);
  74. } catch (...) {
  75. hr = E_POINTER;
  76. }
  77. }
  78. if (FAILED(hr) && pEnum) {
  79. delete pEnum;
  80. }
  81. return hr;
  82. }
  83. /*
  84. * CImpIConnPtCont::FindConnectionPoint
  85. *
  86. * Purpose:
  87. * Returns a pointer to the IConnectionPoint for a given
  88. * outgoing IID.
  89. *
  90. * Parameters:
  91. * riid REFIID of the outgoing interface for which
  92. * a connection point is desired.
  93. * ppCP IConnectionPoint ** in which to return
  94. * the pointer after calling AddRef.
  95. *
  96. * Return Value:
  97. * HRESULT NOERROR if the connection point is found,
  98. * E_NOINTERFACE if it's not supported.
  99. */
  100. STDMETHODIMP
  101. CImpIConnPtCont::FindConnectionPoint (
  102. IN REFIID riid,
  103. OUT IConnectionPoint **ppCP
  104. )
  105. {
  106. HRESULT hr = S_OK;
  107. PCImpIConnectionPoint pConnPt = NULL;
  108. if (ppCP == NULL) {
  109. return E_POINTER;
  110. }
  111. //
  112. // if request matches one of our connection IDs
  113. //
  114. if (IID_ISystemMonitorEvents == riid)
  115. pConnPt = &m_pObj->m_ConnectionPoint[eConnectionPointDirect];
  116. else if (DIID_DISystemMonitorEvents == riid)
  117. pConnPt = &m_pObj->m_ConnectionPoint[eConnectionPointDispatch];
  118. else {
  119. hr = E_NOINTERFACE;
  120. }
  121. if (SUCCEEDED(hr)) {
  122. try {
  123. *ppCP=NULL;
  124. //
  125. // Return the IConnectionPoint interface
  126. //
  127. hr = pConnPt->QueryInterface(IID_IConnectionPoint, (PPVOID)ppCP);
  128. } catch (...) {
  129. hr = E_POINTER;
  130. }
  131. }
  132. return hr;
  133. }
  134. /*
  135. * CImpIConnectionPoint constructor
  136. */
  137. CImpIConnectionPoint::CImpIConnectionPoint (
  138. void
  139. )
  140. : m_cRef(0),
  141. m_pObj(NULL),
  142. m_pUnkOuter(NULL),
  143. m_hEventEventSink(NULL),
  144. m_lSendEventRefCount(0),
  145. m_lUnadviseRefCount(0)
  146. {
  147. m_Connection.pIDirect = NULL;
  148. m_Connection.pIDispatch = NULL;
  149. }
  150. /*
  151. * CImpIConnectionPoint destructor
  152. */
  153. CImpIConnectionPoint::~CImpIConnectionPoint (
  154. void
  155. )
  156. {
  157. DeinitEventSinkLock();
  158. }
  159. /*
  160. * CImpIConnectionPoint::QueryInterface
  161. * CImpIConnectionPoint::AddRef
  162. * CCImpIonnectionPoint::Release
  163. *
  164. */
  165. STDMETHODIMP
  166. CImpIConnectionPoint::QueryInterface (
  167. IN REFIID riid,
  168. OUT LPVOID *ppv
  169. )
  170. {
  171. HRESULT hr = S_OK;
  172. if (ppv == NULL) {
  173. return E_POINTER;
  174. }
  175. try {
  176. *ppv = NULL;
  177. if (IID_IUnknown==riid || IID_IConnectionPoint==riid) {
  178. *ppv = (PVOID)this;
  179. AddRef();
  180. }
  181. else {
  182. hr = E_NOINTERFACE;
  183. }
  184. } catch (...) {
  185. hr = E_POINTER;
  186. }
  187. return hr;
  188. }
  189. STDMETHODIMP_(ULONG)
  190. CImpIConnectionPoint::AddRef(
  191. void
  192. )
  193. {
  194. ++m_cRef;
  195. return m_pUnkOuter->AddRef();
  196. }
  197. STDMETHODIMP_(ULONG)
  198. CImpIConnectionPoint::Release (
  199. void
  200. )
  201. {
  202. --m_cRef;
  203. return m_pUnkOuter->Release();
  204. }
  205. /*
  206. * CImpIConnectionPoint::Init
  207. *
  208. * Purpose:
  209. * Set back-pointers and connection type.
  210. *
  211. * Paramters:
  212. * pObj Containing Object
  213. * pUnkOuter Controlling Object
  214. * iConnectType Connection point type
  215. */
  216. BOOL
  217. CImpIConnectionPoint::Init (
  218. IN PCPolyline pObj,
  219. IN LPUNKNOWN pUnkOuter,
  220. IN INT iConnPtType
  221. )
  222. {
  223. DWORD dwStat = 0;
  224. m_pObj = pObj;
  225. m_pUnkOuter = pUnkOuter;
  226. m_iConnPtType = iConnPtType;
  227. dwStat = InitEventSinkLock();
  228. if (dwStat != ERROR_SUCCESS) {
  229. return FALSE;
  230. }
  231. return TRUE;
  232. }
  233. /*
  234. * CImpIConnectionPoint::GetConnectionInterface
  235. *
  236. * Purpose:
  237. * Returns the IID of the outgoing interface supported through
  238. * this connection point.
  239. *
  240. * Parameters:
  241. * pIID IID * in which to store the IID.
  242. */
  243. STDMETHODIMP
  244. CImpIConnectionPoint::GetConnectionInterface (
  245. OUT IID *pIID
  246. )
  247. {
  248. HRESULT hr = S_OK;
  249. if (pIID == NULL) {
  250. return E_POINTER;
  251. }
  252. try {
  253. *pIID = *apIIDConnectPt[m_iConnPtType];
  254. } catch (...) {
  255. hr = E_POINTER;
  256. }
  257. return hr;
  258. }
  259. /*
  260. * CImpIConnectionPoint::GetConnectionPointContainer
  261. *
  262. * Purpose:
  263. * Returns a pointer to the IConnectionPointContainer that
  264. * is manageing this connection point.
  265. *
  266. * Parameters:
  267. * ppCPC IConnectionPointContainer ** in which to return
  268. * the pointer after calling AddRef.
  269. */
  270. STDMETHODIMP
  271. CImpIConnectionPoint::GetConnectionPointContainer (
  272. OUT IConnectionPointContainer **ppCPC
  273. )
  274. {
  275. HRESULT hr = S_OK;
  276. if (ppCPC == NULL) {
  277. return E_POINTER;
  278. }
  279. try {
  280. *ppCPC = NULL;
  281. m_pObj->QueryInterface(IID_IConnectionPointContainer, (void **)ppCPC);
  282. } catch (...) {
  283. hr = E_POINTER;
  284. }
  285. return hr;
  286. }
  287. /*
  288. * CImpIConnectionPoint::Advise
  289. *
  290. * Purpose:
  291. * Provides this connection point with a notification sink to
  292. * call whenever the appropriate outgoing function/event occurs.
  293. *
  294. * Parameters:
  295. * pUnkSink LPUNKNOWN to the sink to notify. The connection
  296. * point must QueryInterface on this pointer to obtain
  297. * the proper interface to call. The connection
  298. * point must also insure that any pointer held has
  299. * a reference count (QueryInterface will do it).
  300. * pdwCookie DWORD * in which to store the connection key for
  301. * later calls to Unadvise.
  302. */
  303. STDMETHODIMP
  304. CImpIConnectionPoint::Advise (
  305. IN LPUNKNOWN pUnkSink,
  306. OUT DWORD *pdwCookie
  307. )
  308. {
  309. HRESULT hr = S_OK;
  310. if (pUnkSink == NULL || pdwCookie == NULL) {
  311. return E_POINTER;
  312. }
  313. //
  314. // Can only support one connection
  315. //
  316. if (NULL != m_Connection.pIDirect) {
  317. hr = CONNECT_E_ADVISELIMIT;
  318. }
  319. else {
  320. try {
  321. *pdwCookie = 0;
  322. //
  323. // Get interface from sink
  324. //
  325. hr = pUnkSink->QueryInterface(*apIIDConnectPt[m_iConnPtType], (PPVOID)&m_Connection);
  326. if (SUCCEEDED(hr)) {
  327. //
  328. // Return our cookie
  329. //
  330. *pdwCookie = eAdviseKey;
  331. }
  332. } catch (...) {
  333. hr = E_POINTER;
  334. }
  335. }
  336. return hr;
  337. }
  338. /*
  339. * CImpIConnectionPoint::SendEvent
  340. *
  341. * Purpose:
  342. * Sends an event to the attached event sink
  343. *
  344. * Parameters:
  345. * uEventType Event code
  346. * dwParam Parameter to send with event
  347. *
  348. */
  349. void
  350. CImpIConnectionPoint::SendEvent (
  351. IN UINT uEventType,
  352. IN DWORD dwParam
  353. )
  354. {
  355. // If not connected, just return.
  356. if ( EnterSendEvent() ) {
  357. if (m_Connection.pIDirect != NULL) {
  358. // For direct connection, call the method
  359. if (m_iConnPtType == eConnectionPointDirect) {
  360. switch (uEventType) {
  361. case eEventOnCounterSelected:
  362. m_Connection.pIDirect->OnCounterSelected((INT)dwParam);
  363. break;
  364. case eEventOnCounterAdded:
  365. m_Connection.pIDirect->OnCounterAdded((INT)dwParam);
  366. break;
  367. case eEventOnCounterDeleted:
  368. m_Connection.pIDirect->OnCounterDeleted((INT)dwParam);
  369. break;
  370. case eEventOnSampleCollected:
  371. m_Connection.pIDirect->OnSampleCollected();
  372. break;
  373. case eEventOnDblClick:
  374. m_Connection.pIDirect->OnDblClick((INT)dwParam);
  375. break;
  376. }
  377. }
  378. // for dispatch connection, call Invoke
  379. else if ( m_iConnPtType == eConnectionPointDispatch ) {
  380. if ( NULL != m_Connection.pIDispatch ) {
  381. DISPPARAMS dp;
  382. VARIANT vaRet;
  383. VARIANTARG varg;
  384. VariantInit(&vaRet);
  385. if ( uEventType == eEventOnSampleCollected ) {
  386. SETNOPARAMS(dp)
  387. } else {
  388. VariantInit(&varg);
  389. V_VT(&varg) = VT_I4;
  390. V_I4(&varg) = (INT)dwParam;
  391. SETDISPPARAMS(dp, 1, &varg, 0, NULL)
  392. }
  393. m_Connection.pIDispatch->Invoke(uEventType,
  394. IID_NULL,
  395. LOCALE_USER_DEFAULT,
  396. DISPATCH_METHOD,
  397. &dp ,
  398. &vaRet,
  399. NULL,
  400. NULL);
  401. }
  402. }
  403. }
  404. }
  405. ExitSendEvent();
  406. return;
  407. }
  408. /*
  409. * CImpIConnectionPoint::Unadvise
  410. *
  411. * Purpose:
  412. * Terminates the connection to the notification sink identified
  413. * with dwCookie (that was returned from Advise). The connection
  414. * point has to Release any held pointers for that sink.
  415. *
  416. * Parameters:
  417. * dwCookie DWORD connection key from Advise.
  418. */
  419. STDMETHODIMP
  420. CImpIConnectionPoint::Unadvise (
  421. IN DWORD dwCookie
  422. )
  423. {
  424. if (eAdviseKey != dwCookie)
  425. return CONNECT_E_NOCONNECTION;
  426. EnterUnadvise();
  427. m_Connection.pIDirect = NULL;
  428. ExitUnadvise();
  429. return S_OK;
  430. }
  431. /*
  432. * CImpIConnectionPoint::EnumConnections
  433. *
  434. * Purpose:
  435. * Not implemented because only one conection is allowed
  436. */
  437. STDMETHODIMP
  438. CImpIConnectionPoint::EnumConnections (
  439. OUT LPENUMCONNECTIONS *ppEnum
  440. )
  441. {
  442. HRESULT hr = E_NOTIMPL;
  443. if (ppEnum == NULL) {
  444. return E_POINTER;
  445. }
  446. try {
  447. *ppEnum = NULL;
  448. } catch (...) {
  449. hr = E_POINTER;
  450. }
  451. return hr;
  452. }
  453. /*
  454. * Locks for the event sink.
  455. */
  456. DWORD
  457. CImpIConnectionPoint::InitEventSinkLock ( void )
  458. {
  459. DWORD dwStat = 0;
  460. m_lUnadviseRefCount = 0;
  461. m_lSendEventRefCount = 0;
  462. if ( NULL == ( m_hEventEventSink = CreateEvent ( NULL, TRUE, TRUE, NULL ) ) )
  463. dwStat = GetLastError();
  464. return dwStat;
  465. }
  466. void
  467. CImpIConnectionPoint::DeinitEventSinkLock ( void )
  468. {
  469. // Release the event sink lock
  470. if ( NULL != m_hEventEventSink ) {
  471. CloseHandle ( m_hEventEventSink );
  472. m_hEventEventSink = NULL;
  473. }
  474. m_lSendEventRefCount = 0;
  475. m_lUnadviseRefCount = 0;
  476. }
  477. BOOL
  478. CImpIConnectionPoint::EnterSendEvent ( void )
  479. {
  480. // Return value indicates whether lock is granted.
  481. // If lock is not granted, must still call ExitSendEvent.
  482. // Increment the SendEvent reference count when SendEvent is active.
  483. InterlockedIncrement( &m_lSendEventRefCount );
  484. // Grant the lock unless the event sink pointer is being modified in Unadvise.
  485. return ( 0 == m_lUnadviseRefCount );
  486. }
  487. void
  488. CImpIConnectionPoint::ExitSendEvent ( void )
  489. {
  490. LONG lTemp;
  491. // Decrement the SendEvent reference count.
  492. lTemp = InterlockedDecrement( &m_lSendEventRefCount );
  493. // Signal the event sink if SendEvent count decremented to 0.
  494. // lTemp is the value previous to decrement.
  495. if ( 0 == lTemp )
  496. SetEvent( m_hEventEventSink );
  497. }
  498. void
  499. CImpIConnectionPoint::EnterUnadvise ( void )
  500. {
  501. BOOL bStatus;
  502. bStatus = ResetEvent( m_hEventEventSink );
  503. // Increment the Unadvise reference count whenever Unadvise is active.
  504. // Whenever this is > 0, events are not fired.
  505. InterlockedIncrement( &m_lUnadviseRefCount );
  506. // Wait until SendEvent is no longer active.
  507. while ( m_lSendEventRefCount > 0 ) {
  508. WaitForSingleObject( m_hEventEventSink, eEventSinkWaitInterval );
  509. bStatus = ResetEvent( m_hEventEventSink );
  510. }
  511. }
  512. void
  513. CImpIConnectionPoint::ExitUnadvise ( void )
  514. {
  515. // Decrement the Unadvise reference count.
  516. InterlockedDecrement( &m_lUnadviseRefCount );
  517. }
  518. CImpIEnumConnPt::CImpIEnumConnPt (
  519. IN CImpIConnPtCont *pConnPtCont,
  520. IN const IID **ppIID,
  521. IN ULONG cItems
  522. )
  523. {
  524. m_pConnPtCont = pConnPtCont;
  525. m_apIID = ppIID;
  526. m_cItems = cItems;
  527. m_uCurrent = 0;
  528. m_cRef = 0;
  529. }
  530. STDMETHODIMP
  531. CImpIEnumConnPt::QueryInterface (
  532. IN REFIID riid,
  533. OUT PVOID *ppv
  534. )
  535. {
  536. HRESULT hr = S_OK;
  537. if (ppv == NULL) {
  538. return E_POINTER;
  539. }
  540. try {
  541. *ppv = NULL;
  542. if ((riid == IID_IUnknown) || (riid == IID_IEnumConnectionPoints)) {
  543. *ppv = this;
  544. AddRef();
  545. } else {
  546. hr = E_NOINTERFACE;
  547. }
  548. } catch (...) {
  549. hr = E_POINTER;
  550. }
  551. return hr;
  552. }
  553. STDMETHODIMP_(ULONG)
  554. CImpIEnumConnPt::AddRef (
  555. VOID
  556. )
  557. {
  558. return ++m_cRef;
  559. }
  560. STDMETHODIMP_(ULONG)
  561. CImpIEnumConnPt::Release(
  562. VOID
  563. )
  564. {
  565. if (--m_cRef == 0) {
  566. delete this;
  567. return 0;
  568. }
  569. return m_cRef;
  570. }
  571. STDMETHODIMP
  572. CImpIEnumConnPt::Next(
  573. IN ULONG cItems,
  574. OUT IConnectionPoint **apConnPt,
  575. OUT ULONG *pcReturned)
  576. {
  577. ULONG i;
  578. ULONG cRet;
  579. HRESULT hr = S_OK;
  580. if (apConnPt == NULL) {
  581. return E_POINTER;
  582. }
  583. try {
  584. //
  585. // Clear the return values
  586. //
  587. for (i = 0; i < cItems; i++) {
  588. apConnPt[i] = NULL;
  589. }
  590. // Try to fill the caller's array
  591. for (cRet = 0; cRet < cItems; cRet++) {
  592. // No more, return success with false
  593. if (m_uCurrent == m_cItems) {
  594. hr = S_FALSE;
  595. break;
  596. }
  597. // Ask connection point container for next connection point
  598. hr = m_pConnPtCont->FindConnectionPoint(*m_apIID[m_uCurrent], &apConnPt[cRet]);
  599. if (FAILED(hr))
  600. break;
  601. m_uCurrent++;
  602. }
  603. //
  604. // If failed, free the accumulated interfaces
  605. //
  606. if (FAILED(hr)) {
  607. for (i = 0; i < cRet; i++) {
  608. ReleaseInterface(apConnPt[i]);
  609. }
  610. cRet = 0;
  611. }
  612. if (pcReturned) {
  613. *pcReturned = cRet;
  614. }
  615. } catch (...) {
  616. hr = E_POINTER;
  617. }
  618. return hr;
  619. }
  620. /***
  621. *HRESULT CImpIEnumConnPt::Skip(unsigned long)
  622. *Purpose:
  623. * Attempt to skip over the next 'celt' elements in the enumeration
  624. * sequence.
  625. *
  626. *Entry:
  627. * celt = the count of elements to skip
  628. *
  629. *Exit:
  630. * return value = HRESULT
  631. * S_OK
  632. * S_FALSE - the end of the sequence was reached
  633. *
  634. ***********************************************************************/
  635. STDMETHODIMP
  636. CImpIEnumConnPt::Skip(
  637. IN ULONG cItems
  638. )
  639. {
  640. m_uCurrent += cItems;
  641. if (m_uCurrent > m_cItems) {
  642. m_uCurrent = m_cItems;
  643. return S_FALSE;
  644. }
  645. return S_OK;
  646. }
  647. /***
  648. *HRESULT CImpIEnumConnPt::Reset(void)
  649. *Purpose:
  650. * Reset the enumeration sequence back to the beginning.
  651. *
  652. *Entry:
  653. * None
  654. *
  655. *Exit:
  656. * return value = SHRESULT CODE
  657. * S_OK
  658. *
  659. ***********************************************************************/
  660. STDMETHODIMP
  661. CImpIEnumConnPt::Reset(
  662. VOID
  663. )
  664. {
  665. m_uCurrent = 0;
  666. return S_OK;
  667. }
  668. /***
  669. *HRESULT CImpIEnumConnPt::Clone(IEnumVARIANT**)
  670. *Purpose:
  671. * Retrun a CPoint enumerator with exactly the same state as the
  672. * current one.
  673. *
  674. *Entry:
  675. * None
  676. *
  677. *Exit:
  678. * return value = HRESULT
  679. * S_OK
  680. * E_OUTOFMEMORY
  681. *
  682. ***********************************************************************/
  683. STDMETHODIMP
  684. CImpIEnumConnPt::Clone (
  685. OUT IEnumConnectionPoints **ppEnum
  686. )
  687. {
  688. CImpIEnumConnPt *pNewEnum = NULL;
  689. HRESULT hr = S_OK;
  690. if (ppEnum == NULL) {
  691. return E_POINTER;
  692. }
  693. try {
  694. *ppEnum = NULL;
  695. // Create new enumerator
  696. pNewEnum = new CImpIEnumConnPt(m_pConnPtCont, m_apIID, m_cItems);
  697. if (pNewEnum != NULL) {
  698. // Copy current position
  699. pNewEnum->m_uCurrent = m_uCurrent;
  700. *ppEnum = pNewEnum;
  701. }
  702. else {
  703. hr = E_OUTOFMEMORY;
  704. }
  705. } catch (...) {
  706. hr = E_POINTER;
  707. }
  708. if (FAILED(hr) && pNewEnum) {
  709. delete pNewEnum;
  710. }
  711. return hr;
  712. }