Windows-Server-2003/shell/shdocvw/cachecln.cpp

535 lines
15 KiB
C++

// Author: Pritvinath Obla
// Date: 10 July 1997
#include "priv.h"
#include "util.h"
#include <emptyvc.h>
#include <mluisupp.h> // 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;
}