// Author: Karim Farouki // Date: 24 June 1998 #include "priv.h" #include "util.h" #include #include // for MLLoadString #include "resource.h" // for the string ID's typedef HRESULT (* LPFCALLBACK )(LPINTERNET_CACHE_ENTRY_INFO, void *); typedef struct tagRTSCBSTRUCT { IEmptyVolumeCacheCallBack * picb; DWORDLONG * pdwlSpaceUsed; } RTSCBSTRUCT; // RunningTotalSizeCallBack Struct typedef struct tagDECBSTRUCT { IEmptyVolumeCacheCallBack * picb; DWORDLONG dwlSpaceFreed; DWORDLONG dwlTotalSpace; } DECBSTRUCT; // DeleteEntryCallBack Struct class COfflinePagesCacheCleaner : public IEmptyVolumeCache2 { private: // Data ULONG m_cRef; DWORDLONG m_dwlSpaceUsed; TCHAR m_szCacheDir[MAX_PATH + 1]; // Functions HRESULT WalkOfflineCache( LPFCALLBACK lpfCallBack, void * pv ); static HRESULT CALLBACK RunningTotalSizeCallback( LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo, void * pv ); static HRESULT CALLBACK DeleteEntryCallback( LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo, void * pv ); static VOID IncrementFileSize( LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo, DWORDLONG * pdwlSize ); ~COfflinePagesCacheCleaner(void); public: // Constructor/Destructor COfflinePagesCacheCleaner(void); // IUnknown Interface members STDMETHODIMP QueryInterface(REFIID, void **); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); // IEmptyVolumeCache interface methods STDMETHODIMP Initialize( HKEY hkRegKey, LPCWSTR pcwszVolume, LPWSTR * ppwszDisplayName, LPWSTR * ppwszDescription, DWORD * pdwFlags ); STDMETHODIMP GetSpaceUsed( DWORDLONG * pdwlSpaceUsed, IEmptyVolumeCacheCallBack * picb ); STDMETHODIMP Purge( DWORDLONG dwlSpaceToFree, IEmptyVolumeCacheCallBack * picb ); STDMETHODIMP ShowProperties( HWND hwnd ); STDMETHODIMP Deactivate( DWORD * pdwFlags ); // IEmptyVolumeCache2 interface methods STDMETHODIMP InitializeEx( HKEY hkRegKey, LPCWSTR pcwszVolume, LPCWSTR pcwszKeyName, LPWSTR *ppwszDisplayName, LPWSTR *ppwszDescription, LPWSTR *ppwszBtnText, DWORD *pdwFlags ); }; STDAPI COfflinePagesCacheCleaner_CreateInstance( IUnknown * punkOuter, IUnknown ** ppunk, LPCOBJECTINFO poi ) { HRESULT hr = S_OK; *ppunk = NULL; COfflinePagesCacheCleaner * lpOPCC = new COfflinePagesCacheCleaner(); if (lpOPCC == NULL) hr = E_OUTOFMEMORY; else *ppunk = SAFECAST(lpOPCC, IEmptyVolumeCache *); return hr; } COfflinePagesCacheCleaner::COfflinePagesCacheCleaner() : m_cRef(1) { DllAddRef(); } COfflinePagesCacheCleaner::~COfflinePagesCacheCleaner() { DllRelease(); } STDMETHODIMP COfflinePagesCacheCleaner::QueryInterface(REFIID riid, LPVOID * ppv) { HRESULT hr = S_OK; if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IEmptyVolumeCache) || IsEqualIID(riid, IID_IEmptyVolumeCache2)) { *ppv = SAFECAST(this, IEmptyVolumeCache2 *); AddRef(); } else { *ppv = NULL; hr = E_NOINTERFACE; } return hr; } STDMETHODIMP_(ULONG) COfflinePagesCacheCleaner::AddRef() { return ++m_cRef; } STDMETHODIMP_(ULONG) COfflinePagesCacheCleaner::Release() { ULONG uRefCount = --m_cRef; if (!uRefCount) delete this; return uRefCount; } STDMETHODIMP COfflinePagesCacheCleaner::InitializeEx( HKEY hkRegKey, LPCWSTR pcwszVolume, LPCWSTR pcwszKeyName, LPWSTR *ppwszDisplayName, LPWSTR *ppwszDescription, LPWSTR *ppwszBtnText, DWORD *pdwFlags ) { *ppwszBtnText = (LPWSTR)CoTaskMemAlloc( 128*sizeof(WCHAR) ); if ( !*ppwszBtnText ) return E_OUTOFMEMORY; MLLoadString( IDS_CACHEOFF_BTNTEXT, *ppwszBtnText, 128 ); return Initialize(hkRegKey, pcwszVolume, ppwszDisplayName, ppwszDescription, pdwFlags ); } STDMETHODIMP COfflinePagesCacheCleaner::Initialize( HKEY hkRegkey, LPCWSTR pcwszVolume, LPWSTR * ppwszDisplayName, LPWSTR * ppwszDescription, DWORD * pdwFlags ) { HRESULT hr; uCLSSPEC ucs; // Used to see if Webcheck is installed QUERYCONTEXT qc = { 0 }; // Used to see if Webcheck is installed DWORDLONG dwlSize; // Amount of offline cachespace #ifdef UNICODE // We can't use the registry values on NT because they can't be multi-local localized. // Instead we must use strings loaded from resources. *ppwszDisplayName = (LPWSTR)CoTaskMemAlloc( 512*sizeof(WCHAR) ); if ( !*ppwszDisplayName ) return E_OUTOFMEMORY; *ppwszDescription = (LPWSTR)CoTaskMemAlloc( 512*sizeof(WCHAR) ); if ( !*ppwszDescription ) { CoTaskMemFree(*ppwszDisplayName); return E_OUTOFMEMORY; } MLLoadString( IDS_CACHEOFF_DISPLAY, *ppwszDisplayName, 512 ); MLLoadString( IDS_CACHEOFF_DESCRIPTION, *ppwszDescription, 512 ); #else // We can use the default registry DisplayName and Description *ppwszDisplayName = NULL; *ppwszDescription = NULL; #endif // Intentionally am not turning on cleanup by default; turning on *view pages* button *pdwFlags = EVCF_HASSETTINGS; // Let's check if the Internet Cache Folder is in pcwzVolume GetCacheLocation(m_szCacheDir, ARRAYSIZE(m_szCacheDir)); if (StrCmpNI(pcwszVolume, m_szCacheDir, 3)) { // If the cache is on a different drive return S_FALSE so that we don't show up in UI return S_FALSE; } // Determine if offline browsing pack is intalled. ucs.tyspec = TYSPEC_CLSID; ucs.tagged_union.clsid = CLSID_SubscriptionMgr; hr = FaultInIEFeature(NULL, &ucs, &qc, FIEF_FLAG_PEEK | FIEF_FLAG_FORCE_JITUI); if (SUCCEEDED(hr)) // (if offline pack installed) { GetSpaceUsed(&dwlSize, NULL); if (dwlSize) // If there is something in offline cache to delete return S_OK; // load cleaner/ } return S_FALSE; } STDMETHODIMP COfflinePagesCacheCleaner::GetSpaceUsed( DWORDLONG * pdwlSpaceUsed, IEmptyVolumeCacheCallBack * picb ) { HRESULT hr; ASSERT(NULL != pdwlSpaceUsed); if (NULL != pdwlSpaceUsed) { RTSCBSTRUCT * prtscbStruct = new RTSCBSTRUCT; if (NULL != prtscbStruct) { // Initialize GetSpazeUsed Structure prtscbStruct->pdwlSpaceUsed = pdwlSpaceUsed; *(prtscbStruct->pdwlSpaceUsed) = 0; prtscbStruct->picb = picb; // Get Offline Cache Space Usage hr = WalkOfflineCache(RunningTotalSizeCallback, (void *)(prtscbStruct)); m_dwlSpaceUsed = *(prtscbStruct->pdwlSpaceUsed); // Send the last notification to the cleanup manager if (picb != NULL) picb->ScanProgress(*(prtscbStruct->pdwlSpaceUsed), EVCCBF_LASTNOTIFICATION, NULL); delete prtscbStruct; } else { hr = E_OUTOFMEMORY; } } else { hr = E_INVALIDARG; } return hr; } STDMETHODIMP COfflinePagesCacheCleaner::Purge( DWORDLONG dwlSpaceToFree, // Spec makes this irrelevent! IEmptyVolumeCacheCallBack * picb ) { HRESULT hr; DECBSTRUCT * pdecbStruct = new DECBSTRUCT; if (NULL != pdecbStruct) { // Initialize DeleteEntry Structure pdecbStruct->picb = picb; pdecbStruct->dwlSpaceFreed = 0; pdecbStruct->dwlTotalSpace = m_dwlSpaceUsed; // Delete Offline Cache Entries hr = WalkOfflineCache(DeleteEntryCallback, (void *)(pdecbStruct)); // Send the last notification to the cleanup manager if (picb != NULL) { picb->PurgeProgress(m_dwlSpaceUsed, 0, EVCCBF_LASTNOTIFICATION, NULL); } delete pdecbStruct; } else { hr = E_OUTOFMEMORY; } return hr; } STDMETHODIMP COfflinePagesCacheCleaner::ShowProperties(HWND hwnd) { TCHAR szOfflinePath[MAX_PATH]; DWORD dwSize = SIZEOF(szOfflinePath); szOfflinePath[0] = L'\0'; if (SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_SUBSCRIPTION, REGSTR_VAL_DIRECTORY, NULL, (LPBYTE)szOfflinePath, &dwSize) != ERROR_SUCCESS) { TCHAR szWindows[MAX_PATH]; szWindows[0] = L'\0'; GetWindowsDirectory(szWindows, ARRAYSIZE(szWindows)); if (*szWindows) PathCombine(szOfflinePath, szWindows, TEXT("Offline Web Pages")); } if (*szOfflinePath) { PathQuoteSpaces(szOfflinePath); SHELLEXECUTEINFO shei; ZeroMemory(&shei, sizeof(shei)); shei.cbSize = sizeof(shei); shei.lpFile = szOfflinePath; shei.nShow = SW_SHOWNORMAL; ShellExecuteEx(&shei); } // Returning S_OK insures that GetSpaceUsed is recalled (to recalc) the size being // used (in case someone deletes some MAO stuff). return S_OK; } STDMETHODIMP COfflinePagesCacheCleaner::Deactivate(DWORD * pdwFlags) { // We don't implement this. *pdwFlags = 0; return S_OK; } HRESULT COfflinePagesCacheCleaner::WalkOfflineCache( LPFCALLBACK lpfCallBack, void * pv ) { ASSERT(pv); HRESULT hr = S_OK; LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo; HANDLE hCacheEntryInfo; DWORD dwCacheEntryInfoSize; if ((lpCacheEntryInfo = (LPINTERNET_CACHE_ENTRY_INFO) LocalAlloc(LPTR, MAX_CACHE_ENTRY_INFO_SIZE)) == NULL) { hr = E_OUTOFMEMORY; } else { dwCacheEntryInfoSize = MAX_CACHE_ENTRY_INFO_SIZE; if ((hCacheEntryInfo = FindFirstUrlCacheEntry(NULL, lpCacheEntryInfo, &dwCacheEntryInfoSize)) == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); } if (SUCCEEDED(hr)) { do { if (lpCacheEntryInfo->CacheEntryType & STICKY_CACHE_ENTRY) { hr = lpfCallBack(lpCacheEntryInfo, pv); } dwCacheEntryInfoSize = MAX_CACHE_ENTRY_INFO_SIZE; } while ((E_ABORT != hr) && FindNextUrlCacheEntry(hCacheEntryInfo, lpCacheEntryInfo, &dwCacheEntryInfoSize)); if (hr != E_ABORT) { DWORD dwLastErr = GetLastError(); if (dwLastErr != ERROR_NO_MORE_ITEMS) { hr = HRESULT_FROM_WIN32(dwLastErr); } } } LocalFree(lpCacheEntryInfo); lpCacheEntryInfo = NULL; } return hr; } HRESULT CALLBACK COfflinePagesCacheCleaner::RunningTotalSizeCallback( LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo, // Name of the CacheEntry to sum void * pv // A RTSCBSTRUCT ) { HRESULT hr = S_OK; RTSCBSTRUCT * prtscbStruct = (RTSCBSTRUCT *)pv; // Add current file size to total IncrementFileSize(lpCacheEntryInfo, prtscbStruct->pdwlSpaceUsed); // Update the progressbar! if (prtscbStruct->picb != NULL) hr = prtscbStruct->picb->ScanProgress(*(prtscbStruct->pdwlSpaceUsed), 0, NULL); return hr; } HRESULT CALLBACK COfflinePagesCacheCleaner::DeleteEntryCallback( LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo, // Name of the CacheEntry to delete void * pv // Pointer to DECBSTRUCT ) { HRESULT hr = S_OK; DECBSTRUCT * pdecbStruct = (DECBSTRUCT *)pv; // Add current file size to total deleted IncrementFileSize(lpCacheEntryInfo, &(pdecbStruct->dwlSpaceFreed)); DeleteUrlCacheEntry(lpCacheEntryInfo->lpszSourceUrlName); // Update the progress bar! if (pdecbStruct->picb != NULL) { hr = pdecbStruct->picb->PurgeProgress(pdecbStruct->dwlSpaceFreed, pdecbStruct->dwlTotalSpace - pdecbStruct->dwlSpaceFreed, NULL, NULL); } return hr; } VOID COfflinePagesCacheCleaner::IncrementFileSize( LPINTERNET_CACHE_ENTRY_INFO lpCacheEntryInfo, DWORDLONG * pdwlSize ) { ULARGE_INTEGER uliFileSize; uliFileSize.HighPart = lpCacheEntryInfo->dwSizeHigh; uliFileSize.LowPart = lpCacheEntryInfo->dwSizeLow; *pdwlSize += QUAD_PART(uliFileSize); }