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.

1156 lines
28 KiB

  1. /*++
  2. Copyright (c) 1997-1999 Microsoft Corporation
  3. Module Name:
  4. mspstrm.cpp
  5. Abstract:
  6. This module contains implementation of CMSPStream. The object represents
  7. one stream in the filter graph.
  8. --*/
  9. #include "precomp.h"
  10. #pragma hdrstop
  11. /////////////////////////////////////////////////////////////////////////////
  12. // CMSPStream
  13. /////////////////////////////////////////////////////////////////////////////
  14. CMSPStream::CMSPStream()
  15. : m_dwState(STRM_INITIAL),
  16. m_dwMediaType(0),
  17. m_pFTM(NULL),
  18. m_hAddress(NULL),
  19. m_pMSPCall(NULL),
  20. m_pIGraphBuilder(NULL),
  21. m_pIMediaControl(NULL),
  22. m_pPTEventSink( NULL ),
  23. m_lMyPersonalRefcount(0),
  24. m_bFirstAddRef(TRUE)
  25. {
  26. LOG((MSP_TRACE, "CMSPStream::CMSPStream - enter"));
  27. LOG((MSP_TRACE, "CMSPStream::CMSPStream - exit"));
  28. }
  29. CMSPStream::~CMSPStream()
  30. {
  31. LOG((MSP_TRACE, "CMSPStream::~CMSPStream - enter"));
  32. ReleaseSink();
  33. LOG((MSP_TRACE, "CMSPStream::~CMSPStream - exit"));
  34. }
  35. STDMETHODIMP CMSPStream::get_MediaType(
  36. OUT long * plTapiMediaType
  37. )
  38. {
  39. LOG((MSP_TRACE, "CMSPStream::get_MediaType - enter"));
  40. if (MSPB_IsBadWritePtr(plTapiMediaType, sizeof (long *)))
  41. {
  42. LOG((MSP_ERROR, "CMSPStream::get_MediaType - exit E_POINTER"));
  43. return E_POINTER;
  44. }
  45. CLock lock(m_lock);
  46. *plTapiMediaType = m_dwMediaType;
  47. LOG((MSP_TRACE, "CMSPStream::get_MediaType - exit S_OK"));
  48. return S_OK;
  49. }
  50. STDMETHODIMP CMSPStream::get_Direction(
  51. OUT TERMINAL_DIRECTION * pTerminalDirection
  52. )
  53. {
  54. LOG((MSP_TRACE, "CMSPStream::get_Direction - enter"));
  55. if (MSPB_IsBadWritePtr(pTerminalDirection, sizeof (TERMINAL_DIRECTION *)))
  56. {
  57. LOG((MSP_ERROR, "CMSPStream::get_Direction - exit E_POINTER"));
  58. return E_POINTER;
  59. }
  60. CLock lock(m_lock);
  61. *pTerminalDirection = m_Direction;
  62. LOG((MSP_TRACE, "CMSPStream::get_Direction - exit S_OK"));
  63. return S_OK;
  64. }
  65. STDMETHODIMP CMSPStream::SelectTerminal(
  66. IN ITTerminal * pTerminal
  67. )
  68. /*++
  69. Routine Description:
  70. Arguments:
  71. Return Value:
  72. S_OK
  73. E_POINTER
  74. E_OUTOFMEMORY
  75. TAPI_E_MAXTERMINALS
  76. TAPI_E_INVALIDTERMINAL
  77. --*/
  78. {
  79. LOG((MSP_TRACE, "CMSPStream::SelectTerminal - enter"));
  80. //
  81. // Check parameter.
  82. //
  83. if ( IsBadReadPtr(pTerminal, sizeof(ITTerminal) ) )
  84. {
  85. LOG((MSP_ERROR, "CMSPStream::SelectTerminal - exit E_POINTER"));
  86. return E_POINTER;
  87. }
  88. HRESULT hr;
  89. ITTerminalControl *pTerminalControl;
  90. //
  91. // Get the private interface from this terminal.
  92. //
  93. hr = pTerminal->QueryInterface(IID_ITTerminalControl,
  94. (void **) &pTerminalControl);
  95. if (FAILED(hr))
  96. {
  97. LOG((MSP_ERROR, "CMSPStream::SelectTerminal - "
  98. "can't get ITTerminalControl - exit TAPI_E_INVALIDTERMINAL"));
  99. return TAPI_E_INVALIDTERMINAL;
  100. }
  101. //
  102. // Get the address handle and release the private interface.
  103. //
  104. MSP_HANDLE hAddress;
  105. hr = pTerminalControl->get_AddressHandle(&hAddress);
  106. pTerminalControl->Release();
  107. if (FAILED(hr))
  108. {
  109. LOG((MSP_ERROR, "CMSPStream::SelectTerminal - "
  110. "can't get address handle - exit TAPI_E_INVALIDTERMINAL"));
  111. return TAPI_E_INVALIDTERMINAL;
  112. }
  113. //
  114. // Find out if the terminal belongs to this address. Reject it if it belongs
  115. // to another address, but accept it if it is an application-provided terminal
  116. // (NULL address handle).
  117. //
  118. if ( ( hAddress != NULL ) && ( hAddress != (MSP_HANDLE) m_hAddress ) )
  119. {
  120. LOG((MSP_ERROR, "CMSPStream::SelectTerminal - "
  121. "terminal from another address - exit TAPI_E_INVALIDTERMINAL"));
  122. return TAPI_E_INVALIDTERMINAL;
  123. }
  124. //
  125. // Get the type of the terminal
  126. //
  127. TERMINAL_TYPE nTerminalType;
  128. hr = pTerminal->get_TerminalType( &nTerminalType );
  129. if( FAILED(hr) )
  130. {
  131. LOG((MSP_ERROR, "CMSPStream::SelectTerminal "
  132. "get_TerminalType failed, exit E_UNEXPECTED"));
  133. return E_UNEXPECTED;
  134. }
  135. //
  136. // Find out if the terminal is already in our list.
  137. //
  138. CLock lock(m_lock);
  139. if (m_Terminals.Find(pTerminal) >= 0)
  140. {
  141. LOG((MSP_ERROR, "CMSPStream::SelectTerminal - "
  142. "terminal already selected - exit TAPI_E_INVALIDTERMINAL"));
  143. return TAPI_E_INVALIDTERMINAL;
  144. }
  145. //
  146. // Add the new terminal into our list and addref it.
  147. //
  148. if (!m_Terminals.Add(pTerminal))
  149. {
  150. LOG((MSP_ERROR, "CMSPStream::SelectTerminal - "
  151. "exit E_OUTOFMEMORY"));
  152. return E_OUTOFMEMORY;
  153. }
  154. pTerminal->AddRef();
  155. if( TT_DYNAMIC == nTerminalType)
  156. {
  157. hr = RegisterPluggableTerminalEventSink( pTerminal );
  158. if( FAILED(hr) )
  159. {
  160. LOG((MSP_TRACE, "CMSPStream::SelectTerminal - "
  161. "something wrong in RegisterPluggableTerminalEventSink. hr = %lx", hr));
  162. m_Terminals.Remove(pTerminal);
  163. pTerminal->Release();
  164. return hr;
  165. }
  166. }
  167. LOG((MSP_TRACE, "CMSPStream::SelectTerminal - exit S_OK"));
  168. return S_OK;
  169. }
  170. STDMETHODIMP CMSPStream::UnselectTerminal(
  171. IN ITTerminal * pTerminal
  172. )
  173. {
  174. LOG((MSP_TRACE, "CMSPStream::UnselectTerminal - enter"));
  175. //
  176. // find out if the terminal is in our list.
  177. //
  178. CLock lock(m_lock);
  179. int index;
  180. if ((index = m_Terminals.Find(pTerminal)) < 0)
  181. {
  182. LOG((MSP_ERROR, "CMSPStream::UnselectTerminal - "
  183. "exit TAPI_E_INVALIDTERMINAL"));
  184. return TAPI_E_INVALIDTERMINAL;
  185. }
  186. //
  187. // Unregister the PTEventSink object
  188. //
  189. HRESULT hr = E_FAIL;
  190. hr = UnregisterPluggableTerminalEventSink( pTerminal );
  191. if( FAILED(hr) )
  192. {
  193. LOG((MSP_TRACE, "CMSPStream::UnselectTerminal - "
  194. "something wrong in UnregisterPluggableTerminalEventSink"));
  195. }
  196. //
  197. // remove the terminal from our list and release it.
  198. //
  199. if (!m_Terminals.RemoveAt(index))
  200. {
  201. LOG((MSP_ERROR, "CMSPStream::UnselectTerminal - "
  202. "exit E_UNEXPECTED"));
  203. return E_UNEXPECTED;
  204. }
  205. pTerminal->Release();
  206. LOG((MSP_TRACE, "CMSPStream::UnselectTerminal - exit S_OK"));
  207. return S_OK;
  208. }
  209. STDMETHODIMP CMSPStream::EnumerateTerminals(
  210. OUT IEnumTerminal ** ppEnumTerminal
  211. )
  212. {
  213. LOG((MSP_TRACE,
  214. "EnumerateTerminals entered. ppEnumTerminal:%x", ppEnumTerminal));
  215. if (MSPB_IsBadWritePtr(ppEnumTerminal, sizeof(VOID *)))
  216. {
  217. LOG((MSP_ERROR, "ppEnumTerminal is a bad pointer"));
  218. return E_POINTER;
  219. }
  220. // acquire the lock before accessing the Terminal object list.
  221. CLock lock(m_lock);
  222. if (m_Terminals.GetData() == NULL)
  223. {
  224. LOG((MSP_ERROR, "CMSPStream::EnumerateTerminals - "
  225. "stream appears to have been shut down - exit E_UNEXPECTED"));
  226. return E_UNEXPECTED;
  227. }
  228. typedef _CopyInterface<ITTerminal> CCopy;
  229. typedef CSafeComEnum<IEnumTerminal, &IID_IEnumTerminal,
  230. ITTerminal *, CCopy> CEnumerator;
  231. HRESULT hr;
  232. CMSPComObject<CEnumerator> *pEnum = NULL;
  233. hr = CMSPComObject<CEnumerator>::CreateInstance(&pEnum);
  234. if (pEnum == NULL)
  235. {
  236. LOG((MSP_ERROR, "Could not create enumerator object, %x", hr));
  237. return hr;
  238. }
  239. // query for the IID_IEnumTerminal i/f
  240. hr = pEnum->_InternalQueryInterface(IID_IEnumTerminal, (void**)ppEnumTerminal);
  241. if (FAILED(hr))
  242. {
  243. LOG((MSP_ERROR, "query enum interface failed, %x", hr));
  244. delete pEnum;
  245. return hr;
  246. }
  247. // The CSafeComEnum can handle zero-sized array.
  248. hr = pEnum->Init(
  249. m_Terminals.GetData(), // the begin itor
  250. m_Terminals.GetData() + m_Terminals.GetSize(), // the end itor,
  251. NULL, // IUnknown
  252. AtlFlagCopy // copy the data.
  253. );
  254. if (FAILED(hr))
  255. {
  256. LOG((MSP_ERROR, "init enumerator object failed, %x", hr));
  257. (*ppEnumTerminal)->Release();
  258. return hr;
  259. }
  260. LOG((MSP_TRACE, "CMSPStream::EnumerateTerminals - exit S_OK"));
  261. return hr;
  262. }
  263. STDMETHODIMP CMSPStream::get_Terminals(
  264. OUT VARIANT * pVariant
  265. )
  266. {
  267. LOG((MSP_TRACE, "CMSPStream::get_Terminals - enter"));
  268. //
  269. // Check parameters.
  270. //
  271. if ( MSPB_IsBadWritePtr(pVariant, sizeof(VARIANT) ) )
  272. {
  273. LOG((MSP_ERROR, "CMSPStream::get_Terminals - "
  274. "bad pointer argument - exit E_POINTER"));
  275. return E_POINTER;
  276. }
  277. //
  278. // See if this stream has been shut down. Acquire the lock before accessing
  279. // the terminal object list.
  280. //
  281. CLock lock(m_lock);
  282. if (m_Terminals.GetData() == NULL)
  283. {
  284. LOG((MSP_ERROR, "CMSPStream::get_Terminals - "
  285. "stream appears to have been shut down - exit E_UNEXPECTED"));
  286. return E_UNEXPECTED;
  287. }
  288. //
  289. // create the collection object - see mspcoll.h
  290. //
  291. HRESULT hr;
  292. typedef CTapiIfCollection< ITTerminal * > TerminalCollection;
  293. CComObject<TerminalCollection> * pCollection;
  294. hr = CComObject<TerminalCollection>::CreateInstance( &pCollection );
  295. if ( FAILED(hr) )
  296. {
  297. LOG((MSP_ERROR, "CMSPStream::get_Terminals - "
  298. "can't create collection - exit 0x%08x", hr));
  299. return hr;
  300. }
  301. //
  302. // get the Collection's IDispatch interface
  303. //
  304. IDispatch * pDispatch;
  305. hr = pCollection->_InternalQueryInterface(IID_IDispatch,
  306. (void **) &pDispatch );
  307. if ( FAILED(hr) )
  308. {
  309. LOG((MSP_ERROR, "CMSPStream::get_Terminals - "
  310. "QI for IDispatch on collection failed - exit 0x%08x", hr));
  311. delete pCollection;
  312. return hr;
  313. }
  314. //
  315. // Init the collection using an iterator -- pointers to the beginning and
  316. // the ending element plus one.
  317. //
  318. hr = pCollection->Initialize( m_Terminals.GetSize(),
  319. m_Terminals.GetData(),
  320. m_Terminals.GetData() + m_Terminals.GetSize() );
  321. if (FAILED(hr))
  322. {
  323. LOG((MSP_ERROR, "CMSPStream::get_Terminals - "
  324. "Initialize on collection failed - exit 0x%08x", hr));
  325. pDispatch->Release();
  326. return hr;
  327. }
  328. //
  329. // put the IDispatch interface pointer into the variant
  330. //
  331. LOG((MSP_TRACE, "CMSPStream::get_Terminals - "
  332. "placing IDispatch value %08x in variant", pDispatch));
  333. VariantInit(pVariant);
  334. pVariant->vt = VT_DISPATCH;
  335. pVariant->pdispVal = pDispatch;
  336. LOG((MSP_TRACE, "CMSPStream::get_Terminals - exit S_OK"));
  337. return S_OK;
  338. }
  339. STDMETHODIMP CMSPStream::StartStream()
  340. {
  341. LOG((MSP_TRACE, "CMSPStream - RUNNING GRAPH"));
  342. HRESULT hr = m_pIMediaControl->Run();
  343. if(FAILED(hr))
  344. {
  345. LOG((MSP_ERROR, "graph doesn't run, %x", hr));
  346. }
  347. return hr;
  348. }
  349. STDMETHODIMP CMSPStream::PauseStream()
  350. {
  351. LOG((MSP_TRACE, "CMSPStream - PAUSING GRAPH"));
  352. HRESULT hr = m_pIMediaControl->Pause();
  353. if(FAILED(hr))
  354. {
  355. LOG((MSP_ERROR, "graph doesn't pause, %x", hr));
  356. }
  357. return hr;
  358. }
  359. STDMETHODIMP CMSPStream::StopStream()
  360. {
  361. LOG((MSP_TRACE, "CMSPStream - STOPPING GRAPH"));
  362. HRESULT hr = m_pIMediaControl->Stop();
  363. if(FAILED(hr))
  364. {
  365. LOG((MSP_ERROR, "graph doesn't stop, %x", hr));
  366. }
  367. return hr;
  368. }
  369. // methods called by the MSPCall object.
  370. HRESULT CMSPStream::Init(
  371. IN HANDLE hAddress,
  372. IN CMSPCallBase * pMSPCall,
  373. IN IMediaEvent * pGraph,
  374. IN DWORD dwMediaType,
  375. IN TERMINAL_DIRECTION Direction
  376. )
  377. {
  378. LOG((MSP_TRACE, "CMSPStream::Init - enter"));
  379. CLock lock(m_lock);
  380. // This method is called only once when the object is created. No other
  381. // method will be called until this function succeeds. No need to lock.
  382. _ASSERTE(m_hAddress == NULL);
  383. // initialize the terminal array so that the array is not NULL. Used for
  384. // generating an empty enumerator if no terminal is selected.
  385. if (!m_Terminals.Grow())
  386. {
  387. LOG((MSP_ERROR, "CMSPStream::Init - exit E_OUTOFMEMORY"));
  388. return E_OUTOFMEMORY;
  389. }
  390. HRESULT hr;
  391. hr = CoCreateFreeThreadedMarshaler(GetControllingUnknown(), &m_pFTM);
  392. if (FAILED(hr))
  393. {
  394. LOG((MSP_ERROR, "create marshaler failed, %x", hr));
  395. return hr;
  396. }
  397. // Get the media control interface on the graph.
  398. IMediaControl *pMC;
  399. hr = pGraph->QueryInterface(IID_IMediaControl, (void **) &pMC);
  400. if(FAILED(hr))
  401. {
  402. LOG((MSP_ERROR, "get IMediaControl interface, %x", hr));
  403. return hr;
  404. }
  405. // Get the graph builder interface on the graph.
  406. IGraphBuilder *pGB;
  407. hr = pGraph->QueryInterface(IID_IGraphBuilder, (void **) &pGB);
  408. if(FAILED(hr))
  409. {
  410. LOG((MSP_ERROR, "get IGraphBuilder interface, %x", hr));
  411. pMC->Release();
  412. return hr;
  413. }
  414. m_hAddress = hAddress;
  415. m_pMSPCall = pMSPCall;
  416. m_pMSPCall->MSPCallAddRef();
  417. m_pIMediaControl = pMC;
  418. // no addref because QI addrefs for us above
  419. m_pIGraphBuilder = pGB;
  420. // no addref because QI addrefs for us above
  421. m_dwMediaType = dwMediaType;
  422. m_Direction = Direction;
  423. LOG((MSP_TRACE, "CMSPStream::Init - exit S_OK"));
  424. return S_OK;
  425. }
  426. HRESULT CMSPStream::ShutDown()
  427. {
  428. LOG((MSP_TRACE, "CMSPStream::Shutdown - enter"));
  429. CLock lock(m_lock);
  430. //
  431. // We are shut down, so the call is now NULL.
  432. //
  433. m_pMSPCall->MSPCallRelease();
  434. m_pMSPCall = NULL;
  435. //
  436. // Unselect all the terminals. Rather than just removing all the
  437. // terminals, we call UnselectTerminal on each one to give the derived
  438. // class a chance to do whatever else it needs to do when a terminal
  439. // is unselected.
  440. //
  441. // We walk the list in reverse order because the list shrinks with
  442. // each iteration (see msputils.h).
  443. //
  444. for ( int i = m_Terminals.GetSize() - 1; i >= 0; i-- )
  445. {
  446. UnselectTerminal(m_Terminals[i]);
  447. }
  448. //
  449. // At this point the derive class should have removed and released
  450. // all of the terminals from the list. If that's not the case, the
  451. // derived class is buggy.
  452. //
  453. _ASSERTE( m_Terminals.GetSize() == 0 );
  454. //
  455. // no longer need the sink
  456. //
  457. ReleaseSink();
  458. LOG((MSP_TRACE, "CMSPStream::Shutdown - exit S_OK"));
  459. return S_OK;
  460. }
  461. void CMSPStream::FinalRelease()
  462. {
  463. LOG((MSP_TRACE, "CMSPStream::FinalRelease - enter"));
  464. // release the two interface pointers to the graph.
  465. if (m_pIMediaControl)
  466. {
  467. m_pIMediaControl->Release();
  468. }
  469. if (m_pIGraphBuilder)
  470. {
  471. m_pIGraphBuilder->Release();
  472. }
  473. if (m_pFTM)
  474. {
  475. m_pFTM->Release();
  476. }
  477. LOG((MSP_TRACE, "CMSPStream::FinalRelease - exit"));
  478. }
  479. HRESULT CMSPStream::HandleTSPData(
  480. IN BYTE * pData,
  481. IN DWORD dwSize
  482. )
  483. {
  484. LOG((MSP_TRACE, "CMSPStream::HandleTSPData - enter"));
  485. LOG((MSP_TRACE, "CMSPStream::HandleTSPData - exit S_OK"));
  486. return S_OK;
  487. }
  488. HRESULT CMSPStream::ProcessGraphEvent(
  489. IN long lEventCode,
  490. IN LONG_PTR lParam1,
  491. IN LONG_PTR lParam2
  492. )
  493. {
  494. LOG((MSP_TRACE, "CMSPStream::ProcessGraphEvent - enter"));
  495. LOG((MSP_TRACE, "CMSPStream::ProcessGraphEvent - exit S_OK"));
  496. return S_OK;
  497. }
  498. /*++
  499. RegisterPluggableTerminalEventSink
  500. Parameters:
  501. The terminla interface
  502. Description;
  503. Is called by SelectTerminal if is a dynamic terminal
  504. --*/
  505. HRESULT CMSPStream::RegisterPluggableTerminalEventSink(
  506. IN ITTerminal* pTerminal
  507. )
  508. {
  509. LOG((MSP_TRACE, "CMSPStream::RegisterPluggableTerminalEventSink - enter"));
  510. //
  511. // Validates arguments
  512. //
  513. if( IsBadReadPtr( pTerminal, sizeof( ITTerminal) ))
  514. {
  515. LOG((MSP_ERROR, "CMSPStream::RegisterPluggableTerminalEventSink "
  516. "pTerminal invalid, returns E_POINTER"));
  517. return E_POINTER;
  518. }
  519. //
  520. // Get the type of the terminal
  521. //
  522. TERMINAL_TYPE nTerminalType;
  523. HRESULT hr = E_FAIL;
  524. hr = pTerminal->get_TerminalType( &nTerminalType );
  525. if( FAILED(hr) )
  526. {
  527. LOG((MSP_ERROR, "CMSPStream::RegisterPluggableTerminalEventSink "
  528. "get_TerminalType failed, exit E_UNEXPECTED"));
  529. return E_UNEXPECTED;
  530. }
  531. //
  532. // The terminal should by a dynamic terminal
  533. //
  534. if( TT_DYNAMIC != nTerminalType)
  535. {
  536. LOG((MSP_ERROR, "CMSPStream::RegisterPluggableTerminalEventSink "
  537. "terminal is not dynamic, exit E_INVALIDARG"));
  538. return E_INVALIDARG;
  539. }
  540. CLock lock(m_lock);
  541. //
  542. // Create the sink if we don't have one already
  543. //
  544. if(NULL == m_pPTEventSink)
  545. {
  546. //Create a PTEventSink object
  547. CComObject<CPTEventSink>* pPTEventSink;
  548. hr = CComObject<CPTEventSink>::CreateInstance(&pPTEventSink);
  549. if( FAILED(hr) )
  550. {
  551. LOG((MSP_ERROR, "CMSPStream::RegisterPluggableTerminalEventSink "
  552. "CreateInstance failed, returns E_OUTOFMEMORY"));
  553. return E_OUTOFMEMORY;
  554. }
  555. // tell sink that we are ready to be processing its events
  556. hr = pPTEventSink->SetSinkStream(this);
  557. if (FAILED(hr))
  558. {
  559. LOG((MSP_ERROR, "CMSPStream::RegisterPluggableTerminalEventSink "
  560. "event sink refused to accept sink stream. hr = %lx", hr));
  561. delete pPTEventSink;
  562. return hr;
  563. }
  564. // Get ITPluggableTerminalEventSink interface from the sink
  565. hr = pPTEventSink->QueryInterface(IID_ITPluggableTerminalEventSink, (void**)&m_pPTEventSink);
  566. if( FAILED(hr) )
  567. {
  568. LOG((MSP_ERROR, "CMSPStream::RegisterPluggableTerminalEventSink "
  569. "QI for ITPluggableTerminalEventSink failed, returns E_UNEXPECTED"));
  570. //
  571. // ok, the sink is no good. get rid of it.
  572. //
  573. pPTEventSink->SetSinkStream(NULL);
  574. delete pPTEventSink;
  575. pPTEventSink = NULL;
  576. //
  577. // sink does not expose IID_ITPluggableTerminalEventSink interface?
  578. // something is seriously wrong
  579. //
  580. return E_UNEXPECTED;
  581. }
  582. }
  583. // Get the ITDTEventHandler interface
  584. ITPluggableTerminalEventSinkRegistration* pEventRegistration = NULL;
  585. hr = pTerminal->QueryInterface( IID_ITPluggableTerminalEventSinkRegistration,
  586. (void**)&pEventRegistration
  587. );
  588. if( FAILED(hr) )
  589. {
  590. // The dynamic terminal doesn't implement ITPluggableTerminalEventSinkRegistration
  591. // This is bad! We cannot use the new event stuff
  592. LOG((MSP_ERROR, "CMSPStream::RegisterPluggableTerminalEventSink "
  593. "QI for ITPluggableTerminalEventSinkregistration failed, returns S_FALSE"));
  594. //
  595. // no need to keep the sink
  596. //
  597. ReleaseSink();
  598. return S_FALSE;
  599. }
  600. // pass the sink to the terminal
  601. hr = pEventRegistration->RegisterSink(
  602. m_pPTEventSink
  603. );
  604. // Clean up, anyway
  605. pEventRegistration->Release();
  606. if( FAILED(hr) )
  607. {
  608. LOG((MSP_ERROR, "CMSPStream::RegisterPluggableTerminalEventSink "
  609. "RegisterSink failed, returns E_FAIL"));
  610. //
  611. // no need to keep the sink
  612. //
  613. ReleaseSink();
  614. return E_FAIL;
  615. }
  616. LOG((MSP_TRACE, "CMSPStream::RegisterPluggableTerminalEventSink - exit S_OK"));
  617. return S_OK;
  618. }
  619. /*++
  620. UnregisterPluggableTerminalEventSink
  621. Parameters:
  622. The terminal interface
  623. Description;
  624. Is called by UnselectTerminal if is a dynamic terminal
  625. --*/
  626. HRESULT CMSPStream::UnregisterPluggableTerminalEventSink(
  627. IN ITTerminal* pTerminal
  628. )
  629. {
  630. LOG((MSP_TRACE, "CMSPStream::UnregisterPluggableTerminalEventSink - enter"));
  631. //
  632. // Validates arguments
  633. //
  634. if( IsBadReadPtr( pTerminal, sizeof( ITTerminal) ))
  635. {
  636. LOG((MSP_ERROR, "CMSPStream::UnregisterPluggableTerminalEventSink "
  637. "pTerminal invalid, returns E_POINTER"));
  638. return E_POINTER;
  639. }
  640. //
  641. // Get the type of the terminal
  642. //
  643. TERMINAL_TYPE nTerminalType;
  644. HRESULT hr = E_FAIL;
  645. hr = pTerminal->get_TerminalType( &nTerminalType );
  646. if( FAILED(hr) )
  647. {
  648. LOG((MSP_ERROR, "CMSPStream::UnregisterPluggableTerminalEventSink "
  649. "get_TerminalType failed, exit E_UNEXPECTED"));
  650. return E_UNEXPECTED;
  651. }
  652. //
  653. // The terminal should be a dynamic terminal
  654. //
  655. if( TT_DYNAMIC != nTerminalType)
  656. {
  657. LOG((MSP_ERROR, "CMSPStream::UnregisterPluggableTerminalEventSink "
  658. "terminal is not dynamic, exit E_INVALIDARG"));
  659. return E_INVALIDARG;
  660. }
  661. CLock lock(m_lock);
  662. //
  663. // Have we an EventSink object
  664. //
  665. if(NULL == m_pPTEventSink)
  666. {
  667. LOG((MSP_TRACE, "CMSPStream::UnregisterPluggableTerminalEventSink - "
  668. "No EventSink - exit S_OK"));
  669. return S_OK;
  670. }
  671. //
  672. // Get the ITPluggableTemrinalEventSinkRegistration interface
  673. //
  674. ITPluggableTerminalEventSinkRegistration* pEventRegistration = NULL;
  675. hr = pTerminal->QueryInterface( IID_ITPluggableTerminalEventSinkRegistration,
  676. (void**)&pEventRegistration
  677. );
  678. if( FAILED(hr) )
  679. {
  680. //
  681. // The pluggable terminal doesn't implement ITPluggableTerminalEventSinkRegistration
  682. // This is bad!
  683. LOG((MSP_ERROR, "CMSPStream::UnregisterPluggableTerminalEventSink "
  684. "QI for ITPluggableTerminalEventSinkRegistration failed, returns E_NOTIMPL"));
  685. return E_NOTIMPL;
  686. }
  687. hr = pEventRegistration->UnregisterSink( );
  688. //
  689. // Clean up, anyway
  690. //
  691. pEventRegistration->Release();
  692. if( FAILED(hr) )
  693. {
  694. LOG((MSP_ERROR, "CMSPStream::UnregisterPluggableTerminalEventSink "
  695. "UnregisterSink failed, returns E_FAIL"));
  696. return E_FAIL;
  697. }
  698. //
  699. // no longer need this sink
  700. //
  701. ReleaseSink();
  702. LOG((MSP_TRACE, "CMSPStream::UnregisterPluggableTerminalEventSink - exit S_OK"));
  703. return S_OK;
  704. }
  705. //////////////////////////////////////////////////////////////////////////////
  706. //
  707. // CMSPStream::HandleSinkEvent
  708. //
  709. //
  710. // CPTEventSink calls this method when it has an event for us to process
  711. // HandleSinkEvent delegates event processing to the call, if we have one
  712. //
  713. //////////////////////////////////////////////////////////////////////////////
  714. HRESULT CMSPStream::HandleSinkEvent(MSPEVENTITEM *pEventItem)
  715. {
  716. LOG((MSP_TRACE, "CMSPStream::HandleSinkEvent - enter"));
  717. HRESULT hr = TAPI_E_CALLUNAVAIL;
  718. CLock lock(m_lock);
  719. if (NULL != m_pMSPCall)
  720. {
  721. //
  722. // we have a call. ask it to process the event
  723. //
  724. hr = m_pMSPCall->HandleStreamEvent(pEventItem);
  725. }
  726. else
  727. {
  728. LOG((MSP_WARN,
  729. "CMSPStream::HandleSinkEvent - there is no call to pass event to"));
  730. }
  731. LOG((MSP_(hr), "CMSPStream::HandleSinkEvent - exit hr = %lx", hr));
  732. return hr;
  733. }
  734. //////////////////////////////////////////////////////////////////////////////
  735. //
  736. // CMSPStream::ReleaseSink
  737. //
  738. //
  739. // this is a helper function that lets go of sink when it no longer needed
  740. //
  741. //////////////////////////////////////////////////////////////////////////////
  742. HRESULT CMSPStream::ReleaseSink()
  743. {
  744. LOG((MSP_TRACE, "CMSPStream::ReleaseSink - enter"));
  745. HRESULT hr = S_OK;
  746. CLock lock(m_lock);
  747. //
  748. // if sink is present, let it know that we will no longer be available to
  749. // process its events and release it
  750. //
  751. if( m_pPTEventSink)
  752. {
  753. CPTEventSink *pSinkObject = static_cast<CPTEventSink *>(m_pPTEventSink);
  754. HRESULT hr = pSinkObject->SetSinkStream(NULL);
  755. if (FAILED(hr))
  756. {
  757. LOG((MSP_ERROR,
  758. "CMSPStream::ReleaseSink - pSinkObject->SetSinkStream failed. hr - %lx",
  759. hr));
  760. }
  761. m_pPTEventSink->Release();
  762. m_pPTEventSink = NULL;
  763. }
  764. LOG((MSP_(hr), "CMSPStream::ReleaseSink - exit. hr - %lx", hr));
  765. return hr;
  766. }
  767. //////////////////////////////////////////////////////////////////////////////
  768. //
  769. // CMSPStream::InternalAddRef
  770. //
  771. //
  772. // this is a helper function that lets go of sink when it no longer needed
  773. //
  774. //////////////////////////////////////////////////////////////////////////////
  775. ULONG CMSPStream::InternalAddRef()
  776. {
  777. LOG((MSP_TRACE, "CMSPStream::InternalAddRef - enter"));
  778. m_lockRefCount.Lock();
  779. //
  780. // if the refcount is zero, return 1. this is the indication that the
  781. // addref was called while the object is in its finalrelease or entering
  782. // destructor. Note that the only time this could happen is when event sink
  783. // attempts to send an event and addrefs the stream object after the stream
  784. // objects received its last Release() but before the stream object told
  785. // the sink to stop using it (which takes place in stream's destructor).
  786. //
  787. // we also need to be able to tell if refcount was 0 because it's a new
  788. // object or if the addref was called on an object whose refcount became
  789. // zero because of a release.
  790. //
  791. if ( !m_bFirstAddRef && (0 == m_lMyPersonalRefcount) )
  792. {
  793. //
  794. // the caller (event sink logic) should detect this condition (by the
  795. // return value of 1) and not expect that the stream is going to
  796. // continue to be valid.
  797. //
  798. LOG((MSP_WARN, "CMSPStream::InternalAddRef - current refcount is zero... finalrelease/destructor is probably in progress"));
  799. m_lockRefCount.Unlock();
  800. return 1;
  801. }
  802. //
  803. // we have made a transition from non-zero refcount to zero. set the
  804. // flag, so that future addrefs know to return 1 in ths case when refcount
  805. // is 0
  806. //
  807. m_bFirstAddRef = FALSE;
  808. //
  809. // since we are inside a lock, no need to use interlocked api
  810. //
  811. long lNewRefcountValue = (++m_lMyPersonalRefcount);
  812. m_lockRefCount.Unlock();
  813. LOG((MSP_TRACE, "CMSPStream::InternalAddRef - finish. %ld", lNewRefcountValue));
  814. return lNewRefcountValue;
  815. }
  816. ULONG CMSPStream::InternalRelease()
  817. {
  818. LOG((MSP_TRACE, "CMSPStream::InternalRelease - enter"));
  819. m_lockRefCount.Lock();
  820. // try to catch over-releases
  821. _ASSERTE(m_lMyPersonalRefcount > 0);
  822. // we are inside a lock, no need to use interlocked api
  823. long lNewRefcount = (--m_lMyPersonalRefcount);
  824. m_lockRefCount.Unlock();
  825. LOG((MSP_TRACE, "CMSPStream::InternalRelease - finish. %ld", lNewRefcount));
  826. return lNewRefcount;
  827. }
  828. // eof