windows-nt/Source/XPSP1/NT/shell/applets/cleanup/cleanmgr/dmgrinfo.cpp

1744 lines
61 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*
**------------------------------------------------------------------------------
** 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
**------------------------------------------------------------------------------
*/