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.

563 lines
12 KiB

  1. // File: connpnts.cpp
  2. //
  3. // CConnectionPoint
  4. // CConnectionPointContainer
  5. // CEnumConnections
  6. ///////////////////////////////////////////////////////////////////////////
  7. #include "precomp.h"
  8. #include "connpnts.h"
  9. #include <olectl.h>
  10. /* C C O N N E C T I O N P O I N T */
  11. /*-------------------------------------------------------------------------
  12. %%Function: CConnectionPoint
  13. -------------------------------------------------------------------------*/
  14. CConnectionPoint::CConnectionPoint(const IID *pIID, IConnectionPointContainer *pCPCInit) :
  15. m_riid(*pIID),
  16. m_pCPC(pCPCInit),
  17. m_cSinks(0),
  18. m_cAllocatedSinks(0),
  19. m_rgSinks(NULL)
  20. {
  21. TRACE_OUT(("CConnectionPoint - Constructed(%08X)", this));
  22. }
  23. CConnectionPoint::~CConnectionPoint (void)
  24. {
  25. for (ULONG x = 0; x < m_cAllocatedSinks; x += 1)
  26. {
  27. if (m_rgSinks[x] != NULL)
  28. {
  29. IUnknown *pUnk = (IUnknown *)m_rgSinks[x];
  30. pUnk->Release();
  31. }
  32. }
  33. if (m_cAllocatedSinks != 0)
  34. {
  35. HeapFree(GetProcessHeap(), 0, m_rgSinks);
  36. }
  37. TRACE_OUT(("CConnectionPoint - Destructed(%p)", this));
  38. }
  39. STDMETHODIMP_(ULONG) CConnectionPoint::AddRef(void)
  40. {
  41. return RefCount::AddRef();
  42. }
  43. STDMETHODIMP_(ULONG) CConnectionPoint::Release(void)
  44. {
  45. return RefCount::Release();
  46. }
  47. STDMETHODIMP CConnectionPoint::QueryInterface(REFIID riid, void **ppv)
  48. {
  49. HRESULT hr = S_OK;
  50. if ((riid == IID_IUnknown) || (riid == IID_IConnectionPoint))
  51. {
  52. *ppv = (IConnectionPoint *)this;
  53. TRACE_OUT(("CConnectionPoint::QueryInterface(): Returning IConnectionPoint."));
  54. }
  55. else
  56. {
  57. hr = E_NOINTERFACE;
  58. *ppv = NULL;
  59. TRACE_OUT(("CConnectionPoint::QueryInterface(): Called on unknown interface."));
  60. }
  61. if (S_OK == hr)
  62. {
  63. AddRef();
  64. }
  65. return hr;
  66. }
  67. /* N O T I F Y */
  68. /*-------------------------------------------------------------------------
  69. %%Function: Notify
  70. -------------------------------------------------------------------------*/
  71. STDMETHODIMP CConnectionPoint::Notify(void *pv, CONN_NOTIFYPROC pfn)
  72. {
  73. //
  74. // Enumerate each connection
  75. //
  76. AddRef();
  77. for (ULONG x = 0; x < m_cAllocatedSinks; x += 1)
  78. {
  79. if (m_rgSinks[x] != NULL)
  80. {
  81. IUnknown *pUnk = (IUnknown *)m_rgSinks[x];
  82. pUnk->AddRef();
  83. (*pfn)(pUnk, pv, m_riid);
  84. pUnk->Release();
  85. }
  86. }
  87. Release();
  88. return S_OK;
  89. }
  90. /* G E T C O N N E C T I O N I N T E R F A C E */
  91. /*-------------------------------------------------------------------------
  92. %%Function: GetConnectionInterface
  93. -------------------------------------------------------------------------*/
  94. STDMETHODIMP CConnectionPoint::GetConnectionInterface(IID *pIID)
  95. {
  96. // Validate the parameter
  97. //
  98. if (pIID == NULL)
  99. return E_POINTER;
  100. // Support only one connection interface
  101. //
  102. *pIID = m_riid;
  103. return S_OK;
  104. }
  105. STDMETHODIMP CConnectionPoint::GetConnectionPointContainer(IConnectionPointContainer **ppCPC)
  106. {
  107. // Validate the parameter
  108. //
  109. if (ppCPC == NULL)
  110. return E_POINTER;
  111. // Return the container and add its reference count
  112. //
  113. *ppCPC = m_pCPC;
  114. if (m_pCPC != NULL)
  115. {
  116. // The container is still alive
  117. //
  118. m_pCPC->AddRef();
  119. return S_OK;
  120. }
  121. else
  122. {
  123. // The container no longer exists
  124. //
  125. return E_FAIL;
  126. }
  127. }
  128. /* A D V I S E */
  129. /*-------------------------------------------------------------------------
  130. %%Function: Advise
  131. -------------------------------------------------------------------------*/
  132. STDMETHODIMP CConnectionPoint::Advise(IUnknown *pUnk, DWORD *pdwCookie)
  133. {
  134. IUnknown *pSinkInterface;
  135. // Validate the parameter
  136. //
  137. if (pdwCookie == NULL)
  138. return E_POINTER;
  139. *pdwCookie = 0;
  140. if (pUnk == NULL)
  141. return E_INVALIDARG;
  142. HRESULT hr = CONNECT_E_CANNOTCONNECT;
  143. //
  144. // Get the sink interface
  145. //
  146. if (SUCCEEDED(pUnk->QueryInterface(m_riid, (void **)&pSinkInterface)))
  147. {
  148. //
  149. // If the number of active sinks is less than the number of allocated
  150. // sinks, then there is a free slot in the sink table. Otherwise, the
  151. // table must be expanded.
  152. //
  153. ULONG x = m_cAllocatedSinks;
  154. if (m_cSinks < m_cAllocatedSinks)
  155. {
  156. for (x = 0; x < m_cAllocatedSinks; x += 1)
  157. {
  158. if (m_rgSinks[x] == NULL)
  159. {
  160. break;
  161. }
  162. }
  163. }
  164. //
  165. // If a free slot was found in the table, then use the slot. Otherwise,
  166. // expand the sink table.
  167. //
  168. if (x == m_cAllocatedSinks)
  169. {
  170. IUnknown **rgSinks = (IUnknown **)HeapAlloc(GetProcessHeap(),
  171. HEAP_ZERO_MEMORY,
  172. (m_cAllocatedSinks + 8) * sizeof(IUnknown *));
  173. if (rgSinks == NULL)
  174. {
  175. pSinkInterface->Release();
  176. return E_OUTOFMEMORY;
  177. }
  178. for (ULONG z = 0; z < m_cAllocatedSinks; z += 1)
  179. {
  180. rgSinks[z] = m_rgSinks[z];
  181. }
  182. m_cAllocatedSinks += 8;
  183. if (m_rgSinks != NULL) {
  184. HeapFree(GetProcessHeap(), 0, m_rgSinks);
  185. }
  186. m_rgSinks = rgSinks;
  187. }
  188. //
  189. // Add new sink to the table.
  190. //
  191. m_rgSinks[x] = pSinkInterface;
  192. m_cSinks += 1;
  193. *pdwCookie = x + 1;
  194. hr = S_OK;
  195. }
  196. return hr;
  197. }
  198. /* U N A D V I S E */
  199. /*-------------------------------------------------------------------------
  200. %%Function: Unadvise
  201. -------------------------------------------------------------------------*/
  202. STDMETHODIMP CConnectionPoint::Unadvise(DWORD dwCookie)
  203. {
  204. HRESULT hr = CONNECT_E_NOCONNECTION;
  205. //
  206. // Traverse the sink list to find the specified sink object
  207. //
  208. if ((dwCookie != 0) &&
  209. (dwCookie <= m_cAllocatedSinks) &&
  210. (m_rgSinks[dwCookie - 1] != NULL))
  211. {
  212. IUnknown *pUnk = (IUnknown *) m_rgSinks[dwCookie - 1];
  213. pUnk->Release();
  214. m_rgSinks[dwCookie - 1] = NULL;
  215. m_cSinks -= 1;
  216. hr = S_OK;
  217. }
  218. return hr;
  219. }
  220. STDMETHODIMP CConnectionPoint::EnumConnections(IEnumConnections **ppEnum)
  221. {
  222. HRESULT hr = E_POINTER;
  223. // Validate parameters
  224. //
  225. if (ppEnum == NULL)
  226. {
  227. // Create an enumerator
  228. //
  229. *ppEnum = new CEnumConnections(m_rgSinks, m_cSinks, m_cAllocatedSinks);
  230. hr = (NULL != *ppEnum) ? S_OK : E_OUTOFMEMORY;
  231. }
  232. return hr;
  233. }
  234. ///////////////////////////////////////////////////////////////////////////
  235. /* C E N U M C O N N E C T I O N S */
  236. /*-------------------------------------------------------------------------
  237. %%Function: CEnumConnections
  238. -------------------------------------------------------------------------*/
  239. CEnumConnections::CEnumConnections(IUnknown **pSinks, ULONG cSinks, ULONG cAllocatedSinks) :
  240. m_iIndex(0),
  241. m_cConnections(0),
  242. m_pCD(NULL)
  243. {
  244. // Snapshot the connection list
  245. //
  246. if (cSinks > 0)
  247. {
  248. m_pCD = new CONNECTDATA[cSinks];
  249. if (NULL != m_pCD)
  250. {
  251. for (ULONG x = 0; x < cAllocatedSinks; x += 1)
  252. {
  253. if (pSinks[x] != NULL) {
  254. IUnknown *pUnk = (IUnknown *) pSinks[x];
  255. pUnk->AddRef();
  256. m_pCD[m_cConnections++].pUnk = pUnk;
  257. m_pCD[m_cConnections++].dwCookie = x + 1;
  258. }
  259. }
  260. }
  261. }
  262. TRACE_OUT(("CEnumConnections - Constructed(%p)", this));
  263. }
  264. CEnumConnections::~CEnumConnections(void)
  265. {
  266. if (m_pCD != NULL)
  267. {
  268. for (int i = 0; i < m_cConnections; i++)
  269. {
  270. m_pCD[i].pUnk->Release();
  271. };
  272. delete [] m_pCD;
  273. };
  274. TRACE_OUT(("CEnumConnections - Destructed(%08X)", this));
  275. }
  276. STDMETHODIMP_(ULONG) CEnumConnections::AddRef(void)
  277. {
  278. return RefCount::AddRef();
  279. }
  280. STDMETHODIMP_(ULONG) CEnumConnections::Release(void)
  281. {
  282. return RefCount::Release();
  283. }
  284. STDMETHODIMP CEnumConnections::QueryInterface(REFIID riid, void **ppv)
  285. {
  286. HRESULT hr = S_OK;
  287. if ((riid == IID_IEnumConnections) || (riid == IID_IUnknown))
  288. {
  289. *ppv = (IEnumConnections *)this;
  290. TRACE_OUT(("CEnumConnections::QueryInterface(): Returning IEnumConnections."));
  291. }
  292. else
  293. {
  294. hr = E_NOINTERFACE;
  295. *ppv = NULL;
  296. TRACE_OUT(("CEnumConnections::QueryInterface(): Called on unknown interface."));
  297. }
  298. if (S_OK == hr)
  299. {
  300. AddRef();
  301. }
  302. return hr;
  303. }
  304. STDMETHODIMP CEnumConnections::Next(ULONG cConnections, CONNECTDATA *rgpcd, ULONG *pcFetched)
  305. {
  306. ULONG cCopied = 0;
  307. if ((0 == cConnections) && (NULL == rgpcd) && (NULL != pcFetched))
  308. {
  309. // Return the number of remaining elements
  310. *pcFetched = m_cConnections - m_iIndex;
  311. return S_OK;
  312. }
  313. if ((NULL == rgpcd) || ((NULL == pcFetched) && (cConnections != 1)))
  314. return E_POINTER;
  315. if (NULL != m_pCD)
  316. {
  317. while ((cCopied < cConnections) && (m_iIndex < m_cConnections))
  318. {
  319. *rgpcd = m_pCD[m_iIndex];
  320. (*rgpcd).pUnk->AddRef();
  321. rgpcd++;
  322. cCopied++;
  323. m_iIndex++;
  324. }
  325. }
  326. if (pcFetched != NULL)
  327. *pcFetched = cCopied;
  328. return (cConnections == cCopied) ? S_OK : S_FALSE;
  329. }
  330. STDMETHODIMP CEnumConnections::Skip(ULONG cConnections)
  331. {
  332. m_iIndex += cConnections;
  333. if (m_iIndex >= m_cConnections)
  334. {
  335. // Past the end of the list
  336. m_iIndex = m_cConnections;
  337. return S_FALSE;
  338. }
  339. return S_OK;
  340. }
  341. STDMETHODIMP CEnumConnections::Reset(void)
  342. {
  343. m_iIndex = 0;
  344. return S_OK;
  345. }
  346. STDMETHODIMP CEnumConnections::Clone(IEnumConnections **ppEnum)
  347. {
  348. // Validate parameters
  349. //
  350. if (ppEnum != NULL)
  351. return E_POINTER;
  352. HRESULT hr = S_OK;
  353. CEnumConnections * pEnum = new CEnumConnections(NULL, 0, 0);
  354. if (NULL == pEnum)
  355. {
  356. hr = E_OUTOFMEMORY;
  357. }
  358. else if (NULL != m_pCD)
  359. {
  360. pEnum->m_pCD = new CONNECTDATA[m_cConnections];
  361. if (NULL == pEnum->m_pCD)
  362. {
  363. delete pEnum;
  364. pEnum = NULL;
  365. hr = E_OUTOFMEMORY;
  366. }
  367. else
  368. {
  369. pEnum->m_iIndex = m_iIndex;
  370. pEnum->m_cConnections = m_cConnections;
  371. for (int i = 0; i < m_cConnections; ++i)
  372. {
  373. m_pCD[i].pUnk->AddRef();
  374. pEnum->m_pCD[i] = m_pCD[i];
  375. }
  376. }
  377. }
  378. *ppEnum = pEnum;
  379. return hr;
  380. }
  381. ///////////////////////////////////////////////////////////////////////////
  382. /* C C O N N E C T I O N P O I N T C O N T A I N E R */
  383. /*-------------------------------------------------------------------------
  384. %%Function: CConnectionPointContainer
  385. -------------------------------------------------------------------------*/
  386. CConnectionPointContainer::CConnectionPointContainer(const IID **ppiid, int cCp) :
  387. m_ppCp(NULL),
  388. m_cCp(0)
  389. {
  390. m_ppCp = new CConnectionPoint* [cCp];
  391. if (NULL != m_ppCp)
  392. {
  393. for (int i = 0; i < cCp; ++i)
  394. {
  395. CConnectionPoint *pCp = new CConnectionPoint(ppiid[i], this);
  396. if (NULL != pCp)
  397. {
  398. m_ppCp[m_cCp++] = pCp;
  399. }
  400. }
  401. }
  402. }
  403. CConnectionPointContainer::~CConnectionPointContainer()
  404. {
  405. if (NULL != m_ppCp)
  406. {
  407. for (int i = 0; i < m_cCp; ++i)
  408. {
  409. CConnectionPoint *pCp = m_ppCp[i];
  410. if (NULL != pCp)
  411. {
  412. pCp->ContainerReleased();
  413. pCp->Release();
  414. }
  415. }
  416. delete[] m_ppCp;
  417. }
  418. }
  419. HRESULT STDMETHODCALLTYPE
  420. CConnectionPointContainer::NotifySink(void *pv, CONN_NOTIFYPROC pfn)
  421. {
  422. if (NULL != m_ppCp)
  423. {
  424. for (int i = 0; i < m_cCp; ++i)
  425. {
  426. m_ppCp[i]->Notify(pv, pfn);
  427. }
  428. }
  429. return S_OK;
  430. }
  431. STDMETHODIMP
  432. CConnectionPointContainer::EnumConnectionPoints(IEnumConnectionPoints **ppEnum)
  433. {
  434. if (ppEnum == NULL)
  435. return E_POINTER;
  436. // Create an enumerator
  437. *ppEnum = new CEnumConnectionPoints(m_ppCp, m_cCp);
  438. return (NULL != *ppEnum) ? S_OK : E_OUTOFMEMORY;
  439. }
  440. STDMETHODIMP
  441. CConnectionPointContainer::FindConnectionPoint(REFIID riid, IConnectionPoint **ppCp)
  442. {
  443. HRESULT hr = E_POINTER;
  444. if (NULL != ppCp)
  445. {
  446. hr = CONNECT_E_NOCONNECTION;
  447. *ppCp = NULL;
  448. if (NULL != m_ppCp)
  449. {
  450. for (int i = 0; i < m_cCp; ++i)
  451. {
  452. IID iid;
  453. IConnectionPoint *pCp = m_ppCp[i];
  454. if (S_OK == pCp->GetConnectionInterface(&iid))
  455. {
  456. if (riid == iid)
  457. {
  458. pCp->AddRef();
  459. *ppCp = pCp;
  460. hr = S_OK;
  461. break;
  462. }
  463. }
  464. }
  465. }
  466. }
  467. return hr;
  468. }
  469.