// Author: Pritvinath Obla // Date: 10 July 1997 #include "priv.h" #include "util.h" #include #include // for MLLoadString #include "resource.h" // for the string ID's class CInternetCacheCleaner : public IEmptyVolumeCache2 { private: // // Data // ULONG m_cRef; // reference count DWORDLONG m_dwlSpaceUsed; TCHAR m_szCacheDir[MAX_PATH + 1]; // // Functions // HRESULT GetInternetCacheSize( DWORDLONG *pdwlSpaceUsed, IEmptyVolumeCacheCallBack *picb ); HRESULT DelInternetCacheFiles( DWORD dwPercentToFree, IEmptyVolumeCacheCallBack *picb ); public: // // Constructor and Destructor // CInternetCacheCleaner(void); ~CInternetCacheCleaner(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 ); }; // //------------------------------------------------------------------------------ // CInternetCacheCleaner_CreateInstance // // Purpose: CreateInstance function for IClassFactory //------------------------------------------------------------------------------ // STDAPI CInternetCacheCleaner_CreateInstance( IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi ) { *ppunk = NULL; CInternetCacheCleaner *lpICC = new CInternetCacheCleaner(); if (lpICC == NULL) return E_OUTOFMEMORY; *ppunk = SAFECAST(lpICC, IEmptyVolumeCache *); return S_OK; } CInternetCacheCleaner::CInternetCacheCleaner() : m_cRef(1) { DllAddRef(); m_dwlSpaceUsed = 0; *m_szCacheDir = '\0'; } CInternetCacheCleaner::~CInternetCacheCleaner() { DllRelease(); } STDMETHODIMP CInternetCacheCleaner::QueryInterface(REFIID riid, LPVOID *ppv) { if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IEmptyVolumeCache2) || IsEqualIID(riid, IID_IEmptyVolumeCache)) { *ppv = SAFECAST(this, IEmptyVolumeCache2 *); } else { *ppv = NULL; return E_NOINTERFACE; } AddRef(); return NOERROR; } STDMETHODIMP_(ULONG) CInternetCacheCleaner::AddRef() { return ++m_cRef; } STDMETHODIMP_(ULONG) CInternetCacheCleaner::Release() { // // Decrement and check // if (--m_cRef) return m_cRef; // // No references left to this object // delete this; return 0; } // //------------------------------------------------------------------------------ // CInternetCacheCleaner::InitializeEx // // Purpose: Initializes the Internet Cache Cleaner and returns the // specified IEmptyVolumeCache flags to the cache manager //------------------------------------------------------------------------------ // STDMETHODIMP CInternetCacheCleaner::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_CACHECLN_BTNTEXT, *ppwszBtnText, 128 ); return Initialize(hkRegKey, pcwszVolume, ppwszDisplayName, ppwszDescription, pdwFlags ); } // //------------------------------------------------------------------------------ // CInternetCacheCleaner::Initialize // // Purpose: Initializes the Internet Cache Cleaner and returns the // specified IEmptyVolumeCache flags to the cache manager //------------------------------------------------------------------------------ // STDMETHODIMP CInternetCacheCleaner::Initialize( HKEY hkRegKey, LPCWSTR pcwszVolume, LPWSTR *ppwszDisplayName, LPWSTR *ppwszDescription, DWORD *pdwFlags ) { #ifdef UNICODE // We can't use the registry values on NT because they can't be multi-local localized. As // a result we must set the out pointers with values read 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_CACHECLN_DISPLAY, *ppwszDisplayName, 512 ); MLLoadString( IDS_CACHECLN_DESCRIPTION, *ppwszDescription, 512 ); #else // // Let cleanmgr read the default DisplayName and Description // from hkRegKey and use them // *ppwszDisplayName = NULL; *ppwszDescription = NULL; #endif *pdwFlags = 0; // initialize the [out] parameter // // Check if the Internet Cache Folder is in pcwzVolume // GetCacheLocation(m_szCacheDir, ARRAYSIZE(m_szCacheDir)); if (StrCmpNI(pcwszVolume, m_szCacheDir, 3)) { // // Different drives; return S_FALSE so that this cleaner // doesn't show up in cleanmgr's UI // return S_FALSE; } // // Enable this cleaner by default both in cleanup and tuneup modes // *pdwFlags = EVCF_ENABLEBYDEFAULT | EVCF_ENABLEBYDEFAULT_AUTO | EVCF_HASSETTINGS; #if 0 /*** // Since GetInternetCacheSize returns only an approx. size, // we would never get a value of 0 even if the cache is empty // Should enable this check once wininet.dll exports a GetCacheSize API // // Check if there is any disk space to free at all // If not, return S_FALSE so that this cleaner doesn't show up in // cleanmgr's UI // DWORDLONG dwlSpaceUsed; if (SUCCEEDED(GetInternetCacheSize(&dwlSpaceUsed, NULL)) && dwlSpaceUsed == 0) { return S_FALSE; } ***/ #endif return S_OK; } // //------------------------------------------------------------------------------ // CInternetCacheCleaner::GetSpaceUsed // // Purpose: Return the total amount of space this internet cache cleaner // can free up //------------------------------------------------------------------------------ // STDMETHODIMP CInternetCacheCleaner::GetSpaceUsed( DWORDLONG *pdwlSpaceUsed, IEmptyVolumeCacheCallBack *picb ) { HRESULT hr; hr = GetInternetCacheSize(pdwlSpaceUsed, picb); m_dwlSpaceUsed = *pdwlSpaceUsed; // // Send the last notification to the cleanup manager // if (picb != NULL) { picb->ScanProgress(*pdwlSpaceUsed, EVCCBF_LASTNOTIFICATION, NULL); } if (hr != E_ABORT) { if (FAILED(hr)) { // // *pdwlSpaceUsed is only a guesstimate; so return S_FALSE // hr = S_FALSE; } else { // // Return S_OK once wininet exports a GetCacheSize API; // till then use FindFirstUrlCacheEntry/FindNextUrlCacheEntry // to get approx. size of the cache // hr = S_FALSE; } } return hr; } // //------------------------------------------------------------------------------ // CInternetCacheCleaner::Purge // // Purpose: Delete the internet cache files //------------------------------------------------------------------------------ // STDMETHODIMP CInternetCacheCleaner::Purge( DWORDLONG dwlSpaceToFree, IEmptyVolumeCacheCallBack *picb ) { HRESULT hr; DWORD dwPercentToFree = 100; // Optimize the most common scenario: // In most cases, dwlSpaceToFree will be // equal to m_dwlSpaceUsed if (dwlSpaceToFree != m_dwlSpaceUsed) { dwPercentToFree = m_dwlSpaceUsed ? DWORD((dwlSpaceToFree * 100) / m_dwlSpaceUsed) : 100; } hr = DelInternetCacheFiles(dwPercentToFree, picb); // // Send the last notification to the cleanup manager // if (picb != NULL) { picb->PurgeProgress(dwlSpaceToFree, 0, EVCCBF_LASTNOTIFICATION, NULL); } if (hr != E_ABORT) { hr = S_OK; // cannot return anything else } return hr; } // //------------------------------------------------------------------------------ // CInternetCacheCleaner::ShowProperties // // Purpose: Launch the cache viewer to list the internet cache files //------------------------------------------------------------------------------ // STDMETHODIMP CInternetCacheCleaner::ShowProperties( HWND hwnd ) { DWORD dwAttrib; if (*m_szCacheDir == '\0') // Internet cache dir is not yet initialized { GetCacheLocation(m_szCacheDir, ARRAYSIZE(m_szCacheDir)); } dwAttrib = GetFileAttributes(m_szCacheDir); if (dwAttrib != 0xffffffff && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY)) { WCHAR szCache[MAX_PATH]; StringCchCopy(szCache, ARRAYSIZE(szCache), m_szCacheDir); PathQuoteSpaces(szCache); SHELLEXECUTEINFO sei; // // Launch the cache viewer // sei.cbSize = sizeof(SHELLEXECUTEINFO); sei.hwnd = hwnd; sei.lpVerb = NULL; sei.lpFile = szCache; sei.lpParameters = NULL; sei.lpDirectory = NULL; sei.nShow = SW_SHOWNORMAL; sei.fMask = 0; ShellExecuteEx(&sei); } // // The user may or may not delete files directly from the cachevu folder // Since there is no way of knowing this, don't return S_OK which would // trigger cleanmgr to call GetSpaceUsed again // return S_OK; } // //------------------------------------------------------------------------------ // CInternetCacheCleaner::Deactivate // // Purpose: Deactivates the Internet Cache Cleaner...Not implemented //------------------------------------------------------------------------------ // STDMETHODIMP CInternetCacheCleaner::Deactivate( DWORD *pdwFlags ) { *pdwFlags = 0; return S_OK; } // //------------------------------------------------------------------------------ // CInternetCacheCleaner::GetInternetCacheSize // // Purpose: Find the size of the internet cache by calling into wininet APIs // // Notes: The current implementation is temporary; once wininet exports // a real API for getting the cache size, use that //------------------------------------------------------------------------------ // HRESULT CInternetCacheCleaner::GetInternetCacheSize( DWORDLONG *pdwlSpaceUsed, IEmptyVolumeCacheCallBack *picb // not used ) { HRESULT hr = S_OK; DWORD dwLastErr; LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo; HANDLE hCacheEntryInfo; DWORD dwCacheEntryInfoSize; *pdwlSpaceUsed = 0; if ((lpCacheEntryInfo = (LPINTERNET_CACHE_ENTRY_INFOA) LocalAlloc(LPTR, MAX_CACHE_ENTRY_INFO_SIZE)) == NULL) { return E_OUTOFMEMORY; } dwCacheEntryInfoSize = MAX_CACHE_ENTRY_INFO_SIZE; if ((hCacheEntryInfo = FindFirstUrlCacheEntryA(NULL, lpCacheEntryInfo, &dwCacheEntryInfoSize)) == NULL) { hr = HRESULT_FROM_WIN32(GetLastError()); } if (SUCCEEDED(hr)) { do { if (!(lpCacheEntryInfo->CacheEntryType & (STICKY_CACHE_ENTRY | COOKIE_CACHE_ENTRY))) { ULARGE_INTEGER uliFileSize; uliFileSize.HighPart = lpCacheEntryInfo->dwSizeHigh; uliFileSize.LowPart = lpCacheEntryInfo->dwSizeLow; *pdwlSpaceUsed += QUAD_PART(uliFileSize); } dwCacheEntryInfoSize = MAX_CACHE_ENTRY_INFO_SIZE; } while (FindNextUrlCacheEntryA(hCacheEntryInfo, lpCacheEntryInfo, &dwCacheEntryInfoSize)); if ((dwLastErr = GetLastError()) != ERROR_NO_MORE_ITEMS) { hr = HRESULT_FROM_WIN32(dwLastErr); } } if (lpCacheEntryInfo != NULL) { LocalFree(lpCacheEntryInfo); lpCacheEntryInfo = NULL; } return hr; } // //------------------------------------------------------------------------------ // CInternetCacheCleaner::DelInternetCacheFiles // // Purpose: Delete the internet cache files //------------------------------------------------------------------------------ // HRESULT CInternetCacheCleaner::DelInternetCacheFiles( DWORD dwPercentToFree, IEmptyVolumeCacheCallBack *picb // not used ) { HRESULT hr = S_OK; if (*m_szCacheDir == '\0') // Internet cache dir is not yet initialized { hr = GetCacheLocation(m_szCacheDir, ARRAYSIZE(m_szCacheDir)); } if (SUCCEEDED(hr)) { FreeUrlCacheSpace(m_szCacheDir, dwPercentToFree, STICKY_CACHE_ENTRY); } return hr; }