WindowsXP-SP1/shell/shdocvw/cacheoff.cpp

471 lines
14 KiB
C++

// Author: Karim Farouki
// Date: 24 June 1998
#include "priv.h"
#include "util.h"
#include <emptyvc.h>
#include <mluisupp.h> // 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, 512 );
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 )
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, sizeof(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);
if (SHGetValue(HKEY_LOCAL_MACHINE, REGSTR_PATH_SUBSCRIPTION,
REGSTR_VAL_DIRECTORY, NULL, (LPBYTE)szOfflinePath, &dwSize) != ERROR_SUCCESS)
{
TCHAR szWindows[MAX_PATH];
GetWindowsDirectory(szWindows, ARRAYSIZE(szWindows));
PathCombine(szOfflinePath, szWindows, TEXT("Offline Web Pages"));
}
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);
}