Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

895 lines
19 KiB

  1. /*++
  2. Copyright (c) 1997 - 1999 Microsoft Corporation
  3. Module Name:
  4. terminal.cpp
  5. Abstract:
  6. Implementation of terminals object for TAPI 3.0, that are
  7. not handled by the terminal manager.
  8. currently there are these terminals:
  9. phone
  10. Audio in and Audio out terminal associated with a phone device.
  11. Each phone device can have up to 3 types of devices -
  12. handset, headset, and speakerphone. So, a single phone device
  13. can have 6 associated terminals!
  14. Author:
  15. mquinton - 4/17/97
  16. Notes:
  17. optional-notes
  18. Revision History:
  19. --*/
  20. #include "stdafx.h"
  21. HRESULT
  22. WaitForPhoneReply(
  23. DWORD dwID
  24. );
  25. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  26. //
  27. // CTerminal is the base terminal object that all other terminals are
  28. // derived from. It implements the ITTerminal methods.
  29. //
  30. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  31. //
  32. // ITTerminal methods
  33. //
  34. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  35. //
  36. // get_Name
  37. // Alloc and copy the name. The app is responsible for
  38. // freeing
  39. //
  40. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  41. STDMETHODIMP
  42. CTerminal::get_Name(
  43. BSTR * ppName
  44. )
  45. {
  46. LOG((TL_TRACE, "get_Name - enter" ));
  47. if (TAPIIsBadWritePtr( ppName, sizeof (BSTR) ) )
  48. {
  49. LOG((TL_ERROR, "getName - bad pointer"));
  50. return E_POINTER;
  51. }
  52. Lock();
  53. *ppName = SysAllocString( m_pName );
  54. Unlock();
  55. if ( ( NULL == *ppName ) && ( NULL != m_pName ) )
  56. {
  57. LOG((TL_ERROR, "get_Name - SysAllocString Failed" ));
  58. return E_OUTOFMEMORY;
  59. }
  60. LOG((TL_TRACE, "get_Name - exit - return S_OK" ));
  61. return S_OK;
  62. }
  63. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  64. //
  65. // get_State
  66. //
  67. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  68. STDMETHODIMP
  69. CTerminal::get_State(
  70. TERMINAL_STATE * pTerminalState
  71. )
  72. {
  73. LOG((TL_TRACE, "get_State - enter" ));
  74. if (TAPIIsBadWritePtr( pTerminalState, sizeof(TERMINAL_STATE) ) )
  75. {
  76. LOG((TL_ERROR, "get_State - bad pointer"));
  77. return E_POINTER;
  78. }
  79. Lock();
  80. *pTerminalState = m_State;
  81. Unlock();
  82. LOG((TL_TRACE, "get_State - exit - return SUCCESS" ));
  83. return S_OK;
  84. }
  85. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  86. //
  87. // get_TerminalType
  88. // By definition, TAPI terminals are static
  89. //
  90. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  91. STDMETHODIMP
  92. CTerminal::get_TerminalType(
  93. TERMINAL_TYPE * pType
  94. )
  95. {
  96. LOG((TL_TRACE, "get_TerminalType - enter" ));
  97. if ( TAPIIsBadWritePtr( pType, sizeof( TERMINAL_TYPE ) ) )
  98. {
  99. LOG((TL_ERROR, "get_TerminalType - bad pointer"));
  100. return E_POINTER;
  101. }
  102. Lock();
  103. *pType = m_TerminalType;
  104. Unlock();
  105. LOG((TL_TRACE, "get_TerminalType - exit - return S_OK" ));
  106. return S_OK;
  107. }
  108. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  109. //
  110. // get_TerminalClass
  111. //
  112. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  113. STDMETHODIMP
  114. CTerminal::get_TerminalClass(
  115. BSTR * pTerminalClass
  116. )
  117. {
  118. HRESULT hr = S_OK;
  119. CLSID clsid;
  120. LPWSTR pClass = NULL;
  121. LOG((TL_TRACE, "get_TerminalClass - enter" ));
  122. if ( TAPIIsBadWritePtr( pTerminalClass, sizeof( BSTR ) ) )
  123. {
  124. LOG((TL_ERROR, "get_TerminalClass - bad pointer"));
  125. return E_POINTER;
  126. }
  127. Lock();
  128. hr = StringFromIID(
  129. m_Class,
  130. &pClass
  131. );
  132. Unlock();
  133. if (S_OK != hr)
  134. {
  135. return hr;
  136. }
  137. *pTerminalClass = SysAllocString( pClass );
  138. if ( ( NULL == *pTerminalClass ) && ( NULL != pClass ) )
  139. {
  140. LOG((TL_ERROR, "get_TerminalClass - SysAllocString Failed" ));
  141. return E_OUTOFMEMORY;
  142. }
  143. CoTaskMemFree( pClass );
  144. LOG((TL_TRACE, "get_TerminalClass - exit - return SUCCESS" ));
  145. return S_OK;
  146. }
  147. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  148. //
  149. // get_MediaType
  150. //
  151. // returns the supported mediatype BSTR associated with this terminal.
  152. //
  153. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  154. STDMETHODIMP
  155. CTerminal::get_MediaType(
  156. long * plMediaType
  157. )
  158. {
  159. if ( TAPIIsBadWritePtr( plMediaType, sizeof(long) ) )
  160. {
  161. LOG((TL_ERROR, "get_MediaType - inval pointer"));
  162. return E_POINTER;
  163. }
  164. *plMediaType = m_lMediaType;
  165. return S_OK;
  166. }
  167. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  168. //
  169. // get_Direction
  170. //
  171. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  172. STDMETHODIMP
  173. CTerminal::get_Direction(
  174. TERMINAL_DIRECTION * pTerminalDirection
  175. )
  176. {
  177. if (TAPIIsBadWritePtr( pTerminalDirection, sizeof( TERMINAL_DIRECTION ) ) )
  178. {
  179. LOG((TL_ERROR, "get_Direction - bad pointer"));
  180. return E_POINTER;
  181. }
  182. Lock();
  183. *pTerminalDirection = m_Direction;
  184. Unlock();
  185. return S_OK;
  186. }
  187. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  188. //
  189. // GetTerminalNameFromPhoneCaps
  190. //
  191. // Creates a name for a phone device terminal based on the phone
  192. // caps
  193. //
  194. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  195. PWSTR
  196. GetTerminalNameFromPhoneCaps(
  197. LPPHONECAPS pPhoneCaps,
  198. DWORD dwHookSwitchDev,
  199. DWORD dwPhoneID
  200. )
  201. {
  202. PWSTR pszName;
  203. PWSTR pszHookSwitchDevName = NULL;
  204. //
  205. // load the appropriate string to describe
  206. // the hookswitch device
  207. //
  208. switch (dwHookSwitchDev)
  209. {
  210. case PHONEHOOKSWITCHDEV_SPEAKER:
  211. {
  212. pszHookSwitchDevName = MyLoadString( IDS_SPEAKERTERMINAL );
  213. break;
  214. }
  215. case PHONEHOOKSWITCHDEV_HANDSET:
  216. {
  217. pszHookSwitchDevName = MyLoadString( IDS_HANDSETTERMINAL );
  218. break;
  219. }
  220. case PHONEHOOKSWITCHDEV_HEADSET:
  221. {
  222. pszHookSwitchDevName = MyLoadString( IDS_HEADSETTERMINAL );
  223. break;
  224. }
  225. default:
  226. {
  227. return NULL;
  228. }
  229. }
  230. if ( NULL == pszHookSwitchDevName )
  231. {
  232. return NULL;
  233. }
  234. //
  235. // if the sp supplies a name, use it
  236. //
  237. if ( 0 != pPhoneCaps->dwPhoneNameSize )
  238. {
  239. pszName = (PWSTR) ClientAlloc(
  240. ( pPhoneCaps->dwPhoneNameSize +
  241. lstrlenW( pszHookSwitchDevName ) +
  242. 32 ) * sizeof(WCHAR)
  243. );
  244. if (NULL == pszName)
  245. {
  246. ClientFree( pszHookSwitchDevName );
  247. return NULL;
  248. }
  249. CopyMemory(
  250. pszName,
  251. ( ( (LPBYTE)pPhoneCaps ) + pPhoneCaps->dwPhoneNameOffset ),
  252. pPhoneCaps->dwPhoneNameSize
  253. );
  254. }
  255. else
  256. {
  257. PWSTR pszTempName;
  258. //
  259. // else create a name
  260. //
  261. pszTempName = MyLoadString( IDS_PHONEDEVICE );
  262. if ( NULL == pszTempName )
  263. {
  264. ClientFree( pszHookSwitchDevName );
  265. return NULL;
  266. }
  267. pszName = (PWSTR) ClientAlloc(
  268. (lstrlenW( pszTempName ) +
  269. lstrlenW( pszHookSwitchDevName ) +
  270. 32 ) * sizeof(WCHAR)
  271. );
  272. if (NULL == pszName)
  273. {
  274. ClientFree( pszHookSwitchDevName );
  275. ClientFree( pszTempName );
  276. return NULL;
  277. }
  278. wsprintfW(
  279. pszName,
  280. L"%s %d",
  281. pszTempName,
  282. dwPhoneID
  283. );
  284. ClientFree( pszTempName );
  285. }
  286. //
  287. // put them together
  288. //
  289. lstrcatW(
  290. pszName,
  291. L" - "
  292. );
  293. lstrcatW(
  294. pszName,
  295. pszHookSwitchDevName
  296. );
  297. ClientFree( pszHookSwitchDevName );
  298. return pszName;
  299. }
  300. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  301. //
  302. // CTerminal::Create
  303. //
  304. // Static function to create an audio in terminal related to a phone
  305. // device.
  306. //
  307. // pAddress
  308. // Owning address
  309. //
  310. // dwPhoneID
  311. // tapi 2 phone device ID related to this terminal
  312. //
  313. // pPhoneCaps
  314. // PHONEDEVCAPS of the phone device
  315. //
  316. // dwHookSwitchDev
  317. // PHONEHOOKSWITCHDEV_ bit of this phone device
  318. //
  319. // ppTerminal
  320. // return the terminal here!
  321. //
  322. //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  323. HRESULT
  324. CTerminal::Create(
  325. HPHONEAPP hPhoneApp,
  326. DWORD dwPhoneID,
  327. LPPHONECAPS pPhoneCaps,
  328. DWORD dwHookSwitchDev,
  329. TERMINAL_DIRECTION td,
  330. DWORD dwAPIVersion,
  331. ITTerminal ** ppTerminal
  332. )
  333. {
  334. HRESULT hr = S_OK;
  335. CComObject< CTerminal > * p;
  336. //
  337. // create CTerminal
  338. //
  339. hr = CComObject< CTerminal >::CreateInstance( &p );
  340. if (!SUCCEEDED(hr))
  341. {
  342. LOG((TL_ERROR, "CreateInstance for Phone failed - %lx", hr));
  343. return hr;
  344. }
  345. //
  346. // save stuff
  347. //
  348. p->m_dwHookSwitchDev = dwHookSwitchDev;
  349. p->m_dwPhoneID = dwPhoneID;
  350. p->m_hPhoneApp = hPhoneApp;
  351. p->m_Direction = td;
  352. p->m_dwAPIVersion = dwAPIVersion;
  353. //
  354. // class depends on which hookswitchdev this is
  355. //
  356. switch( dwHookSwitchDev )
  357. {
  358. case PHONEHOOKSWITCHDEV_HANDSET:
  359. p->m_Class = CLSID_HandsetTerminal;
  360. break;
  361. case PHONEHOOKSWITCHDEV_HEADSET:
  362. p->m_Class = CLSID_HeadsetTerminal;
  363. break;
  364. case PHONEHOOKSWITCHDEV_SPEAKER:
  365. p->m_Class = CLSID_SpeakerphoneTerminal;
  366. break;
  367. default:
  368. break;
  369. }
  370. //
  371. // create a name
  372. //
  373. p->m_pName = GetTerminalNameFromPhoneCaps(
  374. pPhoneCaps,
  375. dwHookSwitchDev,
  376. dwPhoneID
  377. );
  378. //
  379. // return the created terminal
  380. //
  381. p->AddRef();
  382. *ppTerminal = p;
  383. #if DBG
  384. p->m_pDebug = (PWSTR) ClientAlloc( 1 );
  385. #endif
  386. return S_OK;
  387. }
  388. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  389. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  390. STDMETHODIMP
  391. CTerminal::get_Gain(long *pVal)
  392. {
  393. HRESULT hr;
  394. ITPhoneMSPCallPrivate * pMSPCall;
  395. LOG((TL_TRACE, "get_Gain - Enter"));
  396. if ( TAPIIsBadWritePtr( pVal, sizeof(LONG) ) )
  397. {
  398. LOG((TL_ERROR, "get_Gain - bad pointer"));
  399. return E_POINTER;
  400. }
  401. Lock();
  402. if ( NULL == m_pMSPCall )
  403. {
  404. Unlock();
  405. return TAPI_E_NOTERMINALSELECTED;
  406. }
  407. pMSPCall = m_pMSPCall;
  408. pMSPCall->AddRef();
  409. Unlock();
  410. hr = pMSPCall->GetGain( pVal, m_dwHookSwitchDev );
  411. pMSPCall->Release();
  412. LOG((TL_TRACE, "get_Gain - Exit - return %lx", hr));
  413. return hr;
  414. }
  415. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  416. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  417. STDMETHODIMP
  418. CTerminal::put_Gain(long newVal)
  419. {
  420. HRESULT hr;
  421. ITPhoneMSPCallPrivate * pMSPCall;
  422. LOG((TL_TRACE, "put_Gain - Enter"));
  423. Lock();
  424. if ( NULL == m_pMSPCall )
  425. {
  426. Unlock();
  427. return TAPI_E_NOTERMINALSELECTED;
  428. }
  429. pMSPCall = m_pMSPCall;
  430. pMSPCall->AddRef();
  431. Unlock();
  432. hr = pMSPCall->PutGain( newVal, m_dwHookSwitchDev );
  433. pMSPCall->Release();
  434. LOG((TL_TRACE, "put_Gain - Exit - return %lx", hr));
  435. return hr;
  436. }
  437. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  438. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  439. STDMETHODIMP
  440. CTerminal::get_Balance(long *pVal)
  441. {
  442. LOG((TL_TRACE, "get_Balance - Enter"));
  443. LOG((TL_TRACE, "get_Balance - Exit - return TAPI_E_NOTSUPPORTED"));
  444. // not suppported
  445. return TAPI_E_NOTSUPPORTED;
  446. }
  447. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  448. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  449. STDMETHODIMP
  450. CTerminal::put_Balance(long newVal)
  451. {
  452. LOG((TL_TRACE, "put_Balance - Enter"));
  453. LOG((TL_TRACE, "put_Balance - Exit - return TAPI_E_NOTSUPPORTED"));
  454. // not supported
  455. return TAPI_E_NOTSUPPORTED;
  456. }
  457. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  458. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  459. STDMETHODIMP
  460. CTerminal::get_Volume(long *pVal)
  461. {
  462. HRESULT hr;
  463. ITPhoneMSPCallPrivate * pMSPCall;
  464. LOG((TL_TRACE, "get_Volume - Enter"));
  465. if ( TAPIIsBadWritePtr( pVal, sizeof( long ) ) )
  466. {
  467. LOG((TL_ERROR, "get_Volume - bad pointer"));
  468. return E_POINTER;
  469. }
  470. Lock();
  471. if ( NULL == m_pMSPCall )
  472. {
  473. Unlock();
  474. return TAPI_E_NOTERMINALSELECTED;
  475. }
  476. pMSPCall = m_pMSPCall;
  477. pMSPCall->AddRef();
  478. Unlock();
  479. hr = pMSPCall->GetVolume( pVal, m_dwHookSwitchDev );
  480. pMSPCall->Release();
  481. LOG((TL_TRACE, "get_Volume - Exit - return %lx", hr));
  482. return hr;
  483. }
  484. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  485. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  486. STDMETHODIMP
  487. CTerminal::put_Volume(long newVal)
  488. {
  489. HRESULT hr;
  490. ITPhoneMSPCallPrivate * pMSPCall;
  491. LOG((TL_TRACE, "put_Volume - Enter"));
  492. Lock();
  493. if ( NULL == m_pMSPCall )
  494. {
  495. Unlock();
  496. return TAPI_E_NOTERMINALSELECTED;
  497. }
  498. pMSPCall = m_pMSPCall;
  499. pMSPCall->AddRef();
  500. Unlock();
  501. hr = pMSPCall->PutVolume( newVal, m_dwHookSwitchDev );
  502. pMSPCall->Release();
  503. LOG((TL_TRACE, "put_Volume - Exit - return %lx", hr));
  504. return hr;
  505. }
  506. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  507. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  508. STDMETHODIMP
  509. CTerminal::GetHookSwitchDev(DWORD * pdwHookSwitchDev)
  510. {
  511. Lock();
  512. *pdwHookSwitchDev = m_dwHookSwitchDev;
  513. Unlock();
  514. return S_OK;
  515. }
  516. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  517. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  518. STDMETHODIMP
  519. CTerminal::GetPhoneID(DWORD * pdwPhoneID)
  520. {
  521. Lock();
  522. *pdwPhoneID = m_dwPhoneID;
  523. Unlock();
  524. return S_OK;
  525. }
  526. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  527. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  528. STDMETHODIMP
  529. CTerminal::GetHPhoneApp(HPHONEAPP * phPhoneApp)
  530. {
  531. Lock();
  532. *phPhoneApp = m_hPhoneApp;
  533. Unlock();
  534. return S_OK;
  535. }
  536. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  537. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  538. STDMETHODIMP
  539. CTerminal::GetAPIVersion(DWORD * pdwAPIVersion)
  540. {
  541. Lock();
  542. *pdwAPIVersion = m_dwAPIVersion;
  543. Unlock();
  544. return S_OK;
  545. }
  546. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  547. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  548. STDMETHODIMP
  549. CTerminal::SetMSPCall(ITPhoneMSPCallPrivate * pPhoneMSPCall)
  550. {
  551. Lock();
  552. m_pMSPCall = pPhoneMSPCall;
  553. if ( NULL != m_pMSPCall )
  554. {
  555. m_State = TS_INUSE;
  556. }
  557. else
  558. {
  559. m_State = TS_NOTINUSE;
  560. }
  561. Unlock();
  562. return S_OK;
  563. }
  564. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  565. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  566. void
  567. CTerminal::FinalRelease()
  568. {
  569. if (NULL != m_pName)
  570. {
  571. ClientFree( m_pName );
  572. }
  573. #if DBG
  574. if( m_pDebug != NULL )
  575. {
  576. ClientFree( m_pDebug );
  577. m_pDebug = NULL;
  578. }
  579. #endif
  580. }
  581. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  582. //
  583. // CreateTerminalName
  584. //
  585. // Creates a terminal name for
  586. //
  587. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  588. PWSTR
  589. CreateTerminalName(
  590. CAddress * pAddress,
  591. DWORD dwType,
  592. long lMediaType
  593. )
  594. {
  595. PWSTR pName;
  596. WCHAR szTerminal[256];
  597. WCHAR szMediaType[256];
  598. DWORD dwSize;
  599. //
  600. // create the name
  601. //
  602. // first load the string "Terminal"
  603. //
  604. szTerminal[0] = L'\0';
  605. szMediaType[0] = L'\0';
  606. ::LoadStringW(_Module.GetResourceInstance(), IDS_TERMINAL, szTerminal, 256);
  607. dwSize = lstrlenW( szTerminal ) * sizeof (WCHAR);
  608. switch (dwType)
  609. {
  610. case 0:
  611. break;
  612. case 1:
  613. if ( LINEMEDIAMODE_DATAMODEM == lMediaType)
  614. {
  615. ::LoadStringW(_Module.GetResourceInstance(), IDS_DATAMODEM, szMediaType, 256);
  616. }
  617. else if ( LINEMEDIAMODE_G3FAX == lMediaType)
  618. {
  619. ::LoadStringW(_Module.GetResourceInstance(), IDS_G3FAX, szMediaType, 256);
  620. }
  621. dwSize += (lstrlenW( szMediaType ) * sizeof ( WCHAR ));
  622. break;
  623. default:
  624. break;
  625. }
  626. //
  627. // alloc enough memory for the name
  628. //
  629. dwSize += (lstrlenW( pAddress->GetAddressName() ) * sizeof(WCHAR));
  630. dwSize += 32;
  631. pName = (PWSTR) ClientAlloc( dwSize );
  632. if (NULL == pName)
  633. {
  634. return NULL;
  635. }
  636. //
  637. // terminal name should look like:
  638. // "<addressname> (mediatype) Terminal"
  639. //
  640. lstrcpyW(
  641. pName,
  642. pAddress->GetAddressName()
  643. );
  644. lstrcatW(
  645. pName,
  646. L" "
  647. );
  648. if (dwType == 1)
  649. {
  650. lstrcatW(
  651. pName,
  652. szMediaType
  653. );
  654. lstrcatW(
  655. pName,
  656. L" "
  657. );
  658. }
  659. lstrcatW(
  660. pName,
  661. szTerminal
  662. );
  663. return pName;
  664. }