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.

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