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.

1817 lines
44 KiB

  1. //
  2. // Copyright 2001 - Microsoft Corporation
  3. //
  4. // Created By:
  5. // Geoff Pease (GPease) 23-JAN-2001
  6. //
  7. // Maintained By:
  8. // Geoff Pease (GPease) 23-JAN-2001
  9. //
  10. #include "pch.h"
  11. #include "DocProp.h"
  12. #include "DefProp.h"
  13. #include "IEditVariantsInPlace.h"
  14. #include "PropertyCacheItem.h"
  15. #include "PropertyCache.h"
  16. #include "AdvancedDlg.h"
  17. #include "SimpleDlg.h"
  18. #include "SummaryPage.h"
  19. #include "shutils.h"
  20. #include "WMUser.h"
  21. #include "doctypes.h"
  22. #include "ErrorDlgs.h"
  23. #include "LicensePage.h"
  24. #pragma hdrstop
  25. DEFINE_THISCLASS( "CSummaryPage" )
  26. // ************************************************************************
  27. //
  28. // Constructor / Destructor
  29. //
  30. // ************************************************************************
  31. //
  32. // CreateInstance - used by CFactory
  33. //
  34. HRESULT
  35. CSummaryPage::CreateInstance(
  36. IUnknown ** ppunkOut
  37. )
  38. {
  39. TraceFunc( "" );
  40. HRESULT hr;
  41. Assert( ppunkOut != NULL );
  42. CSummaryPage * pthis = new CSummaryPage;
  43. if ( pthis != NULL )
  44. {
  45. hr = THR( pthis->Init( ) );
  46. if ( SUCCEEDED( hr ) )
  47. {
  48. *ppunkOut = (IShellExtInit *) pthis;
  49. (*ppunkOut)->AddRef( );
  50. }
  51. pthis->Release( );
  52. }
  53. else
  54. {
  55. hr = E_OUTOFMEMORY;
  56. }
  57. HRETURN( hr );
  58. }
  59. //
  60. // Constructor
  61. //
  62. CSummaryPage::CSummaryPage( void )
  63. : _cRef( 1 )
  64. {
  65. TraceFunc( "" );
  66. InterlockedIncrement( &g_cObjects );
  67. Assert( 1 == _cRef ); // we initialize this above
  68. //
  69. // We assume that we are ZERO_INITed - be paranoid.
  70. //
  71. Assert( NULL == _hdlg );
  72. Assert( NULL == _pida );
  73. Assert( FALSE == _fReadOnly );
  74. Assert( FALSE == _fAdvanced );
  75. Assert( NULL == _pAdvancedDlg );
  76. Assert( NULL == _pSimpleDlg );
  77. Assert( 0 == _dwCurrentBindMode );
  78. Assert( NULL == _rgdwDocType );
  79. Assert( 0 == _cSources );
  80. Assert( NULL == _rgpss );
  81. Assert( NULL == _pPropertyCache );
  82. TraceFuncExit();
  83. }
  84. //
  85. // Description:
  86. // Initializes class. Put calls that can fail in here.
  87. //
  88. HRESULT
  89. CSummaryPage::Init( void )
  90. {
  91. TraceFunc( "" );
  92. HRESULT hr = S_OK;
  93. // IUnknown stuff
  94. Assert( 1 == _cRef );
  95. // IShellExtInit stuff
  96. // IShellPropSheetExt stuff
  97. HRETURN( hr );
  98. }
  99. //
  100. // Destructor
  101. //
  102. CSummaryPage::~CSummaryPage( )
  103. {
  104. TraceFunc( "" );
  105. THR( PersistMode( ) );
  106. // ignore failure - what else can we do?
  107. if ( NULL != _pAdvancedDlg )
  108. {
  109. _pAdvancedDlg->Release( );
  110. }
  111. if ( NULL != _pSimpleDlg )
  112. {
  113. _pSimpleDlg->Release( );
  114. }
  115. if ( NULL != _rgdwDocType )
  116. {
  117. TraceFree( _rgdwDocType );
  118. }
  119. if ( NULL != _rgpss )
  120. {
  121. ULONG idx = _cSources;
  122. while ( 0 != idx )
  123. {
  124. idx --;
  125. if ( NULL != _rgpss[ idx ] )
  126. {
  127. _rgpss[ idx ]->Release( );
  128. }
  129. }
  130. TraceFree( _rgpss );
  131. }
  132. if ( NULL != _pPropertyCache )
  133. {
  134. _pPropertyCache->Destroy( );
  135. }
  136. if ( NULL != _pida )
  137. {
  138. TraceFree( _pida );
  139. }
  140. Assert( 0 != g_cObjects );
  141. InterlockedDecrement( &g_cObjects );
  142. TraceFuncExit();
  143. }
  144. // ************************************************************************
  145. //
  146. // IUnknown
  147. //
  148. // ************************************************************************
  149. //
  150. //
  151. //
  152. STDMETHODIMP
  153. CSummaryPage::QueryInterface(
  154. REFIID riid,
  155. LPVOID *ppv
  156. )
  157. {
  158. TraceQIFunc( riid, ppv );
  159. HRESULT hr = E_NOINTERFACE;
  160. if ( IsEqualIID( riid, __uuidof(IUnknown) ) )
  161. {
  162. *ppv = static_cast< IShellExtInit * >( this );
  163. hr = S_OK;
  164. }
  165. else if ( IsEqualIID( riid, __uuidof(IShellExtInit) ) )
  166. {
  167. *ppv = TraceInterface( __THISCLASS__, IShellExtInit, this, 0 );
  168. hr = S_OK;
  169. }
  170. else if ( IsEqualIID( riid, __uuidof(IShellPropSheetExt) ) )
  171. {
  172. *ppv = TraceInterface( __THISCLASS__, IShellPropSheetExt, this, 0 );
  173. hr = S_OK;
  174. }
  175. if ( SUCCEEDED( hr ) )
  176. {
  177. ((IUnknown*) *ppv)->AddRef( );
  178. }
  179. QIRETURN( hr, riid );
  180. }
  181. //
  182. //
  183. //
  184. STDMETHODIMP_(ULONG)
  185. CSummaryPage::AddRef( void )
  186. {
  187. TraceFunc( "[IUnknown]" );
  188. _cRef ++; // apartment
  189. RETURN( _cRef );
  190. }
  191. //
  192. //
  193. //
  194. STDMETHODIMP_(ULONG)
  195. CSummaryPage::Release( void )
  196. {
  197. TraceFunc( "[IUnknown]" );
  198. _cRef --; // apartment
  199. if ( 0 != _cRef )
  200. RETURN( _cRef );
  201. delete this;
  202. RETURN( 0 );
  203. }
  204. // ************************************************************************
  205. //
  206. // IShellExtInit
  207. //
  208. // ************************************************************************
  209. //
  210. //
  211. //
  212. STDMETHODIMP
  213. CSummaryPage::Initialize(
  214. LPCITEMIDLIST pidlFolderIn
  215. , LPDATAOBJECT lpdobjIn
  216. , HKEY hkeyProgIDIn
  217. )
  218. {
  219. TraceFunc( "" );
  220. HRESULT hr;
  221. //
  222. // Make a copy of the PIDLs.
  223. //
  224. Assert( NULL == _pida );
  225. hr = THR( DataObj_CopyHIDA( lpdobjIn, &_pida ) );
  226. if ( FAILED( hr ) )
  227. goto Cleanup;
  228. //
  229. // Start out with READ ONLY access
  230. //
  231. _dwCurrentBindMode = STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE;
  232. _rgdwDocType = (DWORD *) TraceAlloc( HEAP_ZERO_MEMORY, sizeof(DWORD) * _pida->cidl );
  233. if ( NULL == _rgdwDocType )
  234. goto OutOfMemory;
  235. hr = STHR( BindToStorage( ) );
  236. if ( FAILED( hr ) )
  237. goto Cleanup;
  238. //
  239. // We were able to bind to anything?
  240. //
  241. if ( S_FALSE == hr )
  242. {
  243. //
  244. // Nope. Indicate this by failing.
  245. //
  246. hr = E_FAIL;
  247. goto Cleanup;
  248. }
  249. //
  250. // Retrieve the properties
  251. //
  252. hr = THR( RetrieveProperties( ) );
  253. if ( FAILED( hr ) )
  254. goto Cleanup;
  255. //
  256. // Don't hang on to the storage.
  257. //
  258. THR( ReleaseStorage( ) );
  259. hr = S_OK;
  260. Cleanup:
  261. HRETURN( hr );
  262. OutOfMemory:
  263. hr = E_OUTOFMEMORY;
  264. goto Cleanup;
  265. }
  266. // ************************************************************************
  267. //
  268. // IShellPropSheetExt
  269. //
  270. // ************************************************************************
  271. //
  272. //
  273. //
  274. STDMETHODIMP
  275. CSummaryPage::AddPages(
  276. LPFNADDPROPSHEETPAGE lpfnAddPageIn
  277. , LPARAM lParam
  278. )
  279. {
  280. TraceFunc( "" );
  281. HRESULT hr = E_FAIL; // assume failure
  282. HPROPSHEETPAGE hPage;
  283. PROPSHEETPAGE psp = { 0 };
  284. psp.dwSize = sizeof(psp);
  285. psp.dwFlags = PSP_USECALLBACK;
  286. psp.hInstance = g_hInstance;
  287. psp.pszTemplate = MAKEINTRESOURCE(IDD_SUMMARYPAGE);
  288. psp.pfnDlgProc = DlgProc;
  289. psp.pfnCallback = PageCallback;
  290. psp.lParam = (LPARAM) this;
  291. hPage = CreatePropertySheetPage( &psp );
  292. if ( NULL != hPage )
  293. {
  294. BOOL b = TBOOL( lpfnAddPageIn( hPage, lParam ) );
  295. if ( b )
  296. {
  297. hr = S_OK;
  298. }
  299. else
  300. {
  301. DestroyPropertySheetPage( hPage );
  302. }
  303. }
  304. //
  305. // Add the License Page, if needed, but only if there is only
  306. // one source file selected.
  307. //
  308. if ( _fNeedLicensePage && 1 == _cSources )
  309. {
  310. IUnknown * punk;
  311. hr = THR( CLicensePage::CreateInstance( &punk, _pPropertyCache ) );
  312. if ( SUCCEEDED( hr ) )
  313. {
  314. IShellPropSheetExt * pspse;
  315. hr = THR( punk->TYPESAFEQI( pspse ) );
  316. if ( SUCCEEDED( hr ) )
  317. {
  318. hr = THR( pspse->AddPages( lpfnAddPageIn, lParam ) );
  319. pspse->Release( );
  320. }
  321. punk->Release( );
  322. }
  323. }
  324. HRETURN( hr );
  325. }
  326. //
  327. //
  328. //
  329. STDMETHODIMP
  330. CSummaryPage::ReplacePage(
  331. UINT uPageIDIn
  332. , LPFNADDPROPSHEETPAGE lpfnReplacePageIn
  333. , LPARAM lParam
  334. )
  335. {
  336. TraceFunc( "" );
  337. HRESULT hr = THR( E_NOTIMPL );
  338. HRETURN( hr );
  339. }
  340. // ***************************************************************************
  341. //
  342. // Dialog Proc and Property Sheet Callback
  343. //
  344. // ***************************************************************************
  345. //
  346. //
  347. //
  348. INT_PTR CALLBACK
  349. CSummaryPage::DlgProc(
  350. HWND hDlgIn
  351. , UINT uMsgIn
  352. , WPARAM wParam
  353. , LPARAM lParam
  354. )
  355. {
  356. // Don't do TraceFunc because every mouse movement will cause this function to spew.
  357. WndMsg( hDlgIn, uMsgIn, wParam, lParam );
  358. LRESULT lr = FALSE;
  359. CSummaryPage * pPage = (CSummaryPage *) GetWindowLongPtr( hDlgIn, DWLP_USER );
  360. if ( uMsgIn == WM_INITDIALOG )
  361. {
  362. PROPSHEETPAGE * ppage = (PROPSHEETPAGE *) lParam;
  363. SetWindowLongPtr( hDlgIn, DWLP_USER, (LPARAM) ppage->lParam );
  364. pPage = (CSummaryPage *) ppage->lParam;
  365. pPage->_hdlg = hDlgIn;
  366. }
  367. if ( pPage != NULL )
  368. {
  369. Assert( hDlgIn == pPage->_hdlg );
  370. switch( uMsgIn )
  371. {
  372. case WM_INITDIALOG:
  373. lr = pPage->OnInitDialog( );
  374. break;
  375. case WM_NOTIFY:
  376. lr = pPage->OnNotify( (int) wParam, (LPNMHDR) lParam );
  377. break;
  378. case WMU_TOGGLE:
  379. lr = pPage->OnToggle( );
  380. break;
  381. case WM_DESTROY:
  382. SetWindowLongPtr( hDlgIn, DWLP_USER, NULL );
  383. lr = pPage->OnDestroy( );
  384. break;
  385. }
  386. }
  387. return lr;
  388. }
  389. //
  390. //
  391. //
  392. UINT CALLBACK
  393. CSummaryPage::PageCallback(
  394. HWND hwndIn
  395. , UINT uMsgIn
  396. , LPPROPSHEETPAGE ppspIn
  397. )
  398. {
  399. TraceFunc( "" );
  400. UINT uRet = 0;
  401. CSummaryPage * pPage = (CSummaryPage *) ppspIn->lParam;
  402. if ( NULL != pPage )
  403. {
  404. switch ( uMsgIn )
  405. {
  406. case PSPCB_CREATE:
  407. uRet = TRUE; // allow the page to be created
  408. break;
  409. case PSPCB_ADDREF:
  410. pPage->AddRef( );
  411. break;
  412. case PSPCB_RELEASE:
  413. pPage->Release( );
  414. break;
  415. }
  416. }
  417. RETURN( uRet );
  418. }
  419. // ***************************************************************************
  420. //
  421. // Private methods
  422. //
  423. // ***************************************************************************
  424. //
  425. // WM_INITDIALOG handler
  426. //
  427. LRESULT
  428. CSummaryPage::OnInitDialog( void )
  429. {
  430. TraceFunc( "" );
  431. HRESULT hr;
  432. LRESULT lr = FALSE;
  433. Assert( NULL != _hdlg ); // this should have been initialized in the DlgProc.
  434. THR( RecallMode( ) );
  435. // ignore failure
  436. if ( _fAdvanced )
  437. {
  438. hr = THR( EnsureAdvancedDlg( ) );
  439. if ( S_OK == hr )
  440. {
  441. hr = THR( _pAdvancedDlg->Show( ) );
  442. }
  443. }
  444. else
  445. {
  446. hr = THR( EnsureSimpleDlg( ) );
  447. if ( S_OK == hr )
  448. {
  449. //
  450. // This returns S_FALSE indicating that no "Simple" properties
  451. // were found.
  452. //
  453. hr = STHR( _pSimpleDlg->Show( ) );
  454. if ( S_FALSE == hr )
  455. {
  456. hr = THR( EnsureAdvancedDlg( ) );
  457. if ( S_OK == hr )
  458. {
  459. _fAdvanced = TRUE;
  460. THR( _pSimpleDlg->Hide( ) );
  461. THR( _pAdvancedDlg->Show( ) );
  462. }
  463. }
  464. }
  465. }
  466. RETURN( lr );
  467. }
  468. //
  469. // WM_NOTIFY handler
  470. //
  471. LRESULT
  472. CSummaryPage::OnNotify(
  473. int iCtlIdIn
  474. , LPNMHDR pnmhIn
  475. )
  476. {
  477. TraceFunc( "" );
  478. LRESULT lr = FALSE;
  479. switch( pnmhIn->code )
  480. {
  481. case PSN_APPLY:
  482. {
  483. HRESULT hr;
  484. //
  485. // For some reason, we don't get the EN_KILLFOCUS when the user clicks
  486. // the "Apply" button. Calling Show( ) again toggles the focus, causing
  487. // the EN_KILLFOCUS which updates the property cache.
  488. //
  489. if ( !_fAdvanced && ( NULL != _pSimpleDlg ) )
  490. {
  491. STHR( _pSimpleDlg->Show( ) );
  492. }
  493. hr = STHR( PersistProperties( ) );
  494. if ( FAILED( hr ) )
  495. {
  496. DisplayPersistFailure( _hdlg, hr, ( _pida->cidl > 1 ) );
  497. SetWindowLongPtr( _hdlg, DWLP_MSGRESULT, PSNRET_INVALID );
  498. lr = TRUE;
  499. }
  500. }
  501. break;
  502. }
  503. RETURN( lr );
  504. }
  505. //
  506. // WMU_TOGGLE handler
  507. //
  508. LRESULT
  509. CSummaryPage::OnToggle( void )
  510. {
  511. TraceFunc( "" );
  512. HRESULT hr;
  513. BOOL fMultiple = ( 1 < _cSources );
  514. if ( _fAdvanced )
  515. {
  516. hr = THR( _pAdvancedDlg->Hide( ) );
  517. if ( FAILED( hr ) )
  518. goto Cleanup;
  519. ShowSimple:
  520. hr = STHR( EnsureSimpleDlg( ) );
  521. if ( FAILED( hr ) )
  522. goto Cleanup;
  523. if ( S_FALSE == hr )
  524. {
  525. hr = THR( _pSimpleDlg->PopulateProperties( _pPropertyCache, _rgdwDocType[ 0 ], fMultiple ) );
  526. if ( FAILED( hr ) )
  527. goto Cleanup;
  528. }
  529. hr = STHR( _pSimpleDlg->Show( ) );
  530. if ( FAILED( hr ) )
  531. goto ShowAdvanced;
  532. _fAdvanced = FALSE;
  533. }
  534. else
  535. {
  536. hr = THR( _pSimpleDlg->Hide( ) );
  537. if ( FAILED( hr ) )
  538. goto Cleanup;
  539. ShowAdvanced:
  540. hr = STHR( EnsureAdvancedDlg( ) );
  541. if ( FAILED( hr ) )
  542. goto Cleanup;
  543. if ( S_FALSE == hr )
  544. {
  545. hr = THR( _pAdvancedDlg->PopulateProperties( _pPropertyCache, _rgdwDocType[ 0 ], fMultiple ) );
  546. if ( FAILED( hr ) )
  547. goto Cleanup;
  548. }
  549. hr = THR( _pAdvancedDlg->Show( ) );
  550. if ( FAILED( hr ) )
  551. goto ShowSimple;
  552. _fAdvanced = TRUE;
  553. }
  554. hr = S_OK;
  555. Cleanup:
  556. HRETURN( hr );
  557. }
  558. //
  559. // WM_DESTROY handler
  560. //
  561. LRESULT
  562. CSummaryPage::OnDestroy( void )
  563. {
  564. TraceFunc( "" );
  565. LRESULT lr = FALSE;
  566. if ( NULL != _pAdvancedDlg )
  567. {
  568. _pAdvancedDlg->Release( );
  569. _pAdvancedDlg = NULL;
  570. }
  571. if ( NULL != _pSimpleDlg )
  572. {
  573. _pSimpleDlg->Release( );
  574. _pSimpleDlg = NULL;
  575. }
  576. RETURN( lr );
  577. }
  578. //
  579. // Return Values:
  580. // S_OK
  581. // Successfully retrieved a PIDL
  582. //
  583. // S_FALSE
  584. // Call succeeded, no PIDL was found.
  585. //
  586. HRESULT
  587. CSummaryPage::Item(
  588. UINT idxIn
  589. , LPITEMIDLIST * ppidlOut
  590. )
  591. {
  592. TraceFunc( "" );
  593. HRESULT hr = S_FALSE;
  594. Assert( NULL != ppidlOut );
  595. Assert( NULL != _pida );
  596. *ppidlOut = NULL;
  597. if ( idxIn < _pida->cidl )
  598. {
  599. *ppidlOut = IDA_FullIDList( _pida, idxIn );
  600. if ( NULL != *ppidlOut )
  601. {
  602. hr = S_OK;
  603. }
  604. }
  605. HRETURN( hr );
  606. }
  607. //
  608. // Description:
  609. // Checks _pAdvancedDlg to make sure that it is not NULL.
  610. // If it is NULL, it will create a new instance of CAdvancedDlg.
  611. //
  612. // Return Values:
  613. // S_OK
  614. // A new _pAdvancedDlg was created.
  615. //
  616. // S_FALSE
  617. // _pAdvancedDlg was not NULL.
  618. //
  619. // other HRESULTs.
  620. //
  621. HRESULT
  622. CSummaryPage::EnsureAdvancedDlg( void )
  623. {
  624. TraceFunc( "" );
  625. HRESULT hr = S_OK;
  626. if ( NULL == _pAdvancedDlg )
  627. {
  628. hr = THR( CAdvancedDlg::CreateInstance( &_pAdvancedDlg, _hdlg ) );
  629. if ( S_OK == hr )
  630. {
  631. hr = THR( _pAdvancedDlg->PopulateProperties( _pPropertyCache, _rgdwDocType[ 0 ], ( 1 < _cSources ) ) );
  632. }
  633. }
  634. else
  635. {
  636. hr = S_FALSE;
  637. }
  638. HRETURN( hr );
  639. }
  640. //
  641. // Description:
  642. // Checks _pSimpleDlg to make sure that it is not NULL.
  643. // If it is NULL, it will create a new instance of CSimpleDialog.
  644. //
  645. // Return Values:
  646. // S_OK
  647. // A new _pSimpleDlg was created.
  648. //
  649. // S_FALSE
  650. // _pSimpleDlg was not NULL.
  651. //
  652. // other HRESULTs.
  653. //
  654. HRESULT
  655. CSummaryPage::EnsureSimpleDlg( void )
  656. {
  657. TraceFunc( "" );
  658. HRESULT hr = S_OK;
  659. BOOL fMultiple = ( 1 < _cSources );
  660. if ( NULL == _pSimpleDlg )
  661. {
  662. hr = THR( CSimpleDlg::CreateInstance( &_pSimpleDlg, _hdlg, fMultiple ) );
  663. if ( S_OK == hr )
  664. {
  665. hr = THR( _pSimpleDlg->PopulateProperties( _pPropertyCache, _rgdwDocType[ 0 ], fMultiple ) );
  666. }
  667. }
  668. else
  669. {
  670. hr = S_FALSE;
  671. }
  672. HRETURN( hr );
  673. }
  674. //
  675. // Description:
  676. // Persists the UI mode settings for the page.
  677. //
  678. // Return Values:
  679. // S_OK
  680. //
  681. HRESULT CSummaryPage::PersistMode( void )
  682. {
  683. DWORD dwAdvanced = _fAdvanced;
  684. SHRegSetUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\PropSummary"), TEXT("Advanced"),
  685. REG_DWORD, &dwAdvanced, sizeof(dwAdvanced), SHREGSET_HKCU | SHREGSET_FORCE_HKCU);
  686. return S_OK;
  687. }
  688. //
  689. // Description:
  690. // Retrieves the UI mode settings for the page.
  691. //
  692. // Return Values:
  693. // S_OK
  694. //
  695. HRESULT CSummaryPage::RecallMode( void )
  696. {
  697. _fAdvanced = SHRegGetBoolUSValue(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\PropSummary"), TEXT("Advanced"), FALSE, TRUE);
  698. return S_OK;
  699. }
  700. //
  701. // Description:
  702. // Retrieves the properties from the storage and caches
  703. // them.
  704. //
  705. // Return Values:
  706. // S_OK
  707. // All values successfully read and cached.
  708. //
  709. // S_FALSE
  710. // Some values successfully read, but some weren't not.
  711. //
  712. // E_FAIL
  713. // No values were successfully read.
  714. //
  715. // E_OUTOFMEMORY
  716. // Out of memory.
  717. //
  718. // other HRESULTs
  719. //
  720. HRESULT
  721. CSummaryPage::RetrieveProperties( void )
  722. {
  723. TraceFunc( "" );
  724. const ULONG cBlocks = 10; // number of properties to grab at a time.
  725. HRESULT hr;
  726. ULONG cSource;
  727. ULONG idx;
  728. ULONG cPropertiesRetrieved = 0;
  729. ULONG cPropertiesCached = 0;
  730. IPropertyStorage * pPropStg = NULL;
  731. IEnumSTATPROPSETSTG * pEnumPropSet = NULL;
  732. IEnumSTATPROPSTG * pEnumProp = NULL;
  733. CPropertyCacheItem * pItem = NULL;
  734. CPropertyCache ** rgpPropertyCaches = NULL;
  735. IPropertyUI * ppui = NULL;
  736. //
  737. // If there are multiple sources, then follow these rules:
  738. //
  739. // If any of the properties/sources are read-only, mark all the properties as being read-only.
  740. //
  741. // If any of the properties != the first property, mark the item as multiple.
  742. //
  743. //
  744. // Make room for the property cache lists per source.
  745. //
  746. rgpPropertyCaches = ( CPropertyCache ** ) TraceAlloc( HEAP_ZERO_MEMORY, _cSources * sizeof(CPropertyCache *) );
  747. if ( NULL == rgpPropertyCaches )
  748. goto OutOfMemory;
  749. //
  750. // Enumerate the source's property sets via IPropertySetStorage interface
  751. //
  752. for ( cSource = 0; cSource < _cSources; cSource ++ )
  753. {
  754. //
  755. // Cleanup before next pass
  756. //
  757. if ( NULL != pEnumPropSet )
  758. {
  759. pEnumPropSet->Release( );
  760. pEnumPropSet = NULL;
  761. }
  762. hr = THR( CPropertyCache::CreateInstance( &rgpPropertyCaches[ cSource ] ) );
  763. if ( FAILED( hr ) )
  764. continue; // ignore and keep trying...
  765. IPropertySetStorage * pss = _rgpss[ cSource ]; // just borrowing - no need to AddRef( ).
  766. //
  767. // Add properties.
  768. //
  769. if ( NULL != pss )
  770. {
  771. //
  772. // Grab a set enumerator
  773. //
  774. hr = THR( pss->Enum( &pEnumPropSet ) );
  775. if ( FAILED( hr ) )
  776. continue; // ignore and try next source
  777. for( ;; ) // ever
  778. {
  779. STATPROPSETSTG statPropSet[ cBlocks ];
  780. ULONG cSetPropsRetrieved;
  781. hr = STHR( pEnumPropSet->Next( cBlocks, statPropSet, &cSetPropsRetrieved ) );
  782. if ( FAILED( hr ) )
  783. break; // exit condition
  784. if ( 0 == cSetPropsRetrieved )
  785. break; // exit condition
  786. //
  787. // for each property set
  788. //
  789. for ( ULONG cSet = 0; cSet < cSetPropsRetrieved; cSet ++ )
  790. {
  791. UINT uCodePage;
  792. //
  793. // Cleanup before next pass
  794. //
  795. if ( NULL != pPropStg )
  796. {
  797. pPropStg->Release( );
  798. pPropStg = NULL;
  799. }
  800. if ( NULL != pEnumProp )
  801. {
  802. pEnumProp->Release( );
  803. pEnumProp = NULL;
  804. }
  805. //
  806. // Open the set.
  807. //
  808. hr = THR( SHPropStgCreate( pss
  809. , statPropSet[ cSet ].fmtid
  810. , NULL
  811. , PROPSETFLAG_DEFAULT
  812. , _dwCurrentBindMode
  813. , OPEN_EXISTING
  814. , &pPropStg
  815. , &uCodePage
  816. ) );
  817. if ( FAILED( hr ) )
  818. continue; // ignore and try to get the next set
  819. //
  820. // Grab a property enumerator, but first indicate we want to enum all properties (if we can)
  821. //
  822. IQueryPropertyFlags *pqpf;
  823. if (SUCCEEDED(pPropStg->QueryInterface(IID_PPV_ARG(IQueryPropertyFlags, &pqpf))))
  824. {
  825. THR(pqpf->SetEnumFlags(SHCOLSTATE_SLOW));
  826. pqpf->Release();
  827. }
  828. hr = THR( pPropStg->Enum( &pEnumProp ) );
  829. if ( FAILED( hr ) )
  830. continue; // ignore and try to get the next set
  831. for( ;; ) // ever
  832. {
  833. STATPROPSTG statProp[ cBlocks ];
  834. ULONG cPropsRetrieved;
  835. hr = STHR( pEnumProp->Next( cBlocks, statProp, &cPropsRetrieved ) );
  836. if ( FAILED( hr ) )
  837. break; // exit condition
  838. if ( 0 == cPropsRetrieved )
  839. break; // exit condition
  840. cPropertiesRetrieved += cPropsRetrieved;
  841. //
  842. // Retrieve default property item definition and the value for
  843. // each property in this set.
  844. //
  845. for ( ULONG cProp = 0; cProp < cPropsRetrieved; cProp++ )
  846. {
  847. Assert( NULL != rgpPropertyCaches[ cSource ] );
  848. hr = THR( rgpPropertyCaches[ cSource ]->AddNewPropertyCacheItem( &statPropSet[ cSet ].fmtid
  849. , statProp[ cProp ].propid
  850. , statProp[ cProp ].vt
  851. , uCodePage
  852. , _fReadOnly
  853. , pPropStg
  854. , NULL
  855. ) );
  856. if ( FAILED( hr ) )
  857. continue; // ignore
  858. cPropertiesCached ++;
  859. }
  860. }
  861. }
  862. }
  863. }
  864. //
  865. // Some file types have special copy-protection that prohibits us
  866. // from editing their properties because doing so would destroy
  867. // the copy-protection on the file. We need to detect these files
  868. // and toggle their properties to READ-ONLY if their property set
  869. // contains a copy-protection PID and it is enabled.
  870. //
  871. switch ( _rgdwDocType[ cSource ] )
  872. {
  873. case FTYPE_WMA:
  874. case FTYPE_ASF:
  875. case FTYPE_MP3:
  876. case FTYPE_WMV:
  877. hr = THR( CheckForCopyProtection( rgpPropertyCaches[ cSource ] ) );
  878. if ( S_OK == hr )
  879. {
  880. _fReadOnly = TRUE;
  881. _fNeedLicensePage = TRUE;
  882. ChangeGatheredPropertiesToReadOnly( rgpPropertyCaches[ cSource ] );
  883. }
  884. break;
  885. }
  886. //
  887. // Now, iterate our default property sets and add to our collection
  888. // those properties the source is missing.
  889. //
  890. // In DEBUG:
  891. // If the CONTROL key is down, we'll add all the properties in our
  892. // def prop table.
  893. //
  894. for ( idx = 0; NULL != g_rgDefPropertyItems[ idx ].pszName; idx ++ )
  895. {
  896. if ( ( ( _rgdwDocType[ cSource ] & g_rgDefPropertyItems[ idx ].dwSrcType )
  897. && ( g_rgDefPropertyItems[ idx ].fAlwaysPresentProperty )
  898. )
  899. #ifdef DEBUG
  900. || ( GetKeyState( VK_CONTROL ) < 0 )
  901. #endif DEBUG
  902. )
  903. {
  904. hr = STHR( rgpPropertyCaches[ cSource ]->FindItemEntry( g_rgDefPropertyItems[ idx ].pFmtID
  905. , g_rgDefPropertyItems[ idx ].propID
  906. , NULL
  907. ) );
  908. if ( S_FALSE == hr )
  909. {
  910. //
  911. // Create a new item for the missing property.
  912. //
  913. hr = THR( rgpPropertyCaches[ cSource ]->AddNewPropertyCacheItem( g_rgDefPropertyItems[ idx ].pFmtID
  914. , g_rgDefPropertyItems[ idx ].propID
  915. , g_rgDefPropertyItems[ idx ].vt
  916. , 0
  917. , _fReadOnly
  918. , NULL
  919. , NULL
  920. ) );
  921. }
  922. }
  923. }
  924. }
  925. if ( 1 == _cSources )
  926. {
  927. //
  928. // Since there is only one source, give ownership of the list away.
  929. //
  930. Assert( NULL == _pPropertyCache );
  931. _pPropertyCache = rgpPropertyCaches[ 0 ];
  932. rgpPropertyCaches[ 0 ] = NULL;
  933. }
  934. else
  935. {
  936. CollateMultipleProperties( rgpPropertyCaches );
  937. }
  938. if ( NULL == _pPropertyCache )
  939. {
  940. hr = E_FAIL; // nothing retrieved - nothing to show
  941. }
  942. else if ( cPropertiesCached == cPropertiesRetrieved )
  943. {
  944. hr = S_OK; // all retrieved and successfully cached.
  945. }
  946. else if ( 0 != cPropertiesRetrieved )
  947. {
  948. hr = S_FALSE; // missing a few.
  949. }
  950. else
  951. {
  952. hr = E_FAIL; // nothing read and/or cached.
  953. }
  954. Cleanup:
  955. if ( NULL != pEnumPropSet )
  956. {
  957. pEnumPropSet->Release( );
  958. }
  959. if ( NULL != pPropStg )
  960. {
  961. pPropStg->Release( );
  962. }
  963. if ( NULL != pEnumProp )
  964. {
  965. pEnumProp->Release( );
  966. }
  967. if ( NULL != pItem )
  968. {
  969. THR( pItem->Destroy( ) );
  970. }
  971. if ( NULL != ppui )
  972. {
  973. ppui->Release( );
  974. }
  975. if ( NULL != rgpPropertyCaches )
  976. {
  977. idx = _cSources;
  978. while( 0 != idx )
  979. {
  980. idx --;
  981. if ( NULL != rgpPropertyCaches[ idx ] )
  982. {
  983. rgpPropertyCaches[ idx ]->Destroy( );
  984. }
  985. }
  986. TraceFree( rgpPropertyCaches );
  987. }
  988. HRETURN( hr );
  989. OutOfMemory:
  990. hr = E_OUTOFMEMORY;
  991. goto Cleanup;
  992. }
  993. //
  994. // Description:
  995. // Walks thru the property cache and saves the dirty items.
  996. //
  997. // Return Values:
  998. // S_OK
  999. // Success!
  1000. //
  1001. // S_FALSE
  1002. // Success, but nothing was updated.
  1003. //
  1004. // E_OUTOFMEMORY
  1005. // Out of memory.
  1006. //
  1007. // other HRESULTs.
  1008. //
  1009. HRESULT
  1010. CSummaryPage::PersistProperties( void )
  1011. {
  1012. TraceFunc( "" );
  1013. HRESULT hr;
  1014. ULONG cDirtyCount;
  1015. ULONG idx;
  1016. ULONG cStart;
  1017. ULONG cSource;
  1018. CPropertyCacheItem * pItem;
  1019. PROPSPEC * pSpecs = NULL;
  1020. PROPVARIANT * pValues = NULL;
  1021. FMTID * pFmtIds = NULL;
  1022. Assert( NULL != _pida );
  1023. Assert( NULL != _pPropertyCache );
  1024. //
  1025. // If the storage was read-only, then bypass this!
  1026. //
  1027. if ( _fReadOnly )
  1028. {
  1029. hr = S_OK;
  1030. goto Cleanup;
  1031. }
  1032. //
  1033. // Bind to the storage
  1034. //
  1035. _dwCurrentBindMode = STGM_DIRECT | STGM_READWRITE | STGM_SHARE_EXCLUSIVE;
  1036. hr = THR( BindToStorage( ) );
  1037. if ( FAILED( hr ) )
  1038. goto Cleanup;
  1039. //
  1040. // Loop thru the properties to count how many need to be persisted.
  1041. //
  1042. hr = THR( _pPropertyCache->GetNextItem( NULL, &pItem ) );
  1043. if ( FAILED( hr ) )
  1044. goto Cleanup;
  1045. cDirtyCount = 0;
  1046. while ( NULL != pItem )
  1047. {
  1048. hr = STHR( pItem->IsDirty( ) );
  1049. if ( S_OK == hr )
  1050. {
  1051. cDirtyCount ++;
  1052. }
  1053. hr = STHR( pItem->GetNextItem( &pItem ) );
  1054. if ( FAILED( hr ) )
  1055. goto Cleanup;
  1056. if ( S_FALSE == hr )
  1057. break; // exit condition
  1058. }
  1059. //
  1060. // If nothing is dirty, then bail.
  1061. //
  1062. if ( 0 == cDirtyCount )
  1063. {
  1064. hr = S_FALSE;
  1065. goto Cleanup;
  1066. }
  1067. //
  1068. // Allocate memory to persist the properties in one call.
  1069. //
  1070. pSpecs = (PROPSPEC *) TraceAlloc( HEAP_ZERO_MEMORY, cDirtyCount * sizeof(*pSpecs) );
  1071. if ( NULL == pSpecs )
  1072. goto OutOfMemory;
  1073. pValues = (PROPVARIANT *) TraceAlloc( HEAP_ZERO_MEMORY, cDirtyCount * sizeof(*pValues) );
  1074. if ( NULL == pValues )
  1075. goto OutOfMemory;
  1076. pFmtIds = (FMTID *) TraceAlloc( HEAP_ZERO_MEMORY, cDirtyCount * sizeof(*pFmtIds) );
  1077. if ( NULL == pFmtIds )
  1078. goto OutOfMemory;
  1079. //
  1080. // Loop thru the properties filling in the structures.
  1081. //
  1082. hr = THR( _pPropertyCache->GetNextItem( NULL, &pItem ) );
  1083. if ( FAILED( hr ) )
  1084. goto Cleanup;
  1085. cDirtyCount = 0; // reset
  1086. while ( NULL != pItem )
  1087. {
  1088. hr = STHR( pItem->IsDirty( ) );
  1089. if ( S_OK == hr )
  1090. {
  1091. PROPVARIANT * ppropvar;
  1092. hr = THR( pItem->GetPropertyValue( &ppropvar ) );
  1093. if ( FAILED( hr ) )
  1094. goto Cleanup;
  1095. PropVariantInit( &pValues[ cDirtyCount ] );
  1096. hr = THR( PropVariantCopy( &pValues[ cDirtyCount ], ppropvar ) );
  1097. if ( FAILED( hr ) )
  1098. goto Cleanup;
  1099. hr = THR( pItem->GetFmtId( &pFmtIds[ cDirtyCount ] ) );
  1100. if ( FAILED( hr ) )
  1101. goto Cleanup;
  1102. pSpecs[ cDirtyCount ].ulKind = PRSPEC_PROPID;
  1103. hr = THR( pItem->GetPropId( &pSpecs[ cDirtyCount ].propid ) );
  1104. if ( FAILED( hr ) )
  1105. goto Cleanup;
  1106. cDirtyCount ++;
  1107. }
  1108. hr = STHR( pItem->GetNextItem( &pItem ) );
  1109. if ( FAILED( hr ) )
  1110. goto Cleanup;
  1111. if ( S_FALSE == hr )
  1112. break; // exit condition
  1113. }
  1114. //
  1115. // Make the calls!
  1116. //
  1117. hr = S_OK; // assume success!
  1118. for ( cSource = 0; cSource < _cSources; cSource ++ )
  1119. {
  1120. for ( idx = cStart = 0; idx < cDirtyCount; idx ++ )
  1121. {
  1122. //
  1123. // Try to batch up the properties.
  1124. //
  1125. if ( ( idx == cDirtyCount - 1 )
  1126. || ( !IsEqualGUID( pFmtIds[ idx ], pFmtIds[ idx + 1 ] ) )
  1127. )
  1128. {
  1129. HRESULT hrSet;
  1130. IPropertyStorage* pps;
  1131. UINT uCodePage = 0;
  1132. hrSet = THR( SHPropStgCreate( _rgpss[ cSource ]
  1133. , pFmtIds[ idx ]
  1134. , NULL
  1135. , PROPSETFLAG_DEFAULT
  1136. , _dwCurrentBindMode
  1137. , OPEN_ALWAYS
  1138. , &pps
  1139. , &uCodePage
  1140. ) );
  1141. if ( SUCCEEDED( hrSet ) )
  1142. {
  1143. hrSet = THR( SHPropStgWriteMultiple( pps
  1144. , &uCodePage
  1145. , ( idx - cStart ) + 1
  1146. , pSpecs + cStart
  1147. , pValues + cStart
  1148. , PID_FIRST_USABLE
  1149. ) );
  1150. pps->Release();
  1151. }
  1152. if ( FAILED( hrSet ) )
  1153. {
  1154. hr = hrSet;
  1155. }
  1156. cStart = idx + 1;
  1157. }
  1158. }
  1159. }
  1160. Cleanup:
  1161. THR( ReleaseStorage( ) );
  1162. if ( NULL != pSpecs )
  1163. {
  1164. TraceFree( pSpecs );
  1165. }
  1166. if ( NULL != pValues )
  1167. {
  1168. TraceFree( pValues );
  1169. }
  1170. if ( NULL != pFmtIds )
  1171. {
  1172. TraceFree( pFmtIds );
  1173. }
  1174. HRETURN( hr );
  1175. OutOfMemory:
  1176. hr = E_OUTOFMEMORY;
  1177. goto Cleanup;
  1178. }
  1179. //
  1180. // Description:
  1181. // Binds to the storage.
  1182. //
  1183. // Return Values:
  1184. // S_OK
  1185. // Success!
  1186. //
  1187. // other HRESULTs.
  1188. //
  1189. HRESULT
  1190. CSummaryPage::BindToStorage( void )
  1191. {
  1192. TraceFunc( "" );
  1193. //
  1194. // Valid object state
  1195. //
  1196. Assert( NULL != _pida );
  1197. Assert( NULL == _rgpss );
  1198. Assert( NULL != _rgdwDocType );
  1199. _fReadOnly = FALSE;
  1200. HRESULT hr = S_OK;
  1201. _rgpss = (IPropertySetStorage **) TraceAlloc( HEAP_ZERO_MEMORY, sizeof(IPropertySetStorage *) * _pida->cidl );
  1202. if ( _rgpss )
  1203. {
  1204. for ( _cSources = 0; _cSources < _pida->cidl; _cSources ++ )
  1205. {
  1206. LPITEMIDLIST pidl;
  1207. hr = STHR( Item( _cSources, &pidl ) );
  1208. if ( hr == S_FALSE )
  1209. break; // exit condition
  1210. DWORD dwAttribs = SFGAO_READONLY;
  1211. TCHAR szName[MAX_PATH];
  1212. hr = THR( SHGetNameAndFlags( pidl, SHGDN_NORMAL | SHGDN_FORPARSING, szName, ARRAYSIZE(szName), &dwAttribs ) );
  1213. if ( SUCCEEDED( hr ) )
  1214. {
  1215. PTSRV_FILETYPE ftType;
  1216. hr = STHR( CheckForKnownFileType( szName, &ftType ) );
  1217. if ( SUCCEEDED( hr ) )
  1218. {
  1219. _rgdwDocType[ _cSources ] = ftType;
  1220. }
  1221. if ( SFGAO_READONLY & dwAttribs )
  1222. {
  1223. _fReadOnly = TRUE;
  1224. }
  1225. dwAttribs = GetFileAttributes( szName );
  1226. if ( -1 != dwAttribs && FILE_ATTRIBUTE_OFFLINE & dwAttribs )
  1227. {
  1228. _rgdwDocType[ _cSources ] = FTYPE_UNSUPPORTED;
  1229. hr = THR( E_FAIL );
  1230. }
  1231. }
  1232. //
  1233. // Don't try to bind to it if we don't support it.
  1234. //
  1235. if ( SUCCEEDED(hr) && FTYPE_UNSUPPORTED != _rgdwDocType[ _cSources ] )
  1236. {
  1237. hr = THR( BindToObjectWithMode( pidl
  1238. , _dwCurrentBindMode
  1239. , TYPESAFEPARAMS( _rgpss[ _cSources ] )
  1240. ) );
  1241. if ( SUCCEEDED( hr ) )
  1242. {
  1243. //
  1244. // TODO: gpease 19-FEB-2001
  1245. // Test to see if the DOC is an RTF or OLESS document. But, how do
  1246. // we do that?
  1247. //
  1248. }
  1249. else
  1250. {
  1251. Assert( NULL == _rgpss[ _cSources ] );
  1252. _rgdwDocType[ _cSources ] = FTYPE_UNSUPPORTED;
  1253. }
  1254. }
  1255. else
  1256. {
  1257. hr = THR( E_FAIL );
  1258. }
  1259. ILFree( pidl );
  1260. }
  1261. }
  1262. else
  1263. {
  1264. hr = E_OUTOFMEMORY;
  1265. }
  1266. HRETURN( hr );
  1267. }
  1268. //
  1269. // Description:
  1270. // Releases the storage.
  1271. //
  1272. // Return Values:
  1273. // S_OK
  1274. // Success!
  1275. //
  1276. HRESULT
  1277. CSummaryPage::ReleaseStorage( void )
  1278. {
  1279. TraceFunc( "" );
  1280. HRESULT hr = S_OK;
  1281. ULONG idx = _cSources;
  1282. if ( NULL != _rgpss )
  1283. {
  1284. while ( 0 != idx )
  1285. {
  1286. idx --;
  1287. if ( NULL != _rgpss[ idx ] )
  1288. {
  1289. _rgpss[ idx ]->Release( );
  1290. }
  1291. }
  1292. TraceFree( _rgpss );
  1293. _rgpss = NULL;
  1294. }
  1295. HRETURN( hr );
  1296. }
  1297. //
  1298. // Description:
  1299. // Collates the properties from multiple sources and places them in
  1300. // pPropertyCache. It marks the properties "multiple" if more than one
  1301. // property is found and their values don't match.
  1302. //
  1303. // NOTE: the number of entries in rgpPropertyCachesIn is _cSources.
  1304. //
  1305. void
  1306. CSummaryPage::CollateMultipleProperties(
  1307. CPropertyCache ** rgpPropertyCachesIn
  1308. )
  1309. {
  1310. TraceFunc( "" );
  1311. HRESULT hr;
  1312. ULONG cSource;
  1313. CPropertyCacheItem * pItem;
  1314. CPropertyCacheItem * pItemCache;
  1315. CPropertyCacheItem * pItemCacheLast;
  1316. Assert( NULL != rgpPropertyCachesIn );
  1317. //
  1318. // If any of the sources returned "no properties", then the union
  1319. // of those properties is "none." We can take the easy way out and
  1320. // bail here.
  1321. //
  1322. for ( cSource = 0; cSource < _cSources; cSource ++ )
  1323. {
  1324. if ( NULL == rgpPropertyCachesIn[ cSource ] )
  1325. {
  1326. Assert( NULL == _pPropertyCache ); // This must be NULL to ensure we bail above.
  1327. goto Cleanup; // done - nothing to do
  1328. }
  1329. }
  1330. //
  1331. // First give ownership of the first source to the _pPropertyCache. From
  1332. // there we will prune and manipulate that list into the final list.
  1333. //
  1334. _pPropertyCache = rgpPropertyCachesIn[ 0 ];
  1335. rgpPropertyCachesIn[ 0 ] = NULL;
  1336. //
  1337. // Now loop thru the other sources comparing them to the orginal list.
  1338. //
  1339. pItemCache = NULL;
  1340. for( ;; )
  1341. {
  1342. PROPID propidCache;
  1343. FMTID fmtidCache;
  1344. BOOL fFoundMatch = FALSE;
  1345. pItemCacheLast = pItemCache;
  1346. hr = STHR( _pPropertyCache->GetNextItem( pItemCache, &pItemCache ) );
  1347. if ( FAILED( hr ) )
  1348. goto Cleanup;
  1349. if ( S_OK != hr )
  1350. break; // no more items - exit loop
  1351. hr = THR( pItemCache->GetPropId( &propidCache ) );
  1352. if ( FAILED( hr ) )
  1353. goto Cleanup;
  1354. hr = THR( pItemCache->GetFmtId( &fmtidCache ) );
  1355. if ( FAILED( hr ) )
  1356. goto Cleanup;
  1357. for ( cSource = 1; cSource < _cSources; cSource ++ )
  1358. {
  1359. pItem = NULL;
  1360. for ( ;; )
  1361. {
  1362. PROPID propid;
  1363. FMTID fmtid;
  1364. hr = STHR( rgpPropertyCachesIn[ cSource ]->GetNextItem( pItem, &pItem ) );
  1365. if ( S_OK != hr )
  1366. break; // end of list - exit loop
  1367. hr = THR( pItem->GetPropId( &propid ) );
  1368. if ( FAILED( hr ) )
  1369. goto Cleanup;
  1370. hr = THR( pItem->GetFmtId( &fmtid ) );
  1371. if ( FAILED( hr ) )
  1372. goto Cleanup;
  1373. if ( IsEqualIID( fmtid, fmtidCache ) && ( propid == propidCache ) )
  1374. {
  1375. LPCWSTR pcszItem;
  1376. LPCWSTR pcszItemCache;
  1377. //
  1378. // Matched!
  1379. //
  1380. fFoundMatch = TRUE;
  1381. hr = THR( pItem->GetPropertyStringValue( &pcszItem ) );
  1382. if ( FAILED( hr ) )
  1383. break; // ignore it - it can't be displayed
  1384. hr = THR( pItemCache->GetPropertyStringValue( &pcszItemCache ) );
  1385. if ( FAILED( hr ) )
  1386. break; // ignore it - it can't be displayed
  1387. if ( 0 != StrCmp( pcszItem, pcszItemCache ) )
  1388. {
  1389. THR( pItemCache->MarkMultiple( ) );
  1390. // ignore failure
  1391. }
  1392. break; // exit cache loop
  1393. }
  1394. else
  1395. {
  1396. fFoundMatch = FALSE;
  1397. }
  1398. }
  1399. //
  1400. // If it is missing from at least one source, we must remove it. There
  1401. // is no need to keep searching the other sources.
  1402. //
  1403. if ( !fFoundMatch )
  1404. break;
  1405. } // for: cSource
  1406. if ( !fFoundMatch )
  1407. {
  1408. //
  1409. // If a match was not found, delete the property from the property cache list.
  1410. //
  1411. hr = STHR( _pPropertyCache->RemoveItem( pItemCache ) );
  1412. if ( S_OK != hr )
  1413. goto Cleanup;
  1414. pItemCache = pItemCacheLast;
  1415. }
  1416. }
  1417. Cleanup:
  1418. TraceFuncExit( );
  1419. }
  1420. //
  1421. // Description:
  1422. // Walks the property cache and sets all properties to READ-ONLY mode.
  1423. //
  1424. void
  1425. CSummaryPage::ChangeGatheredPropertiesToReadOnly(
  1426. CPropertyCache * pCacheIn
  1427. )
  1428. {
  1429. TraceFunc( "" );
  1430. CPropertyCacheItem * pItem = NULL;
  1431. if ( NULL == pCacheIn )
  1432. goto Cleanup;
  1433. for( ;; )
  1434. {
  1435. HRESULT hr = STHR( pCacheIn->GetNextItem( pItem, &pItem ) );
  1436. if ( S_OK != hr )
  1437. break; // must be done.
  1438. THR( pItem->MarkReadOnly( ) );
  1439. // ignore failure and keep moving
  1440. }
  1441. Cleanup:
  1442. TraceFuncExit( );
  1443. }
  1444. //
  1445. // Description:
  1446. // Checks to see if the property set contains the music copy-protection
  1447. // property, if the property is of type VT_BOOL and if that property is
  1448. // set to TRUE.
  1449. //
  1450. // Return Values:
  1451. // S_OK
  1452. // Property found and is set to TRUE.
  1453. //
  1454. // S_FALSE
  1455. // Property not found or is set to FALSE.
  1456. //
  1457. // E_INVALIDARG
  1458. // pCacheIn is NULL.
  1459. //
  1460. // other HRESULTs
  1461. //
  1462. HRESULT
  1463. CSummaryPage::CheckForCopyProtection(
  1464. CPropertyCache * pCacheIn
  1465. )
  1466. {
  1467. TraceFunc( "" );
  1468. HRESULT hr;
  1469. CPropertyCacheItem * pItem;
  1470. HRESULT hrReturn = S_FALSE;
  1471. if ( NULL == pCacheIn )
  1472. goto InvalidArg;
  1473. hr = STHR( pCacheIn->FindItemEntry( &FMTID_DRM, PIDDRSI_PROTECTED, &pItem ) );
  1474. if ( S_OK == hr )
  1475. {
  1476. PROPVARIANT * ppropvar;
  1477. hr = THR( pItem->GetPropertyValue( &ppropvar ) );
  1478. if ( S_OK == hr )
  1479. {
  1480. if ( ( VT_BOOL == ppropvar->vt )
  1481. && ( VARIANT_TRUE == ppropvar->boolVal )
  1482. )
  1483. {
  1484. hrReturn = S_OK;
  1485. }
  1486. }
  1487. }
  1488. Cleanup:
  1489. HRETURN( hrReturn );
  1490. InvalidArg:
  1491. hr = THR( E_INVALIDARG );
  1492. goto Cleanup;
  1493. }