|
|
#include "common.h"
#include "dataguid.h"
#include "compguid.h"
#include <emptyvc.h>
#include "dataclen.h"
#include "compclen.h"
#include <regstr.h>
#include <olectl.h>
#include <tlhelp32.h>
#define DECL_CRTFREE
#include <crtfree.h>
#ifndef RESOURCE_H
#include "resource.h"
#endif
#include <winsvc.h>
#include <shlwapi.h>
#include <shlwapip.h>
#include <advpub.h>
HINSTANCE g_hDllModule = NULL; // Handle to this DLL itself.
LONG g_cDllObjects = 0; // Count number of existing objects
STDAPI_(int) LibMain(HINSTANCE hInstance, DWORD fdwReason, LPVOID pvRes) { switch (fdwReason) { case DLL_PROCESS_ATTACH: g_hDllModule = hInstance; break;; }
return TRUE; }
STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) { DWORD dw; HRESULT hr; *ppv = NULL; //
// Is the request for one of our cleaner objects?
//
if (IsEqualCLSID(rclsid, CLSID_DataDrivenCleaner)) { dw = ID_SYSTEMDATACLEANER; } else if (IsEqualCLSID(rclsid, CLSID_ContentIndexerCleaner)) { dw = ID_CONTENTINDEXCLEANER; } else if (IsEqualCLSID(rclsid, CLSID_CompCleaner)) { dw = ID_COMPCLEANER; } else if (IsEqualCLSID(rclsid, CLSID_OldFilesInRootPropBag)) { dw = ID_OLDFILESINROOTPROPBAG; } else if (IsEqualCLSID(rclsid, CLSID_TempFilesPropBag)) { dw = ID_TEMPFILESPROPBAG; } else if (IsEqualCLSID(rclsid, CLSID_SetupFilesPropBag)) { dw = ID_SETUPFILESPROPBAG; } else if (IsEqualCLSID(rclsid, CLSID_UninstalledFilesPropBag)) { dw = ID_UNINSTALLEDFILESPROPBAG; } else if (IsEqualCLSID(rclsid, CLSID_IndexCleanerPropBag)) { dw = ID_INDEXCLEANERPROPBAG; } else { return CLASS_E_CLASSNOTAVAILABLE; } if (ID_COMPCLEANER == dw) { CCompCleanerClassFactory *pcf = new CCompCleanerClassFactory(); if (pcf) { hr = pcf->QueryInterface(riid, ppv); pcf->Release(); } else { hr = E_OUTOFMEMORY; } } else { CCleanerClassFactory * pcf = new CCleanerClassFactory(dw); if (pcf) { hr = pcf->QueryInterface(riid, ppv); pcf->Release(); } else { hr = E_OUTOFMEMORY; } } return hr; }
STDAPI DllCanUnloadNow(void) { return (0 == g_cDllObjects) ? S_OK : S_FALSE; }
HRESULT CallRegInstall(LPCSTR szSection) { HRESULT hr = E_FAIL; HINSTANCE hinstAdvPack = LoadLibrary(TEXT("ADVPACK.DLL")); if (hinstAdvPack) { REGINSTALL pfnri = (REGINSTALL)GetProcAddress(hinstAdvPack, "RegInstall"); if (pfnri) { STRENTRY seReg[] = { { "25", "%SystemRoot%" }, { "11", "%SystemRoot%\\system32" }, }; STRTABLE stReg = { ARRAYSIZE(seReg), seReg }; hr = pfnri(g_hDllModule, szSection, &stReg); } // since we only do this from DllInstall() don't load and unload advpack over and over
// FreeLibrary(hinstAdvPack);
} return hr; }
STDAPI DllRegisterServer() { return CallRegInstall("RegDll"); }
STDAPI DllUnregisterServer() { return CallRegInstall("UnregDll"); }
UINT incDllObjectCount(void) { return InterlockedIncrement(&g_cDllObjects); }
UINT decDllObjectCount(void) { #if DBG==1
if( 0 == g_cDllObjects ) { DebugBreak(); // ref counting problem
} #endif
return InterlockedDecrement(&g_cDllObjects); }
CCleanerClassFactory::CCleanerClassFactory(DWORD dw) : _cRef(1), _dwID(dw) { incDllObjectCount(); }
CCleanerClassFactory::~CCleanerClassFactory() { decDllObjectCount(); }
STDMETHODIMP CCleanerClassFactory::QueryInterface(REFIID riid, void **ppv) { *ppv = NULL;
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IClassFactory)) { *ppv = (IClassFactory *)this; AddRef(); return S_OK; } return E_NOINTERFACE; }
STDMETHODIMP_(ULONG) CCleanerClassFactory::AddRef() { return ++_cRef; }
STDMETHODIMP_(ULONG) CCleanerClassFactory::Release() { if (--_cRef) return _cRef;
delete this; return 0; }
STDMETHODIMP CCleanerClassFactory::CreateInstance(IUnknown *pUnkOuter, REFIID riid, void **ppv) { HRESULT hr = E_NOINTERFACE; *ppv = NULL;
if (pUnkOuter) { return CLASS_E_NOAGGREGATION; }
if (_dwID == ID_CONTENTINDEXCLEANER) { CContentIndexCleaner *pContentIndexCleaner = new CContentIndexCleaner(); if (pContentIndexCleaner) { hr = pContentIndexCleaner->QueryInterface(riid, ppv); pContentIndexCleaner->Release(); } else { hr = E_OUTOFMEMORY; } } else if (IsEqualIID(riid, IID_IEmptyVolumeCache)) { CDataDrivenCleaner *pDataDrivenCleaner = new CDataDrivenCleaner(); if (pDataDrivenCleaner) { hr = pDataDrivenCleaner->QueryInterface(riid, ppv); pDataDrivenCleaner->Release(); } else { hr = E_OUTOFMEMORY; } } else if (IsEqualIID(riid, IID_IPropertyBag)) { CDataDrivenPropBag *pDataDrivenPropBag = new CDataDrivenPropBag(_dwID); if (pDataDrivenPropBag) { hr = pDataDrivenPropBag->QueryInterface(riid, ppv); pDataDrivenPropBag->Release(); } else { hr = E_OUTOFMEMORY; } } else { MiDebugMsg((0, TEXT("CDataDrivenCleanerClassFactory::CreateInstance called for unknown riid (%d)"), (_dwID))); }
return hr; }
STDMETHODIMP CCleanerClassFactory::LockServer(BOOL fLock) { if (fLock) incDllObjectCount(); else decDllObjectCount();
return S_OK; }
CDataDrivenCleaner::CDataDrivenCleaner() : _cRef(1) { _cbSpaceUsed.QuadPart = 0; _cbSpaceFreed.QuadPart = 0; _szVolume[0] = 0; _szFolder[0] = 0; _filelist[0] = 0; _dwFlags = 0;
_head = NULL;
incDllObjectCount(); }
CDataDrivenCleaner::~CDataDrivenCleaner() { FreeList(_head); _head = NULL; decDllObjectCount(); }
STDMETHODIMP CDataDrivenCleaner::QueryInterface(REFIID riid, void **ppv) { *ppv = NULL;
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IEmptyVolumeCache)) { *ppv = (IEmptyVolumeCache*) this; AddRef(); return S_OK; } return E_NOINTERFACE; }
STDMETHODIMP_(ULONG) CDataDrivenCleaner::AddRef() { return ++_cRef; }
STDMETHODIMP_(ULONG) CDataDrivenCleaner::Release() { if (--_cRef) return _cRef;
delete this; return 0; }
// Initializes the System Data Driven Cleaner and returns the
// specified IEmptyVolumeCache flags to the cache manager.
STDMETHODIMP CDataDrivenCleaner::Initialize(HKEY hRegKey, LPCWSTR pszVolume, LPWSTR *ppszDisplayName, LPWSTR *ppszDescription, DWORD *pdwFlags) { TCHAR szTempFolder[MAX_PATH]; ULONG DaysLastAccessed = 0; PTSTR pTemp; BOOL bFolderOnVolume;
_bPurged = FALSE;
*ppszDisplayName = NULL; // cleanmgr.exe will get these values from
*ppszDescription = NULL;
_ftMinLastAccessTime.dwLowDateTime = 0; _ftMinLastAccessTime.dwHighDateTime = 0;
if (*pdwFlags & EVCF_SETTINGSMODE) { return S_OK; }
_szFolder[0] = 0; _dwFlags = 0; _filelist[0] = 0; _szCleanupCmdLine[0] = 0; if (hRegKey) { DWORD dwType, cbData; DWORD dwCSIDL;
cbData = sizeof(dwCSIDL); if (ERROR_SUCCESS == RegQueryValueEx(hRegKey, REGSTR_VAL_CSIDL, NULL, &dwType, (LPBYTE)&dwCSIDL, &cbData)) { // CSIDL=<hex CSIDL_ value>
SHGetFolderPath(NULL, dwCSIDL, NULL, 0, _szFolder);
if (_szFolder[0]) { TCHAR szRelPath[MAX_PATH]; cbData = sizeof(szRelPath); if (ERROR_SUCCESS == RegQueryValueEx(hRegKey, REGSTR_VAL_FOLDER, NULL, &dwType, (LPBYTE)szRelPath, &cbData)) { // optionally append "folder" as a relative path
PathAppend(_szFolder, szRelPath); } } }
if (0 == _szFolder[0]) { // still nothing, try "folder"=<path1>|<path2>
cbData = sizeof(_szFolder); if (ERROR_SUCCESS == RegQueryValueEx(hRegKey, REGSTR_VAL_FOLDER, NULL, &dwType, (LPBYTE)_szFolder, &cbData)) { if (REG_SZ == dwType) { // REG_SZ that needs to be converted to a MULTI_SZ
//
// paths separated by '|' like ?:\foo|?:\bar
for (pTemp = _szFolder; *pTemp; pTemp++) { if (*pTemp == TEXT('|')) { *pTemp++ = NULL; } } // double NULL terminated
pTemp++; *pTemp = 0; } else if (REG_EXPAND_SZ == dwType) { // single folder with environment expantion
if (SHExpandEnvironmentStrings(_szFolder, szTempFolder, (ARRAYSIZE(szTempFolder) - 1))) // leave extra space for double NULL
{ StringCchCopy(_szFolder, ARRAYSIZE(_szFolder), szTempFolder); } _szFolder[lstrlen(_szFolder) + 1] = 0; // double NULL terminated.
} else if (REG_MULTI_SZ == dwType) { // nothing else to do, we're done
} else { // invalid data
_szFolder[0] = NULL; } } }
cbData = sizeof(_dwFlags); RegQueryValueEx(hRegKey, REGSTR_VAL_FLAGS, NULL, &dwType, (LPBYTE)&_dwFlags, &cbData);
cbData = sizeof(_filelist); RegQueryValueEx(hRegKey, REGSTR_VAL_FILELIST, NULL, &dwType, (LPBYTE)_filelist, &cbData);
cbData = sizeof(DaysLastAccessed); RegQueryValueEx(hRegKey, REGSTR_VAL_LASTACCESS, NULL, &dwType, (LPBYTE)&DaysLastAccessed, &cbData);
cbData = sizeof(_szCleanupCmdLine); RegQueryValueEx(hRegKey, REGSTR_VAL_CLEANUPSTRING, NULL, &dwType, (LPBYTE)_szCleanupCmdLine, &cbData); }
// If the DDEVCF_RUNIFOUTOFDISKSPACE bit is set then make sure the EVCF_OUTOFDISKSPACE flag
// was passed in. If it was not then return S_FALSE so we won't run.
if ((_dwFlags & DDEVCF_RUNIFOUTOFDISKSPACE) && (!(*pdwFlags & EVCF_OUTOFDISKSPACE))) { return S_FALSE; }
StringCchCopy(_szVolume, ARRAYSIZE(_szVolume), pszVolume);
// Fix up the filelist. The file list can either be a MULTI_SZ list of files or
// a list of files separated by the ':' colon character or a '|' bar character.
// These characters were choosen because they are invalid filename characters.
for (pTemp = _filelist; *pTemp; pTemp++) { if (*pTemp == TEXT(':') || *pTemp == TEXT('|')) { *pTemp++ = 0; } } pTemp++; // double null terminate
*pTemp = 0;
bFolderOnVolume = FALSE; if (_szFolder[0] == 0) { // If no folder value is given so use the current volume
StringCchCopy(_szFolder, ARRAYSIZE(_szFolder), pszVolume); bFolderOnVolume = TRUE; } else { // A valid folder value was given, loop over each folder to check for "?" and ensure that
// we are on a drive that contains some of the specified folders
for (LPTSTR pszFolder = _szFolder; *pszFolder; pszFolder += lstrlen(pszFolder) + 1) { // Replace the first character of each folder (driver letter) if it is a '?'
// with the current volume.
if (*pszFolder == TEXT('?')) { *pszFolder = *pszVolume; bFolderOnVolume = TRUE; }
// If there is a valid "folder" value in the registry make sure that it is
// on the specified volume. If it is not then return S_FALSE so that we are
// not displayed on the list of items that can be freed.
if (!bFolderOnVolume) { StringCchCopy(szTempFolder, ARRAYSIZE(szTempFolder), pszFolder); szTempFolder[lstrlen(pszVolume)] = 0; if (lstrcmpi(pszVolume, szTempFolder) == 0) { bFolderOnVolume = TRUE; } } } }
if (bFolderOnVolume == FALSE) { return S_FALSE; //Don't display us in the list
}
//
// Determine the LastAccessedTime
//
if (DaysLastAccessed) { ULARGE_INTEGER ulTemp, ulLastAccessTime;
//Determine the number of days in 100ns units
ulTemp.LowPart = FILETIME_HOUR_LOW; ulTemp.HighPart = FILETIME_HOUR_HIGH;
ulTemp.QuadPart *= DaysLastAccessed;
//Get the current FILETIME
SYSTEMTIME st; GetSystemTime(&st); FILETIME ft; SystemTimeToFileTime(&st, &ft);
ulLastAccessTime.LowPart = ft.dwLowDateTime; ulLastAccessTime.HighPart = ft.dwHighDateTime;
//Subtract the Last Access number of days (in 100ns units) from
//the current system time.
ulLastAccessTime.QuadPart -= ulTemp.QuadPart;
//Save this minimal Last Access time in the FILETIME member variable
//ftMinLastAccessTime.
_ftMinLastAccessTime.dwLowDateTime = ulLastAccessTime.LowPart; _ftMinLastAccessTime.dwHighDateTime = ulLastAccessTime.HighPart;
_dwFlags |= DDEVCF_PRIVATE_LASTACCESS; }
*pdwFlags = 0; // disable this item by default
if (_dwFlags & DDEVCF_DONTSHOWIFZERO) *pdwFlags |= EVCF_DONTSHOWIFZERO; return S_OK; }
// Returns the total amount of space that the data driven cleaner can remove.
STDMETHODIMP CDataDrivenCleaner::GetSpaceUsed(DWORDLONG *pdwSpaceUsed, IEmptyVolumeCacheCallBack *picb) { _cbSpaceUsed.QuadPart = 0;
//
// Walk all of the folders in the folders list scanning for disk space.
//
for (LPTSTR pszFolder = _szFolder; *pszFolder; pszFolder += lstrlen(pszFolder) + 1) WalkForUsedSpace(pszFolder, picb);
picb->ScanProgress(_cbSpaceUsed.QuadPart, EVCCBF_LASTNOTIFICATION, NULL); *pdwSpaceUsed = _cbSpaceUsed.QuadPart;
return S_OK; }
// Purges (deletes) all of the files specified in the "filelist" portion of the registry.
STDMETHODIMP CDataDrivenCleaner::Purge(DWORDLONG dwSpaceToFree, IEmptyVolumeCacheCallBack *picb) { _bPurged = TRUE;
//
//Delete the files
//
PurgeFiles(picb, FALSE); PurgeFiles(picb, TRUE);
//
//Send the last notification to the cleanup manager
//
picb->PurgeProgress(_cbSpaceFreed.QuadPart, (_cbSpaceUsed.QuadPart - _cbSpaceFreed.QuadPart), EVCCBF_LASTNOTIFICATION, NULL);
//
//Free the list of files
//
FreeList(_head); _head = NULL;
//
//Run the "CleanupString" command line if one was provided
//
if (*_szCleanupCmdLine) { STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0};
si.cb = sizeof(si); if (CreateProcess(NULL, _szCleanupCmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { CloseHandle(pi.hThread); CloseHandle(pi.hProcess); } else { MiDebugMsg((0, TEXT("CreateProcess(%s) failed with error %d"), _szCleanupCmdLine, GetLastError())); } }
return S_OK; }
STDMETHODIMP CDataDrivenCleaner::ShowProperties(HWND hwnd) { return S_OK; }
// Deactivates the System Driven Data cleaner...this basically does nothing.
STDMETHODIMP CDataDrivenCleaner::Deactivate(DWORD *pdwFlags) { *pdwFlags = 0;
//
//See if this object should be removed.
//Note that we will only remove a cleaner if it's Purge() method was run.
//
if (_bPurged && (_dwFlags & DDEVCF_REMOVEAFTERCLEAN)) *pdwFlags |= EVCF_REMOVEFROMLIST; return S_OK; }
/*
** checks if the file is a specified number of days ** old (if the "lastaccess" DWORD is in the registry for this cleaner). ** If the file has not been accessed in the specified number of days ** then it can safely be deleted. If the file has been accessed in ** that number of days then the file will not be deleted. */ BOOL CDataDrivenCleaner::LastAccessisOK(FILETIME ftFileLastAccess) { if (_dwFlags & DDEVCF_PRIVATE_LASTACCESS) { //Is the last access FILETIME for this file less than the current
//FILETIME minus the number of specified days?
return (CompareFileTime(&ftFileLastAccess, &_ftMinLastAccessTime) == -1); } return TRUE; }
// checks if a file is open by doing a CreateFile
// with fdwShareMode of 0. If GetLastError() retuns
// ERROR_SHARING_VIOLATION then this function retuns TRUE because
// someone has the file open. Otherwise this function retuns false.
BOOL TestFileIsOpen(LPCTSTR lpFile, FILETIME *pftFileLastAccess) { #if 0
// too slow, disable this
HANDLE hFile = CreateFile(lpFile, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if ((hFile == INVALID_HANDLE_VALUE) && (GetLastError() == ERROR_SHARING_VIOLATION)) { return TRUE; //File is currently open by someone
}
//
// File is not currently open
//
SetFileTime(hFile, NULL, pftFileLastAccess, NULL); CloseHandle(hFile); #endif
return FALSE; }
// recursively walk the specified directory and
// add all the files under this directory to the delete list.
BOOL CDataDrivenCleaner::WalkAllFiles(LPCTSTR lpPath, IEmptyVolumeCacheCallBack *picb) { BOOL bRet = TRUE; BOOL bFind = TRUE; HANDLE hFind; WIN32_FIND_DATA wd; TCHAR szFindPath[MAX_PATH]; TCHAR szAddFile[MAX_PATH]; ULARGE_INTEGER dwFileSize; static DWORD dwCount = 0;
//
//If this is a directory then tack a *.* onto the end of the path
//and recurse through the rest of the directories
//
DWORD dwAttributes = GetFileAttributes(lpPath); if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (PathCombine(szFindPath, lpPath, TEXT("*.*"))) { bFind = TRUE; hFind = FindFirstFile(szFindPath, &wd); while (hFind != INVALID_HANDLE_VALUE && bFind) { //
//First check if the attributes of this file are OK for us to delete.
//
if (((!(wd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) || (_dwFlags & DDEVCF_REMOVEREADONLY)) && ((!(wd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) || (_dwFlags & DDEVCF_REMOVESYSTEM)) && ((!(wd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)) || (_dwFlags & DDEVCF_REMOVEHIDDEN))) { if (PathCombine(szAddFile, lpPath, wd.cFileName)) { //
//This is a file so check if it is open
//
if ((!(wd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) && (TestFileIsOpen(szAddFile, &wd.ftLastAccessTime) == FALSE) && (LastAccessisOK(wd.ftLastAccessTime))) { //
//File is not open so add it to the list
//
dwFileSize.HighPart = wd.nFileSizeHigh; dwFileSize.LowPart = wd.nFileSizeLow; AddFileToList(szAddFile, dwFileSize, FALSE); } }
//
//CallBack the cleanup Manager to update the UI
//
if ((dwCount++ % 10) == 0) { if (picb->ScanProgress(_cbSpaceUsed.QuadPart, 0, NULL) == E_ABORT) { //
//User aborted
//
FindClose(hFind); return FALSE; } } } bFind = FindNextFile(hFind, &wd); } FindClose(hFind); }
//
//Recurse through all of the directories
//
if (PathCombine(szFindPath, lpPath, TEXT("*.*"))) { bFind = TRUE; hFind = FindFirstFile(szFindPath, &wd); while (hFind != INVALID_HANDLE_VALUE && bFind) { //
//This is a directory
//
if ((wd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (lstrcmp(wd.cFileName, TEXT(".")) != 0) && (lstrcmp(wd.cFileName, TEXT("..")) != 0)) { if (PathCombine(szAddFile, lpPath, wd.cFileName)) { dwFileSize.QuadPart = 0; AddFileToList(szAddFile, dwFileSize, TRUE); if (WalkAllFiles(szAddFile, picb) == FALSE) { //
//User cancled
//
FindClose(hFind); return FALSE; } } } bFind = FindNextFile(hFind, &wd); } FindClose(hFind); } } return bRet; }
// walk the specified directory and create a
// linked list of files that can be deleted. It will also
// increment the member variable to indicate how much disk space
// these files are taking.
// It will look at the dwFlags member variable to determine if it
// needs to recursively walk the tree or not.
BOOL CDataDrivenCleaner::WalkForUsedSpace(LPCTSTR lpPath, IEmptyVolumeCacheCallBack *picb) { BOOL bRet = TRUE; BOOL bFind = TRUE; HANDLE hFind; WIN32_FIND_DATA wd; TCHAR szFindPath[MAX_PATH]; TCHAR szAddFile[MAX_PATH]; ULARGE_INTEGER dwFileSize; static DWORD dwCount = 0; LPTSTR lpSingleFile;
//
//If this is a directory then tack a *.* onto the end of the path
//and recurse through the rest of the directories
//
DWORD dwAttributes = GetFileAttributes(lpPath); if (dwAttributes & FILE_ATTRIBUTE_DIRECTORY) { //
//Enum through the MULTI_SZ filelist
//
for (lpSingleFile = _filelist; *lpSingleFile; lpSingleFile += lstrlen(lpSingleFile) + 1) { StringCchCopy(szFindPath, ARRAYSIZE(szFindPath), lpPath); PathAppend(szFindPath, lpSingleFile);
bFind = TRUE; hFind = FindFirstFile(szFindPath, &wd); while (hFind != INVALID_HANDLE_VALUE && bFind) { if (StrCmp(wd.cFileName, TEXT(".")) == 0 || StrCmp(wd.cFileName, TEXT("..")) == 0) { // ignore these two, otherwise we'll cover the whole disk..
bFind = FindNextFile(hFind, &wd); continue; } //
//First check if the attributes of this file are OK for us to delete.
//
if (((!(wd.dwFileAttributes & FILE_ATTRIBUTE_READONLY)) || (_dwFlags & DDEVCF_REMOVEREADONLY)) && ((!(wd.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) || (_dwFlags & DDEVCF_REMOVESYSTEM)) && ((!(wd.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN)) || (_dwFlags & DDEVCF_REMOVEHIDDEN))) { StringCchCopy(szAddFile, ARRAYSIZE(szAddFile), lpPath); PathAppend(szAddFile, wd.cFileName);
//
//Check if this is a subdirectory
//
if (wd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (_dwFlags & DDEVCF_REMOVEDIRS) { dwFileSize.QuadPart = 0; AddFileToList(szAddFile, dwFileSize, TRUE);
if (WalkAllFiles(szAddFile, picb) == FALSE) { //
//User cancled
//
FindClose(hFind); return FALSE; } } }
//
//This is a file so check if it is open
//
else if ((TestFileIsOpen(szAddFile, &wd.ftLastAccessTime) == FALSE) && (LastAccessisOK(wd.ftLastAccessTime))) { //
//File is not open so add it to the list
//
dwFileSize.HighPart = wd.nFileSizeHigh; dwFileSize.LowPart = wd.nFileSizeLow; AddFileToList(szAddFile, dwFileSize, FALSE); }
//
//CallBack the cleanup Manager to update the UI
//
if ((dwCount++ % 10) == 0) { if (picb->ScanProgress(_cbSpaceUsed.QuadPart, 0, NULL) == E_ABORT) { //
//User aborted
//
FindClose(hFind); return FALSE; } } } bFind = FindNextFile(hFind, &wd); } FindClose(hFind); }
if (_dwFlags & DDEVCF_DOSUBDIRS) { //
//Recurse through all of the directories
//
StringCchCopy(szFindPath, ARRAYSIZE(szFindPath), lpPath); PathAppend(szFindPath, TEXT("*.*"));
bFind = TRUE; hFind = FindFirstFile(szFindPath, &wd); while (hFind != INVALID_HANDLE_VALUE && bFind) { //
//This is a directory
//
if ((wd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && (lstrcmp(wd.cFileName, TEXT(".")) != 0) && (lstrcmp(wd.cFileName, TEXT("..")) != 0)) { StringCchCopy(szAddFile, ARRAYSIZE(szAddFile), lpPath); PathAppend(szAddFile, wd.cFileName);
if (WalkForUsedSpace(szAddFile, picb) == FALSE) { //
//User cancled
//
FindClose(hFind); return FALSE; } } bFind = FindNextFile(hFind, &wd); }
FindClose(hFind); }
if (_dwFlags & DDEVCF_REMOVEPARENTDIR) { // add the parent directory to the list if we are told to remove them....
dwFileSize.QuadPart = 0; AddFileToList(lpPath, dwFileSize, TRUE); } } else { MiDebugMsg((0, TEXT("CDataDrivenCleaner::WalkForUsedSpace -> %s is NOT a directory!"), lpPath)); }
return bRet; }
// Adds a file to the linked list of files.
BOOL CDataDrivenCleaner::AddFileToList(LPCTSTR lpFile, ULARGE_INTEGER filesize, BOOL bDirectory) { BOOL bRet = TRUE; CLEANFILESTRUCT *pNew = (CLEANFILESTRUCT *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pNew));
if (pNew == NULL) { MiDebugMsg((0, TEXT("CDataDrivenCleaner::AddFileToList -> ERROR HeapAlloc() failed with error %d"), GetLastError())); return FALSE; }
StringCchCopy(pNew->file, ARRAYSIZE(pNew->file), lpFile); pNew->ulFileSize.QuadPart = filesize.QuadPart; pNew->bSelected = TRUE; pNew->bDirectory = bDirectory;
if (_head) pNew->pNext = _head; else pNew->pNext = NULL;
_head = pNew;
_cbSpaceUsed.QuadPart += filesize.QuadPart;
return bRet; }
// Removes the files from the disk.
void CDataDrivenCleaner::PurgeFiles(IEmptyVolumeCacheCallBack *picb, BOOL bDoDirectories) { CLEANFILESTRUCT *pCleanFile = _head;
_cbSpaceFreed.QuadPart = 0;
while (pCleanFile) { //
//Remove a directory
//
if (bDoDirectories && pCleanFile->bDirectory) { SetFileAttributes(pCleanFile->file, FILE_ATTRIBUTE_NORMAL); if (!RemoveDirectory(pCleanFile->file)) { MiDebugMsg((0, TEXT("Error RemoveDirectory(%s) returned error %d"), pCleanFile->file, GetLastError())); } }
//
//Remove a file
//
else if (!bDoDirectories && !pCleanFile->bDirectory) { SetFileAttributes(pCleanFile->file, FILE_ATTRIBUTE_NORMAL); if (!DeleteFile(pCleanFile->file)) { MiDebugMsg((0, TEXT("Error DeleteFile(%s) returned error %d"), pCleanFile->file, GetLastError())); } } //
//Adjust the cbSpaceFreed
//
_cbSpaceFreed.QuadPart += pCleanFile->ulFileSize.QuadPart;
//
//Call back the cleanup manager to update the progress bar
//
if (picb->PurgeProgress(_cbSpaceFreed.QuadPart, (_cbSpaceUsed.QuadPart - _cbSpaceFreed.QuadPart), 0, NULL) == E_ABORT) { //
//User aborted so stop removing files
//
return; }
pCleanFile = pCleanFile->pNext; } }
// Frees the memory allocated by AddFileToList.
void CDataDrivenCleaner::FreeList(CLEANFILESTRUCT *pCleanFile) { if (pCleanFile == NULL) return;
if (pCleanFile->pNext) FreeList(pCleanFile->pNext);
HeapFree(GetProcessHeap(), 0, pCleanFile); }
CDataDrivenPropBag::CDataDrivenPropBag(DWORD dw) : _cRef(1), _dwFilter(dw) { incDllObjectCount(); }
CDataDrivenPropBag::~CDataDrivenPropBag() { decDllObjectCount(); }
STDMETHODIMP CDataDrivenPropBag::QueryInterface(REFIID riid, void **ppv) { *ppv = NULL;
if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IPropertyBag)) { *ppv = (IPropertyBag*) this; AddRef(); return S_OK; }
return E_NOINTERFACE; }
STDMETHODIMP_(ULONG) CDataDrivenPropBag::AddRef() { return ++_cRef; }
STDMETHODIMP_(ULONG) CDataDrivenPropBag::Release() { if (--_cRef) return _cRef;
delete this; return 0; }
STDMETHODIMP CDataDrivenPropBag::Read(LPCOLESTR pwszProp, VARIANT *pvar, IErrorLog *) { if (pvar->vt != VT_BSTR) // in/out
{ return E_FAIL; }
DWORD dwID = 0; DWORD dwDisplay; DWORD dwDesc; TCHAR szBuf[MAX_PATH];
switch (_dwFilter) { case ID_OLDFILESINROOTPROPBAG: dwDisplay = IDS_OLDFILESINROOT_DISP; dwDesc = IDS_OLDFILESINROOT_DESC; break; case ID_TEMPFILESPROPBAG: dwDisplay = IDS_TEMPFILES_DISP; dwDesc = IDS_TEMPFILES_DESC; break; case ID_SETUPFILESPROPBAG: dwDisplay = IDS_SETUPFILES_DISP; dwDesc = IDS_SETUPFILES_DESC; break; case ID_UNINSTALLEDFILESPROPBAG: dwDisplay = IDS_UNINSTALLFILES_DISP; dwDesc = IDS_UNINSTALLFILES_DESC; break; case ID_INDEXCLEANERPROPBAG: dwDisplay = IDS_INDEXERFILES_DISP; dwDesc = IDS_INDEXERFILES_DESC; break;
default: return E_UNEXPECTED; }
if (0 == lstrcmpiW(pwszProp, L"display")) { dwID = dwDisplay; } else if (0 == lstrcmpiW(pwszProp, L"description")) { dwID = dwDesc; } else { return E_INVALIDARG; }
if (LoadString(g_hDllModule, dwID, szBuf, ARRAYSIZE(szBuf))) { pvar->bstrVal = SysAllocString(szBuf); if (pvar->bstrVal) { return S_OK; } }
return E_OUTOFMEMORY; }
STDMETHODIMP CDataDrivenPropBag::Write(LPCOLESTR, VARIANT *) { return E_NOTIMPL; }
CContentIndexCleaner::CContentIndexCleaner(void) : _cRef(1) { _pDataDriven = NULL; incDllObjectCount(); }
CContentIndexCleaner::~CContentIndexCleaner(void) { if (_pDataDriven) { _pDataDriven->Release(); } decDllObjectCount(); }
STDMETHODIMP CContentIndexCleaner::QueryInterface(REFIID riid, void **ppv) { *ppv = NULL; if (riid == IID_IUnknown || riid == IID_IEmptyVolumeCache) { *ppv = (IEmptyVolumeCache *) this; AddRef(); return S_OK; } return E_NOINTERFACE; }
STDMETHODIMP_(ULONG) CContentIndexCleaner::AddRef(void) { return ++_cRef; }
STDMETHODIMP_(ULONG) CContentIndexCleaner::Release(void) { if (--_cRef) return _cRef;
delete this; return 0; }
STDMETHODIMP CContentIndexCleaner::Initialize(HKEY hRegKey, LPCWSTR pszVolume, LPWSTR *ppszDisplayName, LPWSTR *ppszDescription, DWORD *pdwFlags) { // check the volume first to see if it is in the list of cache's know about.
// If it isn't, then we can just go ahead. If the volume is a known cache, then
// we must check to see if the service is running...
HKEY hkeyCatalogs; BOOL fFound = FALSE;
LONG lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"System\\CurrentControlSet\\Control\\ContentIndex\\Catalogs", 0, KEY_READ, &hkeyCatalogs); if (lRes != ERROR_SUCCESS) { return S_FALSE; }
int iIndex = 0;
do { WCHAR szBuffer[MAX_PATH]; DWORD dwSize = ARRAYSIZE(szBuffer); lRes = RegEnumKeyExW(hkeyCatalogs, iIndex ++, szBuffer, &dwSize, NULL, NULL, NULL, NULL); if (lRes != ERROR_SUCCESS) { break; }
WCHAR szData[MAX_PATH]; dwSize = sizeof(szData); lRes = SHGetValueW(hkeyCatalogs, szBuffer, L"Location", NULL, szData, &dwSize); if (lRes == ERROR_SUCCESS) { // check to see if it is the same volume... (two characters letter and colon)
if (StrCmpNIW(pszVolume, szData , 2) == 0) { fFound = TRUE; } }
} while (TRUE);
RegCloseKey(hkeyCatalogs);
if (fFound) { // check to see if the index is on or off, if the indexer is on, then we should not allow the user to blow
// this off their hard drive...
SC_HANDLE hSCM = OpenSCManager(NULL, NULL, GENERIC_READ | SC_MANAGER_ENUMERATE_SERVICE); if (hSCM) { SC_HANDLE hCI; hCI = OpenService(hSCM, TEXT("cisvc"), SERVICE_QUERY_STATUS); if (hCI) { SERVICE_STATUS rgSs; if (QueryServiceStatus(hCI, &rgSs)) { if (rgSs.dwCurrentState != SERVICE_RUNNING) fFound = FALSE; } CloseServiceHandle(hCI); } CloseServiceHandle(hSCM); }
// if it wasn't inactive, then we can't delete it...
if (fFound) return S_FALSE; }
CDataDrivenCleaner *pDataDrivenCleaner = new CDataDrivenCleaner; if (pDataDrivenCleaner) { pDataDrivenCleaner->QueryInterface(IID_IEmptyVolumeCache, (void **)&_pDataDriven); pDataDrivenCleaner->Release(); }
return _pDataDriven ? _pDataDriven->Initialize(hRegKey, pszVolume, ppszDisplayName, ppszDescription, pdwFlags) : E_FAIL; } STDMETHODIMP CContentIndexCleaner::GetSpaceUsed(DWORDLONG *pdwSpaceUsed, IEmptyVolumeCacheCallBack *picb) { if (_pDataDriven) return _pDataDriven->GetSpaceUsed(pdwSpaceUsed, picb); return E_FAIL; } STDMETHODIMP CContentIndexCleaner::Purge(DWORDLONG dwSpaceToFree, IEmptyVolumeCacheCallBack *picb) { if (_pDataDriven) return _pDataDriven->Purge(dwSpaceToFree, picb); return E_FAIL; } STDMETHODIMP CContentIndexCleaner::ShowProperties(HWND hwnd) { if (_pDataDriven) return _pDataDriven->ShowProperties(hwnd); return E_FAIL; } STDMETHODIMP CContentIndexCleaner::Deactivate(DWORD *pdwFlags) { if (_pDataDriven) return _pDataDriven->Deactivate(pdwFlags); return E_FAIL; }
|