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.

794 lines
19 KiB

  1. #include "stdafx.h"
  2. #include "device.h"
  3. #include "enumStorage.h"
  4. #include "resource.h"
  5. #include <stdio.h>
  6. #include <mmreg.h>
  7. //#include "findleak.h"
  8. //DECLARE_THIS_FILE;
  9. #define WCS_MIME_TYPE_ALL L"*/*"
  10. #define WMDM_WAVE_FORMAT_ALL (WORD)0xFFFF
  11. #define WAVE_FORMAT_MSAUDIO 0x161
  12. static const _WAVEFORMATEX g_krgWaveFormatsV1[] =
  13. {
  14. // wFormatTag, nChanneels, nSamplesPerSec, nAvgBytesPerSec, nBlockAlign, wBitsPerSample, cbSize
  15. { WAVE_FORMAT_MPEGLAYER3, 0, 0, 0, 0, 0, 0 },
  16. { WAVE_FORMAT_MSAUDIO, 2, 44000, 4000, 0, 0, 0 },
  17. { WAVE_FORMAT_MSAUDIO, 2, 44000, 16000, 0, 0, 0 }
  18. };
  19. //
  20. // These are for CE version 2, in theory, since the player uses the Highest and Lowest
  21. // entries in the table, the CE version 2 table should "outweight" the CE version 1 table
  22. //
  23. static const _WAVEFORMATEX g_krgWaveFormatsV2[] =
  24. {
  25. // wFormatTag, nChanneels, nSamplesPerSec, nAvgBytesPerSec, nBlockAlign, wBitsPerSample, cbSize
  26. { WAVE_FORMAT_MPEGLAYER3, 0, 0, 0, 0, 0, 0 },
  27. { WAVE_FORMAT_MSAUDIO, 2, 1000, 0, 0, 0, 0 },
  28. { WAVE_FORMAT_MSAUDIO, 2, 44000, 0, 0, 0, 0 }
  29. };
  30. static const LPCWSTR g_kszMimeTypes[] =
  31. {
  32. L"audio/mpeg",
  33. L"audio/x-ms-wma",
  34. L"video/x-ms-wmv",
  35. L"video/x-ms-asf"
  36. };
  37. CDevice::CDevice() :
  38. m_pszInitPath(NULL), m_fAllowVideo(FALSE)
  39. {
  40. }
  41. CDevice::~CDevice()
  42. {
  43. delete [] m_pszInitPath;
  44. }
  45. HRESULT CDevice::Init( LPCWSTR pszInitPath )
  46. {
  47. if( NULL == pszInitPath )
  48. {
  49. return( E_INVALIDARG );
  50. }
  51. m_pszInitPath = new WCHAR[ wcslen(pszInitPath) + 1 ];
  52. if( NULL == m_pszInitPath )
  53. {
  54. return( E_OUTOFMEMORY );
  55. }
  56. wcscpy( m_pszInitPath, pszInitPath );
  57. return( S_OK );
  58. }
  59. STDMETHODIMP CDevice::GetName( LPWSTR pwszName, UINT nMaxChars)
  60. {
  61. HKEY hKey = NULL;
  62. HRESULT hr = S_OK;
  63. if( NULL == pwszName || 0 == nMaxChars )
  64. {
  65. return( E_INVALIDARG );
  66. }
  67. memset( pwszName, 0, sizeof(WCHAR)*nMaxChars );
  68. //
  69. // Indicates the base device
  70. //
  71. if( 0 == _wcsicmp(L"\\", m_pszInitPath ) )
  72. {
  73. if( ERROR_SUCCESS == CeRegOpenKeyEx( HKEY_LOCAL_MACHINE, L"Ident", 0, KEY_READ, &hKey ) )
  74. {
  75. DWORD cbData = nMaxChars * sizeof(WCHAR);
  76. if( ERROR_SUCCESS == CeRegQueryValueEx( hKey, L"Name", NULL, NULL, (LPBYTE)pwszName, &cbData) )
  77. {
  78. CeRegCloseKey( hKey );
  79. }
  80. else
  81. {
  82. hr = HRESULT_FROM_WIN32( GetLastError() );
  83. }
  84. }
  85. else
  86. {
  87. hr = HRESULT_FROM_WIN32( GetLastError() );
  88. }
  89. }
  90. else
  91. {
  92. wcsncpy( pwszName, m_pszInitPath, nMaxChars - 1 );
  93. }
  94. return( hr );
  95. }
  96. STDMETHODIMP CDevice::GetManufacturer( LPWSTR pwszName, UINT nMaxChars)
  97. {
  98. return( E_NOTIMPL );
  99. }
  100. STDMETHODIMP CDevice::GetVersion( DWORD *pdwVersion )
  101. {
  102. CEOSVERSIONINFO osv;
  103. HRESULT hr = S_OK;
  104. if( NULL == pdwVersion )
  105. {
  106. return( E_INVALIDARG );
  107. }
  108. osv.dwOSVersionInfoSize = sizeof(osv);
  109. if( !CeGetVersionEx(&osv) )
  110. {
  111. hr = HRESULT_FROM_WIN32( CeGetLastError() );
  112. if( SUCCEEDED( hr ) )
  113. {
  114. hr = CeRapiGetError();
  115. }
  116. }
  117. else
  118. {
  119. *pdwVersion = osv.dwBuildNumber; // The Build Number of CE should suffice!
  120. }
  121. return( hr );
  122. }
  123. STDMETHODIMP CDevice::GetType( DWORD *pdwType )
  124. {
  125. WCHAR szTestSerialPath[MAX_PATH];
  126. HRESULT hrSerial = S_OK;
  127. WMDMID SerialNumber;
  128. if( NULL == pdwType )
  129. {
  130. return( E_INVALIDARG );
  131. }
  132. *pdwType = 0;
  133. memset( &SerialNumber, 0, sizeof(SerialNumber) );
  134. SerialNumber.cbSize = sizeof(SerialNumber);
  135. //
  136. // TODO:Handle the case for WMDM_DEVICE_TYPE_SECURE!
  137. //
  138. if( 0 == _wcsicmp( L"\\", m_pszInitPath ) )
  139. {
  140. hrSerial = CeUtilGetSerialNumber( L"\\", &SerialNumber, NULL, 0 );
  141. }
  142. else
  143. {
  144. memset( szTestSerialPath, 0, sizeof(szTestSerialPath) );
  145. _snwprintf( szTestSerialPath, sizeof(szTestSerialPath)/sizeof(szTestSerialPath[0]) - 1, L"\\%s", m_pszInitPath );
  146. hrSerial = CeUtilGetSerialNumber( szTestSerialPath, &SerialNumber, NULL, 0 );
  147. }
  148. (*pdwType) = ( WMDM_DEVICE_TYPE_STORAGE | WMDM_DEVICE_TYPE_NONSDMI );
  149. if( S_OK == hrSerial )
  150. {
  151. (*pdwType) |= WMDM_DEVICE_TYPE_SDMI;
  152. }
  153. return( S_OK );
  154. }
  155. STDMETHODIMP CDevice::GetSerialNumber( PWMDMID pSerialNumber, BYTE abMac[WMDM_MAC_LENGTH] )
  156. {
  157. HRESULT hr = S_OK;
  158. WCHAR szTestSerialPath[MAX_PATH];
  159. if( 0 == _wcsicmp( L"\\", m_pszInitPath ) )
  160. {
  161. hr = CeUtilGetSerialNumber( m_pszInitPath, pSerialNumber, NULL, 0 );
  162. }
  163. else
  164. {
  165. memset( szTestSerialPath, 0, sizeof(szTestSerialPath) );
  166. _snwprintf( szTestSerialPath, sizeof(szTestSerialPath)/sizeof(szTestSerialPath[0]) - 1, L"\\%s", m_pszInitPath );
  167. hr = CeUtilGetSerialNumber( szTestSerialPath, pSerialNumber, NULL, 0 );
  168. }
  169. if( hr == S_OK )
  170. {
  171. // MAC the parameters
  172. HMAC hMAC;
  173. hr = g_pAppSCServer->MACInit(&hMAC);
  174. if( SUCCEEDED( hr ) )
  175. {
  176. hr = g_pAppSCServer->MACUpdate(hMAC, (BYTE*)(pSerialNumber), sizeof(WMDMID));
  177. }
  178. if( SUCCEEDED( hr ) )
  179. {
  180. hr = g_pAppSCServer->MACFinal(hMAC, abMac);
  181. }
  182. }
  183. else
  184. {
  185. hr = WMDM_E_NOTSUPPORTED;
  186. }
  187. return( hr );
  188. }
  189. STDMETHODIMP CDevice::GetPowerSource( DWORD *pdwPowerSource, DWORD *pdwPercentRemaining)
  190. {
  191. SYSTEM_POWER_STATUS_EX sps;
  192. HRESULT hr = S_OK;
  193. if( NULL == pdwPowerSource )
  194. {
  195. return( E_POINTER );
  196. }
  197. *pdwPowerSource = 0;
  198. if( pdwPercentRemaining )
  199. {
  200. *pdwPercentRemaining = 0;
  201. }
  202. if( !CeGetSystemPowerStatusEx( &sps, TRUE) )
  203. {
  204. hr = HRESULT_FROM_WIN32( CeGetLastError() );
  205. if( SUCCEEDED( hr ) )
  206. {
  207. hr = CeRapiGetError();
  208. }
  209. }
  210. if( SUCCEEDED( hr ) )
  211. {
  212. if( 1 == sps.ACLineStatus )
  213. {
  214. *pdwPowerSource |= WMDM_POWER_IS_EXTERNAL;
  215. }
  216. else if( 0 == sps.ACLineStatus )
  217. {
  218. *pdwPowerSource |= WMDM_POWER_IS_BATTERY;
  219. }
  220. if( 255 != sps.ACLineStatus )
  221. {
  222. *pdwPowerSource |= WMDM_POWER_CAP_EXTERNAL;
  223. }
  224. if( 128 != sps.BatteryFlag && 255 != sps.BatteryFlag )
  225. {
  226. *pdwPowerSource |= WMDM_POWER_CAP_BATTERY;
  227. }
  228. if( pdwPercentRemaining )
  229. {
  230. if( 255 != sps.BatteryLifePercent )
  231. {
  232. *pdwPercentRemaining = sps.BatteryLifePercent;
  233. }
  234. }
  235. }
  236. return( hr );
  237. }
  238. STDMETHODIMP CDevice::GetStatus( DWORD *pdwStatus )
  239. {
  240. if( NULL == pdwStatus )
  241. {
  242. return( E_INVALIDARG );
  243. }
  244. //
  245. // We may want to extend this in the future to handle
  246. // the player is playing, currently copying to device, etc!
  247. //
  248. if( !_Module.g_fDeviceConnected )
  249. {
  250. *pdwStatus = WMDM_STATUS_DEVICE_NOTPRESENT;
  251. }
  252. else
  253. {
  254. *pdwStatus = WMDM_STATUS_READY;
  255. }
  256. return( S_OK );
  257. }
  258. STDMETHODIMP CDevice::GetDeviceIcon( ULONG *hIcon )
  259. {
  260. HRESULT hr = S_OK;
  261. if( NULL == hIcon )
  262. {
  263. return( E_POINTER );
  264. }
  265. *hIcon = HandleToULong(LoadIcon(_Module.GetModuleInstance(), MAKEINTRESOURCE(IDI_CEWMDM_DEVICE) ));
  266. if( NULL == *hIcon )
  267. {
  268. hr = HRESULT_FROM_WIN32( GetLastError() );
  269. }
  270. return( hr );
  271. }
  272. STDMETHODIMP CDevice::EnumStorage( IMDSPEnumStorage **ppEnumStorage )
  273. {
  274. HRESULT hr = S_OK;
  275. CComEnumStorage *pEnumStorage = NULL;
  276. CComPtr<IMDSPEnumStorage> spEnum;
  277. if( NULL == ppEnumStorage )
  278. {
  279. return( E_INVALIDARG );
  280. }
  281. *ppEnumStorage = NULL;
  282. hr = CComEnumStorage::CreateInstance( &pEnumStorage );
  283. spEnum = pEnumStorage;
  284. if( SUCCEEDED( hr ) )
  285. {
  286. hr = pEnumStorage->Init( m_pszInitPath, TRUE, this );
  287. }
  288. if( SUCCEEDED( hr ) )
  289. {
  290. *ppEnumStorage = spEnum;
  291. spEnum.Detach();
  292. }
  293. return( hr );
  294. }
  295. STDMETHODIMP CDevice::GetFormatSupport( _WAVEFORMATEX **pFormatEx,
  296. UINT *pnFormatCount,
  297. LPWSTR **pppwszMimeType,
  298. UINT *pnMimeTypeCount)
  299. {
  300. return InternalGetFormatSupport( pFormatEx, pnFormatCount, pppwszMimeType, pnMimeTypeCount );
  301. }
  302. STDMETHODIMP CDevice::SendOpaqueCommand( OPAQUECOMMAND *pCommand )
  303. {
  304. return( E_NOTIMPL );
  305. }
  306. STDMETHODIMP CDevice::GetStorage( LPCWSTR pszStorageName, IMDSPStorage** ppStorage )
  307. {
  308. return ( E_NOTIMPL );
  309. }
  310. STDMETHODIMP CDevice::GetPnPName( LPWSTR pwszPnPName, UINT nMaxChars )
  311. {
  312. return E_NOTIMPL;
  313. }
  314. STDMETHODIMP CDevice::GetFormatSupport2( DWORD dwFlags,
  315. _WAVEFORMATEX **ppAudioFormatEx,
  316. UINT *pnAudioFormatCount,
  317. _VIDEOINFOHEADER **ppVideoFormatEx,
  318. UINT *pnVideoFormatCount,
  319. WMFILECAPABILITIES **ppFileType,
  320. UINT *pnFileTypeCount)
  321. {
  322. HRESULT hr = S_OK;
  323. LPWSTR *ppwszMimeType = NULL;
  324. UINT nMimeTypeCount;
  325. BOOL fAllowVideo = FALSE;
  326. if( NULL != pnVideoFormatCount )
  327. {
  328. *pnVideoFormatCount = 0;
  329. }
  330. if( NULL != ppVideoFormatEx )
  331. {
  332. *ppVideoFormatEx = NULL;
  333. }
  334. if( NULL != pnFileTypeCount )
  335. {
  336. *pnFileTypeCount = 0;
  337. }
  338. if( NULL != ppFileType )
  339. {
  340. *ppFileType = NULL;
  341. }
  342. if( NULL == pnVideoFormatCount )
  343. {
  344. return( E_INVALIDARG );
  345. }
  346. if( NULL == ppVideoFormatEx )
  347. {
  348. return( E_INVALIDARG );
  349. }
  350. if( NULL == pnFileTypeCount )
  351. {
  352. return( E_INVALIDARG );
  353. }
  354. if( NULL == ppFileType )
  355. {
  356. return( E_INVALIDARG );
  357. }
  358. if ( SUCCEEDED(hr) )
  359. {
  360. // NOTE: This function calls GetCEPlayerVersion which sets m_fAllowVideo
  361. // if you need to put code above this call that depends on that member you must call GetCEPlayerVersion first
  362. hr = InternalGetFormatSupport( ppAudioFormatEx, pnAudioFormatCount, &ppwszMimeType, &nMimeTypeCount );
  363. if ( SUCCEEDED(hr) )
  364. {
  365. // Wrap all of the mime types in WMFILECAPABILITIES
  366. *ppFileType = (WMFILECAPABILITIES *)CoTaskMemAlloc( sizeof(WMFILECAPABILITIES) * nMimeTypeCount );
  367. if (*ppFileType)
  368. {
  369. memset( *ppFileType, 0, sizeof(WMFILECAPABILITIES) * nMimeTypeCount );
  370. for (UINT x=0; x < nMimeTypeCount; x++)
  371. {
  372. (*ppFileType)[x].pwszMimeType = ppwszMimeType[x];
  373. }
  374. *pnFileTypeCount = nMimeTypeCount;
  375. }
  376. else
  377. {
  378. // If the memory alloc fail we need to clean up the return values from GetFormatSupport and the video format struct
  379. hr = E_OUTOFMEMORY;
  380. }
  381. }
  382. }
  383. // If it is the V2 regkey, tell the WMDM that we can support video
  384. if ( SUCCEEDED(hr) && m_fAllowVideo )
  385. {
  386. *ppVideoFormatEx = (_VIDEOINFOHEADER *)CoTaskMemAlloc( sizeof(_VIDEOINFOHEADER) );
  387. if (*ppVideoFormatEx)
  388. {
  389. memset( *ppVideoFormatEx, 0, sizeof(_VIDEOINFOHEADER) );
  390. // Setup the WMDMVIDEOINFOHEADER structure for video
  391. // These values are all being ignored by WMP8
  392. (*ppVideoFormatEx)->bmiHeader.biSize = sizeof(_BITMAPINFOHEADER);
  393. *pnVideoFormatCount = 1;
  394. }
  395. else
  396. {
  397. hr = E_OUTOFMEMORY;
  398. }
  399. }
  400. if ( FAILED(hr) )
  401. {
  402. if ( ppAudioFormatEx )
  403. {
  404. if ( *ppAudioFormatEx )
  405. {
  406. CoTaskMemFree(*ppAudioFormatEx);
  407. }
  408. }
  409. if ( ppwszMimeType )
  410. {
  411. if ( *ppwszMimeType )
  412. {
  413. while( nMimeTypeCount-- )
  414. {
  415. CoTaskMemFree( ppwszMimeType[nMimeTypeCount] );
  416. }
  417. }
  418. CoTaskMemFree(ppwszMimeType);
  419. }
  420. }
  421. return ( hr );
  422. }
  423. STDMETHODIMP CDevice::GetSpecifyPropertyPages( ISpecifyPropertyPages** ppSpecifyPropPages,
  424. IUnknown*** pppUnknowns,
  425. ULONG *pcUnks )
  426. {
  427. HRESULT hr = S_OK;
  428. HINSTANCE hInstance = NULL;
  429. DWORD dwVersion = 1;
  430. hInstance = LoadLibrary( _T("wmploc.dll") );
  431. if( NULL == hInstance )
  432. {
  433. return( E_NOTIMPL );
  434. }
  435. FreeLibrary( hInstance );
  436. GetCEPlayerVersion( &dwVersion );
  437. if( dwVersion < 3 )
  438. {
  439. return( E_NOTIMPL );
  440. }
  441. if( NULL == ppSpecifyPropPages )
  442. {
  443. hr = E_POINTER;
  444. }
  445. else
  446. {
  447. *ppSpecifyPropPages = NULL;
  448. }
  449. if( NULL != pppUnknowns )
  450. {
  451. *pppUnknowns = NULL;
  452. }
  453. if( NULL != pcUnks )
  454. {
  455. *pcUnks = 0;
  456. }
  457. if( SUCCEEDED( hr ) )
  458. {
  459. hr = QueryInterface( __uuidof(ISpecifyPropertyPages), (LPVOID *)ppSpecifyPropPages );
  460. }
  461. return ( hr );
  462. }
  463. STDMETHODIMP CDevice::GetCEPlayerVersion(DWORD *pdwVersion)
  464. {
  465. HRESULT hr = S_OK;
  466. HKEY hkeyVer = NULL;
  467. if (NULL == pdwVersion)
  468. {
  469. return (E_INVALIDARG);
  470. }
  471. else
  472. {
  473. *pdwVersion = 1;
  474. }
  475. // Check the NOW continuously updated reg key on the device (this should NEVER MOVE on the CE player)
  476. if( ERROR_SUCCESS != CeRegOpenKeyEx( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\wmdm\\CurrentInUseVersion", 0, KEY_READ, &hkeyVer ) )
  477. {
  478. //
  479. // On RAPIER Casio Devices, this call fails if the reg key isn't there, but RETURNS a handle, ugly....
  480. //
  481. hkeyVer = NULL;
  482. }
  483. // Check the regkey on the CE device
  484. WCHAR szTargetApp[MAX_PATH];
  485. if ( NULL == hkeyVer )
  486. {
  487. if( ERROR_SUCCESS != CeRegOpenKeyEx( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows Media Player 2\\Version", 0, KEY_READ, &hkeyVer ) )
  488. {
  489. //
  490. // On RAPIER Casio Devices, this call fails if the reg key isn't there, but RETURNS a handle, ugly....
  491. //
  492. hkeyVer = NULL;
  493. }
  494. }
  495. if( NULL != hkeyVer )
  496. {
  497. DWORD cbData = sizeof(szTargetApp);
  498. if( ERROR_SUCCESS == CeRegQueryValueEx( hkeyVer, NULL, NULL, NULL, (LPBYTE)szTargetApp, &cbData ) )
  499. {
  500. LPWSTR pszSplit = wcsrchr( szTargetApp, L'.' );
  501. DWORD hi, lo;
  502. if( NULL != pszSplit )
  503. {
  504. *pszSplit = L'\0';
  505. pszSplit++;
  506. hi = _wtoi( szTargetApp );
  507. lo = _wtoi( pszSplit );
  508. if( hi >= 2 )
  509. {
  510. m_fAllowVideo = TRUE;
  511. }
  512. *pdwVersion = hi;
  513. hr = S_OK;
  514. }
  515. }
  516. CeRegCloseKey( hkeyVer );
  517. }
  518. return hr;
  519. }
  520. STDMETHODIMP CDevice::InternalGetFormatSupport( _WAVEFORMATEX **pFormatEx,
  521. UINT *pnFormatCount,
  522. LPWSTR **pppwszMimeType,
  523. UINT *pnMimeTypeCount)
  524. {
  525. HRESULT hr = S_OK;
  526. UINT idxMimes = 0;
  527. UINT cMimes = 0;
  528. UINT cWaves = 0;
  529. const _WAVEFORMATEX *prgWaveFormats = NULL;
  530. if( NULL != pnFormatCount )
  531. {
  532. *pnFormatCount = 0;
  533. }
  534. if( NULL != pFormatEx )
  535. {
  536. *pFormatEx = NULL;
  537. }
  538. if( NULL != pppwszMimeType )
  539. {
  540. *pppwszMimeType = NULL;
  541. }
  542. if( NULL != pnMimeTypeCount )
  543. {
  544. *pnMimeTypeCount = 0;
  545. }
  546. if( NULL == pnFormatCount )
  547. {
  548. return( E_INVALIDARG );
  549. }
  550. if( NULL == pFormatEx )
  551. {
  552. return( E_INVALIDARG );
  553. }
  554. if( NULL == pppwszMimeType )
  555. {
  556. return( E_INVALIDARG );
  557. }
  558. if( NULL == pnMimeTypeCount )
  559. {
  560. return( E_INVALIDARG );
  561. }
  562. DWORD dwVersion;
  563. hr = GetCEPlayerVersion(&dwVersion);
  564. if(SUCCEEDED( hr ))
  565. {
  566. if( m_fAllowVideo )
  567. {
  568. cWaves = sizeof(g_krgWaveFormatsV2)/sizeof(g_krgWaveFormatsV2[0]);
  569. prgWaveFormats = g_krgWaveFormatsV2;
  570. }
  571. else
  572. {
  573. cWaves = sizeof(g_krgWaveFormatsV1)/sizeof(g_krgWaveFormatsV1[0]);
  574. prgWaveFormats = g_krgWaveFormatsV1;
  575. }
  576. }
  577. if (SUCCEEDED(hr))
  578. {
  579. *pFormatEx = (_WAVEFORMATEX *)CoTaskMemAlloc(sizeof(_WAVEFORMATEX) * cWaves );
  580. if( NULL == *pFormatEx )
  581. {
  582. hr = E_OUTOFMEMORY;
  583. }
  584. }
  585. if( SUCCEEDED( hr ) )
  586. {
  587. *pnFormatCount = cWaves;
  588. memcpy( *pFormatEx, prgWaveFormats, sizeof(_WAVEFORMATEX) * cWaves );
  589. }
  590. if( SUCCEEDED( hr ) )
  591. {
  592. cMimes = (sizeof(g_kszMimeTypes) / sizeof(g_kszMimeTypes[0]) - (m_fAllowVideo ? 0 : 2));
  593. *pppwszMimeType = (LPWSTR *)CoTaskMemAlloc( sizeof(LPWSTR) * cMimes );
  594. if( NULL == pppwszMimeType )
  595. {
  596. hr = E_OUTOFMEMORY;
  597. }
  598. else
  599. {
  600. for( idxMimes = 0; idxMimes < cMimes; idxMimes++ )
  601. {
  602. (*pppwszMimeType)[idxMimes] = NULL;
  603. }
  604. }
  605. }
  606. if( SUCCEEDED( hr ) )
  607. {
  608. for( idxMimes = 0; SUCCEEDED( hr ) && idxMimes < cMimes; idxMimes++ )
  609. {
  610. (*pppwszMimeType)[idxMimes] = (LPWSTR)CoTaskMemAlloc(sizeof(WCHAR)*(wcslen(g_kszMimeTypes[idxMimes])+1));
  611. if( NULL == (*pppwszMimeType)[idxMimes] )
  612. {
  613. hr = E_OUTOFMEMORY;
  614. }
  615. else
  616. {
  617. wcscpy( (*pppwszMimeType)[idxMimes], g_kszMimeTypes[idxMimes]);
  618. }
  619. }
  620. }
  621. if( SUCCEEDED( hr ) )
  622. {
  623. *pnMimeTypeCount = cMimes;
  624. }
  625. else
  626. {
  627. if( *pppwszMimeType )
  628. {
  629. for( idxMimes = 0; SUCCEEDED( hr ) && idxMimes < cMimes; idxMimes++ )
  630. {
  631. if( NULL != (*pppwszMimeType)[idxMimes] )
  632. {
  633. CoTaskMemFree( (*pppwszMimeType)[idxMimes] );
  634. }
  635. }
  636. CoTaskMemFree( *pppwszMimeType );
  637. *pppwszMimeType = NULL;
  638. }
  639. if( *pFormatEx )
  640. {
  641. CoTaskMemFree( *pFormatEx );
  642. *pFormatEx = NULL;
  643. }
  644. *pnMimeTypeCount = 0;
  645. *pnFormatCount = 0;
  646. }
  647. return( hr );
  648. }