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.

932 lines
24 KiB

  1. //+------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1994 - 1998.
  5. //
  6. // File: tnupdr.cxx
  7. //
  8. //+------------------------------------------------------------------
  9. #include "pch.cxx"
  10. #include <filtntfy.h>
  11. #include "tnupdr.hxx"
  12. EXTERN_C const IID IID_IFlatStorage; /* b29d6138-b92f-11d1-83ee-00c04fc2c6d4 */
  13. DECLARE_INFOLEVEL(updr)
  14. #define DEB_INFO DEB_USER1
  15. #define DEB_REGINFO DEB_USER2
  16. #define MIME_TYPES_ROOT L"software\\classes\\Mime\\Database\\Content Type"
  17. #define IMAGE_PREFIX L"image/"
  18. #define IMAGE_PREFIX_LEN 6
  19. extern "C" CLSID CLSID_ThumbnailFCNHandler;
  20. extern "C" CLSID CLSID_ThumbnailUpdater;
  21. class CThumbnailCF : public IClassFactory
  22. {
  23. public:
  24. // Constructor
  25. CThumbnailCF(): _cRefs(1) { }
  26. // IUnknown methods
  27. STDMETHOD (QueryInterface) (REFIID riid, void **ppv);
  28. STDMETHOD_(ULONG,AddRef) (void);
  29. STDMETHOD_(ULONG,Release) (void);
  30. // IClassFactory methods
  31. STDMETHOD (CreateInstance)(IUnknown *pUnkOuter, REFIID riid, void **ppv);
  32. STDMETHOD (LockServer) (BOOL fLock) { return S_OK; }
  33. private:
  34. ULONG _cRefs; // CF reference count
  35. };
  36. //////////////////////////////////////////////////////////////
  37. // Funtion to create a Class Factory Object.
  38. // This is in form DoATClassCreate() wants.
  39. //////////////////////////////////////////////////////////////
  40. HRESULT GetCThumbnailCF(REFCLSID clsid, REFIID iid, void **ppv)
  41. {
  42. HRESULT hr=S_OK;
  43. CThumbnailCF *pCF=NULL;
  44. *ppv = 0;
  45. if( ! IsEqualCLSID(clsid, CLSID_ThumbnailUpdater))
  46. return CLASS_E_CLASSNOTAVAILABLE;
  47. pCF = new CThumbnailCF();
  48. if( NULL == pCF )
  49. return E_OUTOFMEMORY;
  50. hr = pCF->QueryInterface(iid, ppv);
  51. pCF->Release();
  52. return hr;
  53. }
  54. //////////////////////////////////////////////////////////////
  55. // Hook from the DllgetClassObject routine.
  56. // This is special because it must start in an Apartment.
  57. //////////////////////////////////////////////////////////////
  58. HRESULT CThumbnail_ApartmentDllGetClassObject(
  59. REFCLSID clsid,
  60. REFIID iid,
  61. void **ppv)
  62. {
  63. HRESULT hr;
  64. updrDebug((DEB_ITRACE,
  65. "ApartmentDllGetClassObject(%I,%I,%x)\n",
  66. &clsid, &iid, ppv));
  67. if(IsEqualCLSID(clsid, CLSID_ThumbnailUpdater))
  68. {
  69. COleTls tls;
  70. if ( (tls->dwFlags & OLETLS_INNEUTRALAPT)
  71. || !(tls->dwFlags & OLETLS_APARTMENTTHREADED))
  72. {
  73. //We need to switch to a single-threaded apartment.
  74. hr = DoATClassCreate(GetCThumbnailCF, clsid, iid, (IUnknown **)ppv);
  75. }
  76. else
  77. {
  78. //This thread is in a single-threaded apartment.
  79. hr = GetCThumbnailCF(clsid, iid, ppv);
  80. }
  81. }
  82. else
  83. {
  84. hr = CLASS_E_CLASSNOTAVAILABLE;
  85. }
  86. return hr;
  87. }
  88. //+-------------------------------------------------------------------
  89. //
  90. // Member: CThumbnailCF::AddRef, public
  91. //
  92. // Synopsis: Adds a reference to an interface
  93. //
  94. //--------------------------------------------------------------------
  95. STDMETHODIMP_(ULONG) CThumbnailCF::AddRef(void)
  96. {
  97. return InterlockedIncrement((LONG *)&_cRefs);
  98. }
  99. //+-------------------------------------------------------------------
  100. //
  101. // Member: CThumbnailCF::Release, public
  102. //
  103. // Synopsis: Adds a reference to an interface
  104. //
  105. //--------------------------------------------------------------------
  106. STDMETHODIMP_(ULONG) CThumbnailCF::Release(void)
  107. {
  108. ULONG cRefs = (ULONG) InterlockedDecrement((LONG *)&_cRefs);
  109. if (cRefs == 0)
  110. {
  111. delete this;
  112. }
  113. return cRefs;
  114. }
  115. //+-------------------------------------------------------------------
  116. //
  117. // Member: CThumbnailCF::QueryInterface, public
  118. //
  119. // Synopsis: Returns a pointer to the requested interface.
  120. //
  121. //--------------------------------------------------------------------
  122. STDMETHODIMP CThumbnailCF::QueryInterface(REFIID riid, void **ppv)
  123. {
  124. if (IsEqualIID(riid, IID_IClassFactory) ||
  125. IsEqualIID(riid, IID_IUnknown))
  126. {
  127. *ppv = (IClassFactory *) this;
  128. AddRef();
  129. return S_OK;
  130. }
  131. *ppv = NULL;
  132. return E_NOINTERFACE;
  133. }
  134. //////////////////////////////////////////////////////////////
  135. // OLE32 Internal ClassFactory Entry Point
  136. //////////////////////////////////////////////////////////////
  137. HRESULT CThumbnailCF_CreateInstance(
  138. IUnknown *pUnkOuter,
  139. REFIID riid,
  140. void** ppv)
  141. {
  142. HRESULT hr;
  143. CTNUpdater * pact;
  144. updrDebug(( DEB_IWARN, "Thumbnailer: CreateInstance called\n" ));
  145. if(NULL != pUnkOuter)
  146. {
  147. return CLASS_E_NOAGGREGATION;
  148. }
  149. pact = new CTNUpdater;
  150. if(NULL == pact)
  151. {
  152. return E_OUTOFMEMORY;
  153. }
  154. if(!pact->ObjectInit())
  155. {
  156. pact->Release();
  157. return E_OUTOFMEMORY;
  158. }
  159. hr = pact->QueryInterface(riid, ppv);
  160. pact->Release();
  161. return hr;
  162. }
  163. //+-------------------------------------------------------------------
  164. // Member: CThumbnailCF::CreateInstance, public
  165. //--------------------------------------------------------------------
  166. STDMETHODIMP CThumbnailCF::CreateInstance(IUnknown *pUnkOuter,
  167. REFIID riid,
  168. void **ppv)
  169. {
  170. return CThumbnailCF_CreateInstance( pUnkOuter, riid, ppv );
  171. }
  172. //////////////////////////////////////////////////////////////
  173. // CTNUpdater Class
  174. //////////////////////////////////////////////////////////////
  175. //---------------------------------------------------------
  176. // C++ Methods: Constructor
  177. //---------------------------------------------------------
  178. CTNUpdater::CTNUpdater(void)
  179. {
  180. m_cRef = 1;
  181. m_pITE = NULL;
  182. m_hEvRegNotify = NULL;
  183. m_hkeyMime = NULL;
  184. m_ppwszExtensions = NULL;
  185. m_pTempList = NULL;
  186. }
  187. //---------------------------------------------------------
  188. // C++ Methods: Destructor
  189. //---------------------------------------------------------
  190. CTNUpdater::~CTNUpdater(void)
  191. {
  192. if( NULL != m_pTempList )
  193. FreeTempExtensionList();
  194. if( NULL != m_pITE )
  195. m_pITE->Release();
  196. if( NULL != m_hkeyMime )
  197. CloseHandle( m_hkeyMime );
  198. if( NULL != m_hEvRegNotify )
  199. CloseHandle( m_hEvRegNotify );
  200. if( NULL != m_ppwszExtensions )
  201. CoTaskMemFree( m_ppwszExtensions );
  202. }
  203. //---------------------------------------------------------
  204. // non-interface Init routine
  205. //---------------------------------------------------------
  206. BOOL
  207. CTNUpdater::ObjectInit()
  208. {
  209. HRESULT sc;
  210. DWORD status;
  211. //
  212. // Create the event for waiting on registry changes.
  213. //
  214. status = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  215. MIME_TYPES_ROOT,
  216. 0,
  217. KEY_ALL_ACCESS,
  218. &m_hkeyMime );
  219. if( ERROR_SUCCESS != status )
  220. updrErr( EH_Err, LAST_SCODE );
  221. m_hEvRegNotify = CreateEvent( NULL,
  222. TRUE, // Manual Reset
  223. FALSE, // Init signaled
  224. NULL );
  225. if( NULL == m_hEvRegNotify )
  226. updrErr( EH_Err, LAST_SCODE );
  227. updrChk( GetImageFileExtensions() );
  228. return TRUE;
  229. EH_Err:
  230. return FALSE;
  231. }
  232. //---------------------------------------------------------
  233. // IUnknown::AddRef
  234. //---------------------------------------------------------
  235. ULONG
  236. CTNUpdater::AddRef()
  237. {
  238. return InterlockedIncrement((LONG*)&m_cRef);
  239. }
  240. //---------------------------------------------------------
  241. // IUnknown::Release
  242. //---------------------------------------------------------
  243. ULONG
  244. CTNUpdater::Release()
  245. {
  246. LONG cRef;
  247. cRef = InterlockedDecrement((LONG*)&m_cRef);
  248. // ASSERT(cRef >= 0);
  249. if(cRef <= 0)
  250. {
  251. delete this;
  252. }
  253. return cRef;
  254. }
  255. //---------------------------------------------------------
  256. // IUnknown::QueryInterface
  257. //---------------------------------------------------------
  258. HRESULT
  259. CTNUpdater::QueryInterface(
  260. REFIID iid,
  261. void **ppv)
  262. {
  263. HRESULT hr=S_OK;
  264. IUnknown *pUnk=NULL;
  265. if(IsEqualIID(IID_IUnknown, iid))
  266. {
  267. pUnk = (IFilterStatus*)this;
  268. }
  269. else if(IsEqualIID(IID_IFilterStatus, iid))
  270. {
  271. pUnk = (IFilterStatus*)this;
  272. }
  273. else if(IsEqualIID(IID_IOplockStorage, iid))
  274. {
  275. pUnk = (IOplockStorage*)this;
  276. }
  277. else
  278. {
  279. return E_NOINTERFACE;
  280. }
  281. pUnk->AddRef();
  282. *ppv = pUnk;
  283. return S_OK;
  284. }
  285. //---------------------------------------------------------
  286. // IFilterStatus::Initialize
  287. //---------------------------------------------------------
  288. HRESULT
  289. CTNUpdater::Initialize(
  290. const WCHAR *pwszCatalogName,
  291. const WCHAR *pwszCatalogPath)
  292. {
  293. return S_OK;
  294. }
  295. //---------------------------------------------------------
  296. // IFilterStatus::FilterLoad
  297. //---------------------------------------------------------
  298. HRESULT
  299. CTNUpdater::FilterLoad(
  300. const WCHAR *pwszPath,
  301. SCODE scFilterStatus)
  302. {
  303. return S_OK;
  304. }
  305. /*
  306. //---------------------------------------------
  307. // Test routine
  308. //----------------------------------------
  309. HRESULT
  310. test_junk(IStorage *pstg)
  311. {
  312. HRESULT sc=S_OK;
  313. IPropertySetStorage *ppss = NULL;
  314. IPropertyStorage *pps = NULL;
  315. PROPSPEC propSpec[1];
  316. PROPVARIANT propVar[1];
  317. updrChk( pstg->QueryInterface( IID_IPropertySetStorage, (void**)&ppss ) );
  318. updrChk( ppss->Open( FMTID_SummaryInformation,
  319. STGM_READWRITE|STGM_SHARE_EXCLUSIVE,
  320. &pps ) );
  321. propSpec[0].ulKind = PRSPEC_PROPID;
  322. propSpec[0].propid = PIDSI_THUMBNAIL;
  323. updrChk( pps->ReadMultiple(1, propSpec, propVar) );
  324. EH_Err:
  325. // FreePropVariantArray(1, propVar);
  326. if( NULL != ppss )
  327. ppss->Release();
  328. if( NULL != pps )
  329. pps->Release();
  330. return sc;
  331. } */
  332. //---------------------------------------------------------
  333. // IFilterStatus::PreFilter
  334. //
  335. // This routine ALWAYS SUCCEEDS, unless we want to defer processing
  336. // to a later time.
  337. // If it returns any failure, CI will defer filtering the file
  338. // and will submit it again later.
  339. //---------------------------------------------------------
  340. HRESULT
  341. CTNUpdater::PreFilter(
  342. WCHAR const * pwszPath)
  343. {
  344. HRESULT sc=S_OK;
  345. IStorage *pstg=NULL;
  346. IThumbnailExtractor *pITE=NULL;
  347. ITimeAndNoticeControl *pITNC=NULL;
  348. ULONG cStorageFinalReferences=0;
  349. updrDebug(( DEB_INFO | DEB_TRACE,
  350. "PreFilter(\"%ws\")\n", pwszPath ));
  351. // Optimize, don't spend time on files that we don't expect to be
  352. // Images. If it does not have a valid extension then we are done.
  353. //
  354. if( ! HasAnImageFileExtension(pwszPath) )
  355. return S_FALSE;
  356. // Open an Oplock'ed Storage. (w/ SuppressChanges turned on)
  357. //
  358. updrChk( OpenStorageEx(pwszPath,
  359. STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE,
  360. STGFMT_FILE,
  361. 0,
  362. IID_IFlatStorage,
  363. (void**)&pstg) );
  364. if( NULL == m_pITE )
  365. {
  366. updrChk( CoCreateInstance(CLSID_ThumbnailFCNHandler,
  367. NULL, // pUnkOuter
  368. CLSCTX_INPROC_SERVER,
  369. IID_IThumbnailExtractor,
  370. (void**)&pITE) );
  371. m_pITE = pITE;
  372. pITE = NULL;
  373. }
  374. updrChk( m_pITE->OnFileUpdated(pstg) );
  375. EH_Err:
  376. if(NULL != pITNC)
  377. pITNC->Release();
  378. if(NULL != pITE)
  379. pITE->Release();
  380. if(NULL != pstg)
  381. cStorageFinalReferences = pstg->Release();
  382. updrAssert( 0 == cStorageFinalReferences );
  383. updrDebug(( DEB_TRACE, "PreFilter() returned %x\n", sc ));
  384. switch( sc )
  385. {
  386. case STG_E_SHAREVIOLATION: // Someone else has it open when we started.
  387. case STG_E_LOCKVIOLATION:
  388. case STG_E_REVERTED: // Someone else opened if after we started.
  389. break;
  390. // All other problems are likely permanent so don't error.
  391. // all errors tell CI to re-try the file.
  392. default:
  393. if( FAILED( sc ) )
  394. sc = S_FALSE;
  395. else
  396. sc = S_OK;
  397. break;
  398. }
  399. return sc;
  400. }
  401. //---------------------------------------------------------
  402. // IFilterStatus::PostFilter
  403. //---------------------------------------------------------
  404. HRESULT
  405. CTNUpdater::PostFilter(
  406. WCHAR const * pwszPath,
  407. HRESULT hrStatus)
  408. {
  409. return S_OK;
  410. }
  411. //---------------------------------------------------------
  412. // IOplockStorage::CreateStorageEx
  413. //---------------------------------------------------------
  414. HRESULT
  415. CTNUpdater::CreateStorageEx(
  416. LPCWSTR pwcsName,
  417. DWORD grfMode,
  418. DWORD stgfmt,
  419. DWORD grfAttrs,
  420. REFIID riid,
  421. void ** ppstgOpen)
  422. {
  423. return STG_E_INVALIDPARAMETER;
  424. }
  425. //---------------------------------------------------------
  426. // IOplockStorage::OpenStorageEx
  427. //---------------------------------------------------------
  428. HRESULT
  429. CTNUpdater::OpenStorageEx(
  430. LPCWSTR pwcsName,
  431. DWORD grfMode,
  432. DWORD stgfmt,
  433. DWORD grfAttrs,
  434. REFIID riid,
  435. void ** ppstgOpen)
  436. {
  437. HRESULT sc=S_OK;
  438. IStorage *pstg=NULL;
  439. if(0 != (grfMode & STGM_OPLOCKS_DONT_WORK))
  440. return STG_E_INVALIDFLAG;
  441. if( STGFMT_NATIVE == stgfmt
  442. || STGFMT_DOCFILE == stgfmt
  443. || STGFMT_STORAGE == stgfmt)
  444. {
  445. updrErr(EH_Err, STG_E_INVALIDPARAMETER);
  446. }
  447. if( STGFMT_ANY == stgfmt )
  448. updrErr(EH_Err, STG_E_INVALIDPARAMETER);
  449. if( STGFMT_FILE == stgfmt )
  450. {
  451. updrChk( NFFOpen( pwcsName, // PathName
  452. grfMode, // Storage Mode
  453. // Special NFF flags
  454. NFFOPEN_OPLOCK | NFFOPEN_SUPPRESS_CHANGES,
  455. FALSE, // Create API?
  456. riid, // Interface ID
  457. (void**)&pstg ) ); // [out] interface pointer
  458. }
  459. *ppstgOpen = pstg;
  460. pstg = NULL;
  461. sc = S_OK;
  462. EH_Err:
  463. RELEASE_INTERFACE( pstg );
  464. return(sc);
  465. }
  466. //---------------------------------------------------------
  467. // HasAnImageFileExtention, private method.
  468. //---------------------------------------------------------
  469. BOOL
  470. CTNUpdater::HasAnImageFileExtension(
  471. WCHAR const * pwszPath)
  472. {
  473. LPCWSTR pwszDot;
  474. LPWSTR* ppwszExt;
  475. HRESULT sc=S_OK;
  476. if(NULL == pwszPath)
  477. return FALSE;
  478. //
  479. // Scan forward through the string looking for the last dot that
  480. // was not followed by a WHACK or a SPACE.
  481. //
  482. for (pwszDot = NULL; *pwszPath; pwszPath++)
  483. {
  484. switch (*pwszPath) {
  485. case L'.':
  486. pwszDot = pwszPath; // remember the last dot
  487. break;
  488. case L'\\':
  489. case L' ': // extensions can't have spaces
  490. pwszDot = NULL; // forget last dot, it was in a directory
  491. break;
  492. }
  493. }
  494. // If there is no extension fail.
  495. //
  496. if(NULL == pwszDot)
  497. return FALSE;
  498. // If the registry change event is signaled then read a new list.
  499. //
  500. if( WAIT_OBJECT_0 == WaitForSingleObject( m_hEvRegNotify, 0 ) )
  501. updrChk( GetImageFileExtensions() );
  502. for( ppwszExt=m_ppwszExtensions; NULL!=*ppwszExt; ++ppwszExt)
  503. {
  504. // Do a case insensitive compare for a known extension.
  505. if( 0 == _wcsicmp( pwszDot, *ppwszExt ) )
  506. return TRUE;
  507. }
  508. EH_Err:
  509. return FALSE;
  510. }
  511. HRESULT
  512. CTNUpdater::GetImageFileExtensions()
  513. {
  514. DWORD idx, ckeys;
  515. LPWSTR pwszKeyName = NULL;
  516. LPWSTR pwszExtension;
  517. ULONG ccName, ccMaxNameLength;
  518. DWORD status;
  519. HRESULT sc;
  520. FILETIME ftLastTime;
  521. int cszTotalStrs=0; // Count of Extension Strings
  522. int ccTotalChars=0; // Count of total Extension characters w/ NULLs
  523. int cbTotalSize=0; // Total memory to allocate.
  524. TEMPEXTLIST* pExt=NULL; // Src Pointer to the current Extension.
  525. LPWSTR* ppwszPtr=NULL; // Des Pointer into string pointer table.
  526. WCHAR* pwszBuf=NULL; // Des Pointer into character buffer table.
  527. LPWSTR* ppwszTable=NULL;
  528. if( NULL != m_ppwszExtensions )
  529. {
  530. CoTaskMemFree( m_ppwszExtensions );
  531. m_ppwszExtensions = NULL;
  532. }
  533. //
  534. // Ask for notification if this part of the registry changes.
  535. // Set the notify before reading, that way if a change is made while
  536. // we are reading and we miss it, we will pick it up on the next round.
  537. //
  538. status = RegNotifyChangeKeyValue( m_hkeyMime,
  539. TRUE, // watch subtree
  540. REG_NOTIFY_CHANGE_LAST_SET
  541. |REG_NOTIFY_CHANGE_NAME,
  542. m_hEvRegNotify,
  543. TRUE );
  544. if( ERROR_SUCCESS != status )
  545. {
  546. updrDebug(( DEB_ERROR,
  547. "Can't set RegNotifyChangeKeyValue() %x\n",
  548. GetLastError() ));
  549. }
  550. //
  551. // Get the size of the maximum entry.
  552. // Then allocate the buffer for the key name.
  553. //
  554. status = RegQueryInfoKey( m_hkeyMime,
  555. NULL, NULL, NULL,
  556. &ckeys,
  557. &ccMaxNameLength,
  558. NULL, NULL, NULL,
  559. NULL, NULL, NULL );
  560. if(ERROR_SUCCESS != status)
  561. updrErr( EH_Err, LAST_SCODE );
  562. ccMaxNameLength += 1; // Add one for the NULL
  563. updrMem( pwszKeyName = new WCHAR[ ccMaxNameLength * sizeof(WCHAR)] );
  564. //
  565. // Enumerate through all the format types, looking for
  566. // the image types. (they start with "image/")
  567. //
  568. for(idx=0; idx<ckeys; idx++)
  569. {
  570. ccName = ccMaxNameLength;
  571. status = RegEnumKeyEx( m_hkeyMime,
  572. idx,
  573. pwszKeyName,
  574. &ccName,
  575. 0,
  576. NULL,
  577. NULL,
  578. &ftLastTime );
  579. if(ERROR_SUCCESS != status)
  580. {
  581. updrDebug(( DEB_REGINFO,
  582. "Enum of Mime Image types failed %x)\n",
  583. status));
  584. continue;
  585. }
  586. //
  587. // If it is an image format then get the value of the
  588. // "Extension" subkey (if any).
  589. //
  590. if( 0 == _wcsnicmp( pwszKeyName, IMAGE_PREFIX, IMAGE_PREFIX_LEN ) )
  591. {
  592. //
  593. // The extension string is allocated by "GetAFileNameExtension()"
  594. // and given away to "AddToTempExtensionList()".
  595. //
  596. sc = GetAFileNameExtension( pwszKeyName,
  597. &pwszExtension );
  598. if(!FAILED(sc))
  599. {
  600. AddToTempExtensionList( pwszExtension );
  601. pwszExtension = NULL;
  602. }
  603. }
  604. }
  605. //
  606. // Build a table of extensions from the temporary linked list.
  607. //
  608. // Count the size.
  609. //
  610. for(pExt=m_pTempList; pExt!=NULL; pExt=pExt->pNext)
  611. {
  612. cszTotalStrs += 1;
  613. ccTotalChars += wcslen(pExt->pwszExtension) + 1;
  614. }
  615. // Allocate the memory
  616. //
  617. cbTotalSize = (cszTotalStrs+1) * sizeof (WCHAR*);
  618. cbTotalSize += ccTotalChars * sizeof(WCHAR*);
  619. ppwszTable = (LPWSTR*) CoTaskMemAlloc( cbTotalSize );
  620. // Set the pointers to the start of the pointer table and
  621. // the start of the character buffer space.
  622. //
  623. ppwszPtr = ppwszTable;
  624. pwszBuf = (WCHAR*) (ppwszTable + cszTotalStrs+1);
  625. for(pExt=m_pTempList; pExt!=NULL; pExt=pExt->pNext)
  626. {
  627. // Copy the string into the buffer space.
  628. //
  629. wcscpy(pwszBuf, pExt->pwszExtension);
  630. // Record the enrty to point at it.
  631. //
  632. *ppwszPtr = pwszBuf;
  633. // Advance the pointers.
  634. //
  635. ppwszPtr += 1; // Advance one string pointer.
  636. pwszBuf += wcslen(pwszBuf) +1; // Advance one string.
  637. }
  638. // Place a NULL in the last entry, to terminate the list.
  639. //
  640. *ppwszPtr = NULL;
  641. FreeTempExtensionList();
  642. // Success. Copy results out.
  643. //
  644. m_ppwszExtensions = ppwszTable;
  645. ppwszTable = NULL;
  646. EH_Err:
  647. if( NULL != ppwszTable )
  648. CoTaskMemFree( ppwszTable );
  649. if( NULL != pwszKeyName )
  650. delete[] pwszKeyName;
  651. return S_OK;
  652. }
  653. //
  654. // Search the existing list for an identical extension. If you don't find
  655. // one, then push a new one onto the front of the list.
  656. // The string is given to us. If we don't want it, then delete it.
  657. //
  658. HRESULT
  659. CTNUpdater::AddToTempExtensionList(
  660. WCHAR* pwszExtension)
  661. {
  662. TEMPEXTLIST* pExt;
  663. for(pExt=m_pTempList; pExt!=NULL; pExt=pExt->pNext)
  664. {
  665. if( 0 == _wcsicmp(pwszExtension, pExt->pwszExtension) )
  666. break;
  667. }
  668. if(NULL == pExt)
  669. { // If we didn't find it, save it on the list.
  670. pExt = new TEMPEXTLIST;
  671. pExt->pwszExtension = pwszExtension;
  672. pExt->pNext = m_pTempList;
  673. m_pTempList = pExt;
  674. }
  675. else
  676. { // If we already have one, then delete this string.
  677. CoTaskMemFree(pwszExtension);
  678. }
  679. return S_OK;
  680. }
  681. HRESULT
  682. CTNUpdater::FreeTempExtensionList()
  683. {
  684. TEMPEXTLIST* pExt;
  685. TEMPEXTLIST* pExtNext;
  686. pExt=m_pTempList;
  687. while(NULL != pExt)
  688. {
  689. pExtNext = pExt->pNext;
  690. CoTaskMemFree( pExt->pwszExtension );
  691. delete pExt;
  692. pExt = pExtNext;
  693. }
  694. m_pTempList = NULL;
  695. return S_OK;
  696. }
  697. HRESULT
  698. CTNUpdater::GetAFileNameExtension(
  699. WCHAR* pwszKeyName,
  700. WCHAR** ppwszExtension)
  701. {
  702. DWORD status, dwType;
  703. HKEY hkeyImageFormat=NULL;
  704. DWORD cbExtBuf=0;
  705. HRESULT sc=S_OK;
  706. WCHAR *pwszExt=NULL;
  707. status = RegOpenKeyEx( m_hkeyMime,
  708. pwszKeyName,
  709. 0,
  710. KEY_ALL_ACCESS,
  711. &hkeyImageFormat );
  712. if(ERROR_SUCCESS != status)
  713. {
  714. updrDebug(( DEB_ERROR,
  715. "Error, could not open image format key '%ws' err=%d\n",
  716. pwszKeyName, status ));
  717. updrErr( EH_Err, LAST_SCODE );
  718. }
  719. // Get the Size of the extension string.
  720. //
  721. status = RegQueryValueEx( hkeyImageFormat,
  722. L"Extension",
  723. 0,
  724. &dwType,
  725. NULL,
  726. &cbExtBuf );
  727. if(ERROR_SUCCESS != status)
  728. {
  729. if(ERROR_FILE_NOT_FOUND != status)
  730. {
  731. updrDebug(( DEB_REGINFO,
  732. "Error, reading Extension for '%ws' err=%d\n",
  733. pwszKeyName, status ));
  734. }
  735. sc = E_FAIL;
  736. goto EH_Err;
  737. }
  738. if(REG_SZ != dwType)
  739. {
  740. updrDebug(( DEB_REGINFO,
  741. "Error, Extension for '%ws' not REG_SZ type.\n",
  742. pwszKeyName ));
  743. sc = E_FAIL;
  744. goto EH_Err;
  745. }
  746. // Allocate the buffer and read the extension string.
  747. //
  748. updrMem( pwszExt = (WCHAR*)CoTaskMemAlloc(cbExtBuf) );
  749. status = RegQueryValueEx( hkeyImageFormat,
  750. L"Extension",
  751. 0,
  752. &dwType,
  753. (BYTE*)pwszExt,
  754. &cbExtBuf );
  755. if(ERROR_SUCCESS != status)
  756. updrErr( EH_Err, LAST_SCODE );
  757. *ppwszExtension = pwszExt;
  758. pwszExt = NULL;
  759. EH_Err:
  760. if(NULL != pwszExt)
  761. CoTaskMemFree(pwszExt);
  762. if( NULL != hkeyImageFormat )
  763. RegCloseKey(hkeyImageFormat);
  764. return sc;
  765. }