ext.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 28k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //-------------------------------------------------------------------------//
  2. // ext.cpp : CShellExt impl
  3. //-------------------------------------------------------------------------//
  4. #include "pch.h"
  5. #include "ext.h"
  6. #include "ptsniff.h"
  7. #include "propvar.h"
  8. #include "ptserver.h"
  9. #include "ptsrv32.h"
  10. #include "page.h"
  11. //-------------------------------------------------------------------------//
  12. const TCHAR szEXTENSION_SETTINGS_REGKEY[] = TEXT("Software\Microsoft\Windows\CurrentVersion\Explorer\PropSummary");
  13. const TCHAR szUIMODE_REGVAL[]             = TEXT("Advanced");
  14. const FMTID* basic_fmtids[] = {
  15.     &FMTID_SummaryInformation,
  16.     &FMTID_DocSummaryInformation,
  17. };
  18. //  Note: members of the following arrays must be 
  19. //  synch'd and ordered according to BASICPROPERTY enum members.
  20. const PROPID basic_propids[] = {
  21.     PIDSI_TITLE,
  22.     PIDSI_SUBJECT,
  23.     PIDSI_AUTHOR,
  24.     PIDSI_KEYWORDS,
  25.     PIDSI_COMMENTS,
  26.     PIDDSI_CATEGORY,
  27. };
  28. const VARTYPE basic_propvts[] = {
  29.     VT_LPWSTR,
  30.     VT_LPWSTR,
  31.     VT_LPWSTR,
  32.     VT_LPWSTR,
  33.     VT_LPWSTR,
  34.     VT_LPWSTR,
  35. };
  36. const UINT  basic_ctlIDs[] = {
  37.     IDC_TITLE,
  38.     IDC_SUBJECT,
  39.     IDC_AUTHOR,
  40.     IDC_KEYWORDS,
  41.     IDC_COMMENTS,
  42.     IDC_CATEGORY,
  43. };
  44. //-------------------------------------------------------------------------//
  45. inline HRESULT IsValidProp( BASICPROPERTY nProp )
  46. {
  47.     return (nProp >= 0 && nProp < BASICPROP_COUNT) ?
  48.                 S_OK : E_INVALIDARG;
  49. }
  50. //-------------------------------------------------------------------------//
  51. //  CBasicPropertySource  // basic property block.
  52. //-------------------------------------------------------------------------//
  53. //-------------------------------------------------------------------------//
  54. CBasicPropertySource::CBasicPropertySource()
  55.     :   _pbps(NULL),
  56.         _rgItems(NULL)
  57. {
  58.     VariantInit( &_varSource );
  59. }
  60. //-------------------------------------------------------------------------//
  61. void CBasicPropertySource::Free()
  62. {
  63.     VariantClear( &_varSource );
  64.     if( _rgItems )
  65.     {
  66.         delete [] _rgItems;
  67.         _rgItems = NULL;
  68.     }
  69.     if( _pbps )
  70.     {
  71.         _pbps->Release();
  72.         _pbps = NULL;
  73.     }
  74. }
  75. //-------------------------------------------------------------------------//
  76. HRESULT CBasicPropertySource::Acquire( const VARIANT* pvarSource )
  77. {
  78.     BASICPROPITEM* rgItems = NULL;
  79.     HRESULT hr;
  80.     IBasicPropertyServer* pbps;
  81.     hr = CoCreateInstance( CLSID_PTDefaultServer32,
  82.                            NULL, CLSCTX_INPROC_SERVER,
  83.                            IID_IBasicPropertyServer,
  84.                            (LPVOID*)&pbps );
  85.     if( SUCCEEDED( hr ) )
  86.     {
  87.         if( (rgItems = new BASICPROPITEM[BASICPROP_COUNT]) != NULL )
  88.         {
  89.             for( int f=0; f < ARRAYSIZE(basic_fmtids); f++ )
  90.             {
  91.                 int iPropFirst, iPropLast, cProps;
  92.                 if( CShellExt::GetBasicPropInfo( *basic_fmtids[f], iPropFirst, iPropLast, cProps ) )
  93.                 {
  94.                     for( int i = iPropFirst; i <= iPropLast; i++ )
  95.                     {
  96.                         InitBasicPropertyItem( &rgItems[i] );
  97.                         ASSERT( FALSE == rgItems[i].bDirty );
  98.                         rgItems[i].dwAccess = PTIA_READWRITE;
  99.                         rgItems[i].puid.fmtid = *basic_fmtids[f];
  100.                         rgItems[i].puid.propid= basic_propids[i];
  101.                         rgItems[i].puid.vt    = basic_propvts[i];
  102.                     }
  103.                 }
  104.             }
  105.             
  106.             if( SUCCEEDED( (hr = pbps->AcquireBasic( pvarSource, rgItems, BASICPROP_COUNT )) ) )
  107.             {
  108.                 Free();
  109.                 VariantCopy( &_varSource, (VARIANT*)pvarSource );
  110.                 _pbps = pbps;
  111.                 _pbps->AddRef();
  112.                 _rgItems = rgItems;
  113.             }
  114.             else
  115.                 delete [] rgItems;
  116.         }
  117.         pbps->Release();
  118.     }
  119.     return hr;
  120. }
  121. //-------------------------------------------------------------------------//
  122. void CBasicPropertySource::SetDirty( BASICPROPERTY nProp, BOOL bDirty )
  123. {
  124.     ASSERT( _pbps != NULL && _rgItems != NULL );
  125.     ASSERT( BASICPROP_COUNT > (UINT)nProp );
  126.     _rgItems[nProp].bDirty = bDirty;
  127. }
  128. //-------------------------------------------------------------------------//
  129. HRESULT CBasicPropertySource::Persist()
  130. {
  131.     if( !(_pbps && _rgItems) )
  132.     {
  133.         ASSERT( _pbps && _rgItems );
  134.         return E_UNEXPECTED;
  135.     }
  136.     return _pbps->PersistBasic( &_varSource, _rgItems, BASICPROP_COUNT );
  137. }
  138. //-------------------------------------------------------------------------//
  139. int CBasicPropertySource::Compare( BASICPROPERTY nProp, CBasicPropertySource* pOther )
  140. {
  141.     ASSERT( IsValidProp( nProp ) );
  142.     ASSERT( _rgItems != NULL );
  143.     ASSERT( pOther );
  144.     
  145.     return PropVariantCompare( _rgItems[nProp].val, pOther->_rgItems[nProp].val, STRICT_COMPARE );
  146. }
  147. //-------------------------------------------------------------------------//
  148. BSTR CBasicPropertySource::MakeDisplayString( BASICPROPERTY nProp )
  149. {
  150.     ASSERT( IsValidProp( nProp ) );
  151.     ASSERT( _rgItems != NULL );
  152.     BSTR bstrRet;
  153.     if( SUCCEEDED( PropVariantToBstr( &_rgItems[nProp].val, GetACP(), 0L, NULL, &bstrRet ) ) )
  154.         return bstrRet;
  155.     return NULL;
  156. }
  157. //-------------------------------------------------------------------------//
  158. HRESULT CBasicPropertySource::SetPropertyValue( BASICPROPERTY nProp, IN BSTR bstrValue )
  159. {
  160.     if( NULL == _rgItems )
  161.         return E_FAIL;
  162.     if( FAILED( IsValidProp( nProp ) ) || NULL == bstrValue )
  163.         return E_INVALIDARG;
  164.     if( VT_EMPTY == _rgItems[nProp].val.vt )
  165.         _rgItems[nProp].val.vt = _rgItems[nProp].puid.vt;
  166.         
  167.     return PropVariantFromBstr( bstrValue, GetACP(), 0L, NULL, &_rgItems[nProp].val );
  168. }
  169. //-------------------------------------------------------------------------//
  170. // CShellExt
  171. //-------------------------------------------------------------------------//
  172. //-------------------------------------------------------------------------//
  173. //  IShellExtInit::Initialize
  174. STDMETHODIMP CShellExt::Initialize( 
  175.     LPCITEMIDLIST pidlFolder, 
  176.     LPDATAOBJECT pIDataObject, 
  177.     HKEY hkeyProgID )
  178. {
  179.     HRESULT     hr;
  180.     STGMEDIUM   stgmed;
  181.     FORMATETC   fmtetc = { CF_HDROP, NULL, DVASPECT_CONTENT, -1,
  182.                            TYMED_HGLOBAL };
  183.     int         cAdvanced = 0, cBasic = 0; // specialized server file type
  184.     if( SUCCEEDED( (hr = pIDataObject->GetData( &fmtetc, &stgmed )) ) )
  185.     {
  186.         TCHAR szPath[MAX_PATH];
  187.         UINT  i, max = DragQueryFile( (HDROP)stgmed.hGlobal, 0xFFFFFFFF, szPath, 
  188.                                      sizeof(szPath)/sizeof(TCHAR) );
  189.         //  Add path names to file list as VARIANTs
  190.         for( i=0; i < max; i++ )
  191.         {
  192.             if( DragQueryFile( (HDROP)stgmed.hGlobal, i, szPath, 
  193.                                sizeof(szPath)/sizeof(TCHAR) ) )
  194.             {
  195.                 WIN32_FIND_DATA wfd;
  196.                 int             fAdvanced, fBasic;
  197.                 TARGET          t;
  198.                 if( FAILED( (hr = FilterFileFindData(szPath, &wfd )) ) ||
  199.                     0xFFFFFFFF == wfd.dwFileAttributes )
  200.                     continue;
  201.                 t.ftAccess = wfd.ftLastAccessTime;
  202.                 //  Is this a supported property source?
  203.                 fAdvanced = IsSourceSupported( szPath, TRUE /*advanced*/) ? 1 : 0;
  204.                 fBasic    = IsSourceSupported( szPath, FALSE /*basic*/ ) ? 1 : 0;
  205.                 if( fAdvanced || fBasic )
  206.                 {
  207.                     USES_CONVERSION;
  208.                     VARIANT var;
  209.                     VariantInit( &t.varFile );
  210.                     if( (t.varFile.bstrVal = SysAllocString( T2W( szPath ) ))==NULL )
  211.                     {
  212.                         hr = E_FAIL;
  213.                         ReleaseStgMedium(&stgmed);
  214.                         goto ret;
  215.                     }
  216.                     t.varFile.vt = VT_BSTR;
  217.                     if( m_filelist.AppendTail( t ) )
  218.                     {
  219.                         if( wfd.dwFileAttributes & FILE_ATTRIBUTE_READONLY )
  220.                             m_cReadOnly++;
  221.                         if( fAdvanced )
  222.                             cAdvanced++;
  223.                         if( fBasic )
  224.                             cBasic++;
  225.                     }
  226.                     else
  227.                         VariantClear( &t.varFile );
  228.                 }
  229.                 else
  230.                 {
  231.                     m_filelist.Clear();
  232.                     break;
  233.                 }
  234.             }
  235.         }
  236.         hr = m_filelist.Count() > 0 ? S_OK : E_FAIL;
  237.         ReleaseStgMedium(&stgmed);
  238.     }
  239.     //  Determine if we have something to show; if so, increment refcount
  240.     if( SUCCEEDED( hr ) )
  241.     {
  242.         m_fBasicProperties    = SUCCEEDED( (hr = Acquire()) );    // try acquiring basic.
  243.         m_fAdvancedProperties = cAdvanced > 0 && (cAdvanced == m_filelist.Count());
  244.         //  if we found either basic and/or advanced properties, set
  245.         //  outselves up to present.
  246.         if( m_fBasicProperties || m_fAdvancedProperties )
  247.         {
  248.             hr = S_OK;
  249.             InternalAddRef();  // InternalRelease() when page detaches.
  250.         }
  251.     }
  252. ret:
  253.     return hr;
  254. }
  255. //-------------------------------------------------------------------------//
  256. //  IShellPropSheetExt::AddPages
  257. STDMETHODIMP CShellExt::AddPages( 
  258.     LPFNADDPROPSHEETPAGE lpfnAddPage, 
  259.     LPARAM lParam )
  260. {
  261.     if( (m_pPage0 = new CPage0)==NULL )
  262.         return E_OUTOFMEMORY;
  263.     return m_pPage0->Add( this, lpfnAddPage, lParam );
  264. }
  265. //-------------------------------------------------------------------------//
  266. //  IShellPropSheetExt::ReplacePage
  267. STDMETHODIMP CShellExt::ReplacePage( 
  268.     UINT uPageID, 
  269.     LPFNADDPROPSHEETPAGE lpfnReplacePage, 
  270.     LPARAM lParam )
  271. {
  272.     return E_NOTIMPL;
  273. }
  274. //-------------------------------------------------------------------------//
  275. //  ctor
  276. CShellExt::CShellExt()  
  277.     :   m_pPage0(NULL),
  278.         m_fAdvancedProperties(FALSE),
  279.         m_fBasicProperties(TRUE),
  280.         m_cReadOnly(0),
  281.         m_rgBasicSrc(NULL)
  282. {
  283.     //  Initialize
  284.     for( int i = 0; i < BASICPROP_COUNT; i++ )
  285.     {
  286.         m_rgvarFlags[i] = 0L;
  287.         m_rgbstrDisplay[i] = NULL;
  288.         m_rgbDirty[i] = FALSE;
  289.     }
  290. }
  291. //-------------------------------------------------------------------------//
  292. //  dtor
  293. CShellExt::~CShellExt()
  294. {
  295.     FinalRelease();
  296. }
  297. //-------------------------------------------------------------------------//
  298. void CShellExt::FinalRelease()
  299. {
  300.     if( m_rgBasicSrc )
  301.     {
  302.         delete [] m_rgBasicSrc;
  303.         m_rgBasicSrc = NULL;
  304.     }
  305.     for( int i = 0; i < BASICPROP_COUNT; i++ )
  306.     {
  307.         SysFreeString( m_rgbstrDisplay[i] );
  308.         m_rgbstrDisplay[i] = NULL;
  309.     }
  310. }
  311. //-------------------------------------------------------------------------//
  312. //  Determines the support status for the specified file
  313. BOOL CShellExt::IsSourceSupported( 
  314.     LPTSTR pszPath, 
  315.     BOOL   bAdvanced,
  316.     OUT OPTIONAL LPCLSID pclsid )
  317. {
  318.     PTSRV_FILECLASS fileClass;
  319.     PTSRV_FILETYPE  fileType;
  320.     CLSID           clsid;
  321.     if( !pclsid )
  322.         pclsid = &clsid;
  323.     //  If this file type isknown to our default property server
  324.     //  and the default server supports the type...
  325.     if( IsPTsrvKnownFileType( pszPath, &fileType, &fileClass ) &&
  326.         fileClass != PTSFCLASS_UNSUPPORTED )
  327.     {
  328.         BOOL bSupported = PTSFCLASS_OFFICEDOC == fileClass ?
  329.                             /*don't trust office doc based on filename ext alone*/
  330.                             IsPropSetStgFmt( pszPath, STGFMT_ANY, NULL ) :
  331.                             bAdvanced;
  332.         if( bSupported )
  333.         {
  334.             if( pclsid )
  335.                 *pclsid = CLSID_PTDefaultServer32;
  336.             return TRUE;
  337.         }
  338.     }
  339.     //  Try determining if there is a registered property server
  340.     //  object for the type
  341.     if( S_OK == GetPropServerClassForFile( pszPath, bAdvanced, pclsid ) )
  342.         return TRUE;
  343.     //  If the default server has rejected the type, bail now
  344.     if( PTSFCLASS_UNSUPPORTED == fileClass )
  345.         return FALSE;
  346.     //  Last chance: check if we can open property streams on the file
  347.     if( IsPropSetStgFmt( pszPath, STGFMT_ANY, NULL ) )
  348.         return TRUE;    
  349.     return FALSE;
  350. }
  351. //-------------------------------------------------------------------------//
  352. //  Retrieves basic properties (title, subject, category, author, keywords, comments).
  353. //  If this fails for any source file, the property sheet will not appear.
  354. HRESULT CShellExt::Acquire()
  355. {
  356.     HANDLE  hEnum;
  357.     BOOL    bEnum;
  358.     int     iSrc, cSrcs = FileList().Count();
  359.     TARGET  t;
  360.     HRESULT hr = S_OK;
  361.     if( cSrcs <=0 )
  362.         return E_FAIL;
  363.     CBasicPropertySource* rgBasicSrc = new CBasicPropertySource[cSrcs];
  364.     if( NULL == rgBasicSrc )
  365.         return E_OUTOFMEMORY;
  366.     //  Initialize array of property sources.
  367.     for( iSrc = 0, hEnum = FileList().EnumHead( t ), bEnum = TRUE; 
  368.          hEnum && bEnum && iSrc < cSrcs;
  369.          iSrc++, bEnum = FileList().EnumNext( hEnum, t ) )
  370.     {
  371.         hr = rgBasicSrc[iSrc].Acquire( &t.varFile );
  372. #ifdef RESTORE_ACCESS_TIMES
  373.         _RestoreAccessTime( t );
  374. #endif RESTORE_ACCESS_TIMES
  375.         
  376.         if( FAILED( hr ) )
  377.         {
  378.             delete [] rgBasicSrc;
  379.             rgBasicSrc = NULL;
  380.             break;
  381.         }
  382.     }
  383.     FileList().EndEnum( hEnum );
  384.     if( SUCCEEDED( hr ) )
  385.     {
  386.         if( m_rgBasicSrc )
  387.             delete m_rgBasicSrc;
  388.         m_rgBasicSrc = rgBasicSrc;
  389.         //  For each property, resolve value mismatches among multiple sources.
  390.         for( int prop = 0; prop < BASICPROP_COUNT; prop++ )
  391.         {
  392.             
  393.             SysFreeString( m_rgbstrDisplay[prop] );           // clear display text.
  394.             m_rgvarFlags[prop] &= ~AMPF_COMPOSITE_MISMATCH; // clear mismatch flag
  395.             for( int i = 0; i < cSrcs; i++ )
  396.             {
  397.                 for( int j = 0; j< cSrcs; j++ )
  398.                 {            
  399.                     if( i != j && rgBasicSrc[i].Compare( (BASICPROPERTY)prop, &rgBasicSrc[j] ) != 0 )
  400.                     {
  401.                         m_rgvarFlags[prop] |= AMPF_COMPOSITE_MISMATCH; // set mismatch flag
  402.                         break;
  403.                     }
  404.                 }
  405.                 if( m_rgvarFlags[prop] & AMPF_COMPOSITE_MISMATCH ) // test mismatch flag
  406.                     break;
  407.             }
  408.             if( !(m_rgvarFlags[prop] & AMPF_COMPOSITE_MISMATCH) )
  409.                 m_rgbstrDisplay[prop] = rgBasicSrc[0].MakeDisplayString( (BASICPROPERTY)prop ); // regen display text.
  410.         }
  411.     }
  412.     return hr;
  413. }
  414.   
  415. //-------------------------------------------------------------------------//
  416. //  Persists changes to standard properties (title, subject, 
  417. //  category, author).
  418. HRESULT CShellExt::Persist()
  419. {
  420.     HANDLE  hEnum;
  421.     BOOL    bEnum;
  422.     int     iSrc, iProp, cSrcs = FileList().Count();
  423.     HRESULT hr = S_OK, 
  424.             hrSrc;
  425.     if( cSrcs > 0 && m_rgBasicSrc != NULL )
  426.     {
  427.         //  Update property values
  428.         for( iProp = 0; iProp < BASICPROP_COUNT; iProp++ )
  429.         {
  430.             if( m_rgbDirty[iProp] )
  431.             {
  432.                 //  iterate sources and assign new value
  433.                 for( iSrc = 0; iSrc < cSrcs; iSrc++ )
  434.                 {
  435.                     hrSrc = m_rgBasicSrc[iSrc].SetPropertyValue( (BASICPROPERTY)iProp, m_rgbstrDisplay[iProp] );
  436.                     m_rgBasicSrc[iSrc].SetDirty( (BASICPROPERTY)iProp, TRUE );
  437.                     if( FAILED( hrSrc ) )
  438.                         hr = hrSrc;  // but keep going.
  439.                 }
  440.             }
  441.         }            
  442.         for( iSrc = 0; iSrc < cSrcs; iSrc++ )
  443.         {
  444.             hrSrc = m_rgBasicSrc[iSrc].Persist();
  445.             if( FAILED( hrSrc ) )
  446.                 hr = hrSrc;
  447.         }
  448.     }
  449.     if( SUCCEEDED( hr ) )
  450.     {
  451.         for( iProp = 0; iProp < BASICPROP_COUNT; iProp++ )
  452.             SetDirty( (BASICPROPERTY)iProp, FALSE );
  453.     }
  454.     return hr;
  455. }
  456. //-------------------------------------------------------------------------//
  457. //  Caches property values from the user interface
  458. void CShellExt::CacheUIValues( HWND hwndPage )
  459. {
  460.     LPTSTR  pszBuf;    
  461.     int     cchBuf = GetMaxPropertyTextLength( hwndPage )+1;
  462.     if( NULL != (pszBuf = new TCHAR[cchBuf]) )
  463.     {
  464.         for( int i=0; i < BASICPROP_COUNT; i++ )
  465.         {
  466.             if( !IsCompositeMismatch( (BASICPROPERTY)i ) )
  467.             {
  468.                 *pszBuf = (TCHAR)0;
  469.                 GetDlgItemText( hwndPage, basic_ctlIDs[i], pszBuf, cchBuf );
  470.                 CacheDisplayText( (BASICPROPERTY)i, pszBuf );
  471.             }
  472.         }
  473.         delete [] pszBuf;
  474.     }
  475. }
  476. //-------------------------------------------------------------------------//
  477. //  Caches property values from the user interface
  478. void CShellExt::CacheUIValue( HWND hwndPage, BASICPROPERTY nProp )
  479. {
  480.     HWND    hwndCtl;
  481.     if( (hwndCtl = GetDlgItem( hwndPage, basic_ctlIDs[nProp] )) )
  482.     {
  483.         LPTSTR  pszBuf;    
  484.         int     cchBuf = GetWindowTextLength( hwndCtl )+1;
  485.         if( NULL != (pszBuf = new TCHAR[cchBuf]) )
  486.         {
  487.             *pszBuf = (TCHAR)0;
  488.             GetWindowText( hwndCtl, pszBuf, cchBuf );
  489.             CacheDisplayText( nProp, pszBuf );
  490.             delete [] pszBuf;
  491.         }
  492.     }
  493. }
  494. //-------------------------------------------------------------------------//
  495. //  Transfers cached property values to the user interface
  496. void CShellExt::UncacheUIValues( HWND hwndPage )
  497. {
  498.     for( int i=0; i<BASICPROP_COUNT; i++ )
  499.         UncacheUIValue( hwndPage, (BASICPROPERTY)i );
  500. }
  501. //-------------------------------------------------------------------------//
  502. //  Transfers a cached property value to the user interface
  503. void CShellExt::UncacheUIValue( HWND hwndPage, BASICPROPERTY nProp )
  504. {
  505.     USES_CONVERSION;
  506.     SetDlgItemTextW( hwndPage, basic_ctlIDs[nProp], m_rgbstrDisplay[nProp] );
  507. }
  508. //-------------------------------------------------------------------------//
  509. //  Retrieves the maximum length of the properties cached value text.
  510. int CShellExt::GetMaxPropertyTextLength( HWND hwndDlg )
  511. {
  512.     int cchMax = 0;
  513.     for( int i=0; i < BASICPROP_COUNT; i++ )
  514.     {
  515.         int cch = 0;
  516.         if( hwndDlg )
  517.         {
  518.             HWND hwndCtl = GetDlgItem( hwndDlg, basic_ctlIDs[i] );
  519.             ASSERT( NULL != hwndCtl );
  520.             cch = GetWindowTextLength( hwndCtl );
  521.         }
  522.         else if( m_rgbstrDisplay[i] && *m_rgbstrDisplay[i] )
  523.             cch = lstrlenW( m_rgbstrDisplay[i] );
  524.         if( cch > cchMax )
  525.             cchMax = cch;
  526.     }
  527.     return cchMax;
  528. }
  529. //-------------------------------------------------------------------------//
  530. //  Retrieves the value text for the indicated property.
  531. //  If hwndDlg == NULL, the text will be copied from cached data.  Otherwise,
  532. //  the data will be retrieved from the dialog.
  533. BOOL CShellExt::GetPropertyText( HWND hwndDlg, BASICPROPERTY nProp, LPTSTR pszBuf, int cchBuf )
  534. {
  535.     HWND    hwndCtl;
  536.     BSTR    bstrRet = NULL;
  537.     ASSERT( pszBuf );
  538.     *pszBuf = 0;
  539.     if( hwndDlg )
  540.     {
  541.         //  If mismatched composite value, return empty string
  542.         if( IsCompositeMismatch( nProp ) )
  543.             return TRUE;
  544.         if( NULL != (hwndCtl = ::GetDlgItem( hwndDlg, basic_ctlIDs[nProp]) ) )
  545.         {
  546.             GetWindowText( hwndCtl, pszBuf, cchBuf );
  547.             return TRUE;
  548.         }
  549.     }
  550.     else
  551.     {
  552.         USES_CONVERSION;
  553.         if( m_rgbstrDisplay[nProp] )
  554.             lstrcpyn( pszBuf, W2T( m_rgbstrDisplay[nProp] ), cchBuf );
  555.         return TRUE;
  556.     }
  557.     return FALSE;
  558. }
  559. //-------------------------------------------------------------------------//
  560. //  Assigns the UI text
  561. void CShellExt::SetPropertyText( HWND hwndDlg, BASICPROPERTY nProp, LPCTSTR pszText )
  562. {
  563.     HWND    hwndCtl;
  564.     BSTR    bstrRet = NULL;
  565.     if( NULL != (hwndCtl = ::GetDlgItem( hwndDlg, basic_ctlIDs[nProp]) ) )
  566.     {
  567.         USES_CONVERSION;
  568.         SetWindowText( hwndCtl, pszText );
  569.     }
  570.     CacheDisplayText( nProp, pszText );
  571. }
  572. //-------------------------------------------------------------------------//
  573. void CShellExt::CacheDisplayText( BASICPROPERTY nProp, LPCTSTR pszText )
  574. {
  575.     USES_CONVERSION;
  576.     
  577.     if( m_rgbstrDisplay[nProp] && pszText )
  578.         if( lstrcmp( W2T( m_rgbstrDisplay[nProp] ), pszText )==0 )
  579.             return;    // no change
  580.     
  581.     if( m_rgbstrDisplay[nProp] )
  582.     {
  583.         SysFreeString( m_rgbstrDisplay[nProp] );
  584.         m_rgbstrDisplay[nProp] = NULL;
  585.     }
  586.     if( pszText )
  587.     {
  588.         m_rgbstrDisplay[nProp] = SysAllocString( T2W( (LPTSTR)pszText ) );
  589.     }
  590. }
  591. //-------------------------------------------------------------------------//
  592. //  Returns the identifier of the shell prop sheet extension's property 
  593. //  given a dlg control identifier.
  594. BOOL CShellExt::GetBasicPropFromIDC( UINT nIDC, BASICPROPERTY* pnProp ) const
  595. {
  596.     for( int i=0; i<BASICPROP_COUNT; i++ )
  597.     {
  598.         if( basic_ctlIDs[i] == nIDC )
  599.         {
  600.             if( pnProp ) *pnProp = (BASICPROPERTY)i;
  601.             return TRUE;
  602.         }
  603.     }
  604.     return FALSE;
  605. }
  606. //-------------------------------------------------------------------------//
  607. //  Retrieves array parameters for the specified FMTID
  608. BOOL CShellExt::GetBasicPropInfo( REFFMTID fmtid, OUT int& iFirst, OUT int& iLast, OUT int& cProps ) 
  609. {
  610.     if( IsEqualGUID( fmtid, FMTID_SummaryInformation ) )
  611.     {
  612.         iFirst = BASICPROP_SUMMARYINFO_FIRST;
  613.         iLast  = BASICPROP_SUMMARYINFO_LAST;
  614.         cProps = (iLast - iFirst) + 1;
  615.         return TRUE;
  616.     }
  617.     else
  618.     if( IsEqualGUID( fmtid, FMTID_DocSummaryInformation ) )
  619.     {
  620.         iFirst = BASICPROP_DOCSUMMARYINFO_FIRST;
  621.         iLast  = BASICPROP_DOCSUMMARYINFO_LAST;
  622.         cProps = (iLast - iFirst) + 1;
  623.         return TRUE;
  624.     }
  625.     iFirst = cProps = -1;
  626.     return FALSE;
  627. }
  628. //-------------------------------------------------------------------------//
  629. //  Retrieves prop ID parameters for the specified basic property
  630. BOOL CShellExt::GetBasicPropInfo( BASICPROPERTY nProp, OUT const FMTID*& pFmtid, OUT PROPID& nPropID, OUT VARTYPE& vt )
  631. {
  632.     if( nProp >= BASICPROP_SUMMARYINFO_FIRST && 
  633.         nProp <= BASICPROP_SUMMARYINFO_LAST )
  634.         pFmtid = &FMTID_SummaryInformation;
  635.     else
  636.     if( nProp >= BASICPROP_DOCSUMMARYINFO_FIRST && 
  637.         nProp <= BASICPROP_DOCSUMMARYINFO_LAST )
  638.         pFmtid = &FMTID_DocSummaryInformation;
  639.     else
  640.         return FALSE;
  641.     nPropID = basic_propids[nProp];
  642.     vt      = basic_propvts[nProp];
  643.     return TRUE;
  644. }
  645. //-------------------------------------------------------------------------//
  646. //  Reports whether the indicated property's value is a composite of
  647. //  multiple, mismatched values.
  648. BOOL CShellExt::IsCompositeMismatch( BASICPROPERTY nProp ) const
  649. {
  650.     return (m_rgvarFlags[nProp] & AMPF_COMPOSITE_MISMATCH) != 0;
  651. }
  652. //-------------------------------------------------------------------------//
  653. void CShellExt::SetDirty( BASICPROPERTY nProp, BOOL bDirty )
  654. {
  655.     if( (m_rgbDirty[nProp] = bDirty) && IsCompositeMismatch( nProp ) )
  656.         m_rgvarFlags[nProp] &= ~AMPF_COMPOSITE_MISMATCH;
  657. }
  658. //-------------------------------------------------------------------------//
  659. //  issues a shell change notification.
  660. void CShellExt::ChangeNotify( LONG wEventID )
  661. {
  662.     HANDLE  hEnum;
  663.     BOOL    bEnum;
  664.     TARGET  t;
  665.     for( hEnum = FileList().EnumHead( t ), bEnum = TRUE; 
  666.          hEnum && bEnum;
  667.          bEnum = FileList().EnumNext( hEnum, t ) )
  668.     {
  669.         TCHAR szPath[MAX_PATH];
  670.         USES_CONVERSION;
  671.         lstrcpy( szPath, W2T(t.varFile.bstrVal) );
  672.         SHChangeNotify( wEventID, SHCNF_PATH, szPath, NULL );
  673.     }
  674.     FileList().EndEnum( hEnum );
  675.     
  676.     SHChangeNotifyHandleEvents();
  677. }
  678. //-------------------------------------------------------------------------//
  679. HRESULT _RestoreAccessTime( const TARGET& t )
  680. {
  681.     TCHAR szPath[MAX_PATH];
  682.     USES_CONVERSION;
  683.     lstrcpy( szPath, W2T(t.varFile.bstrVal) );
  684.     DWORD dwErr = ERROR_SUCCESS ;
  685.     HANDLE hFile = CreateFile( szPath, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 
  686.                                FILE_FLAG_OPEN_NO_RECALL, NULL );
  687.     if( INVALID_HANDLE_VALUE == hFile )
  688.     {
  689.         dwErr = GetLastError(); 
  690.     }
  691.     else
  692.     {
  693.         if( !SetFileTime( hFile, NULL, &t.ftAccess, NULL ) )
  694.             dwErr = GetLastError();
  695.         CloseHandle( hFile );
  696.     }
  697.     HRESULT hr = HRESULT_FROM_WIN32( dwErr );
  698.     return hr;
  699. }
  700. //-------------------------------------------------------------------------//
  701. //  Restores file access times for target files.
  702. void CShellExt::RestoreAccessTimes()
  703. {
  704.     HANDLE  hEnum;
  705.     BOOL    bEnum;
  706.     TARGET  t;
  707.     for( hEnum = FileList().EnumHead( t ), bEnum = TRUE; 
  708.          hEnum && bEnum;
  709.          bEnum = FileList().EnumNext( hEnum, t ) )
  710.     {
  711.         _RestoreAccessTime( t );
  712.     }
  713.     FileList().EndEnum( hEnum );
  714. }
  715. //-------------------------------------------------------------------------//
  716. //  Displays an error message
  717. int CShellExt::DisplayError( HWND hwndOwner, UINT nIDCaption, ERROR_CONTEXT errctx, HRESULT hr )
  718. {
  719.     UINT nIDErr = 0;
  720.     UINT uType  = MB_OK;
  721.     int  nRet   = IDOK;
  722.     
  723.     #define DEFINE_ERROR( hr, idErr, type ) 
  724.                 case hr: {nIDErr = idErr; uType=type; break;}
  725.     #define DEFINE_MULTIERROR( hr, idErr1, idErrN, type ) 
  726.                 case hr: {nIDErr = m_filelist.Count() > 1 ? idErrN : idErr1; uType=type; break;}
  727.     switch( errctx )
  728.     {
  729.         case ERRCTX_PERSIST_APPLY:
  730.         case ERRCTX_PERSIST_OK:
  731.         {
  732.             UINT uBtnFlags = (ERRCTX_PERSIST_OK == errctx) ? MB_OKCANCEL : MB_OK;
  733.             switch( hr )
  734.             {
  735.                 DEFINE_MULTIERROR( STG_E_ACCESSDENIED, 
  736.                                    IDS_ERR_ACCESSDENIED_1, IDS_ERR_ACCESSDENIED_N, 
  737.                                    uBtnFlags|MB_ICONEXCLAMATION );
  738.                 DEFINE_MULTIERROR( STG_E_LOCKVIOLATION, 
  739.                                    IDS_ERR_LOCKVIOLATION_1, IDS_ERR_LOCKVIOLATION_N, 
  740.                                    uBtnFlags|MB_ICONEXCLAMATION );
  741.             }
  742.         }
  743.         break;
  744.         case ERRCTX_ACQUIRE:
  745.         default:
  746.             break;
  747.     }
  748.     
  749.     if( nIDErr )
  750.     {
  751.         TCHAR szErr[256];
  752.         TCHAR szCaption[128];
  753.         LoadString( HINST_RESDLL, nIDErr,  szErr, ARRAYSIZE(szErr) );
  754.         LoadString( HINST_RESDLL, nIDCaption, szCaption, ARRAYSIZE(szCaption) );
  755.         
  756.         nRet = ::MessageBox( hwndOwner, szErr, szCaption, uType );
  757.     }
  758.     return nRet;
  759. }
  760. HRESULT CShellExt::FilterFileFindData(LPCTSTR pszPath, WIN32_FIND_DATA* pwfd)
  761. {
  762.     HRESULT hr = S_OK;
  763.     HANDLE hfind = FindFirstFile( pszPath, pwfd );
  764.     if (INVALID_HANDLE_VALUE != hfind)
  765.     {
  766.         FindClose(hfind);
  767. #if 0   //  NT raid# 327281: shouldn't avoid encrypted files
  768.         if( pwfd->dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED )
  769.         {
  770.             hr = STG_E_INVALIDFUNCTION;
  771.         }
  772.         else 
  773. #endif 0
  774.         if( pwfd->dwFileAttributes & FILE_ATTRIBUTE_OFFLINE )
  775.         {
  776.             hr = HRESULT_FROM_WIN32( ERROR_FILE_OFFLINE );
  777.         }
  778.         else
  779.         {
  780.             //  Enforce read-only bit if we can't get write access for any reason.
  781.             if ( 0 == (pwfd->dwFileAttributes & FILE_ATTRIBUTE_READONLY) && 
  782.                       !PTCheckWriteAccess( pszPath ) )
  783.                 pwfd->dwFileAttributes |= FILE_ATTRIBUTE_READONLY;
  784.         }
  785.     }
  786.     else
  787.     {
  788.         pwfd->dwFileAttributes = 0xFFFFFFFF;
  789.         hr = STG_E_FILENOTFOUND;
  790.     }
  791.     return hr;
  792. }