//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1997 - 1999 // // File: volclean.cpp // // Authors; // Jeff Saathoff (jeffreys) // // Notes; // CSC disk cleanup implementation (IEmptyVolumeCache) //-------------------------------------------------------------------------- #include "pch.h" #include "folder.h" int CoTaskLoadString(HINSTANCE hInstance, UINT idString, LPWSTR *ppwsz) { int nResult = 0; *ppwsz = NULL; ULONG cchString = SizeofStringResource(hInstance, idString); if (cchString) { cchString++; // for NULL *ppwsz = (LPWSTR)CoTaskMemAlloc(cchString * sizeof(WCHAR)); if (*ppwsz) nResult = LoadStringW(hInstance, idString, *ppwsz, cchString); } return nResult; } /////////////////////////////////////////////////////////////////////////////// // // // IClassFactory::CreateInstance support // // // /////////////////////////////////////////////////////////////////////////////// HRESULT WINAPI CCscVolumeCleaner::CreateInstance(REFIID riid, LPVOID *ppv) { return Create(FALSE, riid, ppv); } HRESULT WINAPI CCscVolumeCleaner::CreateInstance2(REFIID riid, LPVOID *ppv) { return Create(TRUE, riid, ppv); } HRESULT WINAPI CCscVolumeCleaner::Create(BOOL fPinned, REFIID riid, LPVOID *ppv) { HRESULT hr; CCscVolumeCleaner *pThis = new CCscVolumeCleaner(fPinned); if (pThis) { hr = pThis->QueryInterface(riid, ppv); pThis->Release(); } else hr = E_OUTOFMEMORY; return hr; } /////////////////////////////////////////////////////////////////////////////// // // // IUnknown implementation // // // /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CCscVolumeCleaner::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CCscVolumeCleaner, IEmptyVolumeCache), QITABENT(CCscVolumeCleaner, IEmptyVolumeCache2), { 0 }, }; return QISearch(this, qit, riid, ppv); } STDMETHODIMP_(ULONG) CCscVolumeCleaner::AddRef() { return InterlockedIncrement(&m_cRef); } STDMETHODIMP_(ULONG) CCscVolumeCleaner::Release() { if (InterlockedDecrement(&m_cRef)) return m_cRef; delete this; return 0; } /////////////////////////////////////////////////////////////////////////////// // // // IEmptyVolumeCache implementation // // // /////////////////////////////////////////////////////////////////////////////// STDMETHODIMP CCscVolumeCleaner::Initialize(HKEY /*hkRegKey*/, LPCWSTR pcwszVolume, LPWSTR *ppwszDisplayName, LPWSTR *ppwszDescription, LPDWORD pdwFlags) { BOOL bSettingsMode; CSCSPACEUSAGEINFO sui = {0}; USES_CONVERSION; TraceEnter(TRACE_SHELLEX, "IEmptyVolumeCache::Initialize"); TraceAssert(pcwszVolume != NULL); TraceAssert(ppwszDisplayName != NULL); TraceAssert(ppwszDescription != NULL); TraceAssert(pdwFlags != NULL); TraceAssert(IsCSCEnabled()); bSettingsMode = (BOOL)((*pdwFlags) & EVCF_SETTINGSMODE); *ppwszDisplayName = NULL; *ppwszDescription = NULL; *pdwFlags = 0; // If this isn't the volume containing the CSC database, then we have // nothing to free. Note that we don't use the space usage data // returned here. GetCscSpaceUsageInfo(&sui); if (!bSettingsMode && !PathIsSameRoot(sui.szVolume, W2CT(pcwszVolume))) TraceLeaveResult(S_FALSE); m_PurgerSel.SetFlags(m_fPinned ? PURGE_FLAG_PINNED : (PURGE_FLAG_UNPINNED | PURGE_IGNORE_ACCESS)); m_pPurger = new CCachePurger(m_PurgerSel, CachePurgerCallback, this); if (!m_pPurger) TraceLeaveResult(E_FAIL); // If we're freeing auto-cached files, we want to be enabled by default, // but not if we're freeing pinned files. *pdwFlags = 0; if (!m_fPinned) *pdwFlags = EVCF_ENABLEBYDEFAULT | EVCF_ENABLEBYDEFAULT_AUTO; // If policy allows, turn on the "Details" button which launches the viewer if (!CConfig::GetSingleton().NoCacheViewer()) *pdwFlags |= EVCF_HASSETTINGS; // Load the display name string CoTaskLoadString(g_hInstance, m_fPinned ? IDS_APPLICATION : IDS_DISKCLEAN_DISPLAY, ppwszDisplayName); // Load the description string CoTaskLoadString(g_hInstance, m_fPinned ? IDS_DISKCLEAN_PIN_DESCRIPTION : IDS_DISKCLEAN_DESCRIPTION, ppwszDescription); TraceLeaveResult(S_OK); } STDMETHODIMP CCscVolumeCleaner::GetSpaceUsed(DWORDLONG *pdwlSpaceUsed, LPEMPTYVOLUMECACHECALLBACK picb) { m_pDiskCleaner = picb; m_pPurger->Scan(); if (m_pDiskCleaner) m_pDiskCleaner->ScanProgress(m_dwlSpaceToFree, EVCCBF_LASTNOTIFICATION, NULL); *pdwlSpaceUsed = m_dwlSpaceToFree; return S_OK; } STDMETHODIMP CCscVolumeCleaner::Purge(DWORDLONG /*dwlSpaceToFree*/, LPEMPTYVOLUMECACHECALLBACK picb) { m_pDiskCleaner = picb; m_pPurger->Delete(); if (m_pDiskCleaner) m_pDiskCleaner->PurgeProgress(m_dwlSpaceFreed, 0, EVCCBF_LASTNOTIFICATION, NULL); return S_OK; } STDMETHODIMP CCscVolumeCleaner::ShowProperties(HWND /*hwnd*/) { // Launch the viewer COfflineFilesFolder::Open(); return S_FALSE; } STDMETHODIMP CCscVolumeCleaner::Deactivate(LPDWORD /*pdwFlags*/) { // nothing to do here return S_OK; } // IEmptyVolumeCache2 method STDMETHODIMP CCscVolumeCleaner::InitializeEx(HKEY hkRegKey, LPCWSTR pcwszVolume, LPCWSTR pcwszKeyName, LPWSTR *ppwszDisplayName, LPWSTR *ppwszDescription, LPWSTR *ppwszBtnText, LPDWORD pdwFlags) { HRESULT hr = Initialize(hkRegKey, pcwszVolume, ppwszDisplayName, ppwszDescription, pdwFlags); if (S_OK == hr) CoTaskLoadString(g_hInstance, IDS_DISKCLEAN_BTN_TEXT, ppwszBtnText); return hr; } BOOL CCscVolumeCleaner::ScanCallback(CCachePurger *pPurger) { BOOL bContinue = TRUE; // If the pinned state matches what we're looking for, add the // size to the total. if (pPurger->WillDeleteThisFile()) m_dwlSpaceToFree += pPurger->FileBytes(); if (m_pDiskCleaner) bContinue = SUCCEEDED(m_pDiskCleaner->ScanProgress(m_dwlSpaceToFree, 0, NULL)); return bContinue; } BOOL CCscVolumeCleaner::DeleteCallback(CCachePurger *pPurger) { BOOL bContinue = TRUE; // Don't let this go below zero m_dwlSpaceToFree -= min(pPurger->FileBytes(), m_dwlSpaceToFree); m_dwlSpaceFreed += pPurger->FileBytes(); if (m_pDiskCleaner) bContinue = SUCCEEDED(m_pDiskCleaner->PurgeProgress(m_dwlSpaceFreed, m_dwlSpaceToFree, 0, NULL)); return bContinue; } BOOL CALLBACK CCscVolumeCleaner::CachePurgerCallback(CCachePurger *pPurger) { PCSCVOLCLEANER pThis = (PCSCVOLCLEANER)pPurger->CallbackData(); switch (pPurger->Phase()) { case PURGE_PHASE_SCAN: return pThis->ScanCallback(pPurger); case PURGE_PHASE_DELETE: return pThis->DeleteCallback(pPurger); } return FALSE; }