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.

545 lines
16 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dpvacmi.cpp
  6. * Content: Definition of object which implements ACM compression provider interface
  7. *
  8. * History:
  9. * Date By Reason
  10. * =========== =========== ====================
  11. * 10/27/99 rodtoll created
  12. * 12/16/99 rodtoll Bug #123250 - Insert proper names/descriptions for codecs
  13. * Codec names now based on resource entries for format and
  14. * names are constructed using ACM names + bitrate
  15. * 01/20/00 rodtoll Removed dplay reference (DPERR_OUTOFMEMORY)
  16. * 03/03/2000 rodtoll Updated to handle alternative gamevoice build.
  17. * 03/16/2000 rodtoll Fixed problem w/GameVoice build -- always loaded dvoice provider
  18. * 04/21/2000 rodtoll Bug #32889 - Does not run on Win2k on non-admin account
  19. * 06/09/00 rmt Updates to split CLSID and allow whistler compat and support external create funcs
  20. * 08/28/2000 masonb Voice Merge: Removed OSAL_* and dvosal.h added STR_* and strutils.h
  21. * 08/31/2000 rodtoll Whistler Bug #171837, 171838 - Prefix Bug
  22. * 04/22/2001 rodtoll MANBUG #50058 DPVOICE: VoicePosition: No sound for couple of seconds when
  23. * positioning bars moved. Increased # of frames / buffer value for codecs.
  24. * 02/25/2002 rodtoll WINBUG #550063: Potential DOS by forcing server to allocate excessive amounts of memory.
  25. * Reduced upper bounds on individual sub-queues to 32 messages from 64.
  26. * rodtoll WINBUG #552283: Reduce attack surface / dead code removal
  27. * Removed ability to load arbitrary ACM codecs.
  28. *
  29. ***************************************************************************/
  30. #include "dpvacmpch.h"
  31. #define DPVACM_NUM_DEFAULT_TYPES 4
  32. BYTE abTrueSpeechData[] = {
  33. 0x01, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00,
  34. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  35. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  36. 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  37. };
  38. BYTE abGSMData[] = {
  39. 0x40, 0x01
  40. };
  41. BYTE abADPCMData[] = {
  42. 0xF4, 0x01, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00,
  43. 0x00, 0x02, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
  44. 0xC0, 0x00, 0x40, 0x00, 0xF0, 0x00, 0x00, 0x00,
  45. 0xCC, 0x01, 0x30, 0xFF, 0x88, 0x01, 0x18, 0xFF
  46. };
  47. VOID *s_pvExtras[DPVACM_NUM_DEFAULT_TYPES] = {
  48. &abTrueSpeechData,
  49. &abGSMData,
  50. &abADPCMData,
  51. NULL
  52. };
  53. WAVEFORMATEX s_wfxFormats[DPVACM_NUM_DEFAULT_TYPES] =
  54. {
  55. // Tag, Chan, SamS, Avg, Align, Bits, size
  56. { 34, 0x01, 8000, 1067, 32, 1, sizeof( abTrueSpeechData ) },
  57. { 49, 0x01, 8000, 1625, 65, 0, sizeof( abGSMData ) },
  58. { 2, 0x01, 8000, 4096, 256, 4, sizeof( abADPCMData ) },
  59. { 1, 0x01, 8000, 8000, 1, 8, 0 }
  60. };
  61. DVFULLCOMPRESSIONINFO s_dvInfoDefault[DPVACM_NUM_DEFAULT_TYPES] =
  62. {
  63. { sizeof( DVFULLCOMPRESSIONINFO ), DPVCTGUID_TRUESPEECH.Data1, DPVCTGUID_TRUESPEECH.Data2, DPVCTGUID_TRUESPEECH.Data3,
  64. DPVCTGUID_TRUESPEECH.Data4[0], DPVCTGUID_TRUESPEECH.Data4[1], DPVCTGUID_TRUESPEECH.Data4[2], DPVCTGUID_TRUESPEECH.Data4[3],
  65. DPVCTGUID_TRUESPEECH.Data4[4], DPVCTGUID_TRUESPEECH.Data4[5], DPVCTGUID_TRUESPEECH.Data4[6], DPVCTGUID_TRUESPEECH.Data4[7],
  66. NULL, NULL, 0, 8536, NULL, 12, 1, 90, 96, 720, 993, 1986, 3972, 32, 22, 10, 1, 0, 0 },
  67. { sizeof( DVFULLCOMPRESSIONINFO ), DPVCTGUID_GSM.Data1, DPVCTGUID_GSM.Data2, DPVCTGUID_GSM.Data3,
  68. DPVCTGUID_GSM.Data4[0], DPVCTGUID_GSM.Data4[1], DPVCTGUID_GSM.Data4[2], DPVCTGUID_GSM.Data4[3],
  69. DPVCTGUID_GSM.Data4[4], DPVCTGUID_GSM.Data4[5], DPVCTGUID_GSM.Data4[6], DPVCTGUID_GSM.Data4[7],
  70. NULL, NULL, 0, 13000, NULL, 13, 1, 80, 130, 640, 882, 1764, 3528, 32, 24, 10, 1, 0, 0 },
  71. { sizeof( DVFULLCOMPRESSIONINFO ), DPVCTGUID_ADPCM.Data1, DPVCTGUID_ADPCM.Data2, DPVCTGUID_ADPCM.Data3,
  72. DPVCTGUID_ADPCM.Data4[0], DPVCTGUID_ADPCM.Data4[1], DPVCTGUID_ADPCM.Data4[2], DPVCTGUID_ADPCM.Data4[3],
  73. DPVCTGUID_ADPCM.Data4[4], DPVCTGUID_ADPCM.Data4[5], DPVCTGUID_ADPCM.Data4[6], DPVCTGUID_ADPCM.Data4[7],
  74. NULL, NULL, 0, 32768, NULL, 15, 1, 63, 256, 500, 690, 1380, 2760, 32, 31, 10, 1, 0, 0 },
  75. { sizeof( DVFULLCOMPRESSIONINFO ), DPVCTGUID_NONE.Data1, DPVCTGUID_NONE.Data2, DPVCTGUID_NONE.Data3,
  76. DPVCTGUID_NONE.Data4[0], DPVCTGUID_NONE.Data4[1], DPVCTGUID_NONE.Data4[2], DPVCTGUID_NONE.Data4[3],
  77. DPVCTGUID_NONE.Data4[4], DPVCTGUID_NONE.Data4[5], DPVCTGUID_NONE.Data4[6], DPVCTGUID_NONE.Data4[7],
  78. NULL, NULL, 0, 64000, NULL, 20, 1, 50, 394, 394, 543, 1086, 2172, 32, 39, 10, 1, 0, 0 }
  79. };
  80. const wchar_t * const s_wszInfoNames[DPVACM_NUM_DEFAULT_TYPES] =
  81. {
  82. L"DSP Group Truespeech(TM) (8.000 kHz, 1 Bit, Mono)",
  83. L"GSM 6.10 (8.000 kHz, Mono)",
  84. L"Microsoft ADPCM (8.000 kHz, 4 Bit, Mono)",
  85. L"PCM (8.000 kHz, 8 Bit, Mono"
  86. };
  87. WAVEFORMATEX CDPVACMI::s_wfxInnerFormat= {
  88. WAVE_FORMAT_PCM, 1,8000,16000,2,16,0
  89. };
  90. #define MAX_RESOURCE_STRING_LENGTH 200
  91. #undef DPF_MODNAME
  92. #define DPF_MODNAME "CDPVACMI::LoadDefaultTypes"
  93. HRESULT CDPVACMI::LoadDefaultTypes( HINSTANCE hInst )
  94. {
  95. HRESULT hr = DV_OK;
  96. CompressionNode *pNewNode;
  97. CWaveFormat wfxFormat;
  98. for( DWORD dwIndex = 0; dwIndex < DPVACM_NUM_DEFAULT_TYPES; dwIndex++ )
  99. {
  100. pNewNode = new CompressionNode;
  101. if( pNewNode == NULL )
  102. {
  103. DPFX(DPFPREP, DVF_ERRORLEVEL, "Memory allocation failure" );
  104. return DVERR_OUTOFMEMORY;
  105. }
  106. pNewNode->pdvfci = new DVFULLCOMPRESSIONINFO;
  107. if( pNewNode->pdvfci == NULL )
  108. {
  109. delete pNewNode;
  110. DPFX(DPFPREP, DVF_ERRORLEVEL, "Memory allocation failure" );
  111. return DVERR_OUTOFMEMORY;
  112. }
  113. // Copy main portion
  114. memcpy( pNewNode->pdvfci, &s_dvInfoDefault[dwIndex], sizeof( DVFULLCOMPRESSIONINFO ) );
  115. // Copy the waveformat
  116. hr = wfxFormat.InitializeCPY( &s_wfxFormats[dwIndex], s_pvExtras[dwIndex] );
  117. if( FAILED( hr ) )
  118. {
  119. DPFX(DPFPREP, 0, "Unable to initialize built-in type %d", dwIndex );
  120. CN_FreeItem( pNewNode );
  121. continue;
  122. }
  123. pNewNode->pdvfci->lpwfxFormat = wfxFormat.Disconnect();
  124. DNASSERT( pNewNode->pdvfci->lpwfxFormat );
  125. hr = GetCompressionNameAndDescription( hInst, pNewNode->pdvfci );
  126. if( FAILED( hr ) )
  127. {
  128. DPFX(DPFPREP, DVF_ERRORLEVEL, "Error building built-in type: %d hr=0x%x", dwIndex, hr );
  129. DPFX(DPFPREP, DVF_ERRORLEVEL, "Type will not be available" );
  130. CN_FreeItem( pNewNode );
  131. continue;
  132. }
  133. AddEntry( pNewNode );
  134. }
  135. return DV_OK;
  136. }
  137. #undef DPF_MODNAME
  138. #define DPF_MODNAME "CDPVACMI::AddEntry"
  139. void CDPVACMI::AddEntry( CompressionNode *pNewNode )
  140. {
  141. CompressionNode *pcNode, *pcPrevNode;
  142. pcPrevNode = NULL;
  143. pcNode = s_pcnList;
  144. // Run the list and ensure an entry doesn't already exist
  145. // If one does, over-ride it with this new one.
  146. while( pcNode )
  147. {
  148. // A node already exists for this type
  149. if( pcNode->pdvfci->guidType == pNewNode->pdvfci->guidType )
  150. {
  151. // We need to drop this count because we increment it below.
  152. s_dwNumCompressionTypes--;
  153. if( pcPrevNode == NULL )
  154. {
  155. s_pcnList = pcNode->pcnNext;
  156. }
  157. else
  158. {
  159. pcPrevNode->pcnNext = pcNode->pcnNext;
  160. }
  161. CN_FreeItem(pcNode);
  162. break;
  163. }
  164. pcPrevNode = pcNode;
  165. pcNode = pcNode->pcnNext;
  166. }
  167. pNewNode->pcnNext = s_pcnList;
  168. s_pcnList = pNewNode;
  169. s_dwNumCompressionTypes++;
  170. }
  171. #undef DPF_MODNAME
  172. #define DPF_MODNAME "CDPVACMI::InitCompressionList"
  173. HRESULT CDPVACMI::InitCompressionList( HINSTANCE hInst, const wchar_t *szwRegistryBase )
  174. {
  175. HRESULT hr;
  176. hr = IsPCMConverterAvailable();
  177. if( FAILED( hr ) )
  178. {
  179. DPFX(DPFPREP, DVF_ERRORLEVEL, "PCM Converter is disabled hr=0x%x, no ACM compression types are available", hr );
  180. return hr;
  181. }
  182. hr = LoadDefaultTypes( hInst );
  183. if( FAILED( hr ) )
  184. {
  185. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to load built-in types from registry." );
  186. return E_FAIL;
  187. }
  188. return DV_OK;
  189. }
  190. #undef DPF_MODNAME
  191. #define DPF_MODNAME "CDPVACMI::CreateCompressor"
  192. HRESULT CDPVACMI::CreateCompressor( DPVCPIOBJECT *This, LPWAVEFORMATEX lpwfxSrcFormat, GUID guidTargetCT, PDPVCOMPRESSOR *ppCompressor, DWORD dwFlags )
  193. {
  194. HRESULT hr;
  195. hr = COM_CoCreateInstance( CLSID_DPVCPACM_CONVERTER, NULL, CLSCTX_INPROC_SERVER, IID_IDPVConverter, (void **) ppCompressor, FALSE );
  196. if( FAILED( hr ) )
  197. {
  198. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to create converter, hr = 0x%x", hr );
  199. return hr;
  200. }
  201. hr = (*ppCompressor)->lpVtbl->InitCompress( (*ppCompressor), lpwfxSrcFormat, guidTargetCT );
  202. if( FAILED( hr ) )
  203. {
  204. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to init compressor, hr = 0x%x", hr );
  205. (*ppCompressor)->lpVtbl->Release((*ppCompressor));
  206. *ppCompressor = NULL;
  207. return hr;
  208. }
  209. return DV_OK;
  210. }
  211. #undef DPF_MODNAME
  212. #define DPF_MODNAME "CDPVACMI::CreateDeCompressor"
  213. HRESULT CDPVACMI::CreateDeCompressor( DPVCPIOBJECT *This, GUID guidTargetCT, LPWAVEFORMATEX lpwfxSrcFormat, PDPVCOMPRESSOR *ppCompressor, DWORD dwFlags )
  214. {
  215. HRESULT hr;
  216. hr = COM_CoCreateInstance( CLSID_DPVCPACM_CONVERTER, NULL, CLSCTX_INPROC_SERVER, IID_IDPVConverter, (void **) ppCompressor, FALSE );
  217. if( FAILED( hr ) )
  218. {
  219. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to create decompressor, hr = 0x%x", hr );
  220. return hr;
  221. }
  222. hr = (*ppCompressor)->lpVtbl->InitDeCompress( (*ppCompressor), guidTargetCT, lpwfxSrcFormat );
  223. if( FAILED( hr ) )
  224. {
  225. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to init decompressor, hr = 0x%x", hr );
  226. (*ppCompressor)->lpVtbl->Release((*ppCompressor));
  227. *ppCompressor = NULL;
  228. return hr;
  229. }
  230. return DV_OK;
  231. }
  232. // # of chars of extra tacked on by description
  233. // This is equivalent to "XXXXXXX.X kbit/s"
  234. #define DVACMCP_EXTRACHARS 80
  235. #undef DPF_MODNAME
  236. #define DPF_MODNAME "CDPVACMI::GetDriverNameW"
  237. HRESULT CDPVACMI::GetDriverNameW( HACMDRIVERID hadid, wchar_t *szwDriverName )
  238. {
  239. ACMDRIVERDETAILSW acDriverDetails;
  240. MMRESULT mmr;
  241. memset( &acDriverDetails, 0x00, sizeof( ACMDRIVERDETAILS ) );
  242. acDriverDetails.cbStruct = sizeof( ACMDRIVERDETAILS );
  243. mmr = acmDriverDetailsW( hadid, &acDriverDetails, 0 );
  244. if( mmr != 0 )
  245. {
  246. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to get driver details mmr=0x%x", mmr );
  247. return DVERR_COMPRESSIONNOTSUPPORTED;
  248. }
  249. if( acDriverDetails.fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED )
  250. {
  251. DPFX(DPFPREP, DVF_ERRORLEVEL, "Driver is disabled!" );
  252. return DVERR_COMPRESSIONNOTSUPPORTED;
  253. }
  254. wcscpy( szwDriverName, acDriverDetails.szShortName );
  255. return DV_OK;
  256. }
  257. #undef DPF_MODNAME
  258. #define DPF_MODNAME "CDPVACMI::GetDriverNameA"
  259. HRESULT CDPVACMI::GetDriverNameA( HACMDRIVERID hadid, wchar_t *szwDriverName )
  260. {
  261. ACMDRIVERDETAILSA acDriverDetails;
  262. MMRESULT mmr;
  263. memset( &acDriverDetails, 0x00, sizeof( ACMDRIVERDETAILS ) );
  264. acDriverDetails.cbStruct = sizeof( ACMDRIVERDETAILS );
  265. mmr = acmDriverDetailsA( hadid, &acDriverDetails, 0 );
  266. if( mmr != 0 )
  267. {
  268. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to get driver details mmr=0x%x", mmr );
  269. return DVERR_COMPRESSIONNOTSUPPORTED;
  270. }
  271. if( acDriverDetails.fdwSupport & ACMDRIVERDETAILS_SUPPORTF_DISABLED )
  272. {
  273. DPFX(DPFPREP, DVF_ERRORLEVEL, "Driver is disabled!" );
  274. return DVERR_COMPRESSIONNOTSUPPORTED;
  275. }
  276. if( FAILED(STR_jkAnsiToWide( szwDriverName, acDriverDetails.szShortName, ACMDRIVERDETAILS_SHORTNAME_CHARS+1 )) )
  277. {
  278. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to convert driver name to UNICODE" );
  279. return DVERR_COMPRESSIONNOTSUPPORTED;
  280. }
  281. return DV_OK;
  282. }
  283. #undef DPF_MODNAME
  284. #define DPF_MODNAME "CDPVACMI::LoadAndAllocString"
  285. HRESULT CDPVACMI::LoadAndAllocString( HINSTANCE hInstance, UINT uiResourceID, wchar_t **lpswzString )
  286. {
  287. int length;
  288. HRESULT hr;
  289. #ifdef UNICODE
  290. wchar_t wszTmpBuffer[MAX_RESOURCE_STRING_LENGTH];
  291. length = LoadStringW( hInstance, uiResourceID, wszTmpBuffer, MAX_RESOURCE_STRING_LENGTH );
  292. if( length == 0 )
  293. {
  294. hr = GetLastError();
  295. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to load resource ID %d error 0x%x", uiResourceID, hr );
  296. *lpswzString = NULL;
  297. return hr;
  298. }
  299. else
  300. {
  301. *lpswzString = new wchar_t[length+1];
  302. if( *lpswzString == NULL )
  303. {
  304. DPFX(DPFPREP, DVF_ERRORLEVEL, "Alloc failure" );
  305. return DVERR_OUTOFMEMORY;
  306. }
  307. wcscpy( *lpswzString, wszTmpBuffer );
  308. return DV_OK;
  309. }
  310. #else
  311. char szTmpBuffer[MAX_RESOURCE_STRING_LENGTH];
  312. length = LoadStringA( hInstance, uiResourceID, szTmpBuffer, MAX_RESOURCE_STRING_LENGTH );
  313. if( length == 0 )
  314. {
  315. hr = GetLastError();
  316. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to load resource ID %d error 0x%x", uiResourceID, hr );
  317. *lpswzString = NULL;
  318. return hr;
  319. }
  320. else
  321. {
  322. *lpswzString = new wchar_t[length+1];
  323. if( *lpswzString == NULL )
  324. {
  325. DPFX(DPFPREP, DVF_ERRORLEVEL, "Alloc failure" );
  326. return DVERR_OUTOFMEMORY;
  327. }
  328. if( FAILED(STR_jkAnsiToWide( *lpswzString, szTmpBuffer, length+1 )) )
  329. {
  330. hr = GetLastError();
  331. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to upconvert from ansi to unicode hr=0x%x", hr );
  332. return hr;
  333. }
  334. return DV_OK;
  335. }
  336. #endif // UNICODE
  337. }
  338. #undef DPF_MODNAME
  339. #define DPF_MODNAME "CDPVACMI::GetCompressionNameAndDescription"
  340. HRESULT CDPVACMI::GetCompressionNameAndDescription( HINSTANCE hInst, DVFULLCOMPRESSIONINFO *pdvCompressionInfo )
  341. {
  342. MMRESULT mmr;
  343. HACMSTREAM has = NULL;
  344. HACMDRIVERID acDriverID = NULL;
  345. wchar_t szwDriverName[ACMDRIVERDETAILS_SHORTNAME_CHARS+DVACMCP_EXTRACHARS];
  346. wchar_t szExtraCharsBuild[DVACMCP_EXTRACHARS+1];
  347. wchar_t *szwFormat;
  348. HRESULT hr;
  349. // Description is always NULL
  350. pdvCompressionInfo->lpszDescription = NULL;
  351. // Attempt to open a conversion using the parameters specified.
  352. mmr = acmStreamOpen( &has, NULL, &s_wfxInnerFormat, pdvCompressionInfo->lpwfxFormat, NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME );
  353. if( mmr != 0 )
  354. {
  355. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed testing compression type. mmr=0x%x", mmr );
  356. hr = DVERR_COMPRESSIONNOTSUPPORTED;
  357. goto GETINFOERROR;
  358. }
  359. mmr = acmDriverID( (HACMOBJ) has, &acDriverID, 0 );
  360. if( mmr != 0 )
  361. {
  362. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to determine ACM driver for type mmr=0x%x", mmr );
  363. hr = DVERR_COMPRESSIONNOTSUPPORTED;
  364. goto GETINFOERROR;
  365. }
  366. #ifdef UNICODE
  367. hr = GetDriverNameW( acDriverID, szwDriverName );
  368. #else
  369. hr = GetDriverNameA( acDriverID, szwDriverName );
  370. #endif
  371. if( FAILED( hr ) )
  372. {
  373. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed getting driver name hr=0x%x", hr );
  374. goto GETINFOERROR;
  375. }
  376. if( pdvCompressionInfo->dwMaxBitsPerSecond % 1000 == 0 )
  377. {
  378. if( FAILED( LoadAndAllocString( hInst, IDS_CODECNAME_KBITSPERSEC, &szwFormat ) ) )
  379. {
  380. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to load format for name" );
  381. goto GETINFOERROR;
  382. }
  383. swprintf( szExtraCharsBuild, szwFormat, pdvCompressionInfo->dwMaxBitsPerSecond / 1000 );
  384. delete [] szwFormat;
  385. }
  386. else
  387. {
  388. DWORD dwMajor, dwFraction;
  389. dwMajor = pdvCompressionInfo->dwMaxBitsPerSecond / 1000;
  390. dwFraction = (pdvCompressionInfo->dwMaxBitsPerSecond % 1000) / 100;
  391. if( (pdvCompressionInfo->dwMaxBitsPerSecond % 1000) > 500 )
  392. {
  393. dwFraction++;
  394. }
  395. if( dwFraction > 10 )
  396. {
  397. dwMajor++;
  398. dwFraction -= 10;
  399. }
  400. if( FAILED( LoadAndAllocString( hInst, IDS_CODECNAME_KBITSPERSEC_FULL, &szwFormat ) ) )
  401. {
  402. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to load format for name (full)" );
  403. goto GETINFOERROR;
  404. }
  405. swprintf( szExtraCharsBuild, szwFormat, dwMajor, dwFraction );
  406. delete [] szwFormat;
  407. }
  408. if( FAILED( LoadAndAllocString( hInst, IDS_CODECNAME_FORMAT, &szwFormat ) ) )
  409. {
  410. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to load format" );
  411. goto GETINFOERROR;
  412. }
  413. pdvCompressionInfo->lpszName = new wchar_t[wcslen(szwDriverName)+wcslen(szwFormat)+wcslen(szExtraCharsBuild)+1];
  414. if( pdvCompressionInfo->lpszName == NULL )
  415. {
  416. delete [] szwFormat;
  417. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to allocate space for compression name" );
  418. hr = DVERR_OUTOFMEMORY;
  419. goto GETINFOERROR;
  420. }
  421. swprintf( pdvCompressionInfo->lpszName, szwFormat, szwDriverName, szExtraCharsBuild );
  422. acmStreamClose( has, 0 );
  423. if( szwFormat != NULL )
  424. delete [] szwFormat;
  425. return DV_OK;
  426. GETINFOERROR:
  427. if( has != NULL )
  428. {
  429. acmStreamClose( has, 0 );
  430. }
  431. return hr;
  432. }