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.

1109 lines
36 KiB

  1. /*M*
  2. // INTEL CORPORATION PROPRIETARY INFORMATION
  3. // This software is supplied under the terms of a licence agreement or
  4. // nondisclosure agreement with Intel Corporation and may not be copied
  5. // or disclosed except in accordance with the terms of that agreement.
  6. // Copyright (c) 1996 Intel Corporation. All Rights Reserved.
  7. //
  8. // Filename : Connect.cpp
  9. // Purpose : Implementation file for a bunch of objects used
  10. // to generically implement connection points.
  11. // Contents :
  12. *M*/
  13. #ifndef _CONNECT_CPP_
  14. #define _CONNECT_CPP_
  15. #include "connect.h"
  16. #include <wtypes.h>
  17. // These GIUDs are defined in uuid.lib for C++ 4.2, but not in C++ 4.1 or
  18. // earlier. Add them here for Data Router.
  19. #if _MSC_VER < 1020
  20. static const GUID IID_IConnectionPointContainer =
  21. {0xB196B284,0xBAB4,0x101A,0xB6,0x9C,0x00,0xAA,0x00,0x34,0x1D,0x07};
  22. static const GUID IID_IEnumConnectionPoints =
  23. {0xB196B285,0xBAB4,0x101A,0xB6,0x9C,0x00,0xAA,0x00,0x34,0x1D,0x07};
  24. static const GUID IID_IConnectionPoint =
  25. {0xB196B286,0xBAB4,0x101A,0xB6,0x9C,0x00,0xAA,0x00,0x34,0x1D,0x07};
  26. static const GUID IID_IEnumConnections =
  27. {0xB196B287,0xBAB4,0x101A,0xB6,0x9C,0x00,0xAA,0x00,0x34,0x1D,0x07};
  28. #endif
  29. #include "autolock.h"
  30. /*F*
  31. // Name : CConnectionPointEnumerator::AddRef
  32. // Purpose : Increment the reference count for this object.
  33. // Context : Called by any program which wants to ensure
  34. // that this object isn't destroyed before it
  35. // says it is done with it (via Release(), below.)
  36. // Called implicitly when a program successfully
  37. // calls our QueryInterface() method.
  38. // Returns : Current number of references held for this
  39. // object.
  40. // Params : None.
  41. // Notes : Standard COM method.
  42. *F*/
  43. ULONG
  44. CConnectionPointEnumerator::AddRef() {
  45. CAutoLock l(&m_csState);
  46. m_dwRefCount++;
  47. return m_dwRefCount;
  48. } /* CConnectionPointEnumerator::AddRef() */
  49. /*F*
  50. // Name : CConnectionPointEnumerator::CConnectionPointEnumerator()
  51. // Purpose :
  52. // Context :
  53. // Returns :
  54. // Params :
  55. // iConnectList Reference to the list we are using.
  56. // iConnectListCurrentPosition Iterator that indicates the
  57. // entry in our connection list we
  58. // are currently indicating.
  59. // Notes :
  60. *F*/
  61. CConnectionPointEnumerator::CConnectionPointEnumerator(
  62. list<CONNECTDATA>& lConnectList,
  63. list<CONNECTDATA>::iterator iConnectListCurrentPosition) :
  64. m_lConnectList(lConnectList),
  65. m_iConnectListCurrentPosition(iConnectListCurrentPosition),
  66. m_dwRefCount(0)
  67. {
  68. InitializeCriticalSection(&m_csState);
  69. } /* CConnectionPointEnumerator::CConnectionPointEnumerator() */
  70. /*F*
  71. // Name : CConnectionPointEnumerator::~CConnectionPointEnumerator()
  72. // Purpose :
  73. // Context :
  74. // Returns :
  75. // Params :
  76. // Notes :
  77. *F*/
  78. CConnectionPointEnumerator::~CConnectionPointEnumerator()
  79. {
  80. EnterCriticalSection(&m_csState);
  81. LeaveCriticalSection(&m_csState);
  82. DeleteCriticalSection(&m_csState);
  83. } /* CConnectionPointEnumerator::CConnectionPointEnumerator() */
  84. /*F*
  85. // Name : CConnectionPointEnumerator::Clone()
  86. // Purpose :
  87. // Context :
  88. // Returns :
  89. // Params :
  90. // Notes :
  91. *F*/
  92. HRESULT
  93. CConnectionPointEnumerator::Clone(
  94. IEnumConnections **ppEnum)
  95. {
  96. CAutoLock l(&m_csState);
  97. CConnectionPointEnumerator *pNewConnPtEnum;
  98. pNewConnPtEnum = new CConnectionPointEnumerator(m_lConnectList,
  99. m_iConnectListCurrentPosition);
  100. if (pNewConnPtEnum == (CConnectionPointEnumerator *) NULL) {
  101. return E_OUTOFMEMORY;
  102. } /* if */
  103. HRESULT hErr;
  104. hErr = pNewConnPtEnum->QueryInterface(IID_IEnumConnections,
  105. (PVOID *) ppEnum);
  106. if (FAILED(hErr)) {
  107. delete pNewConnPtEnum;
  108. } /* if */
  109. return hErr;
  110. } /* CConnectionPointEnumerator::Clone() */
  111. /*F*
  112. // Name : CConnectionPointEnumerator::Next
  113. // Purpose :
  114. // Context :
  115. // Params :
  116. // E_POINTER Invalid pcFetched parameter passed in.
  117. // NOERROR Successfully created & returned enumerator.
  118. // S_FALSE No more connection points to return.
  119. // Returns :
  120. // Notes : None.
  121. *F*/
  122. HRESULT
  123. CConnectionPointEnumerator::Next(
  124. ULONG cConnections,
  125. PCONNECTDATA pConnectData,
  126. ULONG *pcFetched)
  127. {
  128. CAutoLock l(&m_csState);
  129. if (IsBadWritePtr(pConnectData, cConnections * sizeof(CONNECTDATA))) {
  130. return E_POINTER;
  131. } /* if */
  132. ULONG uTempCounter;
  133. if ((cConnections == 1) && (pcFetched == (ULONG *) NULL)) {
  134. // NULL is allowed to be passed in the pcFetched parameter
  135. // when cConnections is 1, so rather than writing funny logic
  136. // to worry about it I'll just create a temporary local to
  137. // use instead.
  138. pcFetched = &uTempCounter;
  139. } /* if */
  140. *pcFetched = 0;
  141. while ((cConnections > 0) && (m_iConnectListCurrentPosition != m_lConnectList.end())) {
  142. *pConnectData++ = *m_iConnectListCurrentPosition;
  143. (*pcFetched)++;
  144. m_iConnectListCurrentPosition++;
  145. cConnections--;
  146. } /* while */
  147. if (*pcFetched > 0) {
  148. // Successfully returned something.
  149. return NOERROR;
  150. } else {
  151. // Nothing returned.
  152. return S_FALSE;
  153. } /* if */
  154. } /* CConnectionPointEnumerator::Next() */
  155. /*F*
  156. // Name : CConnectionPointEnumerator::QueryInterface
  157. // Purpose : Query us for our IConnectionPoint interface.
  158. // Context :
  159. // Returns : NOERROR if interface successfully found.
  160. // E_NOINTERFACE otherwise.
  161. // Params :
  162. // riid IID of the desired interface
  163. // ppv Pointer to a VOID * to store the
  164. // returned interface in.
  165. // Notes : Implicitly AddRef()s this object on success.
  166. *F*/
  167. STDMETHODIMP
  168. CConnectionPointEnumerator::QueryInterface(
  169. REFIID riid,
  170. void **ppv)
  171. {
  172. CAutoLock l(&m_csState);
  173. if (riid == IID_IEnumConnections) {
  174. // Our own interface
  175. *ppv = (IEnumConnections *) this;
  176. } else if (riid == IID_IUnknown) {
  177. *ppv = (IUnknown *) this;
  178. } else {
  179. return E_NOINTERFACE;
  180. } /* if */
  181. AddRef();
  182. // Implicit AddRef(). The Release() must be explicitly done
  183. // by the routine that called QueryInterface().
  184. return NOERROR;
  185. } /* CConnectionPointEnumerator::QueryInterface() */
  186. /*F*
  187. // Name : CConnectionPointEnumerator::Release
  188. // Purpose : Decrement the reference count for this object.
  189. // Context : Called by any program which holds a reference
  190. // to this object which no longer needs it.
  191. // Returns : Current reference count.
  192. // Params : None.
  193. // Notes : Should be called once for each AddRef()
  194. // a program makes and once for each successful
  195. // QueryInterface() a program made on us.
  196. *F*/
  197. ULONG
  198. CConnectionPointEnumerator::Release() {
  199. EnterCriticalSection(&m_csState);
  200. m_dwRefCount--;
  201. if (m_dwRefCount==0) {
  202. LeaveCriticalSection(&m_csState);
  203. delete this;
  204. return 0;
  205. }
  206. LeaveCriticalSection(&m_csState);
  207. return m_dwRefCount;
  208. } /* CConnectionPointEnumerator::Release() */
  209. /*F*
  210. // Name : CConnectionPointEnumerator::Reset
  211. // Purpose : Start the enumerator at the beginning of the
  212. // connection point list again.
  213. // Context : Any point after construction.
  214. // Returns :
  215. // NOERROR Successfully reset enumerator.
  216. // Params : None.
  217. // Notes : None.
  218. *F*/
  219. HRESULT
  220. CConnectionPointEnumerator::Reset(void)
  221. {
  222. CAutoLock l(&m_csState);
  223. m_iConnectListCurrentPosition = m_lConnectList.begin();
  224. return NOERROR;
  225. } /* CConnectionPointEnumerator::Reset() */
  226. /*F*
  227. // Name : CConnectionPointEnumerator::Skip
  228. // Purpose : Skip forward over the specified number of connection points.
  229. // Context :
  230. // Params :
  231. // uSkipCount Number of connection points to skip.
  232. // Returns :
  233. // NOERROR Successfully created & returned enumerator.
  234. // Notes : None.
  235. *F*/
  236. HRESULT
  237. CConnectionPointEnumerator::Skip(
  238. ULONG uSkipCount)
  239. {
  240. CAutoLock l(&m_csState);
  241. while ((uSkipCount > 0) && (m_iConnectListCurrentPosition != m_lConnectList.end())) {
  242. m_iConnectListCurrentPosition++;
  243. uSkipCount--;
  244. } /* while */
  245. return NOERROR;
  246. } /* CConnectionPointEnumerator::Skip() */
  247. /*F*
  248. // Name : CConnectionPoint::CConnectionPoint()
  249. // Purpose : Constructor. Initializes variables and adds us
  250. // to our connection point container.
  251. // Context : Called at construction time, usually when
  252. // a server is just initializing.
  253. // Returns : Nothing.
  254. // Params :
  255. // pConnptContainer Pointer to the connection point
  256. // container which we belong to.
  257. // riid IID of the interface that
  258. // this connection point represents.
  259. // Notes :
  260. // If AddConnectionPoint() fails, we are dead in the water.
  261. // We should change this later to throw an exception. FIX.
  262. *F*/
  263. CConnectionPoint::CConnectionPoint(
  264. CConnectionPointContainer *pConnPtContainer,
  265. IID riid) :
  266. m_dwCookie(1),
  267. m_dwRefCount(0),
  268. m_pContainer(pConnPtContainer),
  269. m_iIID(riid)
  270. {
  271. InitializeCriticalSection(&m_csState);
  272. CAutoLock l(&m_csState);
  273. if (m_pContainer != (CConnectionPointContainer *) NULL) {
  274. m_pContainer->AddConnectionPoint((IUnknown *) this);
  275. } /* if */
  276. } /* CConnectionPoint::CConnectionPoint() */
  277. /*F*
  278. // Name : CConnectionPoint::~CConnectionPoint()
  279. // Purpose : Destructor.
  280. // Context : Called at destruction time.
  281. // Returns : Nothing.
  282. // Params :
  283. // Notes :
  284. *F*/
  285. CConnectionPoint::~CConnectionPoint()
  286. {
  287. EnterCriticalSection(&m_csState);
  288. // Try to grab the critical section to ensure that nobody else has it.
  289. LeaveCriticalSection(&m_csState);
  290. // Can't delete it while we hold it, so release it just before deletion.
  291. DeleteCriticalSection(&m_csState);
  292. // Pray for no context switch - as far as I can see, there isn't
  293. // anything we can do about one occurring. We just have to assert
  294. // that the application doesn't cause us to be destroyed while still using us.
  295. } /* CConnectionPoint::~CConnectionPoint() */
  296. /*F*
  297. // Name : CConnectionPoint::SetContainer()
  298. // Purpose : Allows the connection point container for this cp to be
  299. // set after construction. Fail if it has been previously set.
  300. // Context : Called before this connection point is used for
  301. // anything which involves its container.
  302. // Returns :
  303. // NOERROR Successfully recorded container.
  304. // E_UNEXPECTED Container previously set.
  305. // E_INVALIDARG Invalid pContainer parameter.
  306. // Params :
  307. // pContainer Pointer to the container to use for this cp.
  308. // Notes :
  309. *F*/
  310. HRESULT
  311. CConnectionPoint::SetContainer(
  312. CConnectionPointContainer *pContainer)
  313. {
  314. CAutoLock l(&m_csState);
  315. if (IsBadReadPtr((PVOID) pContainer, sizeof(CConnectionPointContainer *))) {
  316. // Bogus container passed in.
  317. return E_INVALIDARG;
  318. } /* if */
  319. if (m_pContainer != (CConnectionPointContainer *) NULL) {
  320. // Connection point container previously set.
  321. return E_UNEXPECTED;
  322. } /* if */
  323. m_pContainer = pContainer;
  324. m_pContainer->AddConnectionPoint((IUnknown *) this);
  325. return NOERROR;
  326. } /* CConnectionPoint::SetContainer() */
  327. /*F*
  328. // Name : CConnectionPoint::AddRef
  329. // Purpose : Increment the reference count for this object.
  330. // Context : Called by any program which wants to ensure
  331. // that this object isn't destroyed before it
  332. // says it is done with it (via Release(), below.)
  333. // Called implicitly when a program successfully
  334. // calls our QueryInterface() method.
  335. // Returns : Current number of references held for this
  336. // object.
  337. // Params : None.
  338. // Notes : Standard COM method.
  339. *F*/
  340. ULONG
  341. CConnectionPoint::AddRef() {
  342. CAutoLock l(&m_csState);
  343. m_dwRefCount++;
  344. return m_dwRefCount;
  345. } /* CConnectionPoint::AddRef() */
  346. /*F*
  347. // Name : CConnectionPoint::Advise
  348. // Purpose : Add a new sink to this connection point.
  349. // Context : Called by the application which wishes to
  350. // receive callbacks from this connection point.
  351. // We will query the callback interface from the
  352. // application, AddRef() it, and hand back a cookie.
  353. // Returns :
  354. // NOERROR Successfully setup connection
  355. // E_NOINTERFACE The application doesn't support the
  356. // interface that we expect to callback into.
  357. // E_INVALIDARG Bogus pIUnknown or pdwCookie passed in.
  358. // Params :
  359. // pIUnknownSink Pointer to an IUnknown of the application.
  360. // Used to query for the interface we callback into.
  361. // pdwCookie Out parameter used to hand a cookie back to
  362. // the app that represents this connection.
  363. // We put the interator to our list of connections
  364. // there to allow constant time access during
  365. // the Unadvise() call that occurs later on.
  366. // Notes :
  367. // No need to release pIUnknownSink because its scope
  368. // is known to be encapsulated for the life of this function,
  369. // so the called did not addref it before passing it to us.
  370. *F*/
  371. HRESULT
  372. CConnectionPoint::Advise(
  373. IUnknown *pIUnknownSink,
  374. DWORD *pdwCookie)
  375. {
  376. CAutoLock l(&m_csState);
  377. HRESULT hErr;
  378. if (IsBadReadPtr((PVOID) pIUnknownSink, sizeof(IUnknown *)) ||
  379. IsBadWritePtr((PVOID) pdwCookie, sizeof(DWORD))) {
  380. return E_INVALIDARG;
  381. } /* if */
  382. IUnknown *pIClient;
  383. hErr = pIUnknownSink->QueryInterface(m_iIID,
  384. (PVOID *) &pIClient);
  385. if (FAILED(hErr)) {
  386. return hErr;
  387. } /* if */
  388. CONNECTDATA sNewConnectData;
  389. sNewConnectData.pUnk = pIUnknownSink;
  390. sNewConnectData.dwCookie = m_dwCookie++;
  391. *pdwCookie = sNewConnectData.dwCookie;
  392. m_lConnectList.push_back(sNewConnectData);
  393. return NOERROR;
  394. } /* CConnectionPoint::Advise() */
  395. /*F*
  396. // Name : CConnectionPoint::EnumConnections()
  397. // Purpose : Return an enumerator to look at what connections we have made.
  398. // Context :
  399. // Returns :
  400. // NOERROR Successfully created & returned enumerator.
  401. // E_OUTOFMEMORY Insufficient memory to create enumerator.
  402. // Params :
  403. // ppIEnumConnections Parameter to return enumerator interface pointer in.
  404. // Notes :
  405. *F*/
  406. HRESULT
  407. CConnectionPoint::EnumConnections(
  408. IEnumConnections **ppIEnumConnections)
  409. {
  410. CAutoLock l(&m_csState);
  411. CConnectionPointEnumerator *pNewConnPtEnum;
  412. pNewConnPtEnum = new CConnectionPointEnumerator(m_lConnectList, m_lConnectList.begin());
  413. if (pNewConnPtEnum == (CConnectionPointEnumerator *) NULL) {
  414. return E_OUTOFMEMORY;
  415. } /* if */
  416. HRESULT hErr;
  417. hErr = pNewConnPtEnum->QueryInterface(IID_IEnumConnections,
  418. (PVOID *) ppIEnumConnections);
  419. if (FAILED(hErr)) {
  420. delete pNewConnPtEnum;
  421. } /* if */
  422. return hErr;
  423. } /* CConnectionPoint::EnumConnections() */
  424. /*F*
  425. // Name :
  426. // Purpose :
  427. // Context :
  428. // Returns :
  429. // Params :
  430. // Notes :
  431. *F*/
  432. HRESULT
  433. CConnectionPoint::GetConnectionInterface(
  434. IID *pIConnection)
  435. {
  436. CAutoLock l(&m_csState);
  437. *pIConnection = m_iIID;
  438. return NOERROR;
  439. } /* CConnectionPoint::GetConnectionInterface() */
  440. /*F*
  441. // Name : CConnectionPoint::GetConnectionPointContainer()
  442. // Purpose : Return the connection point container that owns this cp.
  443. // Context : Called by the app when looking for our container (duh).
  444. // Returns :
  445. // E_UNEXPECTED Connection point container for this
  446. // connection point hasn't been
  447. // NOERROR Successfully returned the connection point container
  448. // interface, AddRef()ed.
  449. // Params :
  450. // ppIConnPtcontainer Pointer to the connection point container
  451. // that is to be returned.
  452. // Notes :
  453. *F*/
  454. HRESULT
  455. CConnectionPoint::GetConnectionPointContainer(
  456. IConnectionPointContainer **ppIConnPtContainer)
  457. {
  458. CAutoLock l(&m_csState);
  459. HRESULT hErr;
  460. if (m_pContainer != (CConnectionPointContainer *) NULL) {
  461. // Return an AddRef()ed interface pointer.
  462. hErr = m_pContainer->QueryInterface(IID_IConnectionPointContainer,
  463. (PVOID *) ppIConnPtContainer);
  464. return hErr;
  465. } else {
  466. // Our connection point container hasn't been set yet
  467. // via our constructor or via SetContainer().
  468. return E_UNEXPECTED;
  469. } /* if */
  470. } /* CConnectionPoint::GetConnectionPointContainer() */
  471. /*F*
  472. // Name : CConnectionPoint::QueryInterface
  473. // Purpose : Query us for our IConnectionPoint interface.
  474. // Context :
  475. // Returns : NOERROR if interface successfully found.
  476. // E_NOINTERFACE otherwise.
  477. // Params :
  478. // riid IID of the desired interface
  479. // ppv Pointer to a VOID * to store the
  480. // returned interface in.
  481. // Notes : Implicitly AddRef()s this object on success.
  482. *F*/
  483. STDMETHODIMP
  484. CConnectionPoint::QueryInterface(
  485. REFIID riid,
  486. void **ppv)
  487. {
  488. CAutoLock l(&m_csState);
  489. if (riid == IID_IConnectionPoint) {
  490. // Our own interface
  491. *ppv = (IConnectionPoint *) this;
  492. } else if (riid == IID_IUnknown) {
  493. *ppv = (IUnknown *) this;
  494. } else {
  495. return E_NOINTERFACE;
  496. } /* if */
  497. AddRef();
  498. // Implicit AddRef(). The Release() must be explicitly done
  499. // by the routine that called QueryInterface().
  500. return NOERROR;
  501. } /* CConnectionPoint::QueryInterface() */
  502. /*F*
  503. // Name : CConnectionPoint::Release
  504. // Purpose : Decrement the reference count for this object.
  505. // Context : Called by any program which holds a reference
  506. // to this object which no longer needs it.
  507. // Returns : Current reference count.
  508. // Params : None.
  509. // Notes : Should be called once for each AddRef()
  510. // a program makes and once for each successful
  511. // QueryInterface() a program made on us.
  512. *F*/
  513. ULONG
  514. CConnectionPoint::Release() {
  515. EnterCriticalSection(&m_csState);
  516. m_dwRefCount--;
  517. if (m_dwRefCount==0) {
  518. LeaveCriticalSection(&m_csState);
  519. delete this;
  520. return 0;
  521. }
  522. LeaveCriticalSection(&m_csState);
  523. return m_dwRefCount;
  524. } /* CConnectionPoint::Release() */
  525. struct bCookieMatch : public binary_function<CONNECTDATA, DWORD, bool> {
  526. bool operator()(const CONNECTDATA& connectData, const DWORD& dwCookie) const {
  527. if (connectData.dwCookie == dwCookie) {
  528. return TRUE;
  529. } else {
  530. return FALSE;
  531. } /* if */
  532. } /* operator() */
  533. }; /* bCookieMatch() */
  534. /*F*
  535. // Name : CConnectionPoint::Unadvise()
  536. // Purpose : The connection sink wishes to break off our mutual
  537. // connection.
  538. // Context :
  539. // Params :
  540. // dwCookie Cookie to use to find connection to tear down.
  541. // Returns :
  542. // NOERROR Connection broken down.
  543. // CONNECT_E_NOCONNECTION No connection matching dwCookie.
  544. // Notes :
  545. *F*/
  546. HRESULT
  547. CConnectionPoint::Unadvise(
  548. DWORD dwCookie)
  549. {
  550. CAutoLock l(&m_csState);
  551. list<CONNECTDATA>::iterator iConnectListIterator;
  552. int count = m_lConnectList.size();
  553. iConnectListIterator = find_if(m_lConnectList.begin(), m_lConnectList.end(),
  554. bind2nd(bCookieMatch(), dwCookie));
  555. if (iConnectListIterator != m_lConnectList.end()) {
  556. // Found the connection we are looking for.
  557. (*iConnectListIterator).pUnk->Release(); // Release the interface
  558. m_lConnectList.erase(iConnectListIterator); // Erase the entry
  559. return NOERROR;
  560. } else {
  561. // No connection matching indicated cookie found!
  562. return CONNECT_E_NOCONNECTION;
  563. } /* if */
  564. } /* CConnectionPoint::Unadvise() */
  565. //
  566. //
  567. // Begin CConnectionPointContainerEnumerator
  568. //
  569. //
  570. /*F*
  571. // Name : CConnectionPointContainerEnumerator::AddRef
  572. // Purpose : Increment the reference count for this object.
  573. // Context : Called by any program which wants to ensure
  574. // that this object isn't destroyed before it
  575. // says it is done with it (via Release(), below.)
  576. // Called implicitly when a program successfully
  577. // calls our QueryInterface() method.
  578. // Returns : Current number of references held for this
  579. // object.
  580. // Params : None.
  581. // Notes : Standard COM method.
  582. *F*/
  583. ULONG
  584. CConnectionPointContainerEnumerator::AddRef() {
  585. CAutoLock l(&m_csState);
  586. m_pIUnknownParent->AddRef(); // Per BS Pg. 208
  587. m_dwRefCount++;
  588. return m_dwRefCount;
  589. } /* CConnectionPointContainerEnumerator::AddRef() */
  590. /*F*
  591. // Name : CConnectionPointContainerEnumerator::CConnectionPointContainerEnumerator
  592. // Purpose : Constructor. Stores which connection point we are pointing at.
  593. // Context : Called when this object is created.
  594. // Returns :
  595. // Params :
  596. // iConnPointNumber Integer which indicates which connection point
  597. // this enumerator is currently pointing at.
  598. // Notes : None.
  599. *F*/
  600. CConnectionPointContainerEnumerator::CConnectionPointContainerEnumerator(
  601. IUnknown *pIUnknownParent,
  602. IConnectionPointList_t IConnectionPointList,
  603. IConnectionPointList_t::iterator iConnectionPointListPosition)
  604. {
  605. InitializeCriticalSection(&m_csState);
  606. CAutoLock l(&m_csState);
  607. m_dwRefCount = 0;
  608. // Store these in our member variables.
  609. m_IConnectionPointList = IConnectionPointList;
  610. m_iConnectionPointListPosition = iConnectionPointListPosition;
  611. m_pIUnknownParent = pIUnknownParent;
  612. // Addref() all of our connection points.
  613. IConnectionPointList_t::iterator iConnPtIterator;
  614. for (iConnPtIterator = m_IConnectionPointList.begin();
  615. iConnPtIterator != m_IConnectionPointList.end();
  616. iConnPtIterator++) {
  617. (*iConnPtIterator)->AddRef();
  618. } /* for */
  619. pIUnknownParent->AddRef();
  620. } /* CConnectionPointContainerEnumerator::CConnectionPointContainerEnumerator() */
  621. /*F*
  622. // Name : CConnectionPointContainerEnumerator::~CConnectionPointContainerEnumerator
  623. // Purpose : Destructor.
  624. // Context : Called when this object is destroyed.
  625. // Returns :
  626. // Params :
  627. // Notes : None.
  628. *F*/
  629. CConnectionPointContainerEnumerator::~CConnectionPointContainerEnumerator(void)
  630. {
  631. EnterCriticalSection(&m_csState);
  632. // Release() all of our connection points.
  633. IConnectionPointList_t::iterator iConnPtIterator;
  634. for (iConnPtIterator = m_IConnectionPointList.begin();
  635. iConnPtIterator != m_IConnectionPointList.end();
  636. iConnPtIterator++) {
  637. (*iConnPtIterator)->Release();
  638. } /* for */
  639. DeleteCriticalSection(&m_csState);
  640. } /* CConnectionPointContainerEnumerator::~CConnectionPointContainerEnumerator() */
  641. /*F*
  642. // Name : CConnectionPointContainerEnumerator::Clone
  643. // Purpose : Return an identical enumerator pointing at the same
  644. // point in our list of connection points.
  645. // Context :
  646. // Returns :
  647. // Params :
  648. // E_OUTOFMEMORY Insufficient memory to create new enumerator.
  649. // NOERROR Successfully created & returned enumerator.
  650. // Notes : None.
  651. *F*/
  652. HRESULT
  653. CConnectionPointContainerEnumerator::Clone(
  654. IEnumConnectionPoints **ppIEnumConnPoints)
  655. {
  656. CAutoLock l(&m_csState);
  657. CConnectionPointContainerEnumerator *pNewConnPtContainerEnum;
  658. pNewConnPtContainerEnum = new CConnectionPointContainerEnumerator((IUnknown *) this,
  659. m_IConnectionPointList,
  660. m_iConnectionPointListPosition);
  661. if (pNewConnPtContainerEnum == (CConnectionPointContainerEnumerator *) NULL) {
  662. return E_OUTOFMEMORY;
  663. } /* if */
  664. HRESULT hErr;
  665. hErr = pNewConnPtContainerEnum->QueryInterface(IID_IEnumConnectionPoints,
  666. (PVOID *) ppIEnumConnPoints);
  667. if (FAILED(hErr)) {
  668. delete pNewConnPtContainerEnum;
  669. } /* if */
  670. return hErr;
  671. } /* CConnectionPointContainerEnumerator::Clone() */
  672. /*F*
  673. // Name : CConnectionPointContainerEnumerator::Next
  674. // Purpose :
  675. // Context :
  676. // Params :
  677. // E_POINTER Invalid ppCPArray parameter passed in.
  678. // NOERROR Successfully created & returned enumerator.
  679. // Returns :
  680. // Notes : None.
  681. *F*/
  682. HRESULT
  683. CConnectionPointContainerEnumerator::Next(
  684. ULONG uPointsToReturn,
  685. IConnectionPoint **ppCPArray,
  686. ULONG *puPointsReturned)
  687. {
  688. CAutoLock l(&m_csState);
  689. if (IsBadWritePtr(ppCPArray, uPointsToReturn * sizeof(IConnectionPoint *))) {
  690. return E_POINTER;
  691. } /* if */
  692. *puPointsReturned = 0;
  693. HRESULT hErr;
  694. while ((uPointsToReturn > 0) &&
  695. (m_iConnectionPointListPosition != m_IConnectionPointList.end())) {
  696. hErr = (*m_iConnectionPointListPosition)->QueryInterface(IID_IConnectionPoint,
  697. (PVOID *) ppCPArray);
  698. if (SUCCEEDED(hErr)) {
  699. ppCPArray++;
  700. (*puPointsReturned)++;
  701. uPointsToReturn--;
  702. }/* if */
  703. m_iConnectionPointListPosition++;
  704. } /* while */
  705. return NOERROR;
  706. } /* CConnectionPointContainerEnumerator::Next() */
  707. /*F*
  708. // Name : CConnectionPointContainerEnumerator::QueryInterface
  709. // Purpose : Query us for an interface.
  710. // Context :
  711. // Returns : NOERROR if interface successfully found.
  712. // E_NOINTERFACE otherwise.
  713. // Params :
  714. // riid IID of the desired interface
  715. // ppv Pointer to a VOID * to store the
  716. // returned interface in.
  717. // Notes : Implicitly AddRef()s this object on success.
  718. *F*/
  719. STDMETHODIMP
  720. CConnectionPointContainerEnumerator::QueryInterface(
  721. REFIID riid,
  722. void **ppv)
  723. {
  724. CAutoLock l(&m_csState);
  725. if (riid == IID_IEnumConnectionPoints) {
  726. // Our own interface
  727. *ppv = (IEnumConnectionPoints *) this;
  728. } else if (riid == IID_IUnknown) {
  729. *ppv = (IUnknown *) this;
  730. } else {
  731. return E_NOINTERFACE;
  732. } /* if */
  733. AddRef();
  734. // Implicit AddRef(). The Release() must be explicitly done
  735. // by the routine that called QueryInterface().
  736. return NOERROR;
  737. } /* CConnectionPointContainerEnumerator::QueryInterface() */
  738. /*F*
  739. // Name : CConnectionPointContainerEnumerator::Release
  740. // Purpose : Decrement the reference count for this object.
  741. // Context : Called by any program which holds a reference
  742. // to this object which no longer needs it.
  743. // Returns : Current reference count.
  744. // Params : None.
  745. // Notes : Should be called once for each AddRef()
  746. // a program makes and once for each successful
  747. // QueryInterface() a program made on us.
  748. *F*/
  749. ULONG
  750. CConnectionPointContainerEnumerator::Release() {
  751. EnterCriticalSection(&m_csState);
  752. m_pIUnknownParent->Release(); // Per BS pg.208
  753. m_dwRefCount--;
  754. if (m_dwRefCount==0) {
  755. LeaveCriticalSection(&m_csState);
  756. delete this;
  757. return 0;
  758. }
  759. LeaveCriticalSection(&m_csState);
  760. return m_dwRefCount;
  761. } /* CConnectionPointContainerEnumerator::Release() */
  762. /*F*
  763. // Name : CConnectionPointContainerEnumerator::Reset
  764. // Purpose : Start the enumerator at the beginning of the
  765. // connection point list again.
  766. // Context : Any point after construction.
  767. // Returns :
  768. // NOERROR Successfully reset enumerator.
  769. // Params : None.
  770. // Notes : None.
  771. *F*/
  772. HRESULT
  773. CConnectionPointContainerEnumerator::Reset(void)
  774. {
  775. CAutoLock l(&m_csState);
  776. m_iConnectionPointListPosition = m_IConnectionPointList.begin();
  777. return NOERROR;
  778. } /* CConnectionPointContainerEnumerator::Reset() */
  779. /*F*
  780. // Name : CConnectionPointContainerEnumerator::Skip
  781. // Purpose : Skip forward over the specified number of connection points.
  782. // Context :
  783. // Params :
  784. // uSkipCount Number of connection points to skip.
  785. // Returns :
  786. // NOERROR Successfully created & returned enumerator.
  787. // Notes : None.
  788. *F*/
  789. HRESULT
  790. CConnectionPointContainerEnumerator::Skip(
  791. ULONG uSkipCount)
  792. {
  793. CAutoLock l(&m_csState);
  794. while ((uSkipCount > 0) &&
  795. (m_iConnectionPointListPosition != m_IConnectionPointList.end())) {
  796. m_iConnectionPointListPosition++;
  797. uSkipCount--;
  798. } /* while */
  799. return NOERROR;
  800. } /* CConnectionPointContainerEnumerator::Skip() */
  801. //
  802. //
  803. // Begin CConnectionPointContainer
  804. //
  805. //
  806. /*F*
  807. // Name : CConnectionPointContainer::CConnectionPointContainer
  808. // Purpose : Constructor. Doesn't do much.
  809. // Context : Called when this object is created.
  810. // Returns :
  811. // Params :
  812. // pParentUnknown IUnknown for the parent of this container
  813. // so that we can pass QIs and such to it.
  814. // Notes : None.
  815. *F*/
  816. CConnectionPointContainer::CConnectionPointContainer() :
  817. m_pIParentUnknown((IUnknown *) NULL)
  818. {
  819. InitializeCriticalSection(&m_csState);
  820. CAutoLock l(&m_csState);
  821. } /* CConnectionPointContainer::CConnectionPointContainer() */
  822. /*F*
  823. // Name : CConnectionPointContainer::~CConnectionPointContainer()
  824. // Purpose :
  825. // Context :
  826. // Returns :
  827. // Params : None.
  828. // Notes : None.
  829. *F*/
  830. CConnectionPointContainer::~CConnectionPointContainer()
  831. {
  832. IConnectionPointList_t::iterator iConnPtListIterator;
  833. EnterCriticalSection(&m_csState);
  834. while (m_lConnectionPointList.begin() != m_lConnectionPointList.end()) {
  835. iConnPtListIterator = m_lConnectionPointList.begin();
  836. (*iConnPtListIterator)->Release();
  837. m_lConnectionPointList.erase(iConnPtListIterator);
  838. } /* if */
  839. LeaveCriticalSection(&m_csState);
  840. DeleteCriticalSection(&m_csState);
  841. } /* CConnectionPointContainer::~CConnectionPointContainer() */
  842. /*F*
  843. // Name : CConnectionPointContainer::SetUnknown()
  844. // Purpose : Store the IUnknown of the parent in order
  845. // to delegate IUnknown calls to it. We are
  846. // merely a helper class, not a true COM object.
  847. // Context :
  848. // Returns :
  849. // E_UNEXPECTED Parent IUnknown previously set.
  850. // NOERROR Successfully recorded parent IUnknown.
  851. // Params : None.
  852. // Notes :
  853. // pIParentUnknown Pointer to the IUnknown of the parent
  854. // which we are supposed to delegate to.
  855. *F*/
  856. HRESULT
  857. CConnectionPointContainer::SetUnknown(
  858. IUnknown *pIParentUnknown)
  859. {
  860. if (m_pIParentUnknown != (IUnknown *) NULL) {
  861. // Parent unknown previously set.
  862. return E_UNEXPECTED;
  863. } /* if */
  864. m_pIParentUnknown = pIParentUnknown;
  865. return NOERROR;
  866. } /* CConnectionPointContainer::SetUnknown() */
  867. /*F*
  868. // Name : CConnectionPointContainer::EnumConnectionPoints
  869. // Purpose : Create a connection point container enumerator
  870. // and return it to the callind program.
  871. // Context : Called when a program wants to enumerate through
  872. // the list of connection points we support.
  873. // Returns :
  874. // E_OUTOFMEMORY Insufficient memory to create new enumerator.
  875. // NOERROR Successfully created & returned enumerator.
  876. // Params : None.
  877. // Notes : None.
  878. *F*/
  879. HRESULT
  880. CConnectionPointContainer::EnumConnectionPoints(
  881. IEnumConnectionPoints **ppIEnumConnPoints)
  882. {
  883. CAutoLock l(&m_csState);
  884. CConnectionPointContainerEnumerator *pNewConnPtContainerEnum;
  885. pNewConnPtContainerEnum = new CConnectionPointContainerEnumerator((IUnknown *) this,
  886. m_lConnectionPointList,
  887. m_lConnectionPointList.begin());
  888. if (pNewConnPtContainerEnum == (CConnectionPointContainerEnumerator *) NULL) {
  889. return E_OUTOFMEMORY;
  890. } /* if */
  891. HRESULT hErr;
  892. hErr = pNewConnPtContainerEnum->QueryInterface(IID_IEnumConnectionPoints,
  893. (PVOID *) ppIEnumConnPoints);
  894. if (FAILED(hErr)) {
  895. delete pNewConnPtContainerEnum;
  896. } /* if */
  897. return hErr;
  898. } /* CConnectionPointContainer::EnumConnectionPoints() */
  899. struct bIIDMatch : public binary_function<IConnectionPoint *, IID, bool> {
  900. bool operator()(IConnectionPoint *pICP, const IID riid) const {
  901. IID sIConnection;
  902. HRESULT hErr = pICP->GetConnectionInterface(&sIConnection);
  903. if (FAILED(hErr)) {
  904. // Error with this connection point.
  905. return FALSE;
  906. } /* if */
  907. if (sIConnection == riid) {
  908. // This connection point exposes the requested interface.
  909. return TRUE;
  910. } else {
  911. // This connection point does not expose the requested interface.
  912. return FALSE;
  913. } /* if */
  914. } /* operator() */
  915. }; /* bIIDMatch() */
  916. /*F*
  917. // Name : CConnectionPointContainer::FindConnectionPoint
  918. // Purpose : Check if this connection point container supports
  919. // a particular connection point.
  920. // Context :
  921. // Returns :
  922. // E_POINTER Invalid ppIConnectionPoint parameter passed in.
  923. // CONNECT_E_NOCONNECTION No connection point matching indicated REFIID.
  924. // NOERROR Successfully returned AddRef()ed connection point.
  925. // Params :
  926. // rConnPointIID IID of the desired connection point.
  927. // ppIConnectionPoint Indirect pointer to return connection
  928. // point matching rConnPointIID (if found.)
  929. // Notes : None.
  930. *F*/
  931. HRESULT
  932. CConnectionPointContainer::FindConnectionPoint(
  933. REFIID rConnPointIID,
  934. IConnectionPoint **ppIConnectionPoint)
  935. {
  936. CAutoLock l(&m_csState);
  937. if (IsBadWritePtr(ppIConnectionPoint, sizeof(IConnectionPoint *))) {
  938. return E_POINTER;
  939. } /* if */
  940. IConnectionPointList_t::iterator iConnPtListIterator;
  941. iConnPtListIterator = find_if(m_lConnectionPointList.begin(), m_lConnectionPointList.end(),
  942. bind2nd(bIIDMatch(), rConnPointIID));
  943. if (iConnPtListIterator != m_lConnectionPointList.end()) {
  944. // Found the connection point matching the indicated IID.
  945. *ppIConnectionPoint = *iConnPtListIterator;
  946. (*ppIConnectionPoint)->AddRef();
  947. return NOERROR;
  948. } else {
  949. // No connection point matches the requested IID.
  950. return CONNECT_E_NOCONNECTION;
  951. } /* if */
  952. } /* CConnectionPointContainer::FindConnectionPoint() */
  953. /*F*
  954. // Name : CConnectionPointContainer::AddConnectionPoint
  955. // Purpose : Class method used to allow parent object to
  956. // add connection points to this connection point container.
  957. // Context :
  958. // Returns :
  959. // E_POINTER Invalid pINewConnectionPoint parameter.
  960. // NOERROR Successfully added connection point to our list.
  961. // Also returns error codes returned by QueryInterface()/
  962. // Params :
  963. // pIUnknownNewConnectionPoint IUnknown of the new connection point.
  964. // Notes :
  965. // All connection points should be added before any calls to
  966. // the IConnectionPointContainer interface are made.
  967. *F*/
  968. HRESULT
  969. CConnectionPointContainer::AddConnectionPoint(
  970. IUnknown *pIUnknownNewConnectionPoint)
  971. {
  972. CAutoLock l(&m_csState);
  973. if (IsBadReadPtr((PVOID) pIUnknownNewConnectionPoint, sizeof(IConnectionPoint *))) {
  974. return E_POINTER;
  975. } /* if */
  976. HRESULT hErr;
  977. IConnectionPoint *pINewConnectionPoint;
  978. hErr = pIUnknownNewConnectionPoint->QueryInterface(IID_IConnectionPoint,
  979. (PVOID *) &pINewConnectionPoint);
  980. if (FAILED(hErr)) {
  981. return hErr;
  982. } /* if */
  983. m_lConnectionPointList.push_back(pINewConnectionPoint);
  984. return NOERROR;
  985. } /* CConnectionPointContainer::AddConnectionPoint() */
  986. #endif _CONNECT_CPP_