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.

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