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.

5112 lines
124 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. mspaddr.cpp
  5. Abstract:
  6. This module contains implementation of CMSPAddress.
  7. --*/
  8. #include "precomp.h"
  9. #pragma hdrstop
  10. ///////////////////////////////////////////////////////////////////////////////
  11. //
  12. // AllocateEventItem and FreeEventItem are MSPEVENTITEM allocation routines.
  13. // they are be used to allocate and deallocate MSPEVENTITEM structures
  14. //
  15. ///////////////////////////////////////////////////////////////////////////////
  16. //////////////////////////////////////////////////////////////////////////////
  17. //
  18. // AllocateEventItem
  19. //
  20. // allocate an MSPEVENTITEM. Since the structure is of variable size, the
  21. // number of extra bytes to be allocated (in addition to the size of
  22. // MSPEVENTITEM) is optionally passed as the function's argument
  23. //
  24. // the function returns a pointer to the newly created structure or NULL in
  25. // the case of failure. the caller can then call GetLastError to get more
  26. // information on the failure
  27. //
  28. MSPEVENTITEM *AllocateEventItem(SIZE_T nExtraBytes)
  29. {
  30. LOG((MSP_TRACE, "AllocateEventItem - enter, extra bytes = 0x%p", nExtraBytes));
  31. //
  32. // if the caller passes us too big a number, fail.
  33. //
  34. if ( ( MAXULONG_PTR - sizeof(MSPEVENTITEM) ) < nExtraBytes )
  35. {
  36. SetLastError(ERROR_OUTOFMEMORY);
  37. LOG((MSP_ERROR,
  38. "AllocateEventItem - the caller requested an unreasonably large memory block"));
  39. return NULL;
  40. }
  41. //
  42. // allocate on the process' heap. get the current process' heap handle.
  43. //
  44. HANDLE hHeapHandle = GetProcessHeap();
  45. if (NULL == hHeapHandle)
  46. {
  47. //
  48. // failed to get process's heap. nothing much we can do here.
  49. // this will cause a leak.
  50. //
  51. LOG((MSP_ERROR,
  52. "AllocateEventItem - failed to get current process heap. LastError [%ld]",
  53. GetLastError()));
  54. return NULL;
  55. }
  56. //
  57. // calculate the number of bytes to allocate
  58. //
  59. SIZE_T nTotalAllocationSize = sizeof(MSPEVENTITEM) + nExtraBytes;
  60. //
  61. // attempt to allocate memory and return result of the allocation
  62. //
  63. MSPEVENTITEM *pMspEventItem =
  64. (MSPEVENTITEM *)HeapAlloc(hHeapHandle, 0, nTotalAllocationSize);
  65. if (NULL == pMspEventItem)
  66. {
  67. LOG((MSP_ERROR,
  68. "AllocateEventItem - failed to allocate [0x%p] bytes. Heap Handle [%p] LastError [%ld]",
  69. nTotalAllocationSize, hHeapHandle, GetLastError()));
  70. }
  71. else
  72. {
  73. LOG((MSP_TRACE, "AllocateEventItem - exit. pMspEventItem = [%p]", pMspEventItem));
  74. }
  75. return pMspEventItem;
  76. }
  77. //////////////////////////////////////////////////////////////////////////////
  78. //
  79. // FreeEventItem
  80. //
  81. // deallocate the MSPEVENTITEM passed as an argument. The memory must have
  82. // been previously allocated by AllocateEventItem.
  83. //
  84. // the function eturns FALSE in case of failure. The caller can use
  85. // GetLastError to get a more specific error code.
  86. //
  87. BOOL FreeEventItem(MSPEVENTITEM *pEventItemToBeFreed)
  88. {
  89. LOG((MSP_TRACE, "FreeEventItem - enter. pEventItemToBeFreed = [%p]",
  90. pEventItemToBeFreed));
  91. //
  92. // always allow freeing NULL
  93. //
  94. if (NULL == pEventItemToBeFreed)
  95. {
  96. LOG((MSP_TRACE, "FreeEventItem - finish. NULL -- nothing to do"));
  97. return TRUE;
  98. }
  99. //
  100. // the event item should have been allocated on the process' heap.
  101. // get the current process' heap hadle.
  102. //
  103. HANDLE hHeapHandle = GetProcessHeap();
  104. if (NULL == hHeapHandle)
  105. {
  106. //
  107. // failed to get process's heap. nothing much we can do here.
  108. // this will cause a leak.
  109. //
  110. LOG((MSP_ERROR,
  111. "FreeEventItem - failed to get current process heap. LastError = %ld",
  112. GetLastError()));
  113. return FALSE;
  114. }
  115. //
  116. // attempt to free memory and return result of the operation
  117. //
  118. BOOL bFreeSuccess = HeapFree( hHeapHandle, 0, pEventItemToBeFreed );
  119. if (bFreeSuccess)
  120. {
  121. LOG((MSP_TRACE, "FreeEventItem - exit."));
  122. }
  123. else
  124. {
  125. LOG((MSP_ERROR,
  126. "FreeEventItem - failed to free. Heap Handle [%p] LastError = %ld",
  127. hHeapHandle, GetLastError()));
  128. }
  129. return bFreeSuccess;
  130. }
  131. //////////////////////////////////////////////////////////////////////////////
  132. HRESULT CPlugTerminalClassInfo::FinalConstruct(void)
  133. {
  134. LOG((MSP_TRACE, "CPlugTerminalClassInfo::FinalConstruct - enter"));
  135. HRESULT hr = CoCreateFreeThreadedMarshaler( GetControllingUnknown(),
  136. & m_pFTM );
  137. if ( FAILED(hr) )
  138. {
  139. LOG((MSP_ERROR, "CPlugTerminalClassInfo::FinalConstruct - "
  140. "create FTM returned 0x%08x; exit", hr));
  141. return hr;
  142. }
  143. LOG((MSP_TRACE, "CPlugTerminalClassInfo::FinalConstruct - exit S_OK"));
  144. return S_OK;
  145. }
  146. //////////////////////////////////////////////////////////////////////////////
  147. STDMETHODIMP CPlugTerminalClassInfo::get_Name(
  148. /*[out, retval]*/ BSTR* pName
  149. )
  150. {
  151. //
  152. // Critical section
  153. //
  154. CLock lock(m_CritSect);
  155. LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_Name - enter"));
  156. //
  157. // Validates argument
  158. //
  159. if( MSPB_IsBadWritePtr( pName, sizeof(BSTR)) )
  160. {
  161. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Name exit -"
  162. "pName invalid, returns E_POINTER"));
  163. return E_POINTER;
  164. }
  165. //
  166. // Validates the name
  167. //
  168. if( IsBadStringPtr( m_bstrName, (UINT)-1) )
  169. {
  170. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Name exit -"
  171. "m_bstrName invalid, returns E_UNEXPECTED"));
  172. return E_UNEXPECTED;
  173. }
  174. //
  175. // Return the name
  176. //
  177. *pName = SysAllocString( m_bstrName );
  178. //
  179. // Validates SysAllocString
  180. //
  181. if( *pName == NULL )
  182. {
  183. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Name exit -"
  184. "SysAllocString failed, returns E_OUTOFMEMORY"));
  185. return E_OUTOFMEMORY;
  186. }
  187. LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_Name - exit"));
  188. return S_OK;
  189. }
  190. //////////////////////////////////////////////////////////////////////////////
  191. STDMETHODIMP CPlugTerminalClassInfo::put_Name(
  192. /*[in]*/ BSTR bstrName
  193. )
  194. {
  195. //
  196. // Critical section
  197. //
  198. CLock lock(m_CritSect);
  199. LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_Name - enter"));
  200. //
  201. // Validates argument
  202. //
  203. if(IsBadStringPtr( bstrName, (UINT)-1) )
  204. {
  205. LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_Name exit -"
  206. "bstrName invalid, returns E_POINTER"));
  207. return E_POINTER;
  208. }
  209. //
  210. // Clean-up the old name
  211. //
  212. if(!IsBadStringPtr( m_bstrName, (UINT)-1) )
  213. {
  214. SysFreeString( m_bstrName );
  215. m_bstrName = NULL;
  216. }
  217. //
  218. // Set the new name
  219. //
  220. m_bstrName = SysAllocString( bstrName );
  221. //
  222. // Validates SysAllocString
  223. //
  224. if( NULL == m_bstrName )
  225. {
  226. LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_Name exit -"
  227. "SysAllocString failed, returns E_OUTOFMEMORY"));
  228. return E_OUTOFMEMORY;
  229. }
  230. LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_Name - exit"));
  231. return S_OK;
  232. }
  233. //////////////////////////////////////////////////////////////////////////////
  234. STDMETHODIMP CPlugTerminalClassInfo::get_Company(
  235. /*[out, retval]*/ BSTR* pCompany
  236. )
  237. {
  238. //
  239. // Critical section
  240. //
  241. CLock lock(m_CritSect);
  242. LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_Company - enter"));
  243. //
  244. // Validates argument
  245. //
  246. if( MSPB_IsBadWritePtr( pCompany, sizeof(BSTR)) )
  247. {
  248. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Company exit -"
  249. "pCompany invalid, returns E_POINTER"));
  250. return E_POINTER;
  251. }
  252. //
  253. // Validates the name
  254. //
  255. if( IsBadStringPtr( m_bstrCompany, (UINT)-1) )
  256. {
  257. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Company exit -"
  258. "m_bstrName invalid, returns E_UNEXPECTED"));
  259. return E_UNEXPECTED;
  260. }
  261. //
  262. // Return the name
  263. //
  264. *pCompany = SysAllocString( m_bstrCompany );
  265. //
  266. // Validates SysAllocString
  267. //
  268. if( *pCompany == NULL )
  269. {
  270. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Company exit -"
  271. "SysAllocString failed, returns E_OUTOFMEMORY"));
  272. return E_OUTOFMEMORY;
  273. }
  274. LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_Company - exit"));
  275. return S_OK;
  276. }
  277. //////////////////////////////////////////////////////////////////////////////
  278. STDMETHODIMP CPlugTerminalClassInfo::put_Company(
  279. /*[in]*/ BSTR bstrCompany
  280. )
  281. {
  282. //
  283. // Critical section
  284. //
  285. CLock lock(m_CritSect);
  286. LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_Company - enter"));
  287. //
  288. // Validates argument
  289. //
  290. if(IsBadStringPtr( bstrCompany, (UINT)-1) )
  291. {
  292. LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_Company exit -"
  293. "bstrCompany invalid, returns E_POINTER"));
  294. return E_POINTER;
  295. }
  296. //
  297. // Clean-up the old name
  298. //
  299. if(!IsBadStringPtr( m_bstrCompany, (UINT)-1) )
  300. {
  301. SysFreeString( m_bstrCompany );
  302. m_bstrCompany = NULL;
  303. }
  304. //
  305. // Set the new name
  306. //
  307. m_bstrCompany = SysAllocString( bstrCompany );
  308. //
  309. // Validates SysAllocString
  310. //
  311. if( NULL == m_bstrCompany )
  312. {
  313. LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_Company exit -"
  314. "SysAllocString failed, returns E_OUTOFMEMORY"));
  315. return E_OUTOFMEMORY;
  316. }
  317. LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_Company - exit"));
  318. return S_OK;
  319. }
  320. //////////////////////////////////////////////////////////////////////////////
  321. STDMETHODIMP CPlugTerminalClassInfo::get_Version(
  322. /*[out, retval]*/ BSTR* pVersion
  323. )
  324. {
  325. //
  326. // Critical section
  327. //
  328. CLock lock(m_CritSect);
  329. LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_Version - enter"));
  330. //
  331. // Validates argument
  332. //
  333. if( MSPB_IsBadWritePtr( pVersion, sizeof(BSTR)) )
  334. {
  335. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Version exit -"
  336. "pVersion invalid, returns E_POINTER"));
  337. return E_POINTER;
  338. }
  339. //
  340. // Validates the name
  341. //
  342. if( IsBadStringPtr( m_bstrVersion, (UINT)-1) )
  343. {
  344. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Version exit -"
  345. "m_bstrName invalid, returns E_UNEXPECTED"));
  346. return E_UNEXPECTED;
  347. }
  348. //
  349. // Return the name
  350. //
  351. *pVersion = SysAllocString( m_bstrVersion );
  352. //
  353. // Validates SysAllocString
  354. //
  355. if( *pVersion == NULL )
  356. {
  357. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Version exit -"
  358. "SysAllocString failed, returns E_OUTOFMEMORY"));
  359. return E_OUTOFMEMORY;
  360. }
  361. LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_Version - exit"));
  362. return S_OK;
  363. }
  364. //////////////////////////////////////////////////////////////////////////////
  365. STDMETHODIMP CPlugTerminalClassInfo::put_Version(
  366. /*[in]*/ BSTR bstrVersion
  367. )
  368. {
  369. //
  370. // Critical section
  371. //
  372. CLock lock(m_CritSect);
  373. LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_Version - enter"));
  374. //
  375. // Validates argument
  376. //
  377. if(IsBadStringPtr( bstrVersion, (UINT)-1) )
  378. {
  379. LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_Version exit -"
  380. "bstrVersion invalid, returns E_POINTER"));
  381. return E_POINTER;
  382. }
  383. //
  384. // Clean-up the old name
  385. //
  386. if(!IsBadStringPtr( m_bstrVersion, (UINT)-1) )
  387. {
  388. SysFreeString( m_bstrVersion );
  389. m_bstrVersion = NULL;
  390. }
  391. //
  392. // Set the new name
  393. //
  394. m_bstrVersion = SysAllocString( bstrVersion );
  395. //
  396. // Validates SysAllocString
  397. //
  398. if( NULL == m_bstrVersion )
  399. {
  400. LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_Version exit -"
  401. "SysAllocString failed, returns E_OUTOFMEMORY"));
  402. return E_OUTOFMEMORY;
  403. }
  404. LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_Version - exit"));
  405. return S_OK;
  406. }
  407. //////////////////////////////////////////////////////////////////////////////
  408. STDMETHODIMP CPlugTerminalClassInfo::get_TerminalClass(
  409. /*[out, retval]*/ BSTR* pTerminalClass
  410. )
  411. {
  412. //
  413. // Critical section
  414. //
  415. CLock lock(m_CritSect);
  416. LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_TerminalClass - enter"));
  417. //
  418. // Validates argument
  419. //
  420. if( MSPB_IsBadWritePtr( pTerminalClass, sizeof(BSTR)) )
  421. {
  422. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_TerminalClass exit -"
  423. "pVersion invalid, returns E_POINTER"));
  424. return E_POINTER;
  425. }
  426. //
  427. // Validates the name
  428. //
  429. if( IsBadStringPtr( m_bstrTerminalClass, (UINT)-1) )
  430. {
  431. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_TerminalClass exit -"
  432. "m_bstrName invalid, returns E_UNEXPECTED"));
  433. return E_UNEXPECTED;
  434. }
  435. //
  436. // Return the name
  437. //
  438. *pTerminalClass = SysAllocString( m_bstrTerminalClass );
  439. //
  440. // Validates SysAllocString
  441. //
  442. if( *pTerminalClass == NULL )
  443. {
  444. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_TerminalClass exit -"
  445. "SysAllocString failed, returns E_OUTOFMEMORY"));
  446. return E_OUTOFMEMORY;
  447. }
  448. LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_TerminalClass - exit"));
  449. return S_OK;
  450. }
  451. //////////////////////////////////////////////////////////////////////////////
  452. STDMETHODIMP CPlugTerminalClassInfo::put_TerminalClass(
  453. /*[in]*/ BSTR bstrTerminalClass
  454. )
  455. {
  456. //
  457. // Critical section
  458. //
  459. CLock lock(m_CritSect);
  460. LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_TerminalClass - enter"));
  461. //
  462. // Validates argument
  463. //
  464. if(IsBadStringPtr( bstrTerminalClass, (UINT)-1) )
  465. {
  466. LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_TerminalClass exit -"
  467. "bstrTerminalClass invalid, returns E_POINTER"));
  468. return E_POINTER;
  469. }
  470. //
  471. // Is a real CLSID?
  472. //
  473. CLSID clsid;
  474. HRESULT hr = CLSIDFromString(bstrTerminalClass, &clsid);
  475. if( FAILED(hr) )
  476. {
  477. LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_TerminalClass exit -"
  478. "bstrTerminalClass is not a CLSID, returns E_INVALIDARG"));
  479. return E_INVALIDARG;
  480. }
  481. //
  482. // Clean-up the old name
  483. //
  484. if(!IsBadStringPtr( m_bstrTerminalClass, (UINT)-1) )
  485. {
  486. SysFreeString( m_bstrTerminalClass );
  487. m_bstrTerminalClass = NULL;
  488. }
  489. //
  490. // Set the new name
  491. //
  492. m_bstrTerminalClass = SysAllocString( bstrTerminalClass );
  493. //
  494. // Validates SysAllocString
  495. //
  496. if( NULL == m_bstrTerminalClass )
  497. {
  498. LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_TerminalClass exit -"
  499. "SysAllocString failed, returns E_OUTOFMEMORY"));
  500. return E_OUTOFMEMORY;
  501. }
  502. LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_TerminalClass - exit"));
  503. return S_OK;
  504. }
  505. //////////////////////////////////////////////////////////////////////////////
  506. STDMETHODIMP CPlugTerminalClassInfo::get_CLSID(
  507. /*[out, retval]*/ BSTR* pCLSID
  508. )
  509. {
  510. //
  511. // Critical section
  512. //
  513. CLock lock(m_CritSect);
  514. LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_CLSID - enter"));
  515. //
  516. // Validates argument
  517. //
  518. if( MSPB_IsBadWritePtr( pCLSID, sizeof(BSTR)) )
  519. {
  520. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_CLSID exit -"
  521. "pVersion invalid, returns E_POINTER"));
  522. return E_POINTER;
  523. }
  524. //
  525. // Validates the name
  526. //
  527. if( IsBadStringPtr( m_bstrCLSID, (UINT)-1) )
  528. {
  529. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_CLSID exit -"
  530. "m_bstrName invalid, returns E_UNEXPECTED"));
  531. return E_UNEXPECTED;
  532. }
  533. //
  534. // Return the name
  535. //
  536. *pCLSID = SysAllocString( m_bstrCLSID );
  537. //
  538. // Validates SysAllocString
  539. //
  540. if( *pCLSID == NULL )
  541. {
  542. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_CLSID exit -"
  543. "SysAllocString failed, returns E_OUTOFMEMORY"));
  544. return E_OUTOFMEMORY;
  545. }
  546. LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_CLSID - exit"));
  547. return S_OK;
  548. }
  549. //////////////////////////////////////////////////////////////////////////////
  550. STDMETHODIMP CPlugTerminalClassInfo::put_CLSID(
  551. /*[in]*/ BSTR bstrCLSID
  552. )
  553. {
  554. //
  555. // Critical section
  556. //
  557. CLock lock(m_CritSect);
  558. LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_CLSID - enter"));
  559. //
  560. // Validates argument
  561. //
  562. if(IsBadStringPtr( bstrCLSID, (UINT)-1) )
  563. {
  564. LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_CLSID exit -"
  565. "bstrCLSID invalid, returns E_POINTER"));
  566. return E_POINTER;
  567. }
  568. //
  569. // Is a real CLSID?
  570. //
  571. CLSID clsid;
  572. HRESULT hr = CLSIDFromString(bstrCLSID, &clsid);
  573. if( FAILED(hr) )
  574. {
  575. LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_CLSID exit -"
  576. "bstrCLSID is not a CLSID, returns E_INVALIDARG"));
  577. return E_INVALIDARG;
  578. }
  579. //
  580. // Clean-up the old name
  581. //
  582. if(!IsBadStringPtr( m_bstrCLSID, (UINT)-1) )
  583. {
  584. SysFreeString( m_bstrCLSID );
  585. m_bstrCLSID = NULL;
  586. }
  587. //
  588. // Set the new name
  589. //
  590. m_bstrCLSID = SysAllocString( bstrCLSID );
  591. //
  592. // Validates SysAllocString
  593. //
  594. if( NULL == m_bstrCLSID )
  595. {
  596. LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_CLSID exit -"
  597. "SysAllocString failed, returns E_OUTOFMEMORY"));
  598. return E_OUTOFMEMORY;
  599. }
  600. LOG((MSP_TRACE, "CPlugTerminalClassInfo::put_CLSID - exit"));
  601. return S_OK;
  602. }
  603. //////////////////////////////////////////////////////////////////////////////
  604. STDMETHODIMP CPlugTerminalClassInfo::get_Direction(
  605. /*[out, retval]*/ TERMINAL_DIRECTION* pDirection
  606. )
  607. {
  608. //
  609. // Critical section
  610. //
  611. CLock lock(m_CritSect);
  612. LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_Direction - enter"));
  613. //
  614. // Validates argument
  615. //
  616. if( MSPB_IsBadWritePtr( pDirection, sizeof(long)) )
  617. {
  618. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_Direction exit -"
  619. "pDirection invalid, returns E_POINTER"));
  620. return E_POINTER;
  621. }
  622. //
  623. // Return the name
  624. //
  625. *pDirection = m_Direction;
  626. LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_Direction - exit"));
  627. return S_OK;
  628. }
  629. //////////////////////////////////////////////////////////////////////////////
  630. STDMETHODIMP CPlugTerminalClassInfo::put_Direction(
  631. /*[in]*/ TERMINAL_DIRECTION nDirection
  632. )
  633. {
  634. //
  635. // Critical section
  636. //
  637. CLock lock(m_CritSect);
  638. LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::put_Direction - enter"));
  639. //
  640. // Set the new name
  641. //
  642. m_Direction = nDirection;
  643. LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::put_Direction - exit"));
  644. return S_OK;
  645. }
  646. //////////////////////////////////////////////////////////////////////////////
  647. STDMETHODIMP CPlugTerminalClassInfo::get_MediaTypes(
  648. /*[out, retval]*/ long* pMediaTypes
  649. )
  650. {
  651. //
  652. // Critical section
  653. //
  654. CLock lock(m_CritSect);
  655. LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_MediaTypes - enter"));
  656. //
  657. // Validates argument
  658. //
  659. if( MSPB_IsBadWritePtr( pMediaTypes, sizeof(long)) )
  660. {
  661. LOG((MSP_ERROR, "CPlugTerminalClassInfo::get_MediaTypes exit -"
  662. "pMediaTypes invalid, returns E_POINTER"));
  663. return E_POINTER;
  664. }
  665. //
  666. // Return the name
  667. //
  668. *pMediaTypes = m_lMediaType;
  669. LOG((MSP_TRACE, "CPlugTerminalClassInfo::get_MediaTypes - exit"));
  670. return S_OK;
  671. }
  672. //////////////////////////////////////////////////////////////////////////////
  673. STDMETHODIMP CPlugTerminalClassInfo::put_MediaTypes(
  674. /*[in]*/ long nMediaTypes
  675. )
  676. {
  677. //
  678. // Critical section
  679. //
  680. CLock lock(m_CritSect);
  681. LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::put_MediaTypes - enter"));
  682. //
  683. // Set the new name
  684. //
  685. m_lMediaType = nMediaTypes;
  686. LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::put_MediaTypes - exit"));
  687. return S_OK;
  688. }
  689. //////////////////////////////////////////////////////////////////////////////
  690. HRESULT CPlugTerminalSuperclassInfo::FinalConstruct(void)
  691. {
  692. LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::FinalConstruct - enter"));
  693. HRESULT hr = CoCreateFreeThreadedMarshaler( GetControllingUnknown(),
  694. & m_pFTM );
  695. if ( FAILED(hr) )
  696. {
  697. LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::FinalConstruct - "
  698. "create FTM returned 0x%08x; exit", hr));
  699. return hr;
  700. }
  701. LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::FinalConstruct - exit S_OK"));
  702. return S_OK;
  703. }
  704. //////////////////////////////////////////////////////////////////////////////
  705. STDMETHODIMP CPlugTerminalSuperclassInfo::get_Name(
  706. /*[out, retval]*/ BSTR* pName
  707. )
  708. {
  709. //
  710. // Critical section
  711. //
  712. CLock lock(m_CritSect);
  713. LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::get_Name - enter"));
  714. //
  715. // Validates argument
  716. //
  717. if( MSPB_IsBadWritePtr( pName, sizeof(BSTR)) )
  718. {
  719. LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::get_Name exit -"
  720. "pVersion invalid, returns E_POINTER"));
  721. return E_POINTER;
  722. }
  723. //
  724. // Validates the name
  725. //
  726. if( IsBadStringPtr( m_bstrName, (UINT)-1) )
  727. {
  728. LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::get_Name exit -"
  729. "m_bstrName invalid, returns E_UNEXPECTED"));
  730. return E_UNEXPECTED;
  731. }
  732. //
  733. // Return the name
  734. //
  735. *pName = SysAllocString( m_bstrName );
  736. //
  737. // Validates SysAllocString
  738. //
  739. if( *pName == NULL )
  740. {
  741. LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::get_Name exit -"
  742. "SysAllocString failed, returns E_OUTOFMEMORY"));
  743. return E_OUTOFMEMORY;
  744. }
  745. LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::get_Name - exit"));
  746. return S_OK;
  747. }
  748. //////////////////////////////////////////////////////////////////////////////
  749. STDMETHODIMP CPlugTerminalSuperclassInfo::put_Name(
  750. /*[in]*/ BSTR bstrName
  751. )
  752. {
  753. //
  754. // Critical section
  755. //
  756. CLock lock(m_CritSect);
  757. LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::put_Name - enter"));
  758. //
  759. // Validates argument
  760. //
  761. if(IsBadStringPtr( bstrName, (UINT)-1) )
  762. {
  763. LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::put_Name exit -"
  764. "bstrName invalid, returns E_POINTER"));
  765. return E_POINTER;
  766. }
  767. //
  768. // Clean-up the old name
  769. //
  770. if(!IsBadStringPtr( m_bstrName, (UINT)-1) )
  771. {
  772. SysFreeString( m_bstrName );
  773. m_bstrName = NULL;
  774. }
  775. //
  776. // Set the new name
  777. //
  778. m_bstrName = SysAllocString( bstrName );
  779. //
  780. // Validates SysAllocString
  781. //
  782. if( NULL == m_bstrName )
  783. {
  784. LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::put_Name exit -"
  785. "SysAllocString failed, returns E_OUTOFMEMORY"));
  786. return E_OUTOFMEMORY;
  787. }
  788. LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::put_Name - exit"));
  789. return S_OK;
  790. }
  791. //////////////////////////////////////////////////////////////////////////////
  792. STDMETHODIMP CPlugTerminalSuperclassInfo::get_CLSID(
  793. /*[out, retval]*/ BSTR* pCLSID
  794. )
  795. {
  796. //
  797. // Critical section
  798. //
  799. CLock lock(m_CritSect);
  800. LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::get_CLSID - enter"));
  801. //
  802. // Validates argument
  803. //
  804. if( MSPB_IsBadWritePtr( pCLSID, sizeof(BSTR)) )
  805. {
  806. LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::get_CLSID exit -"
  807. "pVersion invalid, returns E_POINTER"));
  808. return E_POINTER;
  809. }
  810. //
  811. // Validates the name
  812. //
  813. if( IsBadStringPtr( m_bstrCLSID, (UINT)-1) )
  814. {
  815. LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::get_CLSID exit -"
  816. "m_bstrName invalid, returns E_UNEXPECTED"));
  817. return E_UNEXPECTED;
  818. }
  819. //
  820. // Return the name
  821. //
  822. *pCLSID = SysAllocString( m_bstrCLSID );
  823. //
  824. // Validates SysAllocString
  825. //
  826. if( *pCLSID == NULL )
  827. {
  828. LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::get_CLSID exit -"
  829. "SysAllocString failed, returns E_OUTOFMEMORY"));
  830. return E_OUTOFMEMORY;
  831. }
  832. LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::get_CLSID - exit"));
  833. return S_OK;
  834. }
  835. //////////////////////////////////////////////////////////////////////////////
  836. STDMETHODIMP CPlugTerminalSuperclassInfo::put_CLSID(
  837. /*[in]*/ BSTR bstrCLSID
  838. )
  839. {
  840. //
  841. // Critical section
  842. //
  843. CLock lock(m_CritSect);
  844. LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::put_CLSID - enter"));
  845. //
  846. // Validates argument
  847. //
  848. if(IsBadStringPtr( bstrCLSID, (UINT)-1) )
  849. {
  850. LOG((MSP_ERROR, "CPlugTerminalClassInfo::put_CLSID exit -"
  851. "bstrCLSID invalid, returns E_POINTER"));
  852. return E_POINTER;
  853. }
  854. //
  855. // Is a real CLSID?
  856. //
  857. CLSID clsid;
  858. HRESULT hr = CLSIDFromString(bstrCLSID, &clsid);
  859. if( FAILED(hr) )
  860. {
  861. LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::put_CLSID exit -"
  862. "bstrCLSID is not a CLSID, returns E_INVALIDARG"));
  863. return E_INVALIDARG;
  864. }
  865. //
  866. // Clean-up the old name
  867. //
  868. if(!IsBadStringPtr( m_bstrCLSID, (UINT)-1) )
  869. {
  870. SysFreeString( m_bstrCLSID );
  871. m_bstrCLSID = NULL;
  872. }
  873. //
  874. // Set the new name
  875. //
  876. m_bstrCLSID = SysAllocString( bstrCLSID );
  877. //
  878. // Validates SysAllocString
  879. //
  880. if( NULL == m_bstrCLSID )
  881. {
  882. LOG((MSP_ERROR, "CPlugTerminalSuperclassInfo::put_CLSID exit -"
  883. "SysAllocString failed, returns E_OUTOFMEMORY"));
  884. return E_OUTOFMEMORY;
  885. }
  886. LOG((MSP_TRACE, "CPlugTerminalSuperclassInfo::put_CLSID - exit"));
  887. return S_OK;
  888. }
  889. //////////////////////////////////////////////////////////////////////////////
  890. //
  891. // Our available static terminal types.
  892. //
  893. const STATIC_TERMINAL_TYPE CMSPAddress::m_saTerminalTypes[] =
  894. {
  895. {
  896. (DWORD) TAPIMEDIATYPE_AUDIO,
  897. &CLSID_CWaveinClassManager,
  898. CAudioCaptureTerminal::CreateTerminal
  899. },
  900. {
  901. (DWORD) TAPIMEDIATYPE_AUDIO,
  902. &CLSID_CWaveOutClassManager,
  903. CAudioRenderTerminal::CreateTerminal
  904. },
  905. {
  906. (DWORD) TAPIMEDIATYPE_VIDEO,
  907. &CLSID_CVidCapClassManager,
  908. CVideoCaptureTerminal::CreateTerminal
  909. }
  910. };
  911. const DWORD CMSPAddress::m_sdwTerminalTypesCount = sizeof(m_saTerminalTypes)
  912. / sizeof (STATIC_TERMINAL_TYPE);
  913. /////////////////////////////////////////////////////////////////////////////
  914. // CMSPAddress
  915. /////////////////////////////////////////////////////////////////////////////
  916. //
  917. // Check to see if the mediatype is non-zero and is in the mask.
  918. // Your MSP can override this if it needs to do atypically complex
  919. // checks on specific combinations of media types (e.g., can never
  920. // have more than one media type on a call, can have video with audio
  921. // but not video alone, etc.). The default implementation accepts any
  922. // nonempty set of media types that is a subset of the set of types
  923. // in the mask.
  924. //
  925. BOOL CMSPAddress::IsValidSetOfMediaTypes(DWORD dwMediaType, DWORD dwMask)
  926. {
  927. return (dwMediaType != 0) && ((dwMediaType & dwMask) == dwMediaType);
  928. }
  929. CMSPAddress::CMSPAddress()
  930. : m_htEvent(NULL),
  931. m_fTerminalsUpToDate(FALSE),
  932. m_pITTerminalManager(NULL)
  933. {
  934. LOG((MSP_TRACE, "CMSPAddress::CMSPAddress[%p] - enter", this));
  935. LOG((MSP_TRACE, "CMSPAddress::CMSPAddress - finished"));
  936. }
  937. CMSPAddress::~CMSPAddress()
  938. {
  939. LOG((MSP_TRACE, "CMSPAddress::~CMSPAddress[%p] - enter", this));
  940. //
  941. // this should have been taken care of in Shutdown,
  942. // but just in case shutdown was never called, do this again, since
  943. // we need to make sure the thread does not have any stale entries in
  944. // its pnp notification list
  945. //
  946. // the call is likely to return error (since the object is likely to have been
  947. // unregisted earlier) -- so ignore return code
  948. //
  949. g_Thread.UnregisterPnpNotification(this);
  950. LOG((MSP_TRACE, "CMSPAddress::~CMSPAddress - finished"));
  951. }
  952. STDMETHODIMP CMSPAddress::Initialize(
  953. IN MSP_HANDLE htEvent
  954. )
  955. /*++
  956. Routine Description:
  957. This method is called by TAPI3 when this MSP is first created. The method
  958. initiailzes data members and creates the terminal manager. It also tells
  959. the global thread object to Start().
  960. Arguments:
  961. htEvent
  962. Event the MSP signals when passing an event structure back to TAPI.
  963. Return Value:
  964. S_OK
  965. E_INVALIDARG
  966. E_OUTOFMEMORY
  967. TAPI_E_REGISTERCALLBACK
  968. --*/
  969. {
  970. LOG((MSP_TRACE,
  971. "MSP address %x initialize entered, htEvent:%x",
  972. this, htEvent));
  973. if ( htEvent == NULL )
  974. {
  975. LOG((MSP_ERROR, " bad handle: htEvent:%x", htEvent));
  976. return E_INVALIDARG;
  977. }
  978. // lock the event related data
  979. m_EventDataLock.Lock();
  980. if (m_htEvent != NULL)
  981. {
  982. m_EventDataLock.Unlock();
  983. LOG((MSP_ERROR, "Initialze called twice."));
  984. return E_UNEXPECTED;
  985. }
  986. // save handles.
  987. m_htEvent = htEvent;
  988. InitializeListHead(&m_EventList);
  989. HRESULT hr;
  990. // release the lock on the event related data
  991. m_EventDataLock.Unlock();
  992. // lock the terminal related data. This is a auto lock that will unlock
  993. // when the function returns.
  994. CLock lock(m_TerminalDataLock);
  995. // Create the terminal manager.
  996. hr = CoCreateInstance(
  997. CLSID_TerminalManager,
  998. NULL,
  999. CLSCTX_INPROC_SERVER,
  1000. IID_ITTerminalManager,
  1001. (void **) &m_pITTerminalManager
  1002. );
  1003. if (FAILED(hr))
  1004. {
  1005. LOG((MSP_ERROR,
  1006. "Creating terminal manager failed. return: %x", hr));
  1007. return hr;
  1008. }
  1009. hr = g_Thread.Start();
  1010. if (FAILED(hr))
  1011. {
  1012. LOG((MSP_ERROR,
  1013. "Creating thread failed. return: %x", hr));
  1014. return hr;
  1015. }
  1016. hr = g_Thread.RegisterPnpNotification(this);
  1017. if (FAILED(hr))
  1018. {
  1019. LOG((MSP_ERROR,
  1020. "Unable to register for PNP notification. return: %x", hr));
  1021. }
  1022. LOG((MSP_TRACE,
  1023. "MSP address %x initialize exited S_OK, htEvent:%x",
  1024. this, htEvent));
  1025. return S_OK;
  1026. }
  1027. STDMETHODIMP CMSPAddress::Shutdown ()
  1028. /*++
  1029. Routine Description:
  1030. This method is called by TAPI3 when this address in not in use any more.
  1031. This function releases the terminals and releases the terminal manager.
  1032. It releases all unprocessed events, and also stops the worker thread.
  1033. When this functions is called, no call should be alive. However, bugs in
  1034. the app may keep calls or terminals around. Currently this function
  1035. does not attempt to solve this problem. The calls will have their own
  1036. refcounts on the terminals, so it shouldn't fail anyway.
  1037. Arguments:
  1038. None.
  1039. Return Value:
  1040. S_OK
  1041. --*/
  1042. {
  1043. LOG((MSP_TRACE, "CMSPAddress::Shutdown - "
  1044. "MSP address %x is shutting down", this));
  1045. HRESULT hr;
  1046. //
  1047. // Unregister for PNP notification
  1048. //
  1049. hr = g_Thread.UnregisterPnpNotification(this);
  1050. if (FAILED(hr))
  1051. {
  1052. LOG((MSP_ERROR,
  1053. "Unable to unregister for PNP notification. return: %x", hr));
  1054. }
  1055. //
  1056. // Tell the worker thread to stop.
  1057. //
  1058. g_Thread.Stop();
  1059. LOG((MSP_INFO, "CMSPAddress::Shutdown - thread has stopped"));
  1060. // acquire the lock on the terminal data because we are writing to it.
  1061. m_TerminalDataLock.Lock();
  1062. // Release the terminal manager.
  1063. if (m_pITTerminalManager != NULL)
  1064. {
  1065. m_pITTerminalManager->Release();
  1066. m_pITTerminalManager = NULL;
  1067. }
  1068. // release all the terminals.
  1069. for (int i = 0; i < m_Terminals.GetSize(); i ++)
  1070. {
  1071. //
  1072. // Clear its CMSPAddress pointer
  1073. //
  1074. CBaseTerminal * pCTerminal = static_cast<CBaseTerminal *> (m_Terminals[i]);
  1075. m_Terminals[i]->Release();
  1076. }
  1077. m_Terminals.RemoveAll();
  1078. // We are done with terminal related data, release the lock.
  1079. m_TerminalDataLock.Unlock();
  1080. LOG((MSP_INFO, "CMSPAddress::Shutdown - terminals released"));
  1081. // acquire the lock on the event data because we are writing to it.
  1082. m_EventDataLock.Lock();
  1083. m_htEvent = NULL;
  1084. // release all the unprocessed events in the list.
  1085. while (!IsListEmpty(&m_EventList))
  1086. {
  1087. // retrieve first entry
  1088. PLIST_ENTRY pLE = RemoveHeadList(&m_EventList);
  1089. // convert list entry to structure pointer
  1090. PMSPEVENTITEM pItem = CONTAINING_RECORD(pLE, MSPEVENTITEM, Link);
  1091. // release the refcount in the event.
  1092. LOG((MSP_INFO,
  1093. "CMSPAddress::Shutdown:releasing event still in the queue: %x",
  1094. pItem->MSPEventInfo.Event
  1095. ));
  1096. switch (pItem->MSPEventInfo.Event)
  1097. {
  1098. case ME_ADDRESS_EVENT:
  1099. if (pItem->MSPEventInfo.MSP_ADDRESS_EVENT_INFO.pTerminal)
  1100. {
  1101. pItem->MSPEventInfo.MSP_ADDRESS_EVENT_INFO.pTerminal->Release();
  1102. }
  1103. break;
  1104. case ME_CALL_EVENT:
  1105. if (pItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pStream)
  1106. {
  1107. pItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pStream->Release();
  1108. }
  1109. if (pItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pTerminal)
  1110. {
  1111. pItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pTerminal->Release();
  1112. }
  1113. break;
  1114. case ME_PRIVATE_EVENT:
  1115. if (pItem->MSPEventInfo.MSP_PRIVATE_EVENT_INFO.pEvent)
  1116. {
  1117. pItem->MSPEventInfo.MSP_PRIVATE_EVENT_INFO.pEvent->Release();
  1118. }
  1119. break;
  1120. case ME_TSP_DATA:
  1121. // nothing inside the structure that we need to free
  1122. break;
  1123. case ME_FILE_TERMINAL_EVENT:
  1124. if( NULL != pItem->MSPEventInfo.MSP_FILE_TERMINAL_EVENT_INFO.pParentFileTerminal)
  1125. {
  1126. (pItem->MSPEventInfo.MSP_FILE_TERMINAL_EVENT_INFO.pParentFileTerminal)->Release();
  1127. pItem->MSPEventInfo.MSP_FILE_TERMINAL_EVENT_INFO.pParentFileTerminal = NULL;
  1128. }
  1129. if( NULL != pItem->MSPEventInfo.MSP_FILE_TERMINAL_EVENT_INFO.pFileTrack )
  1130. {
  1131. (pItem->MSPEventInfo.MSP_FILE_TERMINAL_EVENT_INFO.pFileTrack)->Release();
  1132. pItem->MSPEventInfo.MSP_FILE_TERMINAL_EVENT_INFO.pFileTrack = NULL;
  1133. }
  1134. break;
  1135. case ME_ASR_TERMINAL_EVENT:
  1136. if( NULL != pItem->MSPEventInfo.MSP_ASR_TERMINAL_EVENT_INFO.pASRTerminal)
  1137. {
  1138. (pItem->MSPEventInfo.MSP_ASR_TERMINAL_EVENT_INFO.pASRTerminal)->Release();
  1139. }
  1140. break;
  1141. case ME_TTS_TERMINAL_EVENT:
  1142. if( NULL != pItem->MSPEventInfo.MSP_TTS_TERMINAL_EVENT_INFO.pTTSTerminal)
  1143. {
  1144. (pItem->MSPEventInfo.MSP_TTS_TERMINAL_EVENT_INFO.pTTSTerminal)->Release();
  1145. }
  1146. break;
  1147. case ME_TONE_TERMINAL_EVENT:
  1148. if( NULL != pItem->MSPEventInfo.MSP_TONE_TERMINAL_EVENT_INFO.pToneTerminal)
  1149. {
  1150. (pItem->MSPEventInfo.MSP_TONE_TERMINAL_EVENT_INFO.pToneTerminal)->Release();
  1151. }
  1152. break;
  1153. default:
  1154. LOG((MSP_WARN, "CMSPAddress::Shutdown: unknown event type: %x",
  1155. pItem->MSPEventInfo.Event));
  1156. break;
  1157. }
  1158. FreeEventItem(pItem);
  1159. }
  1160. // We are done with event related data, release the lcok.
  1161. m_EventDataLock.Unlock();
  1162. LOG((MSP_TRACE, "CMSPAddress::Shutdown - exit S_OK"));
  1163. return S_OK;
  1164. }
  1165. STDMETHODIMP CMSPAddress::ReceiveTSPData(
  1166. IN IUnknown * pMSPCall,
  1167. IN LPBYTE pBuffer,
  1168. IN DWORD dwBufferSize
  1169. )
  1170. /*++
  1171. Routine Description:
  1172. This method is called by TAPI3 when the TSP address sends data to this
  1173. MSP address object. The semantics of the data passed in the buffer are
  1174. specific to each TSP - MSP pair. This method dispatches the received
  1175. buffer to the address (call == NULL) or call (call != NULL).
  1176. Arguments:
  1177. pMSPCall
  1178. The call object that the data is for. If it is NULL, the data is for
  1179. this address.
  1180. pBuffer
  1181. Opaque buffer from TSP.
  1182. dwBufferSize
  1183. Size in bytes of pBuffer
  1184. Return Value:
  1185. S_OK
  1186. --*/
  1187. {
  1188. LOG((MSP_TRACE, "CMSPAddress::ReceiveTSPData entered. pMSPCall:%x",
  1189. pMSPCall));
  1190. _ASSERTE(dwBufferSize > 0);
  1191. _ASSERTE(!IsBadReadPtr(pBuffer, sizeof(BYTE) * (dwBufferSize) ) );
  1192. HRESULT hr;
  1193. if ( NULL == pMSPCall )
  1194. {
  1195. hr = ReceiveTSPAddressData(pBuffer, dwBufferSize);
  1196. if ( FAILED(hr) )
  1197. {
  1198. LOG((MSP_ERROR, "CMSPAddress::ReceiveTSPData - "
  1199. "ReceiveTSPAddressData failed - exit 0x%08x", hr));
  1200. return hr;
  1201. }
  1202. LOG((MSP_TRACE, "CMSPAddress::ReceiveTSPData - "
  1203. "exit S_OK (dispatched to address)"));
  1204. return S_OK;
  1205. }
  1206. //
  1207. // We have a call to dispatch to.
  1208. //
  1209. _ASSERTE(!IsBadReadPtr(pMSPCall, sizeof(IUnknown) ) );
  1210. ITStreamControl * pIStreamControl;
  1211. hr = pMSPCall->QueryInterface(IID_ITStreamControl,
  1212. (void **)&pIStreamControl);
  1213. if ( FAILED(hr) )
  1214. {
  1215. LOG((MSP_ERROR, "CMSPAddress::ReceiveTSPData - "
  1216. "can't get the ITStream Control interface - exit 0x%08x", hr));
  1217. return hr;
  1218. }
  1219. CMSPCallBase * pCall = static_cast<CMSPCallBase *> (pIStreamControl);
  1220. if (pCall == NULL)
  1221. {
  1222. LOG((MSP_ERROR, "CMSPAddress::ReceiveTSPData - "
  1223. "invalid msp call pointer: %x", pMSPCall));
  1224. pIStreamControl->Release();
  1225. return E_UNEXPECTED;
  1226. }
  1227. hr = pCall->ReceiveTSPCallData(pBuffer, dwBufferSize);
  1228. pIStreamControl->Release();
  1229. if ( FAILED(hr) )
  1230. {
  1231. LOG((MSP_ERROR, "CMSPAddress::ReceiveTSPData - "
  1232. "method on call failed - exit 0x%08x", hr));
  1233. return hr;
  1234. }
  1235. LOG((MSP_TRACE, "CMSPAddress::ReceiveTSPData - "
  1236. "exit S_OK (dispatched to call)"));
  1237. return S_OK;
  1238. }
  1239. HRESULT CMSPAddress::GetStaticTerminals(
  1240. IN OUT DWORD * pdwNumTerminals,
  1241. OUT ITTerminal ** ppTerminals
  1242. )
  1243. /*++
  1244. Routine Description:
  1245. This method is called by TAPI3 to get a list of static terminals that can
  1246. be used on this address. If our list is not empty, just return the list.
  1247. If our list is still empty, create the static terminals and return the list.
  1248. Derived class can override this method to have their own terminals. Locks
  1249. the terminal lists.
  1250. Arguments:
  1251. pdwNumTerminals
  1252. Pointer to a DWORD. On entry, indicates the size of the buffer pointed
  1253. to in ppTerminals. On success, it will be filled in with the actual number
  1254. of terminals returned. If the buffer is not big enough, the method will
  1255. return TAPI_E_NOTENOUGHMEMORY, and it will be filled in the with number
  1256. of terminals needed.
  1257. ppTerminals
  1258. On success, filled in with an array of terminals object pointers that are
  1259. supported by the MSP for this address. This value may be NULL, in which
  1260. case pdwNumTerminals will return the needed buffer size.
  1261. Return Value:
  1262. S_OK
  1263. E_OUTOFMEMORY
  1264. TAPI_E_NOTENOUGHMEMORY
  1265. --*/
  1266. {
  1267. LOG((MSP_TRACE,
  1268. "GetStaticTerminals entered. NumTerminals:%x, ppTerminals:%x",
  1269. *pdwNumTerminals, ppTerminals
  1270. ));
  1271. // lock the terminal related data. This is a auto lock that will unlock
  1272. // when the function returns.
  1273. CLock lock(m_TerminalDataLock);
  1274. if (!m_fTerminalsUpToDate)
  1275. {
  1276. HRESULT hr = UpdateTerminalList();
  1277. if (FAILED(hr))
  1278. {
  1279. LOG((MSP_ERROR,
  1280. "CMSPAddress::GetStaticTerminals - "
  1281. "UpdateTerminalList failed - returning 0x%08x", hr));
  1282. return hr;
  1283. }
  1284. }
  1285. //
  1286. // Check if initialized.
  1287. //
  1288. if ( m_htEvent == NULL )
  1289. {
  1290. LOG((MSP_ERROR, "CMSPAddress::GetStaticTerminals - "
  1291. "not initialized - returning E_UNEXPECTED"));
  1292. return E_UNEXPECTED;
  1293. }
  1294. //
  1295. // Check parameters.
  1296. //
  1297. if ( MSPB_IsBadWritePtr(pdwNumTerminals, sizeof(DWORD) ) )
  1298. {
  1299. LOG((MSP_ERROR, "CMSPAddress::GetStaticTerminals - "
  1300. "bad pdwNumTerminals pointer - exit E_POINTER"));
  1301. return E_POINTER;
  1302. }
  1303. if ( ppTerminals != NULL )
  1304. {
  1305. if ( MSPB_IsBadWritePtr(ppTerminals,
  1306. *pdwNumTerminals * sizeof(ITTerminal *) ) )
  1307. {
  1308. LOG((MSP_ERROR, "CMSPAddress::GetStaticTerminals - "
  1309. "bad ppTerminals pointer - exit E_POINTER"));
  1310. return E_POINTER;
  1311. }
  1312. }
  1313. //
  1314. // Grab the size of the terminals list.
  1315. //
  1316. int iSize = m_Terminals.GetSize();
  1317. _ASSERTE( iSize >= 0 );
  1318. //
  1319. // Add our terminals to the output list if the caller wants an output
  1320. // list, and provided there is enough room in the output list.
  1321. //
  1322. if ( ( ppTerminals != NULL ) &&
  1323. ( (DWORD) iSize <= *pdwNumTerminals ) )
  1324. {
  1325. //
  1326. // For each terminal in the list of terminals we created,
  1327. // AddRef and copy the terminal pointer.
  1328. //
  1329. for (int i = 0; i < iSize; i++)
  1330. {
  1331. m_Terminals[i]->AddRef();
  1332. ppTerminals[i] = m_Terminals[i];
  1333. }
  1334. }
  1335. //
  1336. // If there was no output list then we just have to report the number
  1337. // of terminals available.
  1338. //
  1339. if ( ppTerminals == NULL )
  1340. {
  1341. *pdwNumTerminals = (DWORD) iSize;
  1342. LOG((MSP_TRACE,
  1343. "CMSPAddress::GetStaticTerminals - just returned number of "
  1344. "terminals available - exit S_OK"));
  1345. return S_OK;
  1346. }
  1347. //
  1348. // If there was an output list but it was not large enough, then
  1349. // return the appropriate error.
  1350. //
  1351. if ( (DWORD) iSize > *pdwNumTerminals )
  1352. {
  1353. *pdwNumTerminals = (DWORD) iSize;
  1354. LOG((MSP_ERROR,
  1355. "CMSPAddress::GetStaticTerminals - passed-in array not "
  1356. "large enough - exit TAPI_E_NOTENOUGHMEMORY"));
  1357. return TAPI_E_NOTENOUGHMEMORY;
  1358. }
  1359. //
  1360. // Otherwise, everything was fine. We just need to report the actual
  1361. // number of terminals we copied and return S_OK.
  1362. //
  1363. *pdwNumTerminals = (DWORD) iSize;
  1364. LOG((MSP_TRACE,
  1365. "CMSPAddress::GetStaticTerminals - "
  1366. "returned terminals - exit S_OK"));
  1367. return S_OK;
  1368. }
  1369. HRESULT CMSPAddress::IsMonikerInTerminalList(IMoniker* pMoniker)
  1370. {
  1371. CSingleFilterStaticTerminal *pCSingleFilterStaticTerminal;
  1372. //
  1373. // Grab the size of the terminals list.
  1374. //
  1375. int iSize = m_Terminals.GetSize();
  1376. _ASSERTE( iSize >= 0 );
  1377. //
  1378. // Add our terminals to the output list if the caller wants an output
  1379. // list, and provided there is enough room in the output list.
  1380. //
  1381. for (int i = 0; i < iSize; i++)
  1382. {
  1383. pCSingleFilterStaticTerminal = static_cast<CSingleFilterStaticTerminal *>(m_Terminals[i]);
  1384. if ( pCSingleFilterStaticTerminal->CompareMoniker( pMoniker ) == S_OK )
  1385. {
  1386. LOG((MSP_TRACE, "CMSPAddress::IsMonikerInTerminalList - "
  1387. "moniker found in terminal list"));
  1388. pCSingleFilterStaticTerminal->m_bMark = TRUE; // mark this terminal so we don't remove it
  1389. return S_OK;
  1390. }
  1391. }
  1392. LOG((MSP_TRACE, "CMSPAddress::IsMonikerInTerminalList - "
  1393. "moniker not found in terminal list"));
  1394. return S_FALSE;
  1395. }
  1396. HRESULT CMSPAddress::UpdateTerminalListForPnp(
  1397. IN BOOL bDeviceArrival
  1398. )
  1399. {
  1400. CSingleFilterStaticTerminal *pCSingleFilterStaticTerminal;
  1401. //
  1402. // Clear all marks in the terminal list
  1403. //
  1404. int iSize = m_Terminals.GetSize();
  1405. _ASSERTE( iSize >= 0 );
  1406. for (int i = 0; i < iSize; i++)
  1407. {
  1408. pCSingleFilterStaticTerminal = static_cast<CSingleFilterStaticTerminal *>(m_Terminals[i]);
  1409. if (pCSingleFilterStaticTerminal == NULL)
  1410. {
  1411. LOG((MSP_ERROR, "CMSPAddress::IsMonikerInTerminalList - "
  1412. "bad terminal pointer"));
  1413. return E_FAIL;
  1414. }
  1415. pCSingleFilterStaticTerminal->m_bMark = FALSE;
  1416. }
  1417. //
  1418. // Create DevEnum, which is the DirectShow Category Enumerator Creator
  1419. //
  1420. HRESULT hr;
  1421. ICreateDevEnum * pCreateDevEnum;
  1422. hr = CoCreateInstance(CLSID_SystemDeviceEnum,
  1423. NULL,
  1424. CLSCTX_INPROC_SERVER,
  1425. IID_ICreateDevEnum,
  1426. (void**)&pCreateDevEnum);
  1427. if (FAILED(hr))
  1428. {
  1429. LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp "
  1430. "can't CoCreate DevEnum - returning 0x%08x", hr));
  1431. return hr;
  1432. }
  1433. IEnumMoniker * pCatEnum;
  1434. for ( i = 0; i < m_sdwTerminalTypesCount; i++ )
  1435. {
  1436. //
  1437. // Skip any terminal types that don't use one of the supported media
  1438. // modes.
  1439. //
  1440. if ( ! IsValidSingleMediaType(
  1441. m_saTerminalTypes[i].dwMediaType, GetCallMediaTypes() ) )
  1442. {
  1443. continue;
  1444. }
  1445. //
  1446. // Create the actual category enumerator.
  1447. //
  1448. hr = pCreateDevEnum->CreateClassEnumerator(
  1449. *(m_saTerminalTypes[i].clsidClassManager),
  1450. &pCatEnum,
  1451. 0);
  1452. if ( hr != S_OK ) // S_FALSE means the category does not exist!
  1453. {
  1454. LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp "
  1455. "can't create class enumerator - returning 0x%08x", hr));
  1456. continue;
  1457. }
  1458. IMoniker * pMoniker;
  1459. while ((hr = pCatEnum->Next(1, &pMoniker, NULL)) == S_OK)
  1460. {
  1461. if (IsMonikerInTerminalList(pMoniker) == S_FALSE)
  1462. {
  1463. //
  1464. // Create a terminal and give it its moniker.
  1465. //
  1466. ITTerminal * pTerminal;
  1467. hr = (m_saTerminalTypes[i].pfnCreateTerm)(pMoniker,
  1468. (MSP_HANDLE) this,
  1469. &pTerminal);
  1470. //
  1471. // The terminal keeps a reference to the moniker if it needs to.
  1472. //
  1473. pMoniker->Release();
  1474. if (SUCCEEDED(hr))
  1475. {
  1476. //
  1477. // Add this terminal pointer to our list. Don't release it; we
  1478. // keep this one reference to it in the list.
  1479. //
  1480. BOOL fSuccess = m_Terminals.Add(pTerminal);
  1481. if ( ! fSuccess )
  1482. {
  1483. pCatEnum->Release();
  1484. pTerminal->Release();
  1485. LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp - "
  1486. "can't add terminal to list; returning E_OUTOFMEMORY"));
  1487. return E_OUTOFMEMORY;
  1488. }
  1489. //
  1490. // Set its CMSPAddress pointer
  1491. //
  1492. CBaseTerminal * pCTerminal = static_cast<CBaseTerminal *> (pTerminal);
  1493. //
  1494. // Mark this terminal so we don't remove it
  1495. //
  1496. pCSingleFilterStaticTerminal = static_cast<CSingleFilterStaticTerminal *>(pTerminal);
  1497. if (pCSingleFilterStaticTerminal == NULL)
  1498. {
  1499. LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp - "
  1500. "bad terminal pointer"));
  1501. return E_FAIL;
  1502. }
  1503. pCSingleFilterStaticTerminal->m_bMark = TRUE;
  1504. //
  1505. // Post a TAPI message about the new terminal's arrival
  1506. //
  1507. pTerminal->AddRef();
  1508. MSPEVENTITEM *pEventItem;
  1509. pEventItem = AllocateEventItem();
  1510. if (pEventItem == NULL)
  1511. {
  1512. LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp - "
  1513. "can't allocate event item; returning E_OUTOFMEMORY"));
  1514. pTerminal->Release();
  1515. return E_OUTOFMEMORY;
  1516. }
  1517. pEventItem->MSPEventInfo.dwSize = sizeof(MSP_EVENT_INFO);
  1518. pEventItem->MSPEventInfo.Event = ME_ADDRESS_EVENT;
  1519. pEventItem->MSPEventInfo.MSP_ADDRESS_EVENT_INFO.Type = ADDRESS_TERMINAL_AVAILABLE;
  1520. pEventItem->MSPEventInfo.MSP_ADDRESS_EVENT_INFO.pTerminal = pTerminal;
  1521. hr = PostEvent(pEventItem);
  1522. if (FAILED(hr))
  1523. {
  1524. LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp - "
  1525. "post event failed"));
  1526. pTerminal->Release();
  1527. FreeEventItem(pEventItem);
  1528. }
  1529. }
  1530. }
  1531. //
  1532. // If it failed, that either means we skipped the device because it
  1533. // was unsuitable (a routine occurance) or something failed, like
  1534. // out of memory. I should come up with a way to differentiate and
  1535. // handle this well.
  1536. //
  1537. }
  1538. //
  1539. // We are done with the enumerator.
  1540. //
  1541. pCatEnum->Release();
  1542. }
  1543. //
  1544. // Release DevEnum.
  1545. //
  1546. pCreateDevEnum->Release();
  1547. //
  1548. // Sweep the terminal list and clean up any terminals which are no longer present
  1549. //
  1550. iSize = m_Terminals.GetSize();
  1551. _ASSERTE( iSize >= 0 );
  1552. for (i = 0; i < iSize; i++)
  1553. {
  1554. pCSingleFilterStaticTerminal = static_cast<CSingleFilterStaticTerminal *>(m_Terminals[i]);
  1555. if (pCSingleFilterStaticTerminal == NULL)
  1556. {
  1557. LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp - "
  1558. "bad terminal pointer"));
  1559. return E_FAIL;
  1560. }
  1561. if (!pCSingleFilterStaticTerminal->m_bMark)
  1562. {
  1563. //
  1564. // This terminal has is no longer present, lets remove it from the list
  1565. //
  1566. LOG((MSP_TRACE, "CMSPAddress::UpdateTerminalListForPnp "
  1567. "found a terminal to be removed"));
  1568. ITTerminal * pTerminal = m_Terminals[i];
  1569. if (m_Terminals.RemoveAt(i))
  1570. {
  1571. //
  1572. // Clear its CMSPAddress pointer
  1573. //
  1574. CBaseTerminal * pCTerminal = static_cast<CBaseTerminal *> (pTerminal);
  1575. //
  1576. // We don't release the terminal here even though we are removing
  1577. // it from the terminal list because TAPI3.dll will release it
  1578. // when it releases the event.
  1579. //
  1580. //
  1581. // Post a TAPI message about the new terminal's removal
  1582. //
  1583. MSPEVENTITEM *pEventItem;
  1584. pEventItem = AllocateEventItem();
  1585. if (pEventItem == NULL)
  1586. {
  1587. LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp - "
  1588. "can't allocate event item; returning E_OUTOFMEMORY"));
  1589. pTerminal->Release();
  1590. return E_OUTOFMEMORY;
  1591. }
  1592. pEventItem->MSPEventInfo.dwSize = sizeof(MSP_EVENT_INFO);
  1593. pEventItem->MSPEventInfo.Event = ME_ADDRESS_EVENT;
  1594. pEventItem->MSPEventInfo.MSP_ADDRESS_EVENT_INFO.Type = ADDRESS_TERMINAL_UNAVAILABLE;
  1595. pEventItem->MSPEventInfo.MSP_ADDRESS_EVENT_INFO.pTerminal = pTerminal;
  1596. hr = PostEvent(pEventItem);
  1597. if (FAILED(hr))
  1598. {
  1599. LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalListForPnp - "
  1600. "post event failed"));
  1601. pTerminal->Release();
  1602. FreeEventItem(pEventItem);
  1603. }
  1604. //
  1605. // fix up our search indices to account for a removal
  1606. //
  1607. iSize--;
  1608. i--;
  1609. }
  1610. }
  1611. }
  1612. //
  1613. // Our list is now complete.
  1614. //
  1615. m_fTerminalsUpToDate = TRUE;
  1616. LOG((MSP_TRACE, "CMSPAddress::UpdateTerminalListForPnp - exit S_OK"));
  1617. return S_OK;
  1618. }
  1619. HRESULT CMSPAddress::UpdateTerminalList(void)
  1620. {
  1621. //
  1622. // Create DevEnum, which is the DirectShow Category Enumerator Creator
  1623. //
  1624. HRESULT hr;
  1625. ICreateDevEnum * pCreateDevEnum;
  1626. hr = CoCreateInstance(CLSID_SystemDeviceEnum,
  1627. NULL,
  1628. CLSCTX_INPROC_SERVER,
  1629. IID_ICreateDevEnum,
  1630. (void**)&pCreateDevEnum);
  1631. if (FAILED(hr))
  1632. {
  1633. LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalList "
  1634. "can't CoCreate DevEnum - returning 0x%08x", hr));
  1635. return hr;
  1636. }
  1637. IEnumMoniker * pCatEnum;
  1638. for ( DWORD i = 0; i < m_sdwTerminalTypesCount; i++ )
  1639. {
  1640. //
  1641. // Skip any terminal types that don't use one of the supported media
  1642. // modes.
  1643. //
  1644. if ( ! IsValidSingleMediaType(
  1645. m_saTerminalTypes[i].dwMediaType, GetCallMediaTypes() ) )
  1646. {
  1647. continue;
  1648. }
  1649. //
  1650. // Create the actual category enumerator.
  1651. //
  1652. hr = pCreateDevEnum->CreateClassEnumerator(
  1653. *(m_saTerminalTypes[i].clsidClassManager),
  1654. &pCatEnum,
  1655. 0);
  1656. if ( hr != S_OK ) // S_FALSE means the category does not exist!
  1657. {
  1658. LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalList "
  1659. "can't create class enumerator - returning 0x%08x", hr));
  1660. continue;
  1661. }
  1662. IMoniker * pMoniker;
  1663. while ((hr = pCatEnum->Next(1, &pMoniker, NULL)) == S_OK)
  1664. {
  1665. //
  1666. // Create a terminal and give it its moniker.
  1667. //
  1668. ITTerminal * pTerminal;
  1669. hr = (m_saTerminalTypes[i].pfnCreateTerm)(pMoniker,
  1670. (MSP_HANDLE) this,
  1671. &pTerminal);
  1672. //
  1673. // The terminal keeps a reference to the moniker if it needs to.
  1674. //
  1675. pMoniker->Release();
  1676. if (SUCCEEDED(hr))
  1677. {
  1678. //
  1679. // Add this terminal pointer to our list. Don't release it; we
  1680. // keep this one reference to it in the list.
  1681. //
  1682. BOOL fSuccess = m_Terminals.Add(pTerminal);
  1683. if ( ! fSuccess )
  1684. {
  1685. pCatEnum->Release();
  1686. LOG((MSP_ERROR, "CMSPAddress::UpdateTerminalList - "
  1687. "can't add terminal to list; returning E_OUTOFMEMORY"));
  1688. return E_OUTOFMEMORY;
  1689. }
  1690. //
  1691. // Set its CMSPAddress pointer
  1692. //
  1693. CBaseTerminal * pCTerminal = static_cast<CBaseTerminal *> (pTerminal);
  1694. }
  1695. //
  1696. // If it failed, that either means we skipped the device because it
  1697. // was unsuitable (a routine occurance) or something failed, like
  1698. // out of memory. I should come up with a way to differentiate and
  1699. // handle this well.
  1700. //
  1701. }
  1702. //
  1703. // We are done with the enumerator.
  1704. //
  1705. pCatEnum->Release();
  1706. }
  1707. //
  1708. // Release DevEnum.
  1709. //
  1710. pCreateDevEnum->Release();
  1711. //
  1712. // Our list is now complete.
  1713. //
  1714. m_fTerminalsUpToDate = TRUE;
  1715. LOG((MSP_TRACE, "CMSPAddress::UpdateTerminalList - exit S_OK"));
  1716. return S_OK;
  1717. }
  1718. HRESULT CMSPAddress::GetDynamicTerminalClasses(
  1719. IN OUT DWORD * pdwNumClasses,
  1720. OUT IID * pTerminalClasses
  1721. )
  1722. /*++
  1723. Routine Description:
  1724. This method is called by TAPI3 to get a list of dynamic terminal guids
  1725. that can be used on this address. It asks the terminal manager for the
  1726. list of guids and returns them. Derived class can override this method
  1727. to have their own guids.
  1728. Arguments:
  1729. pdwNumClasses
  1730. Pointer to a DWORD. On entry, indicates the size of the buffer
  1731. pointed to in pTerminalClasses. On success, it will be filled in
  1732. with the actual number of class IIDs returned. If the buffer is
  1733. not big enough, the method will return TAPI_E_NOTENOUGHMEMORY,
  1734. and it will be filled in the with number of IIDs needed.
  1735. pTerminalClasses
  1736. On success, filled in with an array of terminal class IIDs that
  1737. are supported by the MSP for this address. This value may be NULL,
  1738. in which case pdwNumClasses will return the needed buffer size.
  1739. Return Value:
  1740. S_OK
  1741. E_OUTOFMEMORY
  1742. TAPI_E_NOTENOUGHMEMORY
  1743. --*/
  1744. {
  1745. LOG((MSP_TRACE,
  1746. "CMSPAddress::GetDynamicTerminalClasses - enter"));
  1747. //
  1748. // Check if initialized.
  1749. //
  1750. // lock the event related data
  1751. m_EventDataLock.Lock();
  1752. if ( m_htEvent == NULL )
  1753. {
  1754. // unlock the event related data
  1755. m_EventDataLock.Unlock();
  1756. LOG((MSP_ERROR,
  1757. "CMSPAddress::GetDynamicTerminalClasses - "
  1758. "not initialized - returning E_UNEXPECTED"));
  1759. return E_UNEXPECTED;
  1760. }
  1761. // unlock the event related data
  1762. m_EventDataLock.Unlock();
  1763. //
  1764. // Ask the Terminal Manager for the dynamic terminals that apply to
  1765. // all of our supported media types. Since the mapping is
  1766. // direct, the Terminal Manager takes care of all argument checking.
  1767. //
  1768. HRESULT hr;
  1769. hr = m_pITTerminalManager->GetDynamicTerminalClasses(
  1770. GetCallMediaTypes(),
  1771. pdwNumClasses,
  1772. pTerminalClasses);
  1773. LOG((MSP_TRACE,
  1774. "CMSPAddress::GetDynamicTerminalClasses - exit 0x%08x", hr));
  1775. return hr;
  1776. }
  1777. STDMETHODIMP CMSPAddress::CreateTerminal(
  1778. IN BSTR pTerminalClass,
  1779. IN long lMediaType,
  1780. IN TERMINAL_DIRECTION Direction,
  1781. OUT ITTerminal ** ppTerminal
  1782. )
  1783. /*++
  1784. Routine Description:
  1785. This method is called by TAPI3 to create a dynamic terminal. It asks the
  1786. terminal manager to create a dynamic terminal. Derived class can
  1787. override this method to have their own way of creating a dynamic terminal.
  1788. Arguments:
  1789. iidTerminalClass
  1790. IID of the terminal class to be created.
  1791. dwMediaType
  1792. TAPI media type of the terminal to be created.
  1793. Direction
  1794. Terminal direction of the terminal to be created.
  1795. ppTerminal
  1796. Returned created terminal object
  1797. Return Value:
  1798. S_OK
  1799. E_OUTOFMEMORY
  1800. TAPI_E_INVALIDMEDIATYPE
  1801. TAPI_E_INVALIDTERMINALDIRECTION
  1802. TAPI_E_INVALIDTERMINALCLASS
  1803. --*/
  1804. {
  1805. LOG((MSP_TRACE,
  1806. "CMSPAddress::CreateTerminal - enter"));
  1807. //
  1808. // Check if initialized.
  1809. //
  1810. // lock the event related data
  1811. m_EventDataLock.Lock();
  1812. if ( m_htEvent == NULL )
  1813. {
  1814. // unlock the event related data
  1815. m_EventDataLock.Unlock();
  1816. LOG((MSP_ERROR,
  1817. "CMSPAddress::CreateTerminal - "
  1818. "not initialized - returning E_UNEXPECTED"));
  1819. return E_UNEXPECTED;
  1820. }
  1821. // unlock the event related data
  1822. m_EventDataLock.Unlock();
  1823. //
  1824. // Get the IID from the BSTR representation.
  1825. //
  1826. HRESULT hr;
  1827. IID iidTerminalClass;
  1828. hr = CLSIDFromString(pTerminalClass, &iidTerminalClass);
  1829. if ( FAILED(hr) )
  1830. {
  1831. LOG((MSP_ERROR, "CMSPAddress::CreateTerminal - "
  1832. "bad CLSID string - returning E_INVALIDARG"));
  1833. return E_INVALIDARG;
  1834. }
  1835. //
  1836. // Make sure we support the requested media type.
  1837. // The terminal manager checks the terminal class, terminal direction,
  1838. // and return pointer.
  1839. //
  1840. //
  1841. // requested media type may be aggregated, but it must still be valid
  1842. //
  1843. if ( !IsValidAggregatedMediaType(lMediaType) )
  1844. {
  1845. LOG((MSP_ERROR, "CMSPAddress::CreateTerminal - "
  1846. "unrecognized media type requested - returning E_INVALIDARG"));
  1847. return E_INVALIDARG;
  1848. }
  1849. //
  1850. // Use the terminal manager to create the dynamic terminal.
  1851. //
  1852. _ASSERTE( m_pITTerminalManager != NULL );
  1853. hr = m_pITTerminalManager->CreateDynamicTerminal(NULL,
  1854. iidTerminalClass,
  1855. (DWORD) lMediaType,
  1856. Direction,
  1857. (MSP_HANDLE) this,
  1858. ppTerminal);
  1859. if ( FAILED(hr) )
  1860. {
  1861. LOG((MSP_ERROR, "CMSPAddress::CreateTerminal - "
  1862. "create dynamic terminal failed - returning 0x%08x", hr));
  1863. return hr;
  1864. }
  1865. LOG((MSP_TRACE, "CMSPAddress::CreateTerminal - exit S_OK"));
  1866. return S_OK;
  1867. }
  1868. STDMETHODIMP CMSPAddress::GetDefaultStaticTerminal(
  1869. IN long lMediaType,
  1870. IN TERMINAL_DIRECTION Direction,
  1871. OUT ITTerminal ** ppTerminal
  1872. )
  1873. /*++
  1874. Routine Description:
  1875. This method is called by TAPI3 to get the default static terminal
  1876. for a certain type and direction. It updates the list if needed, then
  1877. figures out which terminal is the first of the appropriate type in our
  1878. list. Derived classes can override this method to have
  1879. their own way of deciding which terminal is the default. Locks the
  1880. terminal lists.
  1881. Arguments:
  1882. dwMediaType
  1883. The TAPIMEDIATYPE of the terminal to retrieve. Only one bit will be set.
  1884. Direction
  1885. TERMINAL_DIRECTION of the terminal to retrieve.
  1886. ppTerminal
  1887. Default terminal returned
  1888. Return Value:
  1889. S_OK
  1890. E_POINTER
  1891. E_OUTOFMEMORY
  1892. TAPI_E_NOTSUPPORTED
  1893. TAPI_E_INVALIDMEDIATYPE
  1894. TAPI_E_INVALIDTERMINALDIRECTION
  1895. --*/
  1896. {
  1897. LOG((MSP_TRACE,
  1898. "CMSPAddress::GetDefaultStaticTerminal - enter"));
  1899. //
  1900. // Check if initialized.
  1901. //
  1902. // lock the event related data
  1903. m_EventDataLock.Lock();
  1904. if ( m_htEvent == NULL )
  1905. {
  1906. // unlock the event related data
  1907. m_EventDataLock.Unlock();
  1908. LOG((MSP_ERROR,
  1909. "CMSPAddress::GetDefaultStaticTerminal - "
  1910. "not initialized - returning E_UNEXPECTED"));
  1911. return E_UNEXPECTED;
  1912. }
  1913. // unlock the event related data
  1914. m_EventDataLock.Unlock();
  1915. //
  1916. // Make sure we support this media type.
  1917. //
  1918. if ( ! IsValidSingleMediaType( (DWORD) lMediaType, GetCallMediaTypes() ) )
  1919. {
  1920. LOG((MSP_ERROR,
  1921. "CMSPAddress::GetDefaultStaticTerminal - "
  1922. "non-audio terminal requested - returning E_INVALIDARG"));
  1923. return E_INVALIDARG;
  1924. }
  1925. //
  1926. // Check the direction.
  1927. //
  1928. if ( ( Direction != TD_CAPTURE ) && ( Direction != TD_RENDER ) )
  1929. {
  1930. LOG((MSP_ERROR,
  1931. "CMSPAddress::GetDefaultStaticTerminal - "
  1932. "invalid direction - returning E_INVALIDARG"));
  1933. return E_INVALIDARG;
  1934. }
  1935. //
  1936. // Check return pointer.
  1937. //
  1938. if ( MSPB_IsBadWritePtr(ppTerminal, sizeof(ITTerminal *) ) )
  1939. {
  1940. LOG((MSP_ERROR,
  1941. "CMSPAddress::GetDefaultStaticTerminal - "
  1942. "bad terminal return pointer - returning E_POINTER"));
  1943. return E_POINTER;
  1944. }
  1945. // lock the terminal related data. This is a auto lock that will unlock
  1946. // when the function returns.
  1947. CLock lock(m_TerminalDataLock);
  1948. if (!m_fTerminalsUpToDate)
  1949. {
  1950. HRESULT hr = UpdateTerminalList();
  1951. if (FAILED(hr))
  1952. {
  1953. LOG((MSP_ERROR,
  1954. "CMSPAddress::GetDefaultStaticTerminal - "
  1955. "UpdateTerminalList failed - returning 0x%08x", hr));
  1956. return hr;
  1957. }
  1958. }
  1959. //
  1960. // For each terminal in the list of terminals we created...
  1961. //
  1962. int iSize = m_Terminals.GetSize();
  1963. for (int i = 0; i < iSize; i++)
  1964. {
  1965. ITTerminal * pTerminal = m_Terminals[i];
  1966. HRESULT hr;
  1967. //
  1968. // Make sure this is the right direction.
  1969. //
  1970. TERMINAL_DIRECTION dir;
  1971. hr = pTerminal->get_Direction(&dir);
  1972. if (FAILED(hr))
  1973. {
  1974. LOG((MSP_WARN,
  1975. "CMSPAddress::GetDefaultStaticTerminal - "
  1976. "could not get terminal direction - skipping"));
  1977. continue;
  1978. }
  1979. if ( dir != Direction )
  1980. {
  1981. continue;
  1982. }
  1983. //
  1984. // Make sure this is the right media type.
  1985. //
  1986. long lMediaTypeObserved;
  1987. hr = pTerminal->get_MediaType(&lMediaTypeObserved);
  1988. if (FAILED(hr))
  1989. {
  1990. LOG((MSP_WARN,
  1991. "CMSPAddress::GetDefaultStaticTerminal - "
  1992. "could not get terminal media type - skipping"));
  1993. continue;
  1994. }
  1995. if ( ( lMediaTypeObserved & lMediaType) == 0 )
  1996. {
  1997. continue;
  1998. }
  1999. //
  2000. // Ok, so this is the terminal we want. Addref it and give it to the
  2001. // caller.
  2002. //
  2003. pTerminal->AddRef();
  2004. *ppTerminal = pTerminal;
  2005. LOG((MSP_TRACE,
  2006. "CMSPAddress::GetDefaultStaticTerminal - "
  2007. "returned a terminal - exit S_OK"));
  2008. return S_OK;
  2009. }
  2010. //
  2011. // If we get here then we did not find any matching terminals.
  2012. //
  2013. LOG((MSP_TRACE,
  2014. "CMSPAddress::GetDefaultStaticTerminal - "
  2015. "no match - exit TAPI_E_NOITEMS"));
  2016. return TAPI_E_NOITEMS;
  2017. }
  2018. STDMETHODIMP CMSPAddress::get_PluggableSuperclasses(
  2019. OUT VARIANT * pVariant
  2020. )
  2021. {
  2022. LOG((MSP_TRACE,
  2023. "CMSPAddress::get_PluggableSuperclasses - enter"));
  2024. //
  2025. // Check parameters.
  2026. //
  2027. if ( MSPB_IsBadWritePtr(pVariant, sizeof(VARIANT) ) )
  2028. {
  2029. LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - "
  2030. "bad pointer argument - exit E_POINTER"));
  2031. return E_POINTER;
  2032. }
  2033. //
  2034. // Get ITTemrinalManager2
  2035. //
  2036. ITTerminalManager2* pTermMgr2 = NULL;
  2037. HRESULT hr = E_FAIL;
  2038. hr = m_pITTerminalManager->QueryInterface(
  2039. IID_ITTerminalManager2, (void**)&pTermMgr2);
  2040. if( FAILED(hr) )
  2041. {
  2042. LOG((MSP_ERROR,
  2043. "CMSPAddress::get_PluggableSuperclasses - "
  2044. "QI for ITTerminalManager2 failed - returning 0x%08x", hr));
  2045. return hr;
  2046. }
  2047. //
  2048. // Create the collection object - see mspcoll.h
  2049. //
  2050. typedef CTapiIfCollection< ITPluggableTerminalSuperclassInfo* > SuperclassCollection;
  2051. CComObject<SuperclassCollection> * pCollection;
  2052. hr = CComObject<SuperclassCollection>::CreateInstance( &pCollection );
  2053. if ( FAILED(hr) )
  2054. {
  2055. //Clean-up
  2056. pTermMgr2->Release();
  2057. LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - "
  2058. "can't create collection - exit 0x%08x", hr));
  2059. return hr;
  2060. }
  2061. //
  2062. // Get the Collection's IDispatch interface
  2063. //
  2064. IDispatch * pDispatch;
  2065. hr = pCollection->_InternalQueryInterface(
  2066. IID_IDispatch,
  2067. (void **) &pDispatch );
  2068. if ( FAILED(hr) )
  2069. {
  2070. //Clean-up
  2071. pTermMgr2->Release();
  2072. delete pCollection;
  2073. LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - "
  2074. "QI for IDispatch on collection failed - exit 0x%08x", hr));
  2075. return hr;
  2076. }
  2077. //
  2078. // Find out how many superclasses are available.
  2079. //
  2080. DWORD dwNumSuperclasses = 0;
  2081. hr = pTermMgr2->GetPluggableSuperclasses(
  2082. &dwNumSuperclasses,
  2083. NULL);
  2084. if ( FAILED(hr) )
  2085. {
  2086. LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - "
  2087. "can't get number of terminals - exit 0x%08x", hr));
  2088. //Clean-up
  2089. pTermMgr2->Release();
  2090. pDispatch->Release();
  2091. return hr;
  2092. }
  2093. //
  2094. // Allocate an array of IID.
  2095. //
  2096. IID* pSuperclassesIID = new IID[dwNumSuperclasses];
  2097. if ( pSuperclassesIID == NULL )
  2098. {
  2099. LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - "
  2100. "can't allocate IIDs array - exit E_OUTOFMEMORY"));
  2101. //Clean-up
  2102. pTermMgr2->Release();
  2103. pDispatch->Release();
  2104. return E_OUTOFMEMORY;
  2105. }
  2106. //
  2107. // Fill in the array with actual pointers. We must do this before
  2108. // initializing the enumerator, because the enumerator may want to
  2109. // addref the interface pointers during initialize.
  2110. //
  2111. hr = pTermMgr2->GetPluggableSuperclasses(
  2112. &dwNumSuperclasses,
  2113. pSuperclassesIID
  2114. );
  2115. //
  2116. // Clean-up
  2117. //
  2118. pTermMgr2->Release();
  2119. if ( FAILED(hr) )
  2120. {
  2121. LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - "
  2122. "can't get IIDs - exit 0x%08x", hr));
  2123. //Clean-up
  2124. pDispatch->Release();
  2125. delete[] pSuperclassesIID;
  2126. return hr;
  2127. }
  2128. //
  2129. // Allocate an array of ITPluggableTerminalSuperclassInfo
  2130. //
  2131. typedef ITPluggableTerminalSuperclassInfo* SuperclassPtr; // MS parser
  2132. SuperclassPtr * ppSuperclassesInfo = new SuperclassPtr[dwNumSuperclasses];
  2133. if ( ppSuperclassesInfo == NULL )
  2134. {
  2135. LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - "
  2136. "can't allocate SuperclassPtr array - exit E_OUTOFMEMORY"));
  2137. //Clean-up
  2138. pDispatch->Release();
  2139. delete[] pSuperclassesIID;
  2140. return E_OUTOFMEMORY;
  2141. }
  2142. //
  2143. // Get ITPluggableTerminalSuperclassRegistration interface
  2144. //
  2145. ITPluggableTerminalSuperclassRegistration* pSuperclassReg = NULL;
  2146. hr = CoCreateInstance(
  2147. CLSID_PluggableSuperclassRegistration,
  2148. NULL,
  2149. CLSCTX_INPROC_SERVER,
  2150. IID_ITPluggableTerminalSuperclassRegistration,
  2151. (void**)&pSuperclassReg
  2152. );
  2153. if( FAILED(hr) )
  2154. {
  2155. LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - "
  2156. "QI for ITPluggableTerminalSuperclassRegistration - exit 0x%08x",hr));
  2157. //Clean-up
  2158. pDispatch->Release();
  2159. delete[] pSuperclassesIID;
  2160. delete[] ppSuperclassesInfo;
  2161. return hr;
  2162. }
  2163. //
  2164. // Create the objects
  2165. //
  2166. for(DWORD dwIndex = 0; dwIndex < dwNumSuperclasses; dwIndex++)
  2167. {
  2168. //
  2169. // Get the string from the IID
  2170. //
  2171. LPOLESTR lpszCLSID = NULL;
  2172. hr = StringFromIID( pSuperclassesIID[dwIndex], &lpszCLSID);
  2173. if( FAILED(hr) )
  2174. {
  2175. LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - "
  2176. "StringFromIID failed - exit 0x%08x",hr));
  2177. //Clean-up
  2178. pDispatch->Release();
  2179. delete[] pSuperclassesIID;
  2180. delete[] ppSuperclassesInfo;
  2181. pSuperclassReg->Release();
  2182. return hr;
  2183. }
  2184. //
  2185. // Get BSTR for IID
  2186. //
  2187. BSTR bstrCLSID = SysAllocString( lpszCLSID );
  2188. CoTaskMemFree( lpszCLSID ); // Clean-up
  2189. if( NULL == bstrCLSID)
  2190. {
  2191. LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - "
  2192. "SysAllocString failed - exit E_OUTOFMEMORY"));
  2193. // Clean-up
  2194. pDispatch->Release();
  2195. delete[] pSuperclassesIID;
  2196. delete[] ppSuperclassesInfo;
  2197. pSuperclassReg->Release();
  2198. return E_OUTOFMEMORY;
  2199. }
  2200. //
  2201. // Read information from registry
  2202. //
  2203. pSuperclassReg->put_CLSID( bstrCLSID);
  2204. hr = pSuperclassReg->GetTerminalSuperclassInfo();
  2205. if( FAILED(hr) )
  2206. {
  2207. LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - "
  2208. "GetTerminalSuperclassInfo failed - exit 0x%08x",hr));
  2209. // Clean-up
  2210. pDispatch->Release();
  2211. delete[] pSuperclassesIID;
  2212. delete[] ppSuperclassesInfo;
  2213. pSuperclassReg->Release();
  2214. SysFreeString( bstrCLSID);
  2215. return hr;
  2216. }
  2217. //
  2218. // Get the name
  2219. //
  2220. BSTR bstrName = NULL;
  2221. pSuperclassReg->get_Name( &bstrName );
  2222. //
  2223. // Create the information object
  2224. //
  2225. CComObject<CPlugTerminalSuperclassInfo>* pSuperclassInfo = NULL;
  2226. hr = CComObject<CPlugTerminalSuperclassInfo>::CreateInstance(&pSuperclassInfo);
  2227. if( FAILED(hr) )
  2228. {
  2229. LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - "
  2230. "CreateInstance failed - exit 0x%08x", hr));
  2231. //Clean-up
  2232. pDispatch->Release();
  2233. delete[] pSuperclassesIID;
  2234. delete[] ppSuperclassesInfo;
  2235. pSuperclassReg->Release();
  2236. SysFreeString( bstrCLSID );
  2237. SysFreeString( bstrName );
  2238. return hr;
  2239. }
  2240. //
  2241. // Get ITPluggableTerminalSuperclassInfo from this superclass
  2242. //
  2243. pSuperclassInfo->QueryInterface(
  2244. IID_ITPluggableTerminalSuperclassInfo,
  2245. (void**)&ppSuperclassesInfo[dwIndex]
  2246. );
  2247. //
  2248. // Set the fields
  2249. //
  2250. pSuperclassInfo->put_Name( bstrName);
  2251. pSuperclassInfo->put_CLSID( bstrCLSID );
  2252. //
  2253. // Clean-up
  2254. //
  2255. SysFreeString( bstrCLSID );
  2256. SysFreeString( bstrName );
  2257. }
  2258. //
  2259. // Clean-up the IIDs array
  2260. //
  2261. pSuperclassReg->Release();
  2262. delete[] pSuperclassesIID;
  2263. //
  2264. // Init the collection using an iterator -- pointers to the beginning and
  2265. // the ending element plus one. If it succeeds, this method addrefs each
  2266. // element of ppterminals by querying for IDispatch.
  2267. //
  2268. hr = pCollection->Initialize( dwNumSuperclasses,
  2269. ppSuperclassesInfo,
  2270. ppSuperclassesInfo + dwNumSuperclasses );
  2271. if( FAILED(hr) )
  2272. {
  2273. LOG((MSP_ERROR, "CMSPAddress::get_PluggableSuperclasses - exit "
  2274. "pCollection->Initialize failed. returns 0x%08x", hr));
  2275. delete[] ppSuperclassesInfo;
  2276. pDispatch->Release();
  2277. return hr;
  2278. }
  2279. //
  2280. // put the IDispatch interface pointer into the variant
  2281. //
  2282. LOG((MSP_INFO, "CMSPAddress::get_PluggableSuperclasses - "
  2283. "placing IDispatch value %08x in variant", pDispatch));
  2284. VariantInit(pVariant);
  2285. pVariant->vt = VT_DISPATCH;
  2286. pVariant->pdispVal = pDispatch;
  2287. LOG((MSP_TRACE, "CMSPAddress::get_PluggableSuperclasses - exit S_OK"));
  2288. return S_OK;
  2289. }
  2290. STDMETHODIMP CMSPAddress::EnumeratePluggableSuperclasses(
  2291. OUT IEnumPluggableSuperclassInfo** ppSuperclassEnumerator
  2292. )
  2293. {
  2294. LOG((MSP_TRACE,
  2295. "CMSPAddress::EnumeratePluggableSuperclasses - enter"));
  2296. //
  2297. // Check parameters.
  2298. //
  2299. if ( MSPB_IsBadWritePtr(ppSuperclassEnumerator, sizeof(IEnumPluggableTerminalClassInfo*) ) )
  2300. {
  2301. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - "
  2302. "bad pointer argument - exit E_POINTER"));
  2303. return E_POINTER;
  2304. }
  2305. //
  2306. // Get ITTemrinalManager2
  2307. //
  2308. ITTerminalManager2* pTermMgr2 = NULL;
  2309. HRESULT hr = E_FAIL;
  2310. hr = m_pITTerminalManager->QueryInterface(
  2311. IID_ITTerminalManager2, (void**)&pTermMgr2);
  2312. if( FAILED(hr) )
  2313. {
  2314. LOG((MSP_ERROR,
  2315. "CMSPAddress::EnumeratePluggableSuperclasses - "
  2316. "QI for ITTerminalManager2 failed - returning 0x%08x", hr));
  2317. return hr;
  2318. }
  2319. //
  2320. // Find out how many superclasses are available.
  2321. //
  2322. DWORD dwNumSuperclasses = 0;
  2323. hr = pTermMgr2->GetPluggableSuperclasses(
  2324. &dwNumSuperclasses,
  2325. NULL);
  2326. if ( FAILED(hr) )
  2327. {
  2328. // Clean-up
  2329. pTermMgr2->Release();
  2330. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - "
  2331. "can't get number of terminals - exit 0x%08x", hr));
  2332. return hr;
  2333. }
  2334. //
  2335. // Allocate an array of IID.
  2336. //
  2337. IID* pSuperclassesIID = new IID[dwNumSuperclasses];
  2338. if ( pSuperclassesIID == NULL )
  2339. {
  2340. // Clean-up
  2341. pTermMgr2->Release();
  2342. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - "
  2343. "can't allocate IIDs array - exit E_OUTOFMEMORY"));
  2344. return E_OUTOFMEMORY;
  2345. }
  2346. //
  2347. // Fill in the array with actual pointers. We must do this before
  2348. // initializing the enumerator, because the enumerator may want to
  2349. // addref the interface pointers during initialize.
  2350. //
  2351. hr = pTermMgr2->GetPluggableSuperclasses(
  2352. &dwNumSuperclasses,
  2353. pSuperclassesIID
  2354. );
  2355. //
  2356. // Clean-up
  2357. //
  2358. pTermMgr2->Release();
  2359. if ( FAILED(hr) )
  2360. {
  2361. //Clean-up
  2362. delete[] pSuperclassesIID;
  2363. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - "
  2364. "can't get IIDs - exit 0x%08x", hr));
  2365. return hr;
  2366. }
  2367. //
  2368. // Allocate an array of ITPluggableTerminalSuperclassInfo
  2369. //
  2370. typedef ITPluggableTerminalSuperclassInfo* SuperclassPtr; // MS parser
  2371. SuperclassPtr * ppSuperclassesInfo = new SuperclassPtr[dwNumSuperclasses];
  2372. if ( ppSuperclassesInfo == NULL )
  2373. {
  2374. // Clean-up
  2375. delete[] pSuperclassesIID;
  2376. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - "
  2377. "can't allocate SuperclassPtr array - exit E_OUTOFMEMORY"));
  2378. return E_OUTOFMEMORY;
  2379. }
  2380. //
  2381. // Get ITPluggableTerminalSuperclassRegistration interface
  2382. //
  2383. ITPluggableTerminalSuperclassRegistration* pSuperclassReg = NULL;
  2384. hr = CoCreateInstance(
  2385. CLSID_PluggableSuperclassRegistration,
  2386. NULL,
  2387. CLSCTX_INPROC_SERVER,
  2388. IID_ITPluggableTerminalSuperclassRegistration,
  2389. (void**)&pSuperclassReg
  2390. );
  2391. if( FAILED(hr) )
  2392. {
  2393. // Clean-up
  2394. delete[] pSuperclassesIID;
  2395. delete[] ppSuperclassesInfo;
  2396. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - "
  2397. "QI for ITPluggableTerminalSuperclassRegistration - exit 0x%08x",hr));
  2398. return hr;
  2399. }
  2400. //
  2401. // Create the objects
  2402. //
  2403. for(DWORD dwIndex = 0; dwIndex < dwNumSuperclasses; dwIndex++)
  2404. {
  2405. //
  2406. // Get the string from the IID
  2407. //
  2408. LPOLESTR lpszCLSID = NULL;
  2409. hr = StringFromIID( pSuperclassesIID[dwIndex], &lpszCLSID);
  2410. if( FAILED(hr) )
  2411. {
  2412. //Clean-up
  2413. delete[] pSuperclassesIID;
  2414. delete[] ppSuperclassesInfo;
  2415. pSuperclassReg->Release();
  2416. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - "
  2417. "StringFromIID failed - exit 0x%08x",hr));
  2418. return hr;
  2419. }
  2420. //
  2421. // Get BSTR for IID
  2422. //
  2423. BSTR bstrCLSID = SysAllocString( lpszCLSID );
  2424. CoTaskMemFree( lpszCLSID ); // Clean-up
  2425. if( NULL == bstrCLSID)
  2426. {
  2427. //Clean-up
  2428. delete[] pSuperclassesIID;
  2429. delete[] ppSuperclassesInfo;
  2430. pSuperclassReg->Release();
  2431. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - "
  2432. "SysAllocString failed - exit E_OUTOFMEMORY"));
  2433. return E_OUTOFMEMORY;
  2434. }
  2435. //
  2436. // Read information from registry
  2437. //
  2438. pSuperclassReg->put_CLSID( bstrCLSID);
  2439. hr = pSuperclassReg->GetTerminalSuperclassInfo();
  2440. if( FAILED(hr) )
  2441. {
  2442. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - "
  2443. "GetTerminalSuperclassInfo failed - exit 0x%08x",hr));
  2444. // Clean-up
  2445. delete[] pSuperclassesIID;
  2446. delete[] ppSuperclassesInfo;
  2447. pSuperclassReg->Release();
  2448. SysFreeString( bstrCLSID);
  2449. return hr;
  2450. }
  2451. //
  2452. // Get the name
  2453. //
  2454. BSTR bstrName = NULL;
  2455. pSuperclassReg->get_Name( &bstrName );
  2456. //
  2457. // Create the information object
  2458. //
  2459. CComObject<CPlugTerminalSuperclassInfo>* pSuperclassInfo = NULL;
  2460. hr = CComObject<CPlugTerminalSuperclassInfo>::CreateInstance(&pSuperclassInfo);
  2461. if( FAILED(hr) )
  2462. {
  2463. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - "
  2464. "CreateInstance failed - exit 0x%08x", hr));
  2465. // Clean-up
  2466. delete[] pSuperclassesIID;
  2467. delete[] ppSuperclassesInfo;
  2468. pSuperclassReg->Release();
  2469. SysFreeString( bstrCLSID );
  2470. SysFreeString( bstrName );
  2471. return hr;
  2472. }
  2473. //
  2474. // Get ITPluggableTerminalSuperclassInfo from this superclass
  2475. //
  2476. pSuperclassInfo->QueryInterface(
  2477. IID_ITPluggableTerminalSuperclassInfo,
  2478. (void**)&ppSuperclassesInfo[dwIndex]
  2479. );
  2480. //
  2481. // Set the fields
  2482. //
  2483. pSuperclassInfo->put_Name( bstrName);
  2484. pSuperclassInfo->put_CLSID( bstrCLSID );
  2485. //
  2486. // Clean-up
  2487. //
  2488. SysFreeString( bstrCLSID );
  2489. SysFreeString( bstrName );
  2490. }
  2491. //
  2492. // Clean-up the IIDs array
  2493. //
  2494. pSuperclassReg->Release();
  2495. delete[] pSuperclassesIID;
  2496. //
  2497. // Create the enumerator object.
  2498. //
  2499. typedef CSafeComEnum<IEnumPluggableSuperclassInfo,
  2500. &IID_IEnumPluggableSuperclassInfo,
  2501. ITPluggableTerminalSuperclassInfo*,
  2502. _CopyInterface<ITPluggableTerminalSuperclassInfo> > CEnumerator;
  2503. CComObject<CEnumerator> *pEnum = NULL;
  2504. hr = CComObject<CEnumerator>::CreateInstance(&pEnum);
  2505. if ( FAILED(hr) )
  2506. {
  2507. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - "
  2508. "can't create enumerator - exit 0x%08x", hr));
  2509. delete[] ppSuperclassesInfo;
  2510. return hr;
  2511. }
  2512. //
  2513. // Query for the desired interface.
  2514. //
  2515. hr = pEnum->_InternalQueryInterface(
  2516. IID_IEnumPluggableSuperclassInfo,
  2517. (void**) ppSuperclassEnumerator
  2518. );
  2519. if ( FAILED(hr) )
  2520. {
  2521. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - "
  2522. "can't get enumerator interface - exit 0x%08x", hr));
  2523. delete pEnum;
  2524. delete[] ppSuperclassesInfo;
  2525. return hr;
  2526. }
  2527. //
  2528. // Init the enumerator object.
  2529. //
  2530. hr = pEnum->Init(ppSuperclassesInfo,
  2531. ppSuperclassesInfo + dwNumSuperclasses,
  2532. NULL,
  2533. AtlFlagTakeOwnership);
  2534. if ( FAILED(hr) )
  2535. {
  2536. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableSuperclasses - "
  2537. "can't init enumerator - exit 0x%08x", hr));
  2538. (*ppSuperclassEnumerator)->Release();
  2539. delete[] ppSuperclassesInfo;
  2540. return hr;
  2541. }
  2542. LOG((MSP_TRACE, "CMSPAddress::EnumeratePluggableSuperclasses - exit S_OK"));
  2543. return S_OK;
  2544. }
  2545. STDMETHODIMP CMSPAddress::get_PluggableTerminalClasses(
  2546. IN BSTR bstrTerminalSuperclass,
  2547. IN long lMediaType,
  2548. OUT VARIANT * pVariant
  2549. )
  2550. {
  2551. LOG((MSP_TRACE,
  2552. "CMSPAddress::get_PluggableTerminalClasses - enter"));
  2553. //
  2554. // Check parameters.
  2555. //
  2556. if ( MSPB_IsBadWritePtr(pVariant, sizeof(VARIANT) ) )
  2557. {
  2558. LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - "
  2559. "bad pointer argument - exit E_POINTER"));
  2560. return E_POINTER;
  2561. }
  2562. if( IsBadStringPtr( bstrTerminalSuperclass, (UINT)-1))
  2563. {
  2564. LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - "
  2565. "bad pointer argument - exit E_INVALIDARG"));
  2566. return E_INVALIDARG;
  2567. }
  2568. IID iidSuperclass = IID_NULL;
  2569. HRESULT hr = IIDFromString( bstrTerminalSuperclass, &iidSuperclass);
  2570. if( FAILED(hr) )
  2571. {
  2572. LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - "
  2573. "bad pointer argument - exit E_INVALIDARG"));
  2574. return E_INVALIDARG;
  2575. }
  2576. //
  2577. // Get ITTemrinalManager2
  2578. //
  2579. ITTerminalManager2* pTermMgr2 = NULL;
  2580. hr = m_pITTerminalManager->QueryInterface(
  2581. IID_ITTerminalManager2, (void**)&pTermMgr2);
  2582. if( FAILED(hr) )
  2583. {
  2584. LOG((MSP_ERROR,
  2585. "CMSPAddress::get_PluggableTerminalClasses - "
  2586. "QI for ITTerminalManager2 failed - returning 0x%08x", hr));
  2587. return hr;
  2588. }
  2589. //
  2590. // Create the collection object - see mspcoll.h
  2591. //
  2592. typedef CTapiIfCollection< ITPluggableTerminalClassInfo* > ClassCollection;
  2593. CComObject<ClassCollection> * pCollection;
  2594. hr = CComObject<ClassCollection>::CreateInstance( &pCollection );
  2595. if ( FAILED(hr) )
  2596. {
  2597. //Clean-up
  2598. pTermMgr2->Release();
  2599. LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - "
  2600. "can't create collection - exit 0x%08x", hr));
  2601. return hr;
  2602. }
  2603. //
  2604. // Get the Collection's IDispatch interface
  2605. //
  2606. IDispatch * pDispatch;
  2607. hr = pCollection->_InternalQueryInterface(
  2608. IID_IDispatch,
  2609. (void **) &pDispatch );
  2610. if ( FAILED(hr) )
  2611. {
  2612. // Clean-up
  2613. pTermMgr2->Release();
  2614. delete pCollection;
  2615. LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - "
  2616. "QI for IDispatch on collection failed - exit 0x%08x", hr));
  2617. return hr;
  2618. }
  2619. //
  2620. // Find out how many superclasses are available.
  2621. //
  2622. DWORD dwNumClasses = 0;
  2623. hr = pTermMgr2->GetPluggableTerminalClasses(
  2624. iidSuperclass,
  2625. lMediaType,
  2626. &dwNumClasses,
  2627. NULL);
  2628. if ( FAILED(hr) )
  2629. {
  2630. //Clean-up
  2631. pTermMgr2->Release();
  2632. pDispatch->Release();
  2633. LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - "
  2634. "can't get number of terminals - exit 0x%08x", hr));
  2635. return hr;
  2636. }
  2637. //
  2638. // Allocate an array of IID.
  2639. //
  2640. IID* pClassesIID = new IID[dwNumClasses];
  2641. if ( pClassesIID == NULL )
  2642. {
  2643. //Clean-up
  2644. pTermMgr2->Release();
  2645. pDispatch->Release();
  2646. LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - "
  2647. "can't allocate IIDs array - exit E_OUTOFMEMORY"));
  2648. return E_OUTOFMEMORY;
  2649. }
  2650. //
  2651. // Fill in the array with actual pointers. We must do this before
  2652. // initializing the enumerator, because the enumerator may want to
  2653. // addref the interface pointers during initialize.
  2654. //
  2655. hr = pTermMgr2->GetPluggableTerminalClasses(
  2656. iidSuperclass,
  2657. lMediaType,
  2658. &dwNumClasses,
  2659. pClassesIID
  2660. );
  2661. //
  2662. // Clean-up
  2663. //
  2664. pTermMgr2->Release();
  2665. if ( FAILED(hr) )
  2666. {
  2667. //Clean-up
  2668. pDispatch->Release();
  2669. delete[] pClassesIID;
  2670. LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - "
  2671. "can't get IIDs - exit 0x%08x", hr));
  2672. return hr;
  2673. }
  2674. //
  2675. // Allocate an array of ITPluggableTerminalClassInfo
  2676. //
  2677. typedef ITPluggableTerminalClassInfo* ClassPtr;
  2678. ClassPtr * ppClassesInfo = new ClassPtr[dwNumClasses];
  2679. if ( ppClassesInfo == NULL )
  2680. {
  2681. //Clean-up
  2682. pDispatch->Release();
  2683. delete[] pClassesIID;
  2684. LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - "
  2685. "can't allocate ClassPtr array - exit E_OUTOFMEMORY"));
  2686. return E_OUTOFMEMORY;
  2687. }
  2688. //
  2689. // Get ITPluggableTerminalClassRegistration interface
  2690. //
  2691. ITPluggableTerminalClassRegistration* pClassReg = NULL;
  2692. hr = CoCreateInstance(
  2693. CLSID_PluggableTerminalRegistration,
  2694. NULL,
  2695. CLSCTX_INPROC_SERVER,
  2696. IID_ITPluggableTerminalClassRegistration,
  2697. (void**)&pClassReg
  2698. );
  2699. if( FAILED(hr) )
  2700. {
  2701. //Clean-up
  2702. pDispatch->Release();
  2703. delete[] pClassesIID;
  2704. delete[] ppClassesInfo;
  2705. LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - "
  2706. "QI for ITPluggableTerminalClassRegistration - exit 0x%08x",hr));
  2707. return hr;
  2708. }
  2709. //
  2710. // Create the objects
  2711. //
  2712. for(DWORD dwIndex = 0; dwIndex < dwNumClasses; dwIndex++)
  2713. {
  2714. //
  2715. // Get the string from the IID
  2716. //
  2717. LPOLESTR lpszPublicCLSID = NULL;
  2718. hr = StringFromIID( pClassesIID[dwIndex], &lpszPublicCLSID);
  2719. if( FAILED(hr) )
  2720. {
  2721. //Clean-up
  2722. pDispatch->Release();
  2723. delete[] pClassesIID;
  2724. delete[] ppClassesInfo;
  2725. pClassReg->Release();
  2726. LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - "
  2727. "StringFromIID failed - exit 0x%08x",hr));
  2728. return hr;
  2729. }
  2730. //
  2731. // Get BSTR for IID
  2732. //
  2733. BSTR bstrPublicCLSID = SysAllocString( lpszPublicCLSID );
  2734. CoTaskMemFree( lpszPublicCLSID ); // Clean-up
  2735. if( NULL == bstrPublicCLSID)
  2736. {
  2737. //Clean-up
  2738. pDispatch->Release();
  2739. delete[] pClassesIID;
  2740. delete[] ppClassesInfo;
  2741. pClassReg->Release();
  2742. LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - "
  2743. "SysAllocString failed - exit E_OUTOFMEMORY"));
  2744. return E_OUTOFMEMORY;
  2745. }
  2746. //
  2747. // Read information from registry
  2748. //
  2749. pClassReg->put_TerminalClass( bstrPublicCLSID);
  2750. hr = pClassReg->GetTerminalClassInfo(
  2751. bstrTerminalSuperclass);
  2752. if( FAILED(hr) )
  2753. {
  2754. // Clean-up
  2755. pDispatch->Release();
  2756. delete[] pClassesIID;
  2757. delete[] ppClassesInfo;
  2758. pClassReg->Release();
  2759. SysFreeString( bstrPublicCLSID);
  2760. LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - "
  2761. "GetTerminalInfo failed - exit 0x%08x",hr));
  2762. return hr;
  2763. }
  2764. //
  2765. // Get the name
  2766. //
  2767. BSTR bstrName = NULL;
  2768. pClassReg->get_Name( &bstrName );
  2769. BSTR bstrCompany = NULL;
  2770. pClassReg->get_Company( &bstrCompany );
  2771. BSTR bstrVersion = NULL;
  2772. pClassReg->get_Version( &bstrVersion );
  2773. BSTR bstrCLSID = NULL;
  2774. pClassReg->get_CLSID( &bstrCLSID );
  2775. TMGR_DIRECTION Direction = TMGR_TD_CAPTURE;
  2776. pClassReg->get_Direction( &Direction );
  2777. long lMediaType = 0;
  2778. pClassReg->get_MediaTypes( &lMediaType );
  2779. //
  2780. // Create the information object
  2781. //
  2782. CComObject<CPlugTerminalClassInfo>* pClassInfo = NULL;
  2783. hr = CComObject<CPlugTerminalClassInfo>::CreateInstance(&pClassInfo);
  2784. if( FAILED(hr) )
  2785. {
  2786. //Clean-up
  2787. pDispatch->Release();
  2788. delete[] pClassesIID;
  2789. delete[] ppClassesInfo;
  2790. pClassReg->Release();
  2791. SysFreeString( bstrPublicCLSID );
  2792. SysFreeString( bstrName );
  2793. SysFreeString( bstrCompany );
  2794. SysFreeString( bstrVersion );
  2795. SysFreeString( bstrCLSID );
  2796. LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - "
  2797. "CreateInstance failed - exit 0x%08x", hr));
  2798. return hr;
  2799. }
  2800. //
  2801. // Get ITPluggableTerminalClassInfo from this superclass
  2802. //
  2803. pClassInfo->QueryInterface(
  2804. IID_ITPluggableTerminalClassInfo,
  2805. (void**)&ppClassesInfo[dwIndex]
  2806. );
  2807. //
  2808. // Set the fields
  2809. //
  2810. if( NULL == bstrName)
  2811. {
  2812. bstrName = SysAllocString(L"");
  2813. }
  2814. pClassInfo->put_Name( bstrName);
  2815. pClassInfo->put_TerminalClass( bstrPublicCLSID );
  2816. if( NULL == bstrCompany)
  2817. {
  2818. bstrCompany = SysAllocString(L"");
  2819. }
  2820. pClassInfo->put_Company( bstrCompany );
  2821. if( NULL == bstrVersion)
  2822. {
  2823. bstrVersion = SysAllocString(L"");
  2824. }
  2825. pClassInfo->put_Version( bstrVersion );
  2826. if( NULL == bstrCLSID)
  2827. {
  2828. LPOLESTR lpszCLSID = NULL;
  2829. StringFromCLSID( CLSID_NULL, &lpszCLSID);
  2830. bstrCLSID = SysAllocString(lpszCLSID);
  2831. CoTaskMemFree( lpszCLSID);
  2832. }
  2833. pClassInfo->put_CLSID( bstrCLSID );
  2834. TERMINAL_DIRECTION TermDirection = TD_CAPTURE;
  2835. switch( Direction )
  2836. {
  2837. case TMGR_TD_RENDER:
  2838. TermDirection = TD_RENDER;
  2839. break;
  2840. case TMGR_TD_BOTH:
  2841. TermDirection = TD_BIDIRECTIONAL;
  2842. break;
  2843. case TMGR_TD_CAPTURE:
  2844. default:
  2845. TermDirection = TD_CAPTURE;
  2846. break;
  2847. }
  2848. pClassInfo->put_Direction( TermDirection );
  2849. pClassInfo->put_MediaTypes( lMediaType );
  2850. //
  2851. // Clean-up
  2852. //
  2853. SysFreeString( bstrPublicCLSID );
  2854. SysFreeString( bstrName );
  2855. SysFreeString( bstrCompany );
  2856. SysFreeString( bstrVersion );
  2857. SysFreeString( bstrCLSID );
  2858. }
  2859. //
  2860. // Clean-up the IIDs array
  2861. //
  2862. pClassReg->Release();
  2863. delete[] pClassesIID;
  2864. //
  2865. // Init the collection using an iterator -- pointers to the beginning and
  2866. // the ending element plus one. If it succeeds, this method addrefs each
  2867. // element of ppterminals by querying for IDispatch.
  2868. //
  2869. hr = pCollection->Initialize( dwNumClasses,
  2870. ppClassesInfo,
  2871. ppClassesInfo + dwNumClasses );
  2872. if( FAILED(hr) )
  2873. {
  2874. LOG((MSP_ERROR, "CMSPAddress::get_PluggableTerminalClasses - exit "
  2875. "pCollection->Initialize failed. returns 0x%08x", hr));
  2876. delete[] ppClassesInfo;
  2877. pDispatch->Release();
  2878. return hr;
  2879. }
  2880. //
  2881. // put the IDispatch interface pointer into the variant
  2882. //
  2883. LOG((MSP_INFO, "CMSPAddress::get_PluggableTerminalClasses - "
  2884. "placing IDispatch value %08x in variant", pDispatch));
  2885. VariantInit(pVariant);
  2886. pVariant->vt = VT_DISPATCH;
  2887. pVariant->pdispVal = pDispatch;
  2888. LOG((MSP_TRACE, "CMSPAddress::get_PluggableTerminalClasses - exit S_OK"));
  2889. return S_OK;
  2890. }
  2891. STDMETHODIMP CMSPAddress::EnumeratePluggableTerminalClasses(
  2892. IN CLSID iidTerminalSuperclass,
  2893. IN long lMediaType,
  2894. OUT IEnumPluggableTerminalClassInfo ** ppClassEnumerator
  2895. )
  2896. {
  2897. LOG((MSP_TRACE,
  2898. "CMSPAddress::EnumeratePluggableTerminalClasses - enter"));
  2899. //
  2900. // Check parameters.
  2901. //
  2902. if ( MSPB_IsBadWritePtr(ppClassEnumerator, sizeof(IEnumPluggableTerminalClassInfo *) ) )
  2903. {
  2904. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - "
  2905. "bad pointer argument - exit E_POINTER"));
  2906. return E_POINTER;
  2907. }
  2908. LPOLESTR lpszCLSID = NULL;
  2909. HRESULT hr = StringFromCLSID( iidTerminalSuperclass, &lpszCLSID);
  2910. if( FAILED(hr) )
  2911. {
  2912. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - "
  2913. "StringFromCLSID failed - exit 0x%08x", hr));
  2914. return hr;
  2915. }
  2916. BSTR bstrTerminalSuperclass = SysAllocString( lpszCLSID );
  2917. // Clean-up
  2918. CoTaskMemFree(lpszCLSID);
  2919. lpszCLSID = NULL;
  2920. if( NULL == bstrTerminalSuperclass )
  2921. {
  2922. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - "
  2923. "SysAllocString failed - exit E_OUTOFMEMORY"));
  2924. return E_OUTOFMEMORY;
  2925. }
  2926. //
  2927. // Get ITTemrinalManager2
  2928. //
  2929. ITTerminalManager2* pTermMgr2 = NULL;
  2930. hr = m_pITTerminalManager->QueryInterface(
  2931. IID_ITTerminalManager2, (void**)&pTermMgr2);
  2932. if( FAILED(hr) )
  2933. {
  2934. //Clean-up
  2935. SysFreeString( bstrTerminalSuperclass );
  2936. LOG((MSP_ERROR,
  2937. "CMSPAddress::EnumeratePluggableTerminalClasses - "
  2938. "QI for ITTerminalManager2 failed - returning 0x%08x", hr));
  2939. return hr;
  2940. }
  2941. //
  2942. // Find out how many superclasses are available.
  2943. //
  2944. DWORD dwNumClasses = 0;
  2945. hr = pTermMgr2->GetPluggableTerminalClasses(
  2946. iidTerminalSuperclass,
  2947. lMediaType,
  2948. &dwNumClasses,
  2949. NULL);
  2950. if ( FAILED(hr) )
  2951. {
  2952. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - "
  2953. "can't get number of terminals - exit 0x%08x", hr));
  2954. // Clean-up
  2955. SysFreeString( bstrTerminalSuperclass );
  2956. pTermMgr2->Release();
  2957. return hr;
  2958. }
  2959. //
  2960. // Allocate an array of IID.
  2961. //
  2962. IID* pClassesIID = new IID[dwNumClasses];
  2963. if ( pClassesIID == NULL )
  2964. {
  2965. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - "
  2966. "can't allocate IIDs array - exit E_OUTOFMEMORY"));
  2967. // Clean-up
  2968. SysFreeString( bstrTerminalSuperclass );
  2969. pTermMgr2->Release();
  2970. return E_OUTOFMEMORY;
  2971. }
  2972. //
  2973. // Fill in the array with actual pointers. We must do this before
  2974. // initializing the enumerator, because the enumerator may want to
  2975. // addref the interface pointers during initialize.
  2976. //
  2977. hr = pTermMgr2->GetPluggableTerminalClasses(
  2978. iidTerminalSuperclass,
  2979. lMediaType,
  2980. &dwNumClasses,
  2981. pClassesIID
  2982. );
  2983. //
  2984. // Clean-up
  2985. //
  2986. pTermMgr2->Release();
  2987. if ( FAILED(hr) )
  2988. {
  2989. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - "
  2990. "can't get IIDs - exit 0x%08x", hr));
  2991. // Clean-up
  2992. SysFreeString( bstrTerminalSuperclass );
  2993. delete[] pClassesIID;
  2994. return hr;
  2995. }
  2996. //
  2997. // Allocate an array of ITPluggableTerminalClassInfo
  2998. //
  2999. typedef ITPluggableTerminalClassInfo* ClassPtr;
  3000. ClassPtr * ppClassesInfo = new ClassPtr[dwNumClasses];
  3001. if ( ppClassesInfo == NULL )
  3002. {
  3003. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - "
  3004. "can't allocate ClassPtr array - exit E_OUTOFMEMORY"));
  3005. // Clean-up
  3006. SysFreeString( bstrTerminalSuperclass );
  3007. delete[] pClassesIID;
  3008. return E_OUTOFMEMORY;
  3009. }
  3010. //
  3011. // Get ITPluggableTerminalClassRegistration interface
  3012. //
  3013. ITPluggableTerminalClassRegistration* pClassReg = NULL;
  3014. hr = CoCreateInstance(
  3015. CLSID_PluggableTerminalRegistration,
  3016. NULL,
  3017. CLSCTX_INPROC_SERVER,
  3018. IID_ITPluggableTerminalClassRegistration,
  3019. (void**)&pClassReg
  3020. );
  3021. if( FAILED(hr) )
  3022. {
  3023. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - "
  3024. "QI for ITPluggableTerminalClassRegistration - exit 0x%08x",hr));
  3025. // Clean-up
  3026. SysFreeString( bstrTerminalSuperclass );
  3027. delete[] ppClassesInfo;
  3028. delete[] pClassesIID;
  3029. return hr;
  3030. }
  3031. //
  3032. // Create the objects
  3033. //
  3034. for(DWORD dwIndex = 0; dwIndex < dwNumClasses; dwIndex++)
  3035. {
  3036. //
  3037. // Get the string from the IID
  3038. //
  3039. LPOLESTR lpszPublicCLSID = NULL;
  3040. hr = StringFromIID( pClassesIID[dwIndex], &lpszPublicCLSID);
  3041. if( FAILED(hr) )
  3042. {
  3043. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - "
  3044. "StringFromIID failed - exit 0x%08x",hr));
  3045. // Clean-up
  3046. SysFreeString( bstrTerminalSuperclass );
  3047. delete[] pClassesIID;
  3048. delete[] ppClassesInfo;
  3049. pClassReg->Release();
  3050. return hr;
  3051. }
  3052. //
  3053. // Get BSTR for IID
  3054. //
  3055. BSTR bstrPublicCLSID = SysAllocString( lpszPublicCLSID );
  3056. CoTaskMemFree( lpszPublicCLSID ); // Clean-up
  3057. if( NULL == bstrPublicCLSID)
  3058. {
  3059. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - "
  3060. "SysAllocString failed - exit E_OUTOFMEMORY"));
  3061. // Clean-up
  3062. SysFreeString( bstrTerminalSuperclass );
  3063. delete[] pClassesIID;
  3064. delete[] ppClassesInfo;
  3065. pClassReg->Release();
  3066. return E_OUTOFMEMORY;
  3067. }
  3068. //
  3069. // Read information from registry
  3070. //
  3071. pClassReg->put_TerminalClass( bstrPublicCLSID);
  3072. hr = pClassReg->GetTerminalClassInfo(
  3073. bstrTerminalSuperclass);
  3074. if( FAILED(hr) )
  3075. {
  3076. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - "
  3077. "GetTerminalInfo failed - exit 0x%08x",hr));
  3078. // Clean-up
  3079. SysFreeString( bstrTerminalSuperclass );
  3080. delete[] pClassesIID;
  3081. delete[] ppClassesInfo;
  3082. pClassReg->Release();
  3083. SysFreeString( bstrPublicCLSID);
  3084. return hr;
  3085. }
  3086. //
  3087. // Get the name
  3088. //
  3089. BSTR bstrName = NULL;
  3090. pClassReg->get_Name( &bstrName );
  3091. BSTR bstrCompany = NULL;
  3092. pClassReg->get_Company( &bstrCompany );
  3093. BSTR bstrVersion = NULL;
  3094. pClassReg->get_Version( &bstrVersion );
  3095. BSTR bstrCLSID = NULL;
  3096. pClassReg->get_CLSID( &bstrCLSID );
  3097. TMGR_DIRECTION Direction = TMGR_TD_CAPTURE;
  3098. pClassReg->get_Direction( &Direction );
  3099. long lMediaType = 0;
  3100. pClassReg->get_MediaTypes( &lMediaType );
  3101. //
  3102. // Create the information object
  3103. //
  3104. CComObject<CPlugTerminalClassInfo>* pClassInfo = NULL;
  3105. hr = CComObject<CPlugTerminalClassInfo>::CreateInstance(&pClassInfo);
  3106. if( FAILED(hr) )
  3107. {
  3108. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - "
  3109. "CreateInstance failed - exit 0x%08x", hr));
  3110. // Clean-up
  3111. SysFreeString( bstrTerminalSuperclass );
  3112. delete[] pClassesIID;
  3113. delete[] ppClassesInfo;
  3114. pClassReg->Release();
  3115. SysFreeString( bstrPublicCLSID );
  3116. SysFreeString( bstrName );
  3117. SysFreeString( bstrCompany );
  3118. SysFreeString( bstrVersion );
  3119. SysFreeString( bstrCLSID );
  3120. return hr;
  3121. }
  3122. //
  3123. // Get ITPluggableTerminalClassInfo from this superclass
  3124. //
  3125. pClassInfo->QueryInterface(
  3126. IID_ITPluggableTerminalClassInfo,
  3127. (void**)&ppClassesInfo[dwIndex]
  3128. );
  3129. //
  3130. // Set the fields
  3131. //
  3132. if( NULL == bstrName)
  3133. {
  3134. bstrName = SysAllocString(L"");
  3135. }
  3136. pClassInfo->put_Name( bstrName);
  3137. pClassInfo->put_TerminalClass( bstrPublicCLSID );
  3138. if( NULL == bstrCompany)
  3139. {
  3140. bstrCompany = SysAllocString(L"");
  3141. }
  3142. pClassInfo->put_Company( bstrCompany );
  3143. if( NULL == bstrVersion)
  3144. {
  3145. bstrVersion = SysAllocString(L"");
  3146. }
  3147. pClassInfo->put_Version( bstrVersion );
  3148. if( NULL == bstrCLSID)
  3149. {
  3150. LPOLESTR lpszCLSID = NULL;
  3151. StringFromCLSID( CLSID_NULL, &lpszCLSID);
  3152. bstrCLSID = SysAllocString(lpszCLSID);
  3153. CoTaskMemFree( lpszCLSID);
  3154. }
  3155. pClassInfo->put_CLSID( bstrCLSID );
  3156. TERMINAL_DIRECTION TermDirection = TD_CAPTURE;
  3157. switch( Direction )
  3158. {
  3159. case TMGR_TD_RENDER:
  3160. TermDirection = TD_RENDER;
  3161. break;
  3162. case TMGR_TD_BOTH:
  3163. TermDirection = TD_BIDIRECTIONAL;
  3164. break;
  3165. case TMGR_TD_CAPTURE:
  3166. default:
  3167. TermDirection = TD_CAPTURE;
  3168. break;
  3169. }
  3170. pClassInfo->put_Direction( TermDirection );
  3171. pClassInfo->put_MediaTypes( lMediaType );
  3172. //
  3173. // Clean-up
  3174. //
  3175. SysFreeString( bstrPublicCLSID );
  3176. SysFreeString( bstrName );
  3177. SysFreeString( bstrCompany );
  3178. SysFreeString( bstrVersion );
  3179. SysFreeString( bstrCLSID );
  3180. }
  3181. //
  3182. // Clean-up the IIDs array
  3183. //
  3184. SysFreeString( bstrTerminalSuperclass );
  3185. delete[] pClassesIID;
  3186. pClassReg->Release();
  3187. //
  3188. // Create the enumerator object.
  3189. //
  3190. typedef CSafeComEnum<IEnumPluggableTerminalClassInfo,
  3191. &IID_IEnumPluggableTerminalClassInfo,
  3192. ITPluggableTerminalClassInfo*,
  3193. _CopyInterface<ITPluggableTerminalClassInfo> > CEnumerator;
  3194. CComObject<CEnumerator> *pEnum = NULL;
  3195. hr = CComObject<CEnumerator>::CreateInstance(&pEnum);
  3196. if ( FAILED(hr) )
  3197. {
  3198. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - "
  3199. "can't create enumerator - exit 0x%08x", hr));
  3200. delete[] ppClassesInfo;
  3201. return hr;
  3202. }
  3203. //
  3204. // Query for the desired interface.
  3205. //
  3206. hr = pEnum->_InternalQueryInterface(
  3207. IID_IEnumPluggableTerminalClassInfo,
  3208. (void**) ppClassEnumerator
  3209. );
  3210. if ( FAILED(hr) )
  3211. {
  3212. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - "
  3213. "can't get enumerator interface - exit 0x%08x", hr));
  3214. delete pEnum;
  3215. delete[] ppClassesInfo;
  3216. return hr;
  3217. }
  3218. //
  3219. // Init the enumerator object.
  3220. //
  3221. hr = pEnum->Init(ppClassesInfo,
  3222. ppClassesInfo + dwNumClasses,
  3223. NULL,
  3224. AtlFlagTakeOwnership);
  3225. if ( FAILED(hr) )
  3226. {
  3227. LOG((MSP_ERROR, "CMSPAddress::EnumeratePluggableTerminalClasses - "
  3228. "can't init enumerator - exit 0x%08x", hr));
  3229. (*ppClassEnumerator)->Release();
  3230. delete[] ppClassesInfo;
  3231. return hr;
  3232. }
  3233. LOG((MSP_TRACE, "CMSPAddress::EnumeratePluggableTerminalClasses - exit S_OK"));
  3234. return S_OK;
  3235. }
  3236. STDMETHODIMP CMSPAddress::GetEvent(
  3237. IN OUT DWORD * pdwSize,
  3238. OUT BYTE * pBuffer
  3239. )
  3240. /*++
  3241. Routine Description:
  3242. This method is called by TAPI3 to get detailed information about the
  3243. event that just happened. TAPI3 will normally do this after its event
  3244. is signaled. Locks the event list.
  3245. Arguments:
  3246. pMSPEvent
  3247. The MSP_EVENT
  3248. pdwSize
  3249. Pointer to a DWORD. On entry, indicates the size in bytes of the
  3250. buffer pointed to in pbuffer. On success, it will be filled in with
  3251. the actual number of bytes returned. If the buffer is not big enough,
  3252. the method will return TAPI_E_NOTENOUGHMEMORY, and it will be filled
  3253. in the with number of bytes needed.
  3254. pBuffer
  3255. Event buffer filled in by MSP with the relevant events
  3256. Return Value:
  3257. S_OK
  3258. E_OUTOFMEMORY
  3259. TAPI_E_NOEVENT
  3260. TAPI_E_NOTENOUGHMEMORY
  3261. --*/
  3262. {
  3263. // We trust TAPI3 not to give us bad pointers.
  3264. _ASSERTE(!MSPB_IsBadWritePtr(pdwSize, sizeof (DWORD *)));
  3265. _ASSERTE((*pdwSize == 0) ? TRUE :
  3266. !MSPB_IsBadWritePtr(pBuffer, sizeof(BYTE) * (*pdwSize)));
  3267. LOG((MSP_TRACE, "CMSPAddress::GetEvent"));
  3268. CLock lock(m_EventDataLock);
  3269. if (IsListEmpty(&m_EventList))
  3270. {
  3271. return TAPI_E_NOEVENT;
  3272. }
  3273. // retrieve first entry
  3274. PLIST_ENTRY pLE = m_EventList.Flink;
  3275. // convert list entry to structure pointer
  3276. PMSPEVENTITEM pItem = CONTAINING_RECORD(pLE, MSPEVENTITEM, Link);
  3277. if (pItem->MSPEventInfo.dwSize > *pdwSize)
  3278. {
  3279. *pdwSize = pItem->MSPEventInfo.dwSize;
  3280. return TAPI_E_NOTENOUGHMEMORY;
  3281. }
  3282. CopyMemory(pBuffer, &pItem->MSPEventInfo, pItem->MSPEventInfo.dwSize);
  3283. *pdwSize = pItem->MSPEventInfo.dwSize;
  3284. // remove the first entry from the event list.
  3285. RemoveHeadList(&m_EventList);
  3286. // free the memory.
  3287. FreeEventItem(pItem);
  3288. return S_OK;
  3289. }
  3290. HRESULT CMSPAddress::PostEvent(
  3291. IN MSPEVENTITEM * pEventItem
  3292. )
  3293. /*++
  3294. Routine Description:
  3295. This method is called by MSPCalls to post an event to TAPI3. This method
  3296. puts the event at the end of the event list and singals TAPI3.
  3297. Locks the event list.
  3298. Arguments:
  3299. EventItem
  3300. The event to be queued.
  3301. Return Value:
  3302. S_OK
  3303. E_OUTOFMEMORY
  3304. --*/
  3305. {
  3306. CLock lock(m_EventDataLock);
  3307. if (m_htEvent == NULL)
  3308. {
  3309. return E_UNEXPECTED; // the address was shut down.
  3310. }
  3311. InsertTailList(&m_EventList, &pEventItem->Link);
  3312. SetEvent(m_htEvent);
  3313. return S_OK;
  3314. }
  3315. //////////////////////////////////////////////////////////////////////////////
  3316. //////////////////////////////////////////////////////////////////////////////
  3317. //////////////////////////////////////////////////////////////////////////////
  3318. //////////////////////////////////////////////////////////////////////////////
  3319. //////////////////////////////////////////////////////////////////////////////
  3320. // OLE Automation wrappers
  3321. STDMETHODIMP CMSPAddress::get_StaticTerminals (
  3322. OUT VARIANT * pVariant
  3323. )
  3324. {
  3325. LOG((MSP_TRACE, "CMSPAddress::get_StaticTerminals - enter"));
  3326. //
  3327. // Check parameters.
  3328. //
  3329. if ( MSPB_IsBadWritePtr(pVariant, sizeof(VARIANT) ) )
  3330. {
  3331. LOG((MSP_ERROR, "CMSPAddress::get_StaticTerminals - "
  3332. "bad pointer argument - exit E_POINTER"));
  3333. return E_POINTER;
  3334. }
  3335. //
  3336. // create the collection object - see mspcoll.h
  3337. //
  3338. typedef CTapiIfCollection< ITTerminal * > TerminalCollection;
  3339. CComObject<TerminalCollection> * pCollection;
  3340. HRESULT hr = CComObject<TerminalCollection>::CreateInstance( &pCollection );
  3341. if ( FAILED(hr) )
  3342. {
  3343. LOG((MSP_ERROR, "CMSPAddress::get_StaticTerminals - "
  3344. "can't create collection - exit 0x%08x", hr));
  3345. return hr;
  3346. }
  3347. //
  3348. // get the Collection's IDispatch interface
  3349. //
  3350. IDispatch * pDispatch;
  3351. hr = pCollection->_InternalQueryInterface(IID_IDispatch,
  3352. (void **) &pDispatch );
  3353. if ( FAILED(hr) )
  3354. {
  3355. LOG((MSP_ERROR, "CMSPAddress::get_StaticTerminals - "
  3356. "QI for IDispatch on collection failed - exit 0x%08x", hr));
  3357. delete pCollection;
  3358. return hr;
  3359. }
  3360. //
  3361. // Find out how many terminals are available.
  3362. //
  3363. DWORD dwNumTerminals;
  3364. hr = GetStaticTerminals(&dwNumTerminals,
  3365. NULL);
  3366. if ( FAILED(hr) )
  3367. {
  3368. LOG((MSP_ERROR, "CMSPAddress::get_StaticTerminals - "
  3369. "can't get number of terminals - exit 0x%08x", hr));
  3370. pDispatch->Release();
  3371. return hr;
  3372. }
  3373. //
  3374. // Allocate an array of terminal pointers.
  3375. //
  3376. typedef ITTerminal * TermPtr;
  3377. TermPtr * ppTerminals = new TermPtr[dwNumTerminals];
  3378. if ( ppTerminals == NULL )
  3379. {
  3380. LOG((MSP_ERROR, "CMSPAddress::get_StaticTerminals - "
  3381. "can't allocate terminals array - exit E_OUTOFMEMORY"));
  3382. pDispatch->Release();
  3383. return E_OUTOFMEMORY;
  3384. }
  3385. //
  3386. // Fill in the array with actual pointers. We must do this before
  3387. // initializing the enumerator, because the enumerator may want to
  3388. // addref the interface pointers during initialize.
  3389. //
  3390. hr = GetStaticTerminals(&dwNumTerminals,
  3391. ppTerminals);
  3392. if ( FAILED(hr) )
  3393. {
  3394. LOG((MSP_ERROR, "CMSPAddress::get_StaticTerminals - "
  3395. "can't get terminals - exit 0x%08x", hr));
  3396. pDispatch->Release();
  3397. delete ppTerminals;
  3398. return hr;
  3399. }
  3400. //
  3401. // Init the collection using an iterator -- pointers to the beginning and
  3402. // the ending element plus one. If it succeeds, this method addrefs each
  3403. // element of ppterminals by querying for IDispatch.
  3404. //
  3405. hr = pCollection->Initialize( dwNumTerminals,
  3406. ppTerminals,
  3407. ppTerminals + dwNumTerminals );
  3408. //
  3409. // Release the ITTerminal reference to each terminal (leaving the
  3410. // IDispatch reference, if any). Then delete the array; the
  3411. // collection is now storing the pointers.
  3412. //
  3413. for (DWORD i = 0; i < dwNumTerminals; i++)
  3414. {
  3415. ppTerminals[i]->Release();
  3416. }
  3417. delete ppTerminals;
  3418. if (FAILED(hr))
  3419. {
  3420. LOG((MSP_ERROR, "CMSPAddress::get_StaticTerminals - "
  3421. "Initialize on collection failed - exit 0x%08x", hr));
  3422. pDispatch->Release();
  3423. return hr;
  3424. }
  3425. //
  3426. // put the IDispatch interface pointer into the variant
  3427. //
  3428. LOG((MSP_ERROR, "CMSPAddress::get_StaticTerminals - "
  3429. "placing IDispatch value %08x in variant", pDispatch));
  3430. VariantInit(pVariant);
  3431. pVariant->vt = VT_DISPATCH;
  3432. pVariant->pdispVal = pDispatch;
  3433. LOG((MSP_TRACE, "CMSPAddress::get_StaticTerminals - exit S_OK"));
  3434. return S_OK;
  3435. }
  3436. //////////////////////////////////////////////////////////////////////////////
  3437. //////////////////////////////////////////////////////////////////////////////
  3438. STDMETHODIMP CMSPAddress::EnumerateStaticTerminals (
  3439. OUT IEnumTerminal ** ppTerminalEnumerator
  3440. )
  3441. {
  3442. LOG((MSP_TRACE, "CMSPAddress::EnumerateStaticTerminals - "
  3443. "enter"));
  3444. //
  3445. // Check the return pointer.
  3446. //
  3447. if ( MSPB_IsBadWritePtr(ppTerminalEnumerator, sizeof(IEnumTerminal *) ) )
  3448. {
  3449. LOG((MSP_ERROR, "CMSPAddress::EnumerateStaticTerminals - "
  3450. "bad return pointer - exit E_POINTER"));
  3451. return E_POINTER;
  3452. }
  3453. //
  3454. // Create the enumerator object.
  3455. //
  3456. typedef _CopyInterface<ITTerminal> CCopy;
  3457. typedef CSafeComEnum<IEnumTerminal, &IID_IEnumTerminal,
  3458. ITTerminal *, CCopy> CEnumerator;
  3459. HRESULT hr;
  3460. CComObject<CEnumerator> *pEnum = NULL;
  3461. hr = CComObject<CEnumerator>::CreateInstance(&pEnum);
  3462. if ( FAILED(hr) )
  3463. {
  3464. LOG((MSP_ERROR, "CMSPAddress::EnumerateStaticTerminals - "
  3465. "can't create enumerator - exit 0x%08x", hr));
  3466. return hr;
  3467. }
  3468. //
  3469. // Query for the desired interface.
  3470. //
  3471. hr = pEnum->_InternalQueryInterface(IID_IEnumTerminal,
  3472. (void**) ppTerminalEnumerator);
  3473. if ( FAILED(hr) )
  3474. {
  3475. LOG((MSP_ERROR, "CMSPAddress::EnumerateStaticTerminals - "
  3476. "can't get enumerator interface - exit 0x%08x", hr));
  3477. delete pEnum;
  3478. return hr;
  3479. }
  3480. //
  3481. // Find out how many terminals are available.
  3482. //
  3483. DWORD dwNumTerminals;
  3484. hr = GetStaticTerminals(&dwNumTerminals,
  3485. NULL);
  3486. if ( FAILED(hr) )
  3487. {
  3488. LOG((MSP_ERROR, "CMSPAddress::EnumerateStaticTerminals - "
  3489. "can't get number of terminals - exit 0x%08x", hr));
  3490. (*ppTerminalEnumerator)->Release();
  3491. return hr;
  3492. }
  3493. //
  3494. // Allocate an array of terminal pointers.
  3495. //
  3496. typedef ITTerminal * TermPtr;
  3497. TermPtr * ppTerminals = new TermPtr[dwNumTerminals];
  3498. if ( ppTerminals == NULL )
  3499. {
  3500. LOG((MSP_ERROR, "CMSPAddress::EnumerateStaticTerminals - "
  3501. "can't allocate terminals array - exit E_OUTOFMEMORY"));
  3502. (*ppTerminalEnumerator)->Release();
  3503. return E_OUTOFMEMORY;
  3504. }
  3505. //
  3506. // Fill in the array with actual pointers. We must do this before
  3507. // initializing the enumerator, because the enumerator may want to
  3508. // addref the interface pointers during initialize.
  3509. //
  3510. hr = GetStaticTerminals(&dwNumTerminals,
  3511. ppTerminals);
  3512. if ( FAILED(hr) )
  3513. {
  3514. LOG((MSP_ERROR, "CMSPAddress::EnumerateStaticTerminals - "
  3515. "can't get terminals - exit 0x%08x", hr));
  3516. (*ppTerminalEnumerator)->Release();
  3517. delete ppTerminals;
  3518. return hr;
  3519. }
  3520. //
  3521. // Initialize the object with the array of pointers.
  3522. //
  3523. hr = pEnum->Init(ppTerminals,
  3524. ppTerminals + dwNumTerminals,
  3525. NULL,
  3526. AtlFlagTakeOwnership);
  3527. if (FAILED(hr))
  3528. {
  3529. LOG((MSP_ERROR, "CMSPCallBase::EnumerateStaticTerminals - "
  3530. "init enumerator failed - exit 0x%08x", hr));
  3531. for (DWORD i = 0; i < dwNumTerminals; i++)
  3532. {
  3533. ppTerminals[i]->Release();
  3534. }
  3535. delete ppTerminals;
  3536. (*ppTerminalEnumerator)->Release();
  3537. return hr;
  3538. }
  3539. LOG((MSP_TRACE, "CMSPAddress::EnumerateStaticTerminals - exit S_OK"));
  3540. return S_OK;
  3541. }
  3542. //////////////////////////////////////////////////////////////////////////////
  3543. //////////////////////////////////////////////////////////////////////////////
  3544. STDMETHODIMP CMSPAddress::get_DynamicTerminalClasses (
  3545. OUT VARIANT * pVariant
  3546. )
  3547. {
  3548. LOG((MSP_TRACE, "CMSPAddress::get_DynamicTerminalClasses - enter"));
  3549. //
  3550. // Check parameters.
  3551. //
  3552. if ( MSPB_IsBadWritePtr(pVariant, sizeof(VARIANT) ) )
  3553. {
  3554. LOG((MSP_ERROR, "CMSPAddress::get_DynamicTerminalClasses - "
  3555. "bad pointer argument - exit E_POINTER"));
  3556. return E_POINTER;
  3557. }
  3558. //
  3559. // create the collection object - see mspcoll.h
  3560. //
  3561. CComObject<CTapiBstrCollection> * pCollection;
  3562. HRESULT hr = CComObject<CTapiBstrCollection>::CreateInstance( &pCollection );
  3563. if ( FAILED(hr) )
  3564. {
  3565. LOG((MSP_ERROR, "CMSPAddress::get_DynamicTerminalClasses - "
  3566. "can't create collection - exit 0x%08x", hr));
  3567. return hr;
  3568. }
  3569. //
  3570. // get the Collection's IDispatch interface
  3571. //
  3572. IDispatch * pDispatch;
  3573. hr = pCollection->_InternalQueryInterface(IID_IDispatch,
  3574. (void **) &pDispatch );
  3575. if ( FAILED(hr) )
  3576. {
  3577. LOG((MSP_ERROR, "CMSPAddress::get_DynamicTerminalClasses - "
  3578. "QI for IDispatch on collection failed - exit 0x%08x", hr));
  3579. delete pCollection;
  3580. return hr;
  3581. }
  3582. //
  3583. // Find out how many terminals classes are available.
  3584. //
  3585. DWORD dwNumClasses;
  3586. hr = GetDynamicTerminalClasses(&dwNumClasses,
  3587. NULL);
  3588. if ( FAILED(hr) )
  3589. {
  3590. LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - "
  3591. "can't get number of terminal classes - exit 0x%08x", hr));
  3592. pDispatch->Release();
  3593. return hr;
  3594. }
  3595. //
  3596. // Allocate an array of GUIDs.
  3597. //
  3598. IID * pClassGuids = new IID[dwNumClasses];
  3599. if ( pClassGuids == NULL )
  3600. {
  3601. LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - "
  3602. "can't allocate class guids array - exit E_OUTOFMEMORY"));
  3603. pDispatch->Release();
  3604. return E_OUTOFMEMORY;
  3605. }
  3606. //
  3607. // Fill in the array with actual pointers.
  3608. //
  3609. hr = GetDynamicTerminalClasses(&dwNumClasses,
  3610. pClassGuids);
  3611. if ( FAILED(hr) )
  3612. {
  3613. LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - "
  3614. "can't get terminal class guids - exit 0x%08x", hr));
  3615. pDispatch->Release();
  3616. delete pClassGuids;
  3617. return hr;
  3618. }
  3619. //
  3620. // Allocate an array of BSTRs.
  3621. //
  3622. BSTR * pClassBstrs = new BSTR[dwNumClasses];
  3623. if ( pClassBstrs == NULL )
  3624. {
  3625. LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - "
  3626. "can't allocate class bstrs array - exit E_OUTOFMEMORY"));
  3627. pDispatch->Release();
  3628. delete pClassGuids;
  3629. return E_OUTOFMEMORY;
  3630. }
  3631. //
  3632. // Allocate a string for each GUID and copy it to the array,
  3633. // then delete the array of GUIDs.
  3634. //
  3635. const int BUFSIZE = 100;
  3636. WCHAR wszBuffer[BUFSIZE];
  3637. for (DWORD i = 0; i < dwNumClasses; i++)
  3638. {
  3639. int ret = StringFromGUID2(pClassGuids[i], wszBuffer, BUFSIZE);
  3640. _ASSERTE(ret != 0);
  3641. pClassBstrs[i] = SysAllocString(wszBuffer);
  3642. if ( pClassBstrs[i] == NULL )
  3643. {
  3644. LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - "
  3645. "can't allocate a bstr - exit E_OUTOFMEMORY"));
  3646. for (DWORD j = 0; j < i; j++)
  3647. {
  3648. SysFreeString(pClassBstrs[j]);
  3649. }
  3650. delete pClassBstrs;
  3651. delete pClassGuids;
  3652. pDispatch->Release();
  3653. return E_OUTOFMEMORY;
  3654. }
  3655. }
  3656. delete pClassGuids;
  3657. //
  3658. // Init the collection using an iterator -- pointers to the beginning and
  3659. // the ending element plus one.
  3660. //
  3661. hr = pCollection->Initialize( dwNumClasses,
  3662. pClassBstrs,
  3663. pClassBstrs + dwNumClasses );
  3664. if ( FAILED(hr) )
  3665. {
  3666. LOG((MSP_ERROR, "CMSPAddress::get_DynamicTerminalClasses - "
  3667. "Initialize on collection failed - exit 0x%08x", hr));
  3668. pDispatch->Release();
  3669. for (DWORD k = 0; k < dwNumClasses; k++)
  3670. {
  3671. SysFreeString(pClassBstrs[k]);
  3672. }
  3673. delete pClassBstrs;
  3674. return hr;
  3675. }
  3676. delete pClassBstrs;
  3677. //
  3678. // put the IDispatch interface pointer into the variant
  3679. //
  3680. LOG((MSP_ERROR, "CMSPAddress::get_DynamicTerminalClasses - "
  3681. "placing IDispatch value %08x in variant", pDispatch));
  3682. VariantInit(pVariant);
  3683. pVariant->vt = VT_DISPATCH;
  3684. pVariant->pdispVal = pDispatch;
  3685. LOG((MSP_TRACE, "CMSPAddress::get_DynamicTerminalClasses - exit S_OK"));
  3686. return S_OK;
  3687. }
  3688. //////////////////////////////////////////////////////////////////////////////
  3689. //////////////////////////////////////////////////////////////////////////////
  3690. STDMETHODIMP CMSPAddress::EnumerateDynamicTerminalClasses (
  3691. OUT IEnumTerminalClass ** ppTerminalClassEnumerator
  3692. )
  3693. {
  3694. LOG((MSP_TRACE, "CMSPAddress::EnumerateDynamicTerminalClasses - enter"));
  3695. //
  3696. // Check the return pointer.
  3697. //
  3698. if ( MSPB_IsBadWritePtr(ppTerminalClassEnumerator,
  3699. sizeof(IEnumTerminalClass *) ) )
  3700. {
  3701. LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - "
  3702. "bad return pointer - exit E_POINTER"));
  3703. return E_POINTER;
  3704. }
  3705. //
  3706. // Find out how many terminals classes are available.
  3707. //
  3708. HRESULT hr;
  3709. DWORD dwNumClasses;
  3710. hr = GetDynamicTerminalClasses(&dwNumClasses,
  3711. NULL);
  3712. if ( FAILED(hr) )
  3713. {
  3714. LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - "
  3715. "can't get number of terminal classes - exit 0x%08x", hr));
  3716. return hr;
  3717. }
  3718. //
  3719. // Allocate an array of GUIDs.
  3720. //
  3721. IID * pClassGuids = new IID[dwNumClasses];
  3722. if ( pClassGuids == NULL )
  3723. {
  3724. LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - "
  3725. "can't allocate class guids array - exit E_OUTOFMEMORY"));
  3726. return E_OUTOFMEMORY;
  3727. }
  3728. //
  3729. // Fill in the array with actual pointers.
  3730. //
  3731. hr = GetDynamicTerminalClasses(&dwNumClasses,
  3732. pClassGuids);
  3733. if ( FAILED(hr) )
  3734. {
  3735. LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - "
  3736. "can't get terminal class guids - exit 0x%08x", hr));
  3737. delete pClassGuids;
  3738. return hr;
  3739. }
  3740. //
  3741. // Create an enumerator to hold this array, and have it take ownership
  3742. // so that it will delete the array when it is released. The CSafeComEnum
  3743. // can handle zero-length arrays. This Fn also checks the return arg.
  3744. //
  3745. //
  3746. // Create the enumerator object.
  3747. //
  3748. typedef CSafeComEnum<IEnumTerminalClass,
  3749. &IID_IEnumTerminalClass,
  3750. GUID, _Copy<GUID> > CEnumerator;
  3751. CComObject<CEnumerator> *pEnum = NULL;
  3752. hr = CComObject<CEnumerator>::CreateInstance(&pEnum);
  3753. if ( FAILED(hr) )
  3754. {
  3755. LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - "
  3756. "can't create enumerator - exit 0x%08x", hr));
  3757. delete pClassGuids;
  3758. return hr;
  3759. }
  3760. //
  3761. // Query for the desired interface.
  3762. //
  3763. hr = pEnum->_InternalQueryInterface(IID_IEnumTerminalClass,
  3764. (void**) ppTerminalClassEnumerator);
  3765. if ( FAILED(hr) )
  3766. {
  3767. LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - "
  3768. "can't get enumerator interface - exit 0x%08x", hr));
  3769. delete pEnum;
  3770. delete pClassGuids;
  3771. return hr;
  3772. }
  3773. //
  3774. // Init the enumerator object.
  3775. //
  3776. hr = pEnum->Init(pClassGuids,
  3777. pClassGuids + dwNumClasses,
  3778. NULL,
  3779. AtlFlagTakeOwnership);
  3780. if ( FAILED(hr) )
  3781. {
  3782. LOG((MSP_ERROR, "CMSPAddress::EnumerateDynamicTerminalClasses - "
  3783. "can't init enumerator - exit 0x%08x", hr));
  3784. (*ppTerminalClassEnumerator)->Release();
  3785. delete pClassGuids;
  3786. return hr;
  3787. }
  3788. LOG((MSP_TRACE, "CMSPAddress::EnumerateDynamicTerminalClasses - exit S_OK"));
  3789. return S_OK;
  3790. }
  3791. HRESULT CMSPAddress::ReceiveTSPAddressData(
  3792. IN PBYTE pBuffer,
  3793. IN DWORD dwSize
  3794. )
  3795. /*++
  3796. Routine Description:
  3797. Base class receive TSP address data method... does nothing in base class.
  3798. Implemented so that MSP's that only communicate per-call don't have
  3799. to override it.
  3800. Arguments:
  3801. Return Value:
  3802. S_OK
  3803. --*/
  3804. {
  3805. LOG((MSP_TRACE, "CMSPAddress::ReceiveTSPAddressData - enter"));
  3806. LOG((MSP_TRACE, "CMSPAddress::ReceiveTSPAddressData - exit S_OK"));
  3807. return S_OK;
  3808. }
  3809. HRESULT CMSPAddress::PnpNotifHandler(
  3810. IN BOOL bDeviceArrival
  3811. )
  3812. {
  3813. LOG((MSP_TRACE, "CMSPAddress::PnpNotifHandler - enter"));
  3814. if (bDeviceArrival)
  3815. LOG((MSP_TRACE, "CMSPAddress::PnpNotifHandler - device arrival"));
  3816. else
  3817. LOG((MSP_TRACE, "CMSPAddress::PnpNotifHandler - device removal"));
  3818. // lock the terminal related data. This is a auto lock that will unlock
  3819. // when the function returns.
  3820. CLock lock(m_TerminalDataLock);
  3821. // if the terminal list hasn't been built yet, we can skip doing anything
  3822. if (m_fTerminalsUpToDate)
  3823. {
  3824. HRESULT hr = UpdateTerminalListForPnp( bDeviceArrival );
  3825. if (FAILED(hr))
  3826. {
  3827. LOG((MSP_ERROR,
  3828. "CMSPAddress::PnpNotifHandler - "
  3829. "UpdateTerminalList failed - returning 0x%08x", hr));
  3830. return hr;
  3831. }
  3832. }
  3833. LOG((MSP_TRACE, "CMSPAddress::PnpNotifHandler - exit S_OK"));
  3834. return S_OK;
  3835. }
  3836. // eof