|
|
/*
**------------------------------------------------------------------------------ ** Module: Disk Cleanup Applet ** File: dmgrinfo.c ** ** Purpose: Defines the CleanupMgrInfo class for the property tab ** Notes: ** Mod Log: Created by Jason Cobb (2/97) ** ** Copyright (c)1997 Microsoft Corporation, All Rights Reserved **------------------------------------------------------------------------------ */
/*
**------------------------------------------------------------------------------ ** Project include files **------------------------------------------------------------------------------ */ #include "common.h"
#include <limits.h>
#include <emptyvc.h>
#include "dmgrinfo.h"
#include "dmgrdlg.h"
#include "diskutil.h"
#include "resource.h"
#include "msprintf.h"
/*
**------------------------------------------------------------------------------ ** Local variables **------------------------------------------------------------------------------ */ HINSTANCE CleanupMgrInfo::hInstance = NULL;
/*
**------------------------------------------------------------------------------ ** Function prototypes **------------------------------------------------------------------------------ */ INT_PTR CALLBACK ScanAbortDlgProc( HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam );
void ScanAbortThread( CleanupMgrInfo *pcmi );
INT_PTR CALLBACK PurgeAbortDlgProc( HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam );
void PurgeAbortThread( CleanupMgrInfo *pcmi );
/*
**------------------------------------------------------------------------------ ** Function definitions **------------------------------------------------------------------------------ */
void CleanupMgrInfo::Register( HINSTANCE hInstance ) { CleanupMgrInfo::hInstance = hInstance; }
void CleanupMgrInfo::Unregister( void ) { CleanupMgrInfo::hInstance= NULL; }
/*
**------------------------------------------------------------------------------ ** GetCleanupMgrInfoPointer ** ** Purpose: ** Mod Log: Created by Jason Cobb (2/97) **------------------------------------------------------------------------------ */ CleanupMgrInfo * GetCleanupMgrInfoPointer( HWND hDlg ) { //
//Get the DriveInfo
//
CleanupMgrInfo * pcmi = (CleanupMgrInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
return pcmi; }
/*
**------------------------------------------------------------------------------ ** CleanupMgrInfo method definitions **------------------------------------------------------------------------------ */
/*
**------------------------------------------------------------------------------ ** CleanupMgrInit::init ** ** Purpose: sets to default values ** Mod Log: Created by Jason Cobb (2/97) **------------------------------------------------------------------------------ */ void CleanupMgrInfo::init(void) { dre = Drive_INV; szVolName[0] = 0; vtVolume = vtINVALID; dwUIFlags = 0; bPurgeFiles = TRUE; }
/*
**------------------------------------------------------------------------------ ** CleanupMgrInfo::destroy ** ** Purpose: releases any dynamic memory ** Mod Log: Created by Jason Cobb (2/97) **------------------------------------------------------------------------------ */ void CleanupMgrInfo::destroy(void) { //
//Set values back to defaults
//
init(); }
/*
**------------------------------------------------------------------------------ ** CleanupMgrInfo::CleanupMgrInfo ** ** Purpose: Default constructor ** Mod Log: Created by Jason Cobb (2/97) **------------------------------------------------------------------------------ */ CleanupMgrInfo::CleanupMgrInfo (void) { init(); }
/*
**------------------------------------------------------------------------------ ** CleanupMgrInfo::CleanupMgrInfo ** ** Purpose: Constructor ** Mod Log: Created by Jason Cobb (2/97) **------------------------------------------------------------------------------ */ CleanupMgrInfo::CleanupMgrInfo( LPTSTR lpDrive, DWORD dwFlags, ULONG ulProfile ) { HRESULT hr;
init();
hr = CoInitialize(NULL);
if (SUCCEEDED(hr)) { if (create(lpDrive, dwFlags)) { dwReturnCode = RETURN_SUCCESS; dwUIFlags = dwFlags; ulSAGEProfile = ulProfile; bAbortScan = FALSE; bAbortPurge = FALSE; volumeCacheCallBack = NULL; pIEmptyVolumeCacheCallBack = NULL; volumeCacheCallBack = new CVolumeCacheCallBack();
if (volumeCacheCallBack) { hr = volumeCacheCallBack->QueryInterface(IID_IEmptyVolumeCacheCallBack, (LPVOID*)&pIEmptyVolumeCacheCallBack); } else { hr = E_OUTOFMEMORY; }
if (hr != NOERROR) { MiDebugMsg((hr, "CleanupMgrInfo::CleanupMgrInfo failed with error ")); }
//
//Initialize all of the cleanup clients
//
if (initializeClients() && !(dwUIFlags & FLAG_TUNEUP) && !(dwUIFlags & FLAG_SAGESET)) { //
//Have all of the cleanup clients calculate the ammount of disk
//space that they can free up.
//
getSpaceUsedByClients(); } } } }
/*
**------------------------------------------------------------------------------ ** CleanupMgrInfo::~CleanupMgrInfo ** ** Purpose: Destructor ** Mod Log: Created by Jason Cobb (2/97) **------------------------------------------------------------------------------ */ CleanupMgrInfo::~CleanupMgrInfo (void) { if (isValid()) { //
//Cleanup the Volume Cache Clients
//
deactivateClients();
if (volumeCacheCallBack != NULL) { volumeCacheCallBack->Release(); } CoUninitialize();
destroy(); } }
/*
**------------------------------------------------------------------------------ ** CleanupMgrInfo::create ** ** Purpose: Gets Drive info from drive letter ** Mod Log: Created by Jason Cobb (2/97) **------------------------------------------------------------------------------ */ BOOL CleanupMgrInfo::create( LPTSTR lpDrive, DWORD Flags ) { //
//Note: Make sure the assigns to zero stay current
// otherwise we might get garbage stats if
// we fail because of lack of free space
//
DWORD cSectorsPerCluster; DWORD cBytesPerSector; DWORD cBytesPerCluster; DWORD cFreeClusters; DWORD cUsedClusters; DWORD cTotalClusters; ULARGE_INTEGER cbFree; ULARGE_INTEGER cbUsed; ULARGE_INTEGER cbTotal; #ifdef NEC_98
drenum drive; hardware hw_type; #endif
cbFree.QuadPart = 0; cbUsed.QuadPart = 0; //
//Cleanup up any old stuff
//
destroy();
//
//Check parameters
//
if (lpDrive == NULL) return FALSE;
//
//Is it a valid drive path
//
if (!fIsValidDriveString(lpDrive)) return FALSE;
//
//Get drive from path
//
if (!GetDriveFromString(lpDrive, dre)) return FALSE;
lstrcpy(szRoot, lpDrive);
//
// Step 2. Get general info from drive
//
//
//Get volume name
//
if (!GetVolumeInformation (szRoot, // Root name
szVolName, sizeof(szVolName), // Volume Name
NULL, // Volume serial number
NULL, // Max path length
NULL, // flags
szFileSystem, sizeof(szFileSystem))) // file system name
{ //Error - failed to get volume name
goto lblERROR; }
//
//Get the Driver Icon
//
if (Flags & FLAG_SAGESET) hDriveIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(ICON_CLEANMGR)); else hDriveIcon = GetDriveIcon(dre, FALSE);
//
//Get Hardware type
//
if (!GetHardwareType(dre, hwHardware)) { //Error - failed to get hardware
goto lblERROR; }
#ifdef NEC_98
drive = Drive_A; GetHardwareType (Drive_A, hw_type);
if (hw_type != hwFixed) { drive = Drive_B; GetHardwareType (Drive_B, hw_type);
if (hw_type != hwFixed) drive = Drive_C; } #endif
//
//Get disk statistics
//
if (!GetDiskFreeSpace (szRoot, &cSectorsPerCluster, &cBytesPerSector, &cFreeClusters, &cTotalClusters)) { //Error - couldn't get drive stats
goto lblERROR; } //
//Calculate secondary statistics
//
cBytesPerCluster = cBytesPerSector * cSectorsPerCluster; if (cTotalClusters >= cFreeClusters) cUsedClusters = cTotalClusters - cFreeClusters; else cUsedClusters = 0L;
cbFree.QuadPart = UInt32x32To64(cFreeClusters, cBytesPerCluster); cbUsed.QuadPart = UInt32x32To64(cUsedClusters, cBytesPerCluster); cbTotal.QuadPart = cbFree.QuadPart + cbUsed.QuadPart;
//
//Get the current low disk space ratio
//
cbLowSpaceThreshold = GetFreeSpaceRatio(dre, cbTotal);
//
//Should we also load the agressive cleaners? We only do this if we
//are below are critical threshold of disk space left.
//
if (cbLowSpaceThreshold.QuadPart >= cbFree.QuadPart) { MiDebugMsg((0, "*****We are in aggressive mode*****")); bOutOfDiskSpace = TRUE; } else bOutOfDiskSpace = FALSE;
//
// Step 3. Save stats
//
cbDriveFree = cbFree; cbDriveUsed = cbUsed; cbEstCleanupSpace.QuadPart = 0;
//
//Success
//
return TRUE;
lblERROR: //
//Error
//
destroy(); return FALSE; }
/*
**------------------------------------------------------------------------------ ** CleanupMgrInfo::initializeClients ** ** Purpose: Initializes all of the Volume Cache Clients ** Mod Log: Created by Jason Cobb (2/97) **------------------------------------------------------------------------------ */ BOOL CleanupMgrInfo::initializeClients(void) { HKEY hKeyVolCache = NULL; DWORD iSubKey; DWORD dwClient; TCHAR szVolCacheClient[MAX_PATH]; TCHAR szGUID[MAX_PATH]; DWORD dwGUIDSize; DWORD dwType; DWORD dwState, cb, cw; TCHAR szProfile[64]; BOOL bRet = TRUE; BOOL bCleanup;
iNumVolumeCacheClients = 0; pClientInfo = NULL; MiDebugMsg((0, "CleanupMgrInfo::initializeClients entered"));
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_VOLUMECACHE, 0, KEY_READ, &hKeyVolCache) == ERROR_SUCCESS) { //
//Enumerate through all of the clients to see how large we need to make the pClientInfo array
//
iSubKey = 0; while(RegEnumKey(hKeyVolCache, iSubKey, szVolCacheClient, ARRAYSIZE(szVolCacheClient)) != ERROR_NO_MORE_ITEMS) { iSubKey++; } if ((pClientInfo = (PCLIENTINFO)LocalAlloc(LPTR, (iSubKey * sizeof(CLIENTINFO)))) == NULL) { #ifdef DEBUG
MessageBox(NULL, TEXT("FATAL ERROR LocalAlloc() failed!"), TEXT("CLEANMGR DEBUG"), MB_OK); #endif
RegCloseKey(hKeyVolCache); return FALSE; } //
//Fill in the pClientInfo data structure and initialize all of the volume cache clients
//
iSubKey = 0; dwClient = 0; while(RegEnumKey(hKeyVolCache, iSubKey, szVolCacheClient, ARRAYSIZE(szVolCacheClient)) != ERROR_NO_MORE_ITEMS) { // default is we failed, so cleanup the current item....
bCleanup = TRUE; if (RegOpenKeyEx(hKeyVolCache, szVolCacheClient, 0, MAXIMUM_ALLOWED, &(pClientInfo[dwClient].hClientKey)) == ERROR_SUCCESS) { lstrcpy(pClientInfo[dwClient].szRegKeyName, szVolCacheClient); dwGUIDSize = sizeof(szGUID); dwType = REG_SZ; if (RegQueryValueEx(pClientInfo[dwClient].hClientKey, NULL, NULL, &dwType, (LPBYTE)szGUID, &dwGUIDSize) == ERROR_SUCCESS) { HRESULT hr; WCHAR wcsFmtID[39];
#ifdef UNICODE
StrCpyN( wcsFmtID, szGUID, ARRAYSIZE( wcsFmtID )); #else
//Convert to Unicode.
MultiByteToWideChar(CP_ACP, 0, szGUID, -1, wcsFmtID, ARRAYSIZE( wcsFmtID )) ; #endif
//Convert to GUID.
hr = CLSIDFromString((LPOLESTR)wcsFmtID, &(pClientInfo[dwClient].clsid));
if (FAILED(hr)) { MiDebugMsg((hr, "CLSIDFromString(%s,) returned error ", szGUID)); }
//
//Create an instance of the COM object for this cleanup client
//
pClientInfo[dwClient].pVolumeCache = NULL; hr = CoCreateInstance(pClientInfo[dwClient].clsid, NULL, CLSCTX_INPROC_SERVER, IID_IEmptyVolumeCache, (void **) &(pClientInfo[dwClient].pVolumeCache));
if (SUCCEEDED(hr)) { WCHAR wcsRoot[MAX_PATH];
MiDebugMsg((hr, "CleanupMgrInfo::initializeClients Created IID_IEmptyVolumeCache")); //
//Set the flags to pass to the cleanup client
//
pClientInfo[dwClient].dwInitializeFlags = 0; if (dwUIFlags & FLAG_SAGESET) pClientInfo[dwClient].dwInitializeFlags |= EVCF_SETTINGSMODE; if (bOutOfDiskSpace) pClientInfo[dwClient].dwInitializeFlags |= EVCF_OUTOFDISKSPACE;
#ifdef UNICODE
StrCpyN( wcsRoot, szRoot, ARRAYSIZE( wcsRoot )); #else
//
//Convert szRoot to UNICODE
//
MultiByteToWideChar(CP_ACP, 0, szRoot, -1, wcsRoot, ARRAYSIZE( wcsRoot )); #endif
// Try to use version two of the interface if it is supported
IEmptyVolumeCache2 * pEVC2; hr = pClientInfo[dwClient].pVolumeCache->QueryInterface( IID_IEmptyVolumeCache2, (void**)&pEVC2 ); if (SUCCEEDED(hr)) { // version 2 exists so that we can have a mutli-local enabled data driven cleaner. It
// allows the added Advanced Button to be set to a localized value. It tells the
// object being called which key it is being called for so that one object can support
// multiple filters.
WCHAR wcsFilterName[MAX_PATH]; MiDebugMsg((hr, "CleanupMgrInfo::initializeClients found V2 interface")); #ifdef UNICODE
StrCpyN( wcsFilterName, szVolCacheClient, ARRAYSIZE( wcsFilterName )); #else
MultiByteToWideChar(CP_ACP, 0, szVolCacheClient, -1, wcsFilterName, ARRAYSIZE( wcsFilterName )) ; #endif
hr = pEVC2->InitializeEx(pClientInfo[dwClient].hClientKey, (LPCWSTR)wcsRoot, (LPCWSTR)wcsFilterName, &((LPWSTR)pClientInfo[dwClient].wcsDisplayName), &((LPWSTR)pClientInfo[dwClient].wcsDescription), &((LPWSTR)pClientInfo[dwClient].wcsAdvancedButtonText), &(pClientInfo[dwClient].dwInitializeFlags)); pEVC2->Release(); } else { MiDebugMsg((hr, "CleanupMgrInfo::initializeClients using V1 interface")); //
//Initialize the cleanup client
//
if ((pClientInfo[dwClient].wcsDescription = (LPWSTR)CoTaskMemAlloc(DESCRIPTION_LENGTH*sizeof(WCHAR))) == NULL) return FALSE;
// We seem to have shipped this thing with a giant leak. The object is supposted to set
// pClientInfo[dwClient].wcsDescription to NULL if the registry value should be used instead
// of the buffer. However we just allocated a buffer for pClientInfo[dwClient].wcsDescription
// in the code above (this is the dumbass part). All the filters then set this pointer to
// NULL and it's bye-bye buffer. I can't simply not allocate this memory because some cleaners
// might rely on being able to use this memory and we shipped it that way.
LPWSTR wszDumbassLeakProtection = pClientInfo[dwClient].wcsDescription; hr = pClientInfo[dwClient].pVolumeCache->Initialize(pClientInfo[dwClient].hClientKey, (LPCWSTR)wcsRoot, &((LPWSTR)pClientInfo[dwClient].wcsDisplayName), &((LPWSTR)pClientInfo[dwClient].wcsDescription), &(pClientInfo[dwClient].dwInitializeFlags)); if ( wszDumbassLeakProtection != pClientInfo[dwClient].wcsDescription ) { // REVIEW: Use try...except around CoTaskMemFree in case some smart cleaner
// realized our mistake and deleted the memory for us?
MiDebugMsg((hr, "CleanupMgrInfo::initializeClients prevent mem leak hack")); CoTaskMemFree( wszDumbassLeakProtection ); }
if ( S_OK == hr ) { // To make it easier to make a cleaner we have a default implementation of IEmptyVolumeCache
// that works entirerly using registry data. The problem is that display strings are strored
// in the registry. This is invalid for NT because NT must be multi-local localizable and
// the only way to do that is to load all display strings from a resource. As a hack, you
// can now implement IPropertyBag using an object with it's guid stored under the propertybag
// value in the registry. We will cocreate this object and query for IPropertyBag. If this
// works then we will attempt to read the localized strings from the property bag before we
// fall back on checking the registry.
TCHAR szPropBagGUID[MAX_PATH]; HRESULT hrFoo; IPropertyBag * ppb = NULL; VARIANT var;
VariantInit( &var ); dwGUIDSize = sizeof(szPropBagGUID); dwType = REG_SZ; if (RegQueryValueEx(pClientInfo[dwClient].hClientKey, TEXT("PropertyBag"), NULL, &dwType, (LPBYTE)szPropBagGUID, &dwGUIDSize) == ERROR_SUCCESS) { WCHAR wcsFmtID[39]; CLSID clsid;
MiDebugMsg((hr, "CleanupMgrInfo::initializeClients found PropBag key"));
#ifdef UNICODE
StrCpyN( wcsFmtID, szPropBagGUID, ARRAYSIZE( wcsFmtID )); #else
MultiByteToWideChar(CP_ACP, 0, szPropBagGUID, -1, wcsFmtID, ARRAYSIZE( wcsFmtID )) ; #endif
//Convert to GUID.
CLSIDFromString((LPOLESTR)wcsFmtID, &clsid);
//
//Create an instance of the COM object for this cleanup client
//
hrFoo = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IPropertyBag, (void **) &ppb);
if ( FAILED(hrFoo) ) { MiDebugMsg((hrFoo, "CleanupMgrInfo::initializeClients failed to create PropBag")); } }
//
//If the client did not return the DisplayName via the Initialize
//Interface then we need to get it from the registry.
//
if ((pClientInfo[dwClient].wcsDisplayName) == NULL) { LPTSTR lpszDisplayName;
if ( ppb ) { WCHAR wszSrc[MAX_PATH]; MiDebugMsg((hr, "CleanupMgrInfo::initializeClients checking PropBag for display"));
SHTCharToUnicode(REGSTR_VAL_DISPLAY, wszSrc, MAX_PATH);
// do propertybag stuff
var.vt = VT_BSTR; var.bstrVal = NULL; hrFoo = ppb->Read( wszSrc, &var, NULL ); if (SUCCEEDED(hrFoo)) { if ( var.vt == VT_BSTR ) { DWORD dwSize = (lstrlenW(var.bstrVal)+1)*sizeof(WCHAR); pClientInfo[dwClient].wcsDisplayName = (LPWSTR)CoTaskMemAlloc(dwSize); StrCpyW( pClientInfo[dwClient].wcsDisplayName, var.bstrVal ); } VariantClear( &var ); } }
if ((pClientInfo[dwClient].wcsDisplayName) == NULL) { //
//First check if their is a "display" value for the client's
//name that is displayed in the list box. If not then use
//the key name itself.
//
cb = 0; dwType = REG_SZ; RegQueryValueEx(pClientInfo[dwClient].hClientKey, REGSTR_VAL_DISPLAY, NULL, &dwType, (LPBYTE)NULL, &cb); if ((lpszDisplayName = (LPTSTR)LocalAlloc(LPTR, max(cb, (ULONG)(lstrlen(szVolCacheClient) + 1))* sizeof (TCHAR ))) != NULL) { if (RegQueryValueEx(pClientInfo[dwClient].hClientKey, REGSTR_VAL_DISPLAY, NULL, &dwType, (LPBYTE)lpszDisplayName, &cb) != ERROR_SUCCESS) { //
//Count not find "display" value so use the key name instead
//
StrCpy(lpszDisplayName, szVolCacheClient); }
#ifdef UNICODE
cw = (lstrlen( lpszDisplayName ) + 1) * sizeof( WCHAR); #else
//
//Convert this value to UNICODE
//
cw = (MultiByteToWideChar(CP_ACP, 0, lpszDisplayName, -1, NULL, 0) * sizeof(WCHAR)); #endif
if ((pClientInfo[dwClient].wcsDisplayName = (LPWSTR)CoTaskMemAlloc(cw)) != NULL) { #ifdef UNICODE
StrCpy( pClientInfo[dwClient].wcsDisplayName, lpszDisplayName ); #else
MultiByteToWideChar(CP_ACP, 0, lpszDisplayName, -1, (pClientInfo[dwClient].wcsDisplayName), cw); #endif
} LocalFree(lpszDisplayName); } } }
//
//If the client did not return the Description via the Initialize
//Interface then we need to get it from the registry.
//
if ((pClientInfo[dwClient].wcsDescription) == NULL) { LPTSTR lpszDescription;
if ( ppb ) { WCHAR wszSrc[MAX_PATH]; MiDebugMsg((hr, "CleanupMgrInfo::initializeClients checking PropBag for description"));
SHTCharToUnicode(REGSTR_VAL_DESCRIPTION, wszSrc, MAX_PATH);
// do propertybag stuff
var.vt = VT_BSTR; var.bstrVal = NULL; hrFoo = ppb->Read( wszSrc, &var, NULL ); if (SUCCEEDED(hrFoo)) { if ( var.vt == VT_BSTR ) { DWORD dwSize = (lstrlenW(var.bstrVal)+1)*sizeof(WCHAR); pClientInfo[dwClient].wcsDescription = (LPWSTR)CoTaskMemAlloc(dwSize); StrCpyW( pClientInfo[dwClient].wcsDescription, var.bstrVal ); } VariantClear( &var ); } }
if ((pClientInfo[dwClient].wcsDescription) == NULL) { //
//Check if their is a "description" value for the client
//
cb = 0; dwType = REG_SZ; RegQueryValueEx(pClientInfo[dwClient].hClientKey, REGSTR_VAL_DESCRIPTION, NULL, &dwType, (LPBYTE)NULL, &cb); if ((lpszDescription = (LPTSTR)LocalAlloc(LPTR, (cb + 1 ) * sizeof( TCHAR ))) != NULL) { if (RegQueryValueEx(pClientInfo[dwClient].hClientKey, REGSTR_VAL_DESCRIPTION, NULL, &dwType, (LPBYTE)lpszDescription, &cb) == ERROR_SUCCESS) { #ifdef UNICODE
cw = ( lstrlen( lpszDescription ) + 1 ) * sizeof( WCHAR ); #else
//
//Convert this value to UNICODE
//
cw = (MultiByteToWideChar(CP_ACP, 0, lpszDescription, -1, NULL, 0) * sizeof(WCHAR)); #endif
if ((pClientInfo[dwClient].wcsDescription = (LPWSTR)CoTaskMemAlloc(cw)) != NULL) { #ifdef UNICODE
StrCpy( pClientInfo[dwClient].wcsDescription, lpszDescription ); #else
MultiByteToWideChar(CP_ACP, 0, lpszDescription, -1, (pClientInfo[dwClient].wcsDescription), cw); #endif
} }
LocalFree(lpszDescription); } } }
//
//Set the Advanced Button text
//
pClientInfo[dwClient].wcsAdvancedButtonText = NULL;
if (pClientInfo[dwClient].dwInitializeFlags & EVCF_HASSETTINGS) { if ( ppb ) { WCHAR wszSrc[MAX_PATH]; MiDebugMsg((hr, "CleanupMgrInfo::initializeClients checking PropBag for button text"));
SHTCharToUnicode(REGSTR_VAL_ADVANCEDBUTTONTEXT, wszSrc, MAX_PATH);
// do propertybag stuff
var.vt = VT_BSTR; var.bstrVal = NULL; hrFoo = ppb->Read( wszSrc, &var, NULL ); if (SUCCEEDED(hrFoo)) { if ( var.vt == VT_BSTR ) { DWORD dwSize = (lstrlenW(var.bstrVal)+1)*sizeof(WCHAR); pClientInfo[dwClient].wcsAdvancedButtonText = (LPWSTR)CoTaskMemAlloc(dwSize); StrCpyW( pClientInfo[dwClient].wcsAdvancedButtonText, var.bstrVal ); } VariantClear( &var ); } } if ( pClientInfo[dwClient].wcsAdvancedButtonText == NULL ) { LPTSTR lpszAdvancedButtonText; TCHAR szDetails[BUTTONTEXT_LENGTH];
LoadString(g_hInstance, IDS_DETAILS, szDetails, ARRAYSIZE(szDetails));
cb = 0; dwType = REG_SZ; RegQueryValueEx(pClientInfo[dwClient].hClientKey, REGSTR_VAL_ADVANCEDBUTTONTEXT, NULL, &dwType, (LPBYTE)NULL, &cb); if ((lpszAdvancedButtonText = (LPTSTR)LocalAlloc(LPTR, max(cb, (UINT) (lstrlen(szDetails) + 1)*sizeof(TCHAR)))) != NULL) { if (RegQueryValueEx(pClientInfo[dwClient].hClientKey, REGSTR_VAL_ADVANCEDBUTTONTEXT, NULL, &dwType, (LPBYTE)lpszAdvancedButtonText, &cb) != ERROR_SUCCESS) StrCpy(lpszAdvancedButtonText, szDetails);
#ifdef UNICODE
cw = (lstrlen( lpszAdvancedButtonText ) + 1) * sizeof( WCHAR ); #else
//
//Convert this value to UNICODE
//
cw = (MultiByteToWideChar(CP_ACP, 0, lpszAdvancedButtonText, -1, NULL, 0) * sizeof(WCHAR)); #endif
if ((pClientInfo[dwClient].wcsAdvancedButtonText = (LPWSTR)CoTaskMemAlloc(cw)) != NULL) { #ifdef UNICODE
StrCpy( pClientInfo[dwClient].wcsAdvancedButtonText, lpszAdvancedButtonText ); #else
MultiByteToWideChar(CP_ACP, 0, lpszAdvancedButtonText, -1, (pClientInfo[dwClient].wcsAdvancedButtonText), cw); #endif
}
LocalFree(lpszAdvancedButtonText); } } }
if (ppb) { ppb->Release(); } } }
// Now we're back to stuff that both version 1 and version 2 require
if (SUCCEEDED(hr)) { if (S_OK == hr) { //
//Default to showing this client in the UI
//
pClientInfo[dwClient].bShow = TRUE; //
//Get the "priority" from the registry
//
cb = sizeof(pClientInfo[dwClient].dwPriority); dwType = REG_DWORD; if (RegQueryValueEx(pClientInfo[dwClient].hClientKey, REGSTR_VAL_PRIORITY, NULL, &dwType, (LPBYTE)&(pClientInfo[dwClient].dwPriority), &cb) != ERROR_SUCCESS) pClientInfo[dwClient].dwPriority = DEFAULT_PRIORITY; //
//Flags
//
if (dwUIFlags & FLAG_SAGERUN || dwUIFlags & FLAG_SAGESET) wsprintf(szProfile, TEXT("%s%04d"), SZ_STATE, ulSAGEProfile); else lstrcpy(szProfile, SZ_STATE); dwState = 0; cb = sizeof(dwState); dwType = REG_DWORD; // If we were called with the low disk flag, select every cleaner by default
if (dwUIFlags & FLAG_LOWDISK) { pClientInfo[iSubKey].bSelected = TRUE; }
// Otherwise, check the registry
else if (RegQueryValueEx(pClientInfo[dwClient].hClientKey, szProfile, NULL, &dwType, (LPBYTE)&dwState, &cb) == ERROR_SUCCESS) { if (dwUIFlags & FLAG_SAGERUN || dwUIFlags & FLAG_SAGESET) { pClientInfo[dwClient].bSelected = (dwState & STATE_SAGE_SELECTED); } else { pClientInfo[dwClient].bSelected = (dwState & STATE_SELECTED); } } else { //
//No registry settings for this profile so use the cleanup clients
//default settings.
//
if (dwUIFlags & FLAG_SAGERUN || dwUIFlags & FLAG_SAGESET) { pClientInfo[dwClient].bSelected = (pClientInfo[dwClient].dwInitializeFlags & EVCF_ENABLEBYDEFAULT_AUTO) ? TRUE : FALSE; } else { pClientInfo[dwClient].bSelected = (pClientInfo[dwClient].dwInitializeFlags & EVCF_ENABLEBYDEFAULT) ? TRUE : FALSE; } } //
//Get the icon of the cleanup client
//
// first test to see if it is overridden...
TCHAR szIconPath[MAX_PATH]; cb = sizeof( szIconPath ); BOOL fOverridden = FALSE; if ( RegQueryValueEx(pClientInfo[dwClient].hClientKey, TEXT("IconPath"), NULL, &dwType, (LPBYTE)szIconPath, &cb) == ERROR_SUCCESS ) { fOverridden = TRUE; } else { lstrcpy( szIconPath, szGUID ); } pClientInfo[dwClient].hIcon = GetClientIcon(szIconPath, fOverridden);
bCleanup = FALSE; } else { //
//This should be S_FALSE. This means that the client has nothing to
//cleanup now so we don't even need to show it in the list.
//Therefor we will just call its Release() function and close it's
//registry key.
//
// drop through and let it cleanup below...
} } else { MiDebugMsg((hr, "Client %d Initialize() retuned error ", dwClient)); } } else { MiDebugMsg((hr, "Client %d %s returned error ", dwClient, szGUID)); } } #ifdef DEBUG
else { MessageBox(NULL, szVolCacheClient, TEXT("ERROR Opening GUID key"), MB_OK); } #endif
} #ifdef DEBUG
else { MessageBox(NULL, szVolCacheClient, TEXT("ERROR Opening the client key"), MB_OK); } #endif
if ( bCleanup ) { deactivateSingleClient(&(pClientInfo[dwClient])); ZeroMemory( &(pClientInfo[dwClient]), sizeof( CLIENTINFO )); } else { dwClient ++; } iSubKey++; } iNumVolumeCacheClients = dwClient; } #ifdef DEBUG
else { MessageBox(NULL, TEXT("ERROR Opening up Volume Cache key"), TEXT("CLEANMGR DEBUG"), MB_OK); } #endif
if( hKeyVolCache ) { RegCloseKey(hKeyVolCache); } return bRet; }
/*
**------------------------------------------------------------------------------ ** CleanupMgrInfo::deactivateClients ** ** Purpose: Initializes all of the Volume Cache Clients ** Mod Log: Created by Jason Cobb (2/97) **------------------------------------------------------------------------------ */ void CleanupMgrInfo::deactivateClients(void) { int i; for (i=0; i<iNumVolumeCacheClients; i++) { deactivateSingleClient(&(pClientInfo[i])); }
//
//Free the pClientInfo array
//
if (pClientInfo) { MiDebugMsg((0, "LocalFree() on ClientInfo structure")); LocalFree( pClientInfo); } }
/*
**------------------------------------------------------------------------------ ** CleanupMgrInfo::deactivateSingleClient ** ** Purpose: Deactivate's the given client and closes its registry key ** Mod Log: Created by Jason Cobb (2/97) **------------------------------------------------------------------------------ */ void CleanupMgrInfo::deactivateSingleClient(PCLIENTINFO pSingleClientInfo) { DWORD dwDeactivateFlags = 0; TCHAR szProfile[64]; if (pSingleClientInfo->pVolumeCache != NULL) { //
//Call the clients Deactivate function
//
pSingleClientInfo->pVolumeCache->Deactivate(&dwDeactivateFlags);
//
//Release the client
//
pSingleClientInfo->pVolumeCache->Release(); pSingleClientInfo->pVolumeCache = NULL; } if (pSingleClientInfo->hClientKey != 0) { DWORD dwState, cb, dwType, dwSelectedFlag;
if (dwUIFlags & FLAG_SAVE_STATE) { //
//Save the state flags
//
if (dwUIFlags & FLAG_SAGESET) { dwSelectedFlag = STATE_SAGE_SELECTED; wsprintf(szProfile, TEXT("%s%04d"), SZ_STATE, ulSAGEProfile); } else { dwSelectedFlag = STATE_SELECTED; lstrcpy(szProfile, SZ_STATE); }
dwState = 0; cb = sizeof(dwState); dwType = REG_DWORD; RegQueryValueEx(pSingleClientInfo->hClientKey, szProfile, NULL, &dwType, (LPBYTE)&dwState, &cb);
if (pSingleClientInfo->bSelected) dwState |= dwSelectedFlag; else dwState &= ~dwSelectedFlag;
RegSetValueEx(pSingleClientInfo->hClientKey, szProfile, 0, REG_DWORD, (LPBYTE)&dwState, sizeof(dwState)); } //
//Close all of the registry keys
//
RegCloseKey(pSingleClientInfo->hClientKey);
//
//Should we remove this entry from the registry?
//
if (dwDeactivateFlags & EVCF_REMOVEFROMLIST && pSingleClientInfo->bSelected) { HKEY hKeyVolCache; if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_VOLUMECACHE, 0, KEY_ALL_ACCESS, &hKeyVolCache) == ERROR_SUCCESS) { SHDeleteKey(hKeyVolCache, pSingleClientInfo->szRegKeyName); RegCloseKey(hKeyVolCache); } } }
//
//Free the DisplayName and Description memory
//
if (pSingleClientInfo->wcsDisplayName) CoTaskMemFree(pSingleClientInfo->wcsDisplayName); if (pSingleClientInfo->wcsDescription) CoTaskMemFree(pSingleClientInfo->wcsDescription); }
/*
**------------------------------------------------------------------------------ ** CleanupMgrInfo::getSpaceUsedByClients ** ** Purpose: Calls the IEmptyVolumeCache->GetSpaceUsed interface for each client ** to determine the total amount of cache space. This function is ** called on a secondary thread because it can take quite a long time. ** Mod Log: Created by Jason Cobb (2/97) **------------------------------------------------------------------------------ */ BOOL CleanupMgrInfo::getSpaceUsedByClients(void) { int i; HRESULT hr; BOOL bRet = TRUE; TCHAR szDisplayName[256]; cbEstCleanupSpace.QuadPart = 0; bAbortScan = FALSE;
hAbortScanEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
// Someone should make sure the window created in the ScanAbortThread thread is visible before
// the hAbortScanEvent event is signaled
hAbortScanThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ScanAbortThread, (LPVOID)this, 0, &dwAbortScanThreadID);
//
//Wait until the Abort Scan window is created
//
WaitForSingleObject(hAbortScanEvent, INFINITE);
CloseHandle(hAbortScanEvent);
if (volumeCacheCallBack != NULL) { volumeCacheCallBack->SetCleanupMgrInfo((PVOID)this); }
for (i=0; i<iNumVolumeCacheClients; i++) { //
//Update the progress UI
//
szDisplayName[0] = '\0'; #ifdef UNICODE
StrCpyN( szDisplayName, pClientInfo[i].wcsDisplayName, ARRAYSIZE( szDisplayName )); #else
WideCharToMultiByte(CP_ACP, 0, pClientInfo[i].wcsDisplayName, -1, szDisplayName, ARRAYSIZE(szDisplayName), NULL, NULL); #endif
PostMessage(hAbortScanWnd, WMAPP_UPDATEPROGRESS, (WPARAM)i, (LPARAM)szDisplayName);
//
//Query the client for the ammount of cache disk space that it could
//possible free.
//
if (pClientInfo[i].pVolumeCache != NULL && volumeCacheCallBack != NULL) { volumeCacheCallBack->SetCurrentClient((PVOID)&(pClientInfo[i])); hr = pClientInfo[i].pVolumeCache->GetSpaceUsed(&(pClientInfo[i].dwUsedSpace.QuadPart), pIEmptyVolumeCacheCallBack); if (FAILED(hr)) { dwReturnCode = RETURN_CLEANER_FAILED; MiDebugMsg((hr, "Client %d GetSpaceUsed failed with error ", i)); } MiDebugMsg((0, "Client %d has %d disk space it can free", i, pClientInfo[i].dwUsedSpace.QuadPart)); }
//
//See if this cleaner wants to be hidden if it has no space to free
//
if ((pClientInfo[i].dwUsedSpace.QuadPart == 0) && (pClientInfo[i].dwInitializeFlags & EVCF_DONTSHOWIFZERO)) { MiDebugMsg((0, "Not showing client %d because it has no space to free", i)); pClientInfo[i].bShow = FALSE; }
cbEstCleanupSpace.QuadPart += pClientInfo[i].dwUsedSpace.QuadPart;
//
//Did the user abort?
//
if (bAbortScan == TRUE) { dwReturnCode = RETURN_USER_CANCELED_SCAN; bRet = FALSE; break; } }
// the dismissal of the progress dialog is now delayed until the propsheet comes up..
return bRet; }
/*
**------------------------------------------------------------------------------ ** CleanupMgrInfo::calculateSpaceToPurge ** ** Purpose: Calculates the amount of space that is going to be purged ** by adding up all of the selected clients. It also calculates ** the progress bar divisor number. This is needed because a ** progress bar has a MAX of 0xFFFF. ** ** Mod Log: Created by Jason Cobb (6/97) **------------------------------------------------------------------------------ */ void CleanupMgrInfo::calculateSpaceToPurge(void) { int i; cbSpaceToPurge.QuadPart = 0;
for (i=0; i<iNumVolumeCacheClients; i++) { //
//If this client is not selected or we are not showing it then don't purge it
//
if (pClientInfo[i].bShow == FALSE || pClientInfo[i].bSelected == FALSE) continue; cbSpaceToPurge.QuadPart += pClientInfo[i].dwUsedSpace.QuadPart; }
cbProgressDivider.QuadPart = (cbSpaceToPurge.QuadPart / PROGRESS_DIVISOR) + 1; }
/*
**------------------------------------------------------------------------------ ** CleanupMgrInfo::purgeClients ** ** Purpose: Calls the IEmptyVolumeCache->Purge interface for each client ** to have the client cleaner object start removeing their files ** Mod Log: Created by Jason Cobb (2/97) **------------------------------------------------------------------------------ */ BOOL CleanupMgrInfo::purgeClients(void) { int i; HRESULT hr; BOOL bRet = TRUE; TCHAR szDisplayName[256]; cbTotalPurgedSoFar.QuadPart = 0; bAbortPurge = FALSE;
//
//Calculate the amount of space that will be purged.
//
calculateSpaceToPurge(); MiDebugMsg((0, "Total number of bytes to delete is %d", cbSpaceToPurge.LowPart));
hAbortPurgeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
// Someone should (but it hasn't broken in 3 years), make sure the window created in PurgeAbortThread is visible before
// the hAbortPurgeEvent is signaled
hAbortPurgeThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PurgeAbortThread, (LPVOID)this, 0, &dwAbortPurgeThreadID);
//
//Wait until the Abort Purge window is created
//
WaitForSingleObject(hAbortPurgeEvent, INFINITE);
CloseHandle(hAbortPurgeEvent);
if (volumeCacheCallBack != NULL) { volumeCacheCallBack->SetCleanupMgrInfo((PVOID)this); }
for (i=0; i<iNumVolumeCacheClients; i++) { //
//If this client is not selected or we are not showing it then don't purge it
//
if (pClientInfo[i].bShow == FALSE || pClientInfo[i].bSelected == FALSE) continue; #ifdef UNICODE
StrCpyN( szDisplayName, pClientInfo[i].wcsDisplayName, ARRAYSIZE( szDisplayName )); #else
//
//Convert UNICODE display name to ANSI and then add it to the list
//
WideCharToMultiByte(CP_ACP, 0, pClientInfo[i].wcsDisplayName, -1, szDisplayName, sizeof(szDisplayName), NULL, NULL); #endif
PostMessage(hAbortPurgeWnd, WMAPP_UPDATESTATUS, 0, (LPARAM)szDisplayName);
cbCurrentClientPurgedSoFar.QuadPart = 0;
//
//Query the client for the ammount of cache disk space that it could
//possible free.
//
if (pClientInfo[i].pVolumeCache != NULL && volumeCacheCallBack != NULL) { volumeCacheCallBack->SetCurrentClient((PVOID)&(pClientInfo[i]));
hr = pClientInfo[i].pVolumeCache->Purge(pClientInfo[i].dwUsedSpace.QuadPart, pIEmptyVolumeCacheCallBack); if (FAILED(hr)) { dwReturnCode = RETURN_CLEANER_FAILED; MiDebugMsg((hr, "Client %d Purge failed with error ", i)); } }
cbTotalPurgedSoFar.QuadPart += pClientInfo[i].dwUsedSpace.QuadPart; cbCurrentClientPurgedSoFar.QuadPart = 0;
//
//Update the progress bar
//
PostMessage(hAbortPurgeWnd, WMAPP_UPDATEPROGRESS, 0, 0);
//
//Did the user abort?
//
if (bAbortPurge == TRUE) { dwReturnCode = RETURN_USER_CANCELED_PURGE; bRet = FALSE; break; }
Sleep(1000); }
if (!bAbortPurge) { bAbortPurge = TRUE;
//
//Wait for Purge thread to finish
//
WaitForSingleObject(hAbortPurgeThread, INFINITE);
bAbortPurge = FALSE; }
return bRet; }
/*
**------------------------------------------------------------------------------ ** GetClientIcon ** ** Purpose: Gets the Icon for this client. ** The icon will be inferred using the standard OLE mechanism ** under HKCR\CLSID\{clsid}\DefaultIcon (with the default value ** for this being the <Module Path>, <icon index>). ** If no icon is specified the standard windows icon will be used. ** Mod Log: Created by Jason Cobb (2/97) **------------------------------------------------------------------------------ */ HICON CleanupMgrInfo::GetClientIcon( LPTSTR lpGUID, BOOL fIconPath ) { HKEY hk; HICON hIconLarge, hIconSmall; HICON hIcon = NULL; TCHAR szIconKey[MAX_PATH]; TCHAR szDefaultIcon[MAX_PATH]; DWORD dwType, cbBytes; TCHAR szIconExeName[MAX_PATH]; int i, iIconIndex;
if ( fIconPath ) { StrCpy( szDefaultIcon, lpGUID ); } if ( !fIconPath ) { wsprintf(szIconKey, SZ_DEFAULTICONPATH, lpGUID); if (RegOpenKey(HKEY_CLASSES_ROOT, szIconKey, &hk) == ERROR_SUCCESS) { dwType = REG_SZ; cbBytes = sizeof(szDefaultIcon); if (RegQueryValueEx(hk, NULL, NULL, &dwType, (LPBYTE)szDefaultIcon, &cbBytes) == ERROR_SUCCESS) { fIconPath = TRUE; } RegCloseKey(hk); } }
if (fIconPath) { //
//Parse out the exe where the icon lives
//
for(i=0; i<lstrlen(szDefaultIcon); i++) { if (szDefaultIcon[i] == ',') break;
szIconExeName[i] = szDefaultIcon[i]; }
szIconExeName[i] = '\0';
//
//Parse out the icon index
//
i++; iIconIndex = StrToInt(&(szDefaultIcon[i]));
if (ExtractIconEx(szIconExeName, iIconIndex, (HICON FAR *)&hIconLarge, (HICON FAR *)&hIconSmall, 1)) { if (hIconSmall) hIcon = hIconSmall; else hIcon = hIconLarge; } } if (hIcon == NULL) { if ((hIcon = LoadIcon(CleanupMgrInfo::hInstance, MAKEINTRESOURCE(ICON_GENERIC))) == NULL) { MiDebugMsg((0, "LoadIcon failed with error %d", GetLastError())); } } return hIcon; }
INT_PTR CALLBACK ScanAbortDlgProc( HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam ) { CleanupMgrInfo *pcmi;
switch(Message) { case WM_INITDIALOG: SetWindowLongPtr (hDlg, DWLP_USER, 0L);
//
//Get the CleanupMgrInfo
//
pcmi = (CleanupMgrInfo *)lParam; if (pcmi == NULL) { //Error - passed in invalid CleanupMgrInfo info
return FALSE; }
//
//Save pointer to CleanupMgrInfo object
//
SetWindowLongPtr(hDlg, DWLP_USER, lParam);
TCHAR * psz; psz = SHFormatMessage( MSG_SCAN_ABORT_TEXT, pcmi->szVolName, pcmi->szRoot[0] ); SetDlgItemText (hDlg, IDC_ABORT_TEXT, psz); LocalFree(psz);
//
//Set the limits on the progress bar
//
SendDlgItemMessage(hDlg, IDC_ABORT_SCAN_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, pcmi->iNumVolumeCacheClients)); break;
case WMAPP_UPDATEPROGRESS: if (lParam != NULL) SetDlgItemText(hDlg, IDC_SCAN_STATUS_TEXT, (LPTSTR)lParam); else SetDlgItemText(hDlg, IDC_SCAN_STATUS_TEXT, TEXT("")); SendDlgItemMessage(hDlg, IDC_ABORT_SCAN_PROGRESS, PBM_SETPOS, (WPARAM)wParam, 0); break;
case WM_CLOSE: case WM_COMMAND: pcmi = (CleanupMgrInfo *)GetWindowLongPtr (hDlg, DWLP_USER); if (pcmi != NULL) pcmi->bAbortScan = TRUE; break;
default: return FALSE; }
return TRUE; }
BOOL PASCAL MessagePump( HWND hDialogWnd ) { MSG Msg; BOOL fGotMessage;
if ((fGotMessage = PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))) { if (!IsDialogMessage(hDialogWnd, &Msg)) { TranslateMessage(&Msg); DispatchMessage(&Msg); } }
return fGotMessage; }
void ScanAbortThread( CleanupMgrInfo *pcmi ) { if ((pcmi->hAbortScanWnd = CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_SCAN_ABORT), NULL, ScanAbortDlgProc, (LPARAM)pcmi)) == NULL) { return; }
// Show the window (except when the /SETUP flag is specified)
if (!(pcmi->dwUIFlags & FLAG_SETUP)) ShowWindow(pcmi->hAbortScanWnd, SW_SHOW);
// Trigger the event so we can continue with the scan.
// If this is triggered from WM_INITDIALOG it can move too quickly
// and will end up sending a message to NULL instead of the scan abort window
// because the hwnd doesn't get set until CreateDialogParam returns.
SetEvent(pcmi->hAbortScanEvent); //
//Keep spinning till the Scan is stopped
//
while (!(pcmi->bAbortScan)) { MessagePump(pcmi->hAbortScanWnd); }
//
//Destroy the Abort Scan dialog
//
if (pcmi->hAbortScanWnd != NULL) { DestroyWindow(pcmi->hAbortScanWnd); pcmi->hAbortScanWnd = NULL; } }
INT_PTR CALLBACK PurgeAbortDlgProc( HWND hDlg, UINT Message, WPARAM wParam, LPARAM lParam ) { CleanupMgrInfo *pcmi; DWORD dwCurrent;
switch(Message) { case WM_INITDIALOG: SetWindowLongPtr (hDlg, DWLP_USER, 0L);
//
//Get the CleanupMgrInfo
//
pcmi = (CleanupMgrInfo *)lParam; if (pcmi == NULL) { //Error - passed in invalid CleanupMgrInfo info
return FALSE; }
//
//Save pointer to CleanupMgrInfo object
//
SetWindowLongPtr(hDlg, DWLP_USER, lParam);
TCHAR * psz; psz = SHFormatMessage( MSG_PURGE_ABORT_TEXT, pcmi->szVolName, pcmi->szRoot[0]); SetDlgItemText (hDlg, IDC_PURGE_TEXT, psz); LocalFree(psz);
//
//Set the limits on the progress bar
//
if (pcmi->cbProgressDivider.QuadPart != 0) dwCurrent = (DWORD)(pcmi->cbSpaceToPurge.QuadPart / pcmi->cbProgressDivider.QuadPart); else dwCurrent = (DWORD)(pcmi->cbSpaceToPurge.QuadPart);
SendDlgItemMessage(hDlg, IDC_ABORT_PURGE_PROGRESS, PBM_SETRANGE, 0, MAKELPARAM(0, dwCurrent));
break;
case WMAPP_UPDATESTATUS: if (lParam != NULL) SetDlgItemText(hDlg, IDC_PURGE_STATUS_TEXT, (LPTSTR)lParam); else SetDlgItemText(hDlg, IDC_PURGE_STATUS_TEXT, TEXT("")); break;
case WMAPP_UPDATEPROGRESS: pcmi = (CleanupMgrInfo *)GetWindowLongPtr (hDlg, DWLP_USER); if (pcmi != NULL) { if (pcmi->cbProgressDivider.QuadPart != 0) dwCurrent = (DWORD)((pcmi->cbTotalPurgedSoFar.QuadPart + pcmi->cbCurrentClientPurgedSoFar.QuadPart) / pcmi->cbProgressDivider.QuadPart); else dwCurrent = (DWORD)(pcmi->cbTotalPurgedSoFar.QuadPart + pcmi->cbCurrentClientPurgedSoFar.QuadPart);
SendDlgItemMessage(hDlg, IDC_ABORT_PURGE_PROGRESS, PBM_SETPOS, (WPARAM)dwCurrent, 0); } break;
case WM_CLOSE: case WM_COMMAND: pcmi = (CleanupMgrInfo *)GetWindowLongPtr (hDlg, DWLP_USER); if (pcmi != NULL) pcmi->bAbortPurge = TRUE; break;
default: return FALSE; }
return TRUE; }
void PurgeAbortThread( CleanupMgrInfo *pcmi ) { if ((pcmi->hAbortPurgeWnd = CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_PURGE_ABORT), NULL, PurgeAbortDlgProc, (LPARAM)pcmi)) == NULL) { return; }
// Show the window (except when the /SETUP flag is specified)
if (!(pcmi->dwUIFlags & FLAG_SETUP)) ShowWindow(pcmi->hAbortPurgeWnd, SW_SHOW);
// Make sure the HWND has been set before setting off the event
PulseEvent(pcmi->hAbortPurgeEvent);
//
//Keep spinning till the Purge is stopped
//
while (!(pcmi->bAbortPurge)) { MessagePump(pcmi->hAbortPurgeWnd); }
//
//Destroy the Abort Purge dialog
//
if (pcmi->hAbortPurgeWnd != NULL) { DestroyWindow(pcmi->hAbortPurgeWnd); pcmi->hAbortPurgeWnd = NULL; } } /*
**------------------------------------------------------------------------------ ** End of File **------------------------------------------------------------------------------ */
|