dmgrinfo.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 62k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. /*
  2. **------------------------------------------------------------------------------
  3. ** Module:  Disk Cleanup Applet
  4. ** File:    dmgrinfo.c
  5. **
  6. ** Purpose: Defines the CleanupMgrInfo class for the property tab
  7. ** Notes:   
  8. ** Mod Log: Created by Jason Cobb (2/97)
  9. **
  10. ** Copyright (c)1997 Microsoft Corporation, All Rights Reserved
  11. **------------------------------------------------------------------------------
  12. */
  13. /*
  14. **------------------------------------------------------------------------------
  15. ** Project include files
  16. **------------------------------------------------------------------------------
  17. */
  18. #include "common.h"
  19. #include <limits.h>
  20. #include <emptyvc.h>
  21. #include "dmgrinfo.h"
  22. #include "dmgrdlg.h"
  23. #include "diskutil.h"
  24. #include "resource.h"
  25. #include "msprintf.h"
  26. /*
  27. **------------------------------------------------------------------------------
  28. **  Local variables
  29. **------------------------------------------------------------------------------
  30. */
  31. HINSTANCE   CleanupMgrInfo::hInstance             = NULL;
  32. /*
  33. **------------------------------------------------------------------------------
  34. ** Function prototypes
  35. **------------------------------------------------------------------------------
  36. */
  37. INT_PTR CALLBACK
  38. ScanAbortDlgProc(
  39.     HWND hDlg,
  40.     UINT Message,
  41.     WPARAM wParam,
  42.     LPARAM lParam
  43.     );
  44. void
  45. ScanAbortThread(
  46.     CleanupMgrInfo *pcmi
  47.     );
  48. INT_PTR CALLBACK
  49. PurgeAbortDlgProc(
  50.     HWND hDlg,
  51.     UINT Message,
  52.     WPARAM wParam,
  53.     LPARAM lParam
  54.     );
  55. void
  56. PurgeAbortThread(
  57.     CleanupMgrInfo *pcmi
  58.     );
  59. /*
  60. **------------------------------------------------------------------------------
  61. ** Function definitions
  62. **------------------------------------------------------------------------------
  63. */
  64. void
  65. CleanupMgrInfo::Register(
  66.     HINSTANCE hInstance
  67.     )
  68. {
  69.     CleanupMgrInfo::hInstance = hInstance;
  70. }
  71. void
  72. CleanupMgrInfo::Unregister(
  73.     void
  74.     )
  75. {
  76.     CleanupMgrInfo::hInstance= NULL;
  77. }
  78. /*
  79. **------------------------------------------------------------------------------
  80. ** GetCleanupMgrInfoPointer
  81. **
  82. ** Purpose:    
  83. ** Mod Log:    Created by Jason Cobb (2/97)
  84. **------------------------------------------------------------------------------
  85. */
  86. CleanupMgrInfo * GetCleanupMgrInfoPointer(
  87.     HWND hDlg
  88.     )
  89. {
  90.     //   
  91.     //Get the DriveInfo
  92.     //
  93.     CleanupMgrInfo * pcmi = (CleanupMgrInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
  94.     return pcmi;
  95. }
  96. /*
  97. **------------------------------------------------------------------------------
  98. ** CleanupMgrInfo method definitions
  99. **------------------------------------------------------------------------------
  100. */
  101. /*
  102. **------------------------------------------------------------------------------
  103. ** CleanupMgrInit::init
  104. **
  105. ** Purpose:    sets to default values
  106. ** Mod Log:    Created by Jason Cobb (2/97)
  107. **------------------------------------------------------------------------------
  108. */
  109. void 
  110. CleanupMgrInfo::init(void)
  111. {
  112.     dre             = Drive_INV;
  113.     szVolName[0]    = 0;
  114.     vtVolume        = vtINVALID;
  115.     dwUIFlags       = 0;
  116.     bPurgeFiles     = TRUE;
  117. }
  118. /*
  119. **------------------------------------------------------------------------------
  120. ** CleanupMgrInfo::destroy
  121. **
  122. ** Purpose:    releases any dynamic memory
  123. ** Mod Log:    Created by Jason Cobb (2/97)
  124. **------------------------------------------------------------------------------
  125. */
  126. void 
  127. CleanupMgrInfo::destroy(void)
  128. {
  129.     //
  130.     //Set values back to defaults
  131.     //
  132.     init();
  133. }
  134. /*
  135. **------------------------------------------------------------------------------
  136. ** CleanupMgrInfo::CleanupMgrInfo
  137. **
  138. ** Purpose:    Default constructor
  139. ** Mod Log:    Created by Jason Cobb (2/97)
  140. **------------------------------------------------------------------------------
  141. */
  142. CleanupMgrInfo::CleanupMgrInfo (void)
  143. {
  144.     init();
  145. }
  146. /*
  147. **------------------------------------------------------------------------------
  148. ** CleanupMgrInfo::CleanupMgrInfo
  149. **
  150. ** Purpose:    Constructor
  151. ** Mod Log:    Created by Jason Cobb (2/97)
  152. **------------------------------------------------------------------------------
  153. */
  154. CleanupMgrInfo::CleanupMgrInfo(
  155.     LPTSTR lpDrive,
  156.     DWORD dwFlags,
  157.     ULONG ulProfile
  158.     )
  159. {
  160.     HRESULT hr;
  161.     init();
  162.     if (create(lpDrive, dwFlags))
  163.     {
  164.         CoInitialize(NULL);
  165.         dwReturnCode = RETURN_SUCCESS;
  166.         dwUIFlags = dwFlags;
  167.         ulSAGEProfile = ulProfile;
  168.         bAbortScan = FALSE;
  169.         bAbortPurge = FALSE;
  170.     
  171.         volumeCacheCallBack = NULL;
  172.         pIEmptyVolumeCacheCallBack = NULL;
  173.         volumeCacheCallBack = new CVolumeCacheCallBack();
  174.         hr = volumeCacheCallBack->QueryInterface(IID_IEmptyVolumeCacheCallBack,
  175.                                            (LPVOID*)&pIEmptyVolumeCacheCallBack);
  176.         if (hr != NOERROR)
  177.         {
  178.             MiDebugMsg((hr, "CleanupMgrInfo::CleanupMgrInfo failed with error "));
  179.         }
  180.         //
  181.         //Initialize all of the cleanup clients
  182.         //
  183.         if (initializeClients() && !(dwUIFlags & FLAG_TUNEUP) && !(dwUIFlags & FLAG_SAGESET))
  184.         {
  185.             //
  186.             //Have all of the cleanup clients calculate the ammount of disk
  187.             //space that they can free up.
  188.             //
  189.             getSpaceUsedByClients();
  190.         }
  191.     }
  192. }
  193. /*
  194. **------------------------------------------------------------------------------
  195. ** CleanupMgrInfo::~CleanupMgrInfo
  196. **
  197. ** Purpose:    Destructor
  198. ** Mod Log:    Created by Jason Cobb (2/97)
  199. **------------------------------------------------------------------------------
  200. */
  201. CleanupMgrInfo::~CleanupMgrInfo (void)
  202. {
  203.     if (isValid())
  204.     {
  205.         //
  206.         //Cleanup the Volume Cache Clients
  207.         //
  208.         deactivateClients();    
  209.         volumeCacheCallBack->Release();
  210.    
  211.         CoUninitialize();
  212.         destroy();   
  213.     }
  214. }
  215. /*
  216. **------------------------------------------------------------------------------
  217. ** CleanupMgrInfo::create
  218. **
  219. ** Purpose:    Gets Drive info from drive letter
  220. ** Mod Log:    Created by Jason Cobb (2/97)
  221. **------------------------------------------------------------------------------
  222. */
  223. BOOL 
  224. CleanupMgrInfo::create(
  225.     LPTSTR lpDrive,
  226.     DWORD Flags
  227.     )
  228. {
  229.      
  230.     //
  231.     //Note:  Make sure the assigns to zero stay current
  232.     //       otherwise we might get garbage stats if
  233.     //       we fail because of lack of free space
  234.     //
  235.     DWORD cSectorsPerCluster;
  236.     DWORD cBytesPerSector;
  237.     DWORD cBytesPerCluster;
  238.     DWORD cFreeClusters;
  239.     DWORD cUsedClusters;
  240.     DWORD cTotalClusters;
  241.     ULARGE_INTEGER cbFree;
  242.     ULARGE_INTEGER cbUsed;
  243.     ULARGE_INTEGER cbTotal;
  244. #ifdef NEC_98
  245.     drenum drive;
  246.     hardware hw_type;
  247. #endif
  248.     cbFree.QuadPart = 0;
  249.     cbUsed.QuadPart = 0;
  250.     
  251.     //
  252.     //Cleanup up any old stuff
  253.     //
  254.     destroy();
  255.       
  256.     //
  257.     //Check parameters
  258.     //
  259.     if (lpDrive == NULL)
  260.         return FALSE;
  261.       
  262.     //  
  263.     //Is it a valid drive path
  264.     //
  265.     if (!fIsValidDriveString(lpDrive))
  266.         return FALSE;
  267.     //
  268.     //Get drive from path
  269.     //
  270.     if (!GetDriveFromString(lpDrive, dre))
  271.         return FALSE;
  272.     lstrcpy(szRoot, lpDrive);
  273.       
  274.     // 
  275.     // Step 2.  Get general info from drive
  276.     //
  277.     //
  278.     //Get volume name
  279.     //
  280.     if (!GetVolumeInformation (szRoot,                              // Root name
  281.                                szVolName, sizeof(szVolName),        // Volume Name
  282.                                NULL,                                // Volume serial number
  283.                                NULL,                                // Max path length
  284.                                NULL,                                // flags
  285.                                szFileSystem, sizeof(szFileSystem))) // file system name                         
  286.     {
  287.         //Error - failed to get volume name
  288.         goto lblERROR;
  289.     }
  290.     //
  291.     //Get the Driver Icon
  292.     //
  293.     if (Flags & FLAG_SAGESET)
  294.         hDriveIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(ICON_CLEANMGR));
  295.     else
  296.         hDriveIcon = GetDriveIcon(dre, FALSE);
  297.     //  
  298.     //Get Hardware type
  299.     //
  300.     if (!GetHardwareType(dre, hwHardware))
  301.     {
  302.         //Error - failed to get hardware
  303.         goto lblERROR;
  304.     }
  305. #ifdef NEC_98
  306.     drive = Drive_A;
  307.     GetHardwareType (Drive_A, hw_type);
  308.     if (hw_type != hwFixed) 
  309.     {
  310.         drive = Drive_B;
  311.         GetHardwareType (Drive_B, hw_type);
  312.         if (hw_type != hwFixed)
  313.             drive = Drive_C;
  314.     }
  315. #endif
  316.     // 
  317.     //Get disk statistics
  318.     //
  319.     if (!GetDiskFreeSpace (szRoot, 
  320.                            &cSectorsPerCluster, 
  321.                            &cBytesPerSector,
  322.                            &cFreeClusters,
  323.                            &cTotalClusters))
  324.     {
  325.         //Error - couldn't get drive stats
  326.         goto lblERROR;
  327.     }
  328.       
  329.     //  
  330.     //Calculate secondary statistics
  331.     //
  332.     cBytesPerCluster = cBytesPerSector * cSectorsPerCluster;
  333.     if (cTotalClusters >= cFreeClusters)
  334.         cUsedClusters = cTotalClusters - cFreeClusters;
  335.     else
  336.         cUsedClusters = 0L;
  337.     cbFree.QuadPart   = UInt32x32To64(cFreeClusters, cBytesPerCluster);
  338.     cbUsed.QuadPart   = UInt32x32To64(cUsedClusters, cBytesPerCluster);
  339.     cbTotal.QuadPart  = cbFree.QuadPart + cbUsed.QuadPart;
  340.     //
  341.     //Get the current low disk space ratio
  342.     //
  343.     cbLowSpaceThreshold = GetFreeSpaceRatio(dre, cbTotal);
  344.     //
  345.     //Should we also load the agressive cleaners? We only do this if we
  346.     //are below are critical threshold of disk space left.
  347.     //
  348.     if (cbLowSpaceThreshold.QuadPart >= cbFree.QuadPart)
  349.     {
  350.         MiDebugMsg((0, "*****We are in aggressive mode*****"));
  351.         bOutOfDiskSpace = TRUE;
  352.     }
  353.     else
  354.         bOutOfDiskSpace = FALSE;
  355.     // 
  356.     // Step 3.  Save stats
  357.     //
  358.     cbDriveFree          = cbFree;
  359.     cbDriveUsed          = cbUsed;
  360.     cbEstCleanupSpace.QuadPart    = 0;
  361.     //
  362.     //Success
  363.     //
  364.     return TRUE;
  365. lblERROR:
  366.     //  
  367.     //Error
  368.     //
  369.     destroy();
  370.     return FALSE;
  371. }
  372. /*
  373. **------------------------------------------------------------------------------
  374. ** CleanupMgrInfo::initializeClients
  375. **
  376. ** Purpose:    Initializes all of the Volume Cache Clients
  377. ** Mod Log:    Created by Jason Cobb (2/97)
  378. **------------------------------------------------------------------------------
  379. */
  380. BOOL 
  381. CleanupMgrInfo::initializeClients(void)
  382. {
  383.     HKEY    hKeyVolCache;
  384.     DWORD   iSubKey;
  385.     DWORD   dwClient;
  386.     TCHAR   szVolCacheClient[MAX_PATH];
  387.     TCHAR   szGUID[MAX_PATH];
  388.     DWORD   dwGUIDSize;
  389.     DWORD   dwType;
  390.     DWORD   dwState, cb, cw;
  391.     TCHAR   szProfile[64];
  392.     BOOL    bRet = TRUE;
  393.     BOOL    bCleanup;
  394.     iNumVolumeCacheClients = 0;
  395.     pClientInfo = NULL;
  396.     
  397.     MiDebugMsg((0, "CleanupMgrInfo::initializeClients entered"));
  398.     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_VOLUMECACHE, 0, KEY_READ, &hKeyVolCache) == ERROR_SUCCESS)
  399.     {
  400.         //
  401.         //Enumerate through all of the clients to see how large we need to make the pClientInfo array
  402.         //
  403.         // BUGBUG: Use RegQueryInfoKey to save some ring transitions
  404.         iSubKey = 0;
  405.         while(RegEnumKey(hKeyVolCache, iSubKey, szVolCacheClient, sizeof(szVolCacheClient)) != ERROR_NO_MORE_ITEMS)
  406.         {
  407.             iSubKey++;        
  408.         }
  409.         
  410.         if ((pClientInfo = (PCLIENTINFO)LocalAlloc(LPTR, (iSubKey * sizeof(CLIENTINFO)))) == NULL)
  411.         {
  412. #ifdef DEBUG
  413.             MessageBox(NULL, TEXT("FATAL ERROR LocalAlloc() failed!"), TEXT("CLEANMGR DEBUG"), MB_OK);
  414. #endif
  415.             RegCloseKey(hKeyVolCache);
  416.             return FALSE;
  417.         }
  418.         
  419.         //
  420.         //Fill in the pClientInfo data structure and initialize all of the volume cache clients
  421.         //   
  422.         iSubKey = 0;
  423.         dwClient = 0;
  424.         while(RegEnumKey(hKeyVolCache, iSubKey, szVolCacheClient, sizeof(szVolCacheClient)) != ERROR_NO_MORE_ITEMS)
  425.         {
  426.             // default is we failed, so cleanup the current item....
  427.             bCleanup = TRUE;
  428.             
  429.             if (RegOpenKeyEx(hKeyVolCache, szVolCacheClient, 0, MAXIMUM_ALLOWED, &(pClientInfo[dwClient].hClientKey)) == ERROR_SUCCESS)
  430.             {
  431.                 lstrcpy(pClientInfo[dwClient].szRegKeyName, szVolCacheClient);
  432.             
  433.                 dwGUIDSize = sizeof(szGUID);
  434.                 dwType = REG_SZ;
  435.                 if (RegQueryValueEx(pClientInfo[dwClient].hClientKey, NULL, NULL, &dwType, (LPBYTE)szGUID, &dwGUIDSize) == ERROR_SUCCESS)
  436.                 {
  437.                     HRESULT hr;
  438.                     WCHAR   wcsFmtID[39];
  439. #ifdef UNICODE
  440.                     StrCpyN( wcsFmtID, szGUID, ARRAYSIZE( wcsFmtID ));
  441. #else
  442.                     //Convert to Unicode.
  443.                     MultiByteToWideChar(CP_ACP, 0, szGUID, -1, wcsFmtID, ARRAYSIZE( wcsFmtID )) ;
  444. #endif
  445.                     //Convert to GUID.
  446.                     hr = CLSIDFromString((LPOLESTR)wcsFmtID, &(pClientInfo[dwClient].clsid));
  447.                     if (FAILED(hr))
  448.                     {
  449.                         MiDebugMsg((hr, "CLSIDFromString(%s,) returned error ", szGUID));
  450.                     }
  451.                     //
  452.                     //Create an instance of the COM object for this cleanup client
  453.                     //
  454.                     pClientInfo[dwClient].pVolumeCache = NULL;
  455.                     hr = CoCreateInstance(pClientInfo[dwClient].clsid,
  456.                                                     NULL,
  457.                                                     CLSCTX_INPROC_SERVER,
  458.                                                     IID_IEmptyVolumeCache,
  459.                                                     (void **) &(pClientInfo[dwClient].pVolumeCache));
  460.                     if (SUCCEEDED(hr))
  461.                     {
  462.                         WCHAR   wcsRoot[MAX_PATH];
  463.                         MiDebugMsg((hr, "CleanupMgrInfo::initializeClients Created IID_IEmptyVolumeCache"));
  464.                         //
  465.                         //Set the flags to pass to the cleanup client
  466.                         //
  467.                         pClientInfo[dwClient].dwInitializeFlags = 0;
  468.                         if (dwUIFlags & FLAG_SAGESET)
  469.                             pClientInfo[dwClient].dwInitializeFlags |= EVCF_SETTINGSMODE;
  470.                         if (bOutOfDiskSpace)
  471.                             pClientInfo[dwClient].dwInitializeFlags |= EVCF_OUTOFDISKSPACE;
  472. #ifdef UNICODE
  473.                         StrCpyN( wcsRoot, szRoot, ARRAYSIZE( wcsRoot ));
  474. #else
  475.                         //
  476.                         //Convert szRoot to UNICODE
  477.                         //
  478.                         MultiByteToWideChar(CP_ACP, 0, szRoot, -1, wcsRoot, ARRAYSIZE( wcsRoot ));
  479. #endif
  480.                         // Try to use version two of the interface if it is supported
  481.                         IEmptyVolumeCache2 * pEVC2;
  482.                         hr = pClientInfo[dwClient].pVolumeCache->QueryInterface( IID_IEmptyVolumeCache2, (void**)&pEVC2 );
  483.                         if (SUCCEEDED(hr))
  484.                         {
  485.                             // version 2 exists so that we can have a mutli-local enabled data driven cleaner.  It
  486.                             // allows the added Advanced Button to be set to a localized value.  It tells the
  487.                             // object being called which key it is being called for so that one object can support
  488.                             // multiple filters.
  489.                             WCHAR   wcsFilterName[MAX_PATH];
  490.                             MiDebugMsg((hr, "CleanupMgrInfo::initializeClients found V2 interface"));
  491. #ifdef UNICODE
  492.                             StrCpyN( wcsFilterName, szVolCacheClient, ARRAYSIZE( wcsFilterName ));
  493. #else
  494.                             MultiByteToWideChar(CP_ACP, 0, szVolCacheClient, -1, wcsFilterName, ARRAYSIZE( wcsFilterName )) ;
  495. #endif
  496.                             hr = pEVC2->InitializeEx(pClientInfo[dwClient].hClientKey,
  497.                                                     (LPCWSTR)wcsRoot,
  498.                                                     (LPCWSTR)wcsFilterName,
  499.                                                     &((LPWSTR)pClientInfo[dwClient].wcsDisplayName),
  500.                                                     &((LPWSTR)pClientInfo[dwClient].wcsDescription),
  501.                                                     &((LPWSTR)pClientInfo[dwClient].wcsAdvancedButtonText),
  502.                                                     &(pClientInfo[dwClient].dwInitializeFlags));
  503.                             pEVC2->Release();
  504.                         }
  505.                         else
  506.                         {
  507.                             MiDebugMsg((hr, "CleanupMgrInfo::initializeClients using V1 interface"));
  508.                             //
  509.                             //Initialize the cleanup client
  510.                             //
  511.                             if ((pClientInfo[dwClient].wcsDescription = (LPWSTR)CoTaskMemAlloc(DESCRIPTION_LENGTH*sizeof(WCHAR))) == NULL)
  512.                                 return FALSE;
  513.                             // We seem to have shipped this thing with a giant leak.  The object is supposted to set
  514.                             // pClientInfo[dwClient].wcsDescription to NULL if the registry value should be used instead
  515.                             // of the buffer.  However we just allocated a buffer for pClientInfo[dwClient].wcsDescription
  516.                             // in the code above (this is the dumbass part).  All the filters then set this pointer to
  517.                             // NULL and it's bye-bye buffer.  I can't simply not allocate this memory because some cleaners
  518.                             // might rely on being able to use this memory and we shipped it that way.
  519.                             LPWSTR wszDumbassLeakProtection = pClientInfo[dwClient].wcsDescription;
  520.                             hr = pClientInfo[dwClient].pVolumeCache->Initialize(pClientInfo[dwClient].hClientKey,
  521.                                                                                (LPCWSTR)wcsRoot,
  522.                                                                                &((LPWSTR)pClientInfo[dwClient].wcsDisplayName),
  523.                                                                                &((LPWSTR)pClientInfo[dwClient].wcsDescription),
  524.                                                                                &(pClientInfo[dwClient].dwInitializeFlags));                                                                
  525.                             if ( wszDumbassLeakProtection != pClientInfo[dwClient].wcsDescription )
  526.                             {
  527.                                 // REVIEW: Use try...except around CoTaskMemFree in case some smart cleaner
  528.                                 // realized our mistake and deleted the memory for us?
  529.                                 MiDebugMsg((hr, "CleanupMgrInfo::initializeClients prevent mem leak hack"));
  530.                                 CoTaskMemFree( wszDumbassLeakProtection );
  531.                             }
  532.                             if ( S_OK == hr )
  533.                             {
  534.                                 // To make it easier to make a cleaner we have a default implementation of IEmptyVolumeCache
  535.                                 // that works entirerly using registry data.  The problem is that display strings are strored
  536.                                 // in the registry.  This is invalid for NT because NT must be multi-local localizable and
  537.                                 // the only way to do that is to load all display strings from a resource.  As a hack, you
  538.                                 // can now implement IPropertyBag using an object with it's guid stored under the propertybag
  539.                                 // value in the registry.  We will cocreate this object and query for IPropertyBag.  If this
  540.                                 // works then we will attempt to read the localized strings from the property bag before we
  541.                                 // fall back on checking the registry.
  542.                                 TCHAR   szPropBagGUID[MAX_PATH];
  543.                                 HRESULT hrFoo;
  544.                                 IPropertyBag * ppb = NULL;
  545.                                 VARIANT var;
  546.                                 VariantInit( &var );
  547.                                 dwGUIDSize = sizeof(szPropBagGUID);
  548.                                 dwType = REG_SZ;
  549.                                 if (RegQueryValueEx(pClientInfo[dwClient].hClientKey, TEXT("PropertyBag"), NULL, &dwType, (LPBYTE)szPropBagGUID, &dwGUIDSize) == ERROR_SUCCESS)
  550.                                 {
  551.                                     WCHAR   wcsFmtID[39];
  552.                                     CLSID   clsid;
  553.                                     MiDebugMsg((hr, "CleanupMgrInfo::initializeClients found PropBag key"));
  554. #ifdef UNICODE
  555.                                     StrCpyN( wcsFmtID, szPropBagGUID, ARRAYSIZE( wcsFmtID ));
  556. #else
  557.                                     MultiByteToWideChar(CP_ACP, 0, szPropBagGUID, -1, wcsFmtID, ARRAYSIZE( wcsFmtID )) ;
  558. #endif
  559.                                     //Convert to GUID.
  560.                                     CLSIDFromString((LPOLESTR)wcsFmtID, &clsid);
  561.                                     //
  562.                                     //Create an instance of the COM object for this cleanup client
  563.                                     //
  564.                                     hrFoo = CoCreateInstance(clsid,
  565.                                                           NULL,
  566.                                                           CLSCTX_INPROC_SERVER,
  567.                                                           IID_IPropertyBag,
  568.                                                           (void **) &ppb);
  569.                                     if ( FAILED(hrFoo) )
  570.                                     {
  571.                                         MiDebugMsg((hrFoo, "CleanupMgrInfo::initializeClients failed to create PropBag"));
  572.                                     }
  573.                                 }
  574.                                 //
  575.                                 //If the client did not return the DisplayName via the Initialize
  576.                                 //Interface then we need to get it from the registry.
  577.                                 //
  578.                                 if ((pClientInfo[dwClient].wcsDisplayName) == NULL)
  579.                                 {
  580.                                     LPTSTR  lpszDisplayName;
  581.                                     if ( ppb )
  582.                                     {
  583.                                         WCHAR wszSrc[MAX_PATH];
  584.                                         MiDebugMsg((hr, "CleanupMgrInfo::initializeClients checking PropBag for display"));
  585.                                         SHTCharToUnicode(REGSTR_VAL_DISPLAY, wszSrc, MAX_PATH);
  586.                                         // do propertybag stuff
  587.                                         var.vt = VT_BSTR;
  588.                                         var.bstrVal = NULL;
  589.                                         hrFoo = ppb->Read( wszSrc, &var, NULL );
  590.                                         if (SUCCEEDED(hrFoo))
  591.                                         {
  592.                                             if ( var.vt == VT_BSTR )
  593.                                             {
  594.                                                 DWORD dwSize = (lstrlenW(var.bstrVal)+1)*sizeof(WCHAR);
  595.                                                 pClientInfo[dwClient].wcsDisplayName = (LPWSTR)CoTaskMemAlloc(dwSize);
  596.                                                 StrCpyW( pClientInfo[dwClient].wcsDisplayName, var.bstrVal );
  597.                                             }
  598.                                             VariantClear( &var );
  599.                                         }
  600.                                     }
  601.                                     if ((pClientInfo[dwClient].wcsDisplayName) == NULL)
  602.                                     {
  603.                                         //
  604.                                         //First check if their is a "display" value for the client's 
  605.                                         //name that is displayed in the list box.  If not then use
  606.                                         //the key name itself.
  607.                                         //
  608.                                         cb = 0;
  609.                                         dwType = REG_SZ;
  610.                                         RegQueryValueEx(pClientInfo[dwClient].hClientKey, REGSTR_VAL_DISPLAY, NULL, &dwType, (LPBYTE)NULL, &cb);
  611.                                         if ((lpszDisplayName = (LPTSTR)LocalAlloc(LPTR, max(cb, (ULONG)(lstrlen(szVolCacheClient) + 1))* sizeof (TCHAR ))) != NULL)
  612.                                         {
  613.                                             if (RegQueryValueEx(pClientInfo[dwClient].hClientKey, REGSTR_VAL_DISPLAY, NULL, &dwType, (LPBYTE)lpszDisplayName, &cb) != ERROR_SUCCESS)
  614.                                             {
  615.                                                 //
  616.                                                 //Count not find "display" value so use the key name instead
  617.                                                 //
  618.                                                 StrCpy(lpszDisplayName, szVolCacheClient);
  619.                                             }
  620.     #ifdef UNICODE
  621.                                             cw = (lstrlen( lpszDisplayName ) + 1) * sizeof( WCHAR);
  622.     #else
  623.                                             //
  624.                                             //Convert this value to UNICODE
  625.                                             //
  626.                                             cw = (MultiByteToWideChar(CP_ACP, 0, lpszDisplayName, -1, NULL, 0) * sizeof(WCHAR));
  627.     #endif
  628.                                             if ((pClientInfo[dwClient].wcsDisplayName = (LPWSTR)CoTaskMemAlloc(cw)) != NULL)
  629.                                             {
  630.     #ifdef UNICODE
  631.                                                 StrCpy( pClientInfo[dwClient].wcsDisplayName, lpszDisplayName );
  632.     #else
  633.                                                 MultiByteToWideChar(CP_ACP, 0, lpszDisplayName, -1, (pClientInfo[dwClient].wcsDisplayName), cw);
  634.     #endif
  635.                                             }
  636.                                             LocalFree(lpszDisplayName);
  637.                                         }
  638.                                     }
  639.                                 }
  640.                                 //
  641.                                 //If the client did not return the Description via the Initialize
  642.                                 //Interface then we need to get it from the registry.
  643.                                 //
  644.                                 if ((pClientInfo[dwClient].wcsDescription) == NULL)
  645.                                 {
  646.                                     LPTSTR  lpszDescription;
  647.                                     if ( ppb )
  648.                                     {
  649.                                         WCHAR wszSrc[MAX_PATH];
  650.                                         MiDebugMsg((hr, "CleanupMgrInfo::initializeClients checking PropBag for description"));
  651.                                         SHTCharToUnicode(REGSTR_VAL_DESCRIPTION, wszSrc, MAX_PATH);
  652.                                         // do propertybag stuff
  653.                                         var.vt = VT_BSTR;
  654.                                         var.bstrVal = NULL;
  655.                                         hrFoo = ppb->Read( wszSrc, &var, NULL );
  656.                                         if (SUCCEEDED(hrFoo))
  657.                                         {
  658.                                             if ( var.vt == VT_BSTR )
  659.                                             {
  660.                                                 DWORD dwSize = (lstrlenW(var.bstrVal)+1)*sizeof(WCHAR);
  661.                                                 pClientInfo[dwClient].wcsDescription = (LPWSTR)CoTaskMemAlloc(dwSize);
  662.                                                 StrCpyW( pClientInfo[dwClient].wcsDescription, var.bstrVal );
  663.                                             }
  664.                                             VariantClear( &var );
  665.                                         }
  666.                                     }
  667.                                     if ((pClientInfo[dwClient].wcsDescription) == NULL)
  668.                                     {
  669.                                         //
  670.                                         //Check if their is a "description" value for the client 
  671.                                         //
  672.                                         cb = 0;
  673.                                         dwType = REG_SZ;
  674.                                         RegQueryValueEx(pClientInfo[dwClient].hClientKey, REGSTR_VAL_DESCRIPTION, NULL, &dwType, (LPBYTE)NULL, &cb);
  675.                                         if ((lpszDescription = (LPTSTR)LocalAlloc(LPTR, (cb + 1 ) * sizeof( TCHAR ))) != NULL)
  676.                                         {
  677.                                             if (RegQueryValueEx(pClientInfo[dwClient].hClientKey, REGSTR_VAL_DESCRIPTION, NULL, &dwType, (LPBYTE)lpszDescription, &cb) == ERROR_SUCCESS)
  678.                                             {
  679. #ifdef UNICODE
  680.                                                 cw = ( lstrlen( lpszDescription ) + 1 ) * sizeof( WCHAR );
  681. #else
  682.                                                 //
  683.                                                 //Convert this value to UNICODE
  684.                                                 //
  685.                                                 cw = (MultiByteToWideChar(CP_ACP, 0, lpszDescription, -1, NULL, 0) * sizeof(WCHAR));
  686. #endif
  687.                                                 if ((pClientInfo[dwClient].wcsDescription = (LPWSTR)CoTaskMemAlloc(cw)) != NULL)
  688.                                                 {
  689. #ifdef UNICODE                                          
  690.                                                     StrCpy( pClientInfo[dwClient].wcsDescription, lpszDescription );
  691. #else
  692.                                                     MultiByteToWideChar(CP_ACP, 0, lpszDescription, -1, (pClientInfo[dwClient].wcsDescription), cw);
  693. #endif
  694.                                                 }
  695.                                             }
  696.                                             LocalFree(lpszDescription);
  697.                                         }
  698.                                     }
  699.                                 }
  700.                                 //
  701.                                 //Set the Advanced Button text
  702.                                 //
  703.                                 pClientInfo[dwClient].wcsAdvancedButtonText = NULL;
  704.                                 if (pClientInfo[dwClient].dwInitializeFlags & EVCF_HASSETTINGS)
  705.                                 {
  706.                                     if ( ppb )
  707.                                     {
  708.                                         WCHAR wszSrc[MAX_PATH];
  709.                                         MiDebugMsg((hr, "CleanupMgrInfo::initializeClients checking PropBag for button text"));
  710.                                         SHTCharToUnicode(REGSTR_VAL_ADVANCEDBUTTONTEXT, wszSrc, MAX_PATH);
  711.                                         // do propertybag stuff
  712.                                         var.vt = VT_BSTR;
  713.                                         var.bstrVal = NULL;
  714.                                         hrFoo = ppb->Read( wszSrc, &var, NULL );
  715.                                         if (SUCCEEDED(hrFoo))
  716.                                         {
  717.                                             if ( var.vt == VT_BSTR )
  718.                                             {
  719.                                                 DWORD dwSize = (lstrlenW(var.bstrVal)+1)*sizeof(WCHAR);
  720.                                                 pClientInfo[dwClient].wcsAdvancedButtonText = (LPWSTR)CoTaskMemAlloc(dwSize);
  721.                                                 StrCpyW( pClientInfo[dwClient].wcsAdvancedButtonText, var.bstrVal );
  722.                                             }
  723.                                             VariantClear( &var );
  724.                                         }
  725.                                     }
  726.                                     if ( pClientInfo[dwClient].wcsAdvancedButtonText == NULL )
  727.                                     {
  728.                                         LPTSTR  lpszAdvancedButtonText;
  729.                                         TCHAR   szDetails[BUTTONTEXT_LENGTH];
  730.                                         LoadString(g_hInstance, IDS_DETAILS, szDetails, sizeof(szDetails));
  731.                                         cb = 0;
  732.                                         dwType = REG_SZ;
  733.                                         RegQueryValueEx(pClientInfo[dwClient].hClientKey, REGSTR_VAL_ADVANCEDBUTTONTEXT, NULL, &dwType, (LPBYTE)NULL, &cb);
  734.                                         if ((lpszAdvancedButtonText = (LPTSTR)LocalAlloc(LPTR, max(cb, (UINT) (lstrlen(szDetails) + 1)*sizeof(TCHAR)))) != NULL)
  735.                                         {
  736.                                             if (RegQueryValueEx(pClientInfo[dwClient].hClientKey, REGSTR_VAL_ADVANCEDBUTTONTEXT, NULL, &dwType, (LPBYTE)lpszAdvancedButtonText, &cb) != ERROR_SUCCESS)
  737.                                             StrCpy(lpszAdvancedButtonText, szDetails);
  738. #ifdef UNICODE
  739.                                             cw = (lstrlen( lpszAdvancedButtonText ) + 1) * sizeof( WCHAR );
  740. #else
  741.                                             //
  742.                                             //Convert this value to UNICODE
  743.                                             //
  744.                                             cw = (MultiByteToWideChar(CP_ACP, 0, lpszAdvancedButtonText, -1, NULL, 0) * sizeof(WCHAR));
  745. #endif
  746.                                             if ((pClientInfo[dwClient].wcsAdvancedButtonText = (LPWSTR)CoTaskMemAlloc(cw)) != NULL)
  747.                                             {
  748. #ifdef UNICODE
  749.                                                 StrCpy( pClientInfo[dwClient].wcsAdvancedButtonText, lpszAdvancedButtonText );
  750. #else
  751.                                                 MultiByteToWideChar(CP_ACP, 0, lpszAdvancedButtonText, -1, (pClientInfo[dwClient].wcsAdvancedButtonText), cw);
  752. #endif
  753.                                             }
  754.                                             LocalFree(lpszAdvancedButtonText);
  755.                                         }
  756.                                     }
  757.                                 }
  758.                                 if (ppb)
  759.                                 {
  760.                                     ppb->Release();
  761.                                 }
  762.                             }
  763.                         }
  764.                         // Now we're back to stuff that both version 1 and version 2 require
  765.                         if (SUCCEEDED(hr))
  766.                         {
  767.                             if (S_OK == hr)
  768.                             {
  769.                                 //
  770.                                 //Default to showing this client in the UI
  771.                                 //
  772.                                 pClientInfo[dwClient].bShow = TRUE;
  773.                             
  774.                                 //
  775.                                 //Get the "priority" from the registry
  776.                                 //
  777.                                 cb = sizeof(pClientInfo[dwClient].dwPriority);
  778.                                 dwType = REG_DWORD;
  779.                                 if (RegQueryValueEx(pClientInfo[dwClient].hClientKey, REGSTR_VAL_PRIORITY, NULL, &dwType, (LPBYTE)&(pClientInfo[dwClient].dwPriority), &cb) != ERROR_SUCCESS)
  780.                                     pClientInfo[dwClient].dwPriority = DEFAULT_PRIORITY;
  781.                                 
  782.                                 //
  783.                                 //Flags
  784.                                 //
  785.                                 if (dwUIFlags & FLAG_SAGERUN || dwUIFlags & FLAG_SAGESET)
  786.                                     wsprintf(szProfile, TEXT("%s%04d"), SZ_STATE, ulSAGEProfile);
  787.                                 else
  788.                                     lstrcpy(szProfile, SZ_STATE);
  789.                                     
  790.                                 dwState = 0;
  791.                                 cb = sizeof(dwState);
  792.                                 dwType = REG_DWORD;
  793.                                 if (RegQueryValueEx(pClientInfo[dwClient].hClientKey, szProfile, NULL,
  794.                                     &dwType, (LPBYTE)&dwState, &cb) == ERROR_SUCCESS)
  795.                                 {
  796.                                     if (dwUIFlags & FLAG_SAGERUN || dwUIFlags & FLAG_SAGESET)
  797.                                     {
  798.                                         pClientInfo[dwClient].bSelected = (dwState & STATE_SAGE_SELECTED);
  799.                                     }
  800.                                     else
  801.                                     {
  802.                                         pClientInfo[dwClient].bSelected = (dwState & STATE_SELECTED);
  803.                                     }
  804.                                 }
  805.                                 else
  806.                                 {
  807.                                     //
  808.                                     //No registry settings for this profile so use the cleanup clients
  809.                                     //default settings.
  810.                                     //
  811.                                     if (dwUIFlags & FLAG_SAGERUN || dwUIFlags & FLAG_SAGESET)
  812.                                     {
  813.                                         pClientInfo[dwClient].bSelected = (pClientInfo[dwClient].dwInitializeFlags & EVCF_ENABLEBYDEFAULT_AUTO) ? TRUE : FALSE;
  814.                                     }
  815.                                     else
  816.                                     {
  817.                                         pClientInfo[dwClient].bSelected = (pClientInfo[dwClient].dwInitializeFlags & EVCF_ENABLEBYDEFAULT) ? TRUE : FALSE;
  818.                                     }
  819.                                 }
  820.                                 
  821.                                 //
  822.                                 //Get the icon of the cleanup client
  823.                                 //
  824.                                 // first test to see if it is overridden...
  825.                                 TCHAR szIconPath[MAX_PATH];
  826.                                 cb = sizeof( szIconPath );
  827.                                 BOOL fOverridden = FALSE;
  828.                                 
  829.                                 if ( RegQueryValueEx(pClientInfo[dwClient].hClientKey, TEXT("IconPath"), NULL,
  830.                                     &dwType, (LPBYTE)szIconPath, &cb) == ERROR_SUCCESS )
  831.                                 {
  832.                                     fOverridden = TRUE;
  833.                                 }
  834.                                 else
  835.                                 {
  836.                                     lstrcpy( szIconPath, szGUID );
  837.                                 }
  838.                                 
  839.                                 pClientInfo[dwClient].hIcon = GetClientIcon(szIconPath, fOverridden);
  840.                                 bCleanup = FALSE;
  841.                             }
  842.                             else
  843.                             {
  844.                                 //
  845.                                 //This should be S_FALSE.  This means that the client has nothing to 
  846.                                 //cleanup now so we don't even need to show it in the list.
  847.                                 //Therefor we will just call its Release() function and close it's
  848.                                 //registry key.
  849.                                 //
  850.                                 // drop through and let it cleanup below...
  851.                             }
  852.                         }
  853.                         else
  854.                         {
  855.                             MiDebugMsg((hr, "Client %d Initialize() retuned error ", dwClient));
  856.                         }                                                                      
  857.                     }
  858.                     else
  859.                     {
  860.                         MiDebugMsg((hr, "Client %d %s returned error ", dwClient, szGUID));
  861.                     }
  862.                 }
  863. #ifdef DEBUG
  864.                 else
  865.                 {
  866.                     MessageBox(NULL, szVolCacheClient, TEXT("ERROR Opening GUID key"), MB_OK);
  867.                 }                
  868. #endif
  869.             }
  870. #ifdef DEBUG
  871.             else
  872.             {
  873.                 MessageBox(NULL, szVolCacheClient, TEXT("ERROR Opening the client key"), MB_OK);
  874.             }
  875. #endif
  876.             if ( bCleanup )
  877.             {
  878.                 deactivateSingleClient(&(pClientInfo[dwClient]));
  879.                 ZeroMemory( &(pClientInfo[dwClient]), sizeof( CLIENTINFO ));
  880.             }
  881.             else
  882.             {
  883.                 dwClient ++;
  884.             }
  885.             iSubKey++;        
  886.         }
  887.         iNumVolumeCacheClients = dwClient;
  888.     }
  889. #ifdef DEBUG
  890.     else
  891.     {
  892.         MessageBox(NULL, TEXT("ERROR Opening up Volume Cache key"), TEXT("CLEANMGR DEBUG"), MB_OK);
  893.     }
  894. #endif
  895.     RegCloseKey(hKeyVolCache);
  896.     return bRet;
  897. }
  898. /*
  899. **------------------------------------------------------------------------------
  900. ** CleanupMgrInfo::deactivateClients
  901. **
  902. ** Purpose:    Initializes all of the Volume Cache Clients
  903. ** Mod Log:    Created by Jason Cobb (2/97)
  904. **------------------------------------------------------------------------------
  905. */
  906. void 
  907. CleanupMgrInfo::deactivateClients(void)
  908. {
  909.     int     i;
  910.     
  911.     for (i=0; i<iNumVolumeCacheClients; i++)
  912.     {
  913.         deactivateSingleClient(&(pClientInfo[i]));
  914.     }
  915.     //
  916.     //Free the pClientInfo array
  917.     //
  918.     if (pClientInfo)
  919.     {
  920.         MiDebugMsg((0, "LocalFree() on ClientInfo structure"));
  921.         LocalFree( pClientInfo);
  922.     }
  923. }
  924. /*
  925. **------------------------------------------------------------------------------
  926. ** CleanupMgrInfo::deactivateSingleClient
  927. **
  928. ** Purpose:    Deactivate's the given client and closes its registry key
  929. ** Mod Log:    Created by Jason Cobb (2/97)
  930. **------------------------------------------------------------------------------
  931. */
  932. void 
  933. CleanupMgrInfo::deactivateSingleClient(PCLIENTINFO pSingleClientInfo)
  934. {
  935.     DWORD   dwDeactivateFlags;
  936.     TCHAR   szProfile[64];
  937.     
  938.     if (pSingleClientInfo->pVolumeCache != NULL)
  939.     {
  940.         //
  941.         //Call the clients Deactivate function
  942.         //
  943.         dwDeactivateFlags = 0;
  944.         pSingleClientInfo->pVolumeCache->Deactivate(&dwDeactivateFlags);
  945.         //
  946.         //Release the client
  947.         //
  948.         pSingleClientInfo->pVolumeCache->Release();
  949.         pSingleClientInfo->pVolumeCache = NULL;
  950.     }
  951.             
  952.     if (pSingleClientInfo->hClientKey != 0)
  953.     {
  954.         DWORD   dwState, cb, dwType, dwSelectedFlag;
  955.         if (dwUIFlags & FLAG_SAVE_STATE)
  956.         {
  957.             //
  958.             //Save the state flags
  959.             //
  960.             if (dwUIFlags & FLAG_SAGESET)
  961.             {
  962.                 dwSelectedFlag = STATE_SAGE_SELECTED;
  963.                 wsprintf(szProfile, TEXT("%s%04d"), SZ_STATE, ulSAGEProfile);
  964.             }
  965.             else
  966.             {
  967.                 dwSelectedFlag = STATE_SELECTED;
  968.                 lstrcpy(szProfile, SZ_STATE);
  969.             }
  970.             dwState = 0;
  971.             cb = sizeof(dwState);
  972.             dwType = REG_DWORD;
  973.             RegQueryValueEx(pSingleClientInfo->hClientKey, szProfile, NULL,
  974.                 &dwType, (LPBYTE)&dwState, &cb);
  975.             if (pSingleClientInfo->bSelected)
  976.                 dwState |= dwSelectedFlag;
  977.             else
  978.                 dwState &= ~dwSelectedFlag;
  979.             RegSetValueEx(pSingleClientInfo->hClientKey, szProfile, 0, REG_DWORD,
  980.                 (LPBYTE)&dwState, sizeof(dwState));
  981.         }
  982.     
  983.         //
  984.         //Close all of the registry keys
  985.         //
  986.         RegCloseKey(pSingleClientInfo->hClientKey);
  987.         //
  988.         //Should we remove this entry from the registry?
  989.         //
  990.         if (dwDeactivateFlags & EVCF_REMOVEFROMLIST && pSingleClientInfo->bSelected)
  991.         {
  992.             HKEY    hKeyVolCache;
  993.             
  994.             if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGSTR_PATH_VOLUMECACHE, 0, KEY_ALL_ACCESS, &hKeyVolCache) == ERROR_SUCCESS)
  995.             {
  996.                 SHDeleteKey(hKeyVolCache, pSingleClientInfo->szRegKeyName);
  997.                 RegCloseKey(hKeyVolCache);
  998.             }
  999.         }            
  1000.             
  1001.     }
  1002.     //
  1003.     //Free the DisplayName and Description memory
  1004.     //
  1005.     if (pSingleClientInfo->wcsDisplayName)
  1006.         CoTaskMemFree(pSingleClientInfo->wcsDisplayName);
  1007.         
  1008.     if (pSingleClientInfo->wcsDescription)
  1009.         CoTaskMemFree(pSingleClientInfo->wcsDescription);
  1010. }
  1011. /*
  1012. **------------------------------------------------------------------------------
  1013. ** CleanupMgrInfo::getSpaceUsedByClients
  1014. **
  1015. ** Purpose:    Calls the IEmptyVolumeCache->GetSpaceUsed interface for each client
  1016. **             to determine the total amount of cache space.  This function is
  1017. **             called on a secondary thread because it can take quite a long time.
  1018. ** Mod Log:    Created by Jason Cobb (2/97)
  1019. **------------------------------------------------------------------------------
  1020. */
  1021. BOOL
  1022. CleanupMgrInfo::getSpaceUsedByClients(void)
  1023. {
  1024.     int         i;
  1025.     HRESULT     hr;
  1026.     BOOL        bRet = TRUE;
  1027.     TCHAR       szDisplayName[256];
  1028.         
  1029.     cbEstCleanupSpace.QuadPart = 0;
  1030.     bAbortScan = FALSE;
  1031.     hAbortScanEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  1032.     // BUGBUG: Make sure the window created in the ScanAbortThread thread is visible before
  1033.     // the hAbortScanEvent event is signaled
  1034.     hAbortScanThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)ScanAbortThread,
  1035.         (LPVOID)this, 0, &dwAbortScanThreadID);
  1036.     //
  1037.     //Wait until the Abort Scan window is created
  1038.     //
  1039.     WaitForSingleObject(hAbortScanEvent, INFINITE);
  1040.     CloseHandle(hAbortScanEvent);
  1041.     volumeCacheCallBack->SetCleanupMgrInfo((PVOID)this);
  1042.     for (i=0; i<iNumVolumeCacheClients; i++)
  1043.     {
  1044.         //
  1045.         //Update the progress UI
  1046.         //
  1047.         szDisplayName[0] = '';
  1048.         
  1049. #ifdef UNICODE
  1050.         StrCpyN( szDisplayName, pClientInfo[i].wcsDisplayName, ARRAYSIZE( szDisplayName ));
  1051. #else
  1052.         WideCharToMultiByte(CP_ACP, 0, pClientInfo[i].wcsDisplayName, -1, szDisplayName, ARRAYSIZE(szDisplayName), NULL, NULL);
  1053. #endif
  1054.         
  1055.         PostMessage(hAbortScanWnd, WMAPP_UPDATEPROGRESS, (WPARAM)i, (LPARAM)szDisplayName);
  1056.         //
  1057.         //Query the client for the ammount of cache disk space that it could
  1058.         //possible free.
  1059.         //
  1060.         if (pClientInfo[i].pVolumeCache != NULL)
  1061.         {
  1062.             volumeCacheCallBack->SetCurrentClient((PVOID)&(pClientInfo[i]));
  1063.             hr = pClientInfo[i].pVolumeCache->GetSpaceUsed(&(pClientInfo[i].dwUsedSpace.QuadPart), 
  1064.                                                                     pIEmptyVolumeCacheCallBack);      
  1065.             
  1066.             if (FAILED(hr))
  1067.             {
  1068.                 dwReturnCode = RETURN_CLEANER_FAILED;
  1069.                 MiDebugMsg((hr, "Client %d GetSpaceUsed failed with error ", i));
  1070.             }
  1071.             
  1072.             MiDebugMsg((0, "Client %d has %d disk space it can free", i,
  1073.                 pClientInfo[i].dwUsedSpace.QuadPart));
  1074.         }
  1075.         //
  1076.         //See if this cleaner wants to be hidden if it has no space to free
  1077.         //
  1078.         if ((pClientInfo[i].dwUsedSpace.QuadPart == 0) &&
  1079.             (pClientInfo[i].dwInitializeFlags & EVCF_DONTSHOWIFZERO))
  1080.         {
  1081.             MiDebugMsg((0, "Not showing client %d because it has no space to free", i));
  1082.             pClientInfo[i].bShow = FALSE;
  1083.         }
  1084.         cbEstCleanupSpace.QuadPart += pClientInfo[i].dwUsedSpace.QuadPart;
  1085.         //
  1086.         //Did the user abort?
  1087.         //
  1088.         if (bAbortScan == TRUE)
  1089.         {
  1090.             dwReturnCode = RETURN_USER_CANCELED_SCAN;
  1091.             bRet = FALSE;
  1092.             break;
  1093.         }
  1094.     }
  1095.     // the dismissal of the progress dialog is now delayed until the propsheet comes up..
  1096.     return bRet;
  1097. }
  1098. /*
  1099. **------------------------------------------------------------------------------
  1100. ** CleanupMgrInfo::calculateSpaceToPurge
  1101. **
  1102. ** Purpose:    Calculates the amount of space that is going to be purged
  1103. **             by adding up all of the selected clients.  It also calculates
  1104. **             the progress bar divisor number.  This is needed because a
  1105. **             progress bar has a MAX of 0xFFFF.
  1106. **
  1107. ** Mod Log:    Created by Jason Cobb (6/97)
  1108. **------------------------------------------------------------------------------
  1109. */
  1110. void
  1111. CleanupMgrInfo::calculateSpaceToPurge(void)
  1112. {
  1113.     int i;
  1114.     
  1115.     cbSpaceToPurge.QuadPart = 0;
  1116.     for (i=0; i<iNumVolumeCacheClients; i++)
  1117.     {
  1118.         //
  1119.         //If this client is not selected or we are not showing it then don't purge it
  1120.         //
  1121.         if (pClientInfo[i].bShow == FALSE || pClientInfo[i].bSelected == FALSE)
  1122.             continue;
  1123.     
  1124.         cbSpaceToPurge.QuadPart += pClientInfo[i].dwUsedSpace.QuadPart;
  1125.     }
  1126.     cbProgressDivider.QuadPart = (cbSpaceToPurge.QuadPart / PROGRESS_DIVISOR) + 1;
  1127. }
  1128. /*
  1129. **------------------------------------------------------------------------------
  1130. ** CleanupMgrInfo::purgeClients
  1131. **
  1132. ** Purpose:    Calls the IEmptyVolumeCache->Purge interface for each client
  1133. **             to have the client cleaner object start removeing their files
  1134. ** Mod Log:    Created by Jason Cobb (2/97)
  1135. **------------------------------------------------------------------------------
  1136. */
  1137. BOOL
  1138. CleanupMgrInfo::purgeClients(void)
  1139. {
  1140.     int         i;
  1141.     HRESULT     hr;
  1142.     BOOL        bRet = TRUE;
  1143.     TCHAR       szDisplayName[256];
  1144.         
  1145.     cbTotalPurgedSoFar.QuadPart = 0;
  1146.     bAbortPurge = FALSE;
  1147.     //
  1148.     //Calculate the amount of space that will be purged.
  1149.     //
  1150.     calculateSpaceToPurge();
  1151.     MiDebugMsg((0, "Total number of bytes to delete is %d", cbSpaceToPurge.LowPart));
  1152.     hAbortPurgeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  1153.     // BUGBUG:  Make sure the window created in PurgeAbortThread is visible before
  1154.     // the hAbortPurgeEvent is signaled
  1155.     hAbortPurgeThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PurgeAbortThread,
  1156.         (LPVOID)this, 0, &dwAbortPurgeThreadID);
  1157.     //
  1158.     //Wait until the Abort Purge window is created
  1159.     //
  1160.     WaitForSingleObject(hAbortPurgeEvent, INFINITE);
  1161.     CloseHandle(hAbortPurgeEvent);
  1162.     volumeCacheCallBack->SetCleanupMgrInfo((PVOID)this);
  1163.     for (i=0; i<iNumVolumeCacheClients; i++)
  1164.     {
  1165.         //
  1166.         //If this client is not selected or we are not showing it then don't purge it
  1167.         //
  1168.         if (pClientInfo[i].bShow == FALSE || pClientInfo[i].bSelected == FALSE)
  1169.             continue;
  1170.     
  1171. #ifdef UNICODE
  1172.         StrCpyN( szDisplayName, pClientInfo[i].wcsDisplayName, ARRAYSIZE( szDisplayName ));
  1173. #else
  1174.         //
  1175.         //Convert UNICODE display name to ANSI and then add it to the list
  1176.         //
  1177.         WideCharToMultiByte(CP_ACP, 0, pClientInfo[i].wcsDisplayName, -1, szDisplayName, sizeof(szDisplayName), NULL, NULL);
  1178. #endif
  1179.         PostMessage(hAbortPurgeWnd, WMAPP_UPDATESTATUS, 0, (LPARAM)szDisplayName);
  1180.         cbCurrentClientPurgedSoFar.QuadPart = 0;
  1181.         //
  1182.         //Query the client for the ammount of cache disk space that it could
  1183.         //possible free.
  1184.         //
  1185.         if (pClientInfo[i].pVolumeCache != NULL)
  1186.         {
  1187.             volumeCacheCallBack->SetCurrentClient((PVOID)&(pClientInfo[i]));
  1188.             hr = pClientInfo[i].pVolumeCache->Purge(pClientInfo[i].dwUsedSpace.QuadPart, pIEmptyVolumeCacheCallBack);
  1189.             
  1190.             if (FAILED(hr))
  1191.             {
  1192.                 dwReturnCode = RETURN_CLEANER_FAILED;
  1193.                 MiDebugMsg((hr, "Client %d Purge failed with error ", i));
  1194.             }
  1195.         }
  1196.         cbTotalPurgedSoFar.QuadPart += pClientInfo[i].dwUsedSpace.QuadPart;
  1197.         cbCurrentClientPurgedSoFar.QuadPart = 0;
  1198.         //
  1199.         //Update the progress bar
  1200.         //
  1201.         PostMessage(hAbortPurgeWnd, WMAPP_UPDATEPROGRESS, 0, 0);
  1202.         //
  1203.         //Did the user abort?
  1204.         //
  1205.         if (bAbortPurge == TRUE)
  1206.         {
  1207.             dwReturnCode = RETURN_USER_CANCELED_PURGE;
  1208.             bRet = FALSE;
  1209.             break;
  1210.         }
  1211.         Sleep(1000);
  1212.     }
  1213.     if (!bAbortPurge)
  1214.     {
  1215.         bAbortPurge = TRUE;
  1216.         //
  1217.         //Wait for Purge thread to finish
  1218.         //  
  1219.         WaitForSingleObject(hAbortPurgeThread, INFINITE);
  1220.         bAbortPurge = FALSE;
  1221.     }
  1222.     return bRet;
  1223. }
  1224. /*
  1225. **------------------------------------------------------------------------------
  1226. ** GetClientIcon
  1227. **
  1228. ** Purpose:    Gets the Icon for this client.  
  1229. **             The icon will be inferred using the standard OLE mechanism
  1230. **             under HKCRCLSID{clsid}DefaultIcon (with the default value
  1231. **             for this being the <Module Path>, <icon index>).
  1232. **             If no icon is specified the standard windows icon will be used.
  1233. ** Mod Log:    Created by Jason Cobb (2/97)
  1234. **------------------------------------------------------------------------------
  1235. */
  1236. HICON
  1237. CleanupMgrInfo::GetClientIcon(
  1238.     LPTSTR  lpGUID,
  1239.     BOOL    fIconPath
  1240.     )
  1241. {
  1242.     HKEY    hk;
  1243.     HICON   hIconLarge, hIconSmall;
  1244.     HICON   hIcon = NULL;
  1245.     TCHAR   szIconKey[MAX_PATH];
  1246.     TCHAR   szDefaultIcon[MAX_PATH];
  1247.     DWORD   dwType, cbBytes;
  1248.     TCHAR   szIconExeName[MAX_PATH];
  1249.     int     i, iIconIndex;
  1250.     if ( fIconPath )
  1251.     {
  1252.         StrCpy( szDefaultIcon, lpGUID );
  1253.     }
  1254.     if ( !fIconPath )
  1255.     {
  1256.         wsprintf(szIconKey, SZ_DEFAULTICONPATH, lpGUID);
  1257.         if (RegOpenKey(HKEY_CLASSES_ROOT, szIconKey, &hk) == ERROR_SUCCESS)
  1258.         {
  1259.             dwType = REG_SZ;
  1260.             cbBytes = sizeof(szDefaultIcon);
  1261.             if (RegQueryValueEx(hk, NULL, NULL, &dwType, (LPBYTE)szDefaultIcon, &cbBytes) == ERROR_SUCCESS)
  1262.             {
  1263.                 fIconPath = TRUE;
  1264.             }
  1265.             RegCloseKey(hk);
  1266.         }
  1267.     }
  1268.     if (fIconPath)
  1269.     {
  1270.         //
  1271.         //Parse out the exe where the icon lives
  1272.         //
  1273.         for(i=0; i<lstrlen(szDefaultIcon); i++)
  1274.         {
  1275.             if (szDefaultIcon[i] == ',')
  1276.                 break;
  1277.             szIconExeName[i] = szDefaultIcon[i];
  1278.         }
  1279.         szIconExeName[i] = '';
  1280.         //
  1281.         //Parse out the icon index
  1282.         //
  1283.         i++;
  1284.         iIconIndex = StrToInt(&(szDefaultIcon[i]));
  1285.         ExtractIconEx(szIconExeName, iIconIndex, (HICON FAR *)&hIconLarge, (HICON FAR *)&hIconSmall, 1);
  1286.         if (hIconSmall)
  1287.             hIcon = hIconSmall;
  1288.         else
  1289.             hIcon = hIconLarge;
  1290.     }
  1291.     
  1292.     if (hIcon == NULL)
  1293.     {
  1294.         if ((hIcon = LoadIcon(CleanupMgrInfo::hInstance, MAKEINTRESOURCE(ICON_GENERIC))) == NULL)
  1295.         {
  1296.             MiDebugMsg((0, "LoadIcon failed with error %d", GetLastError()));
  1297.         }   
  1298.     }
  1299.     
  1300.     return hIcon;
  1301. }
  1302. INT_PTR CALLBACK
  1303. ScanAbortDlgProc(
  1304.     HWND hDlg,
  1305.     UINT Message,
  1306.     WPARAM wParam,
  1307.     LPARAM lParam
  1308.     )
  1309. {
  1310.     CleanupMgrInfo *pcmi;
  1311.     switch(Message)
  1312.     {
  1313.         case WM_INITDIALOG:
  1314.             SetWindowLongPtr (hDlg, DWLP_USER, 0L);
  1315.             //   
  1316.             //Get the CleanupMgrInfo
  1317.             //
  1318.             pcmi = (CleanupMgrInfo *)lParam;    
  1319.             if (pcmi == NULL)
  1320.             {   
  1321.                 //Error - passed in invalid CleanupMgrInfo info
  1322.                 return FALSE;
  1323.             }       
  1324.             //
  1325.             //Save pointer to CleanupMgrInfo object
  1326.             //
  1327.             SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  1328.             TCHAR * psz;
  1329.             psz = SHFormatMessage( MSG_SCAN_ABORT_TEXT, pcmi->szVolName, pcmi->szRoot[0] );
  1330.             SetDlgItemText (hDlg, IDC_ABORT_TEXT, psz);
  1331.             LocalFree(psz);
  1332.             //
  1333.             //Set the limits on the progress bar
  1334.             //
  1335.             SendDlgItemMessage(hDlg, IDC_ABORT_SCAN_PROGRESS, PBM_SETRANGE,
  1336.                 0, MAKELPARAM(0, pcmi->iNumVolumeCacheClients));
  1337.             PulseEvent(pcmi->hAbortScanEvent);
  1338.             break;
  1339.         case WMAPP_UPDATEPROGRESS:
  1340.             if (lParam != NULL)
  1341.                 SetDlgItemText(hDlg, IDC_SCAN_STATUS_TEXT, (LPTSTR)lParam);
  1342.             else
  1343.                 SetDlgItemText(hDlg, IDC_SCAN_STATUS_TEXT, TEXT(""));
  1344.                 
  1345.             SendDlgItemMessage(hDlg, IDC_ABORT_SCAN_PROGRESS, PBM_SETPOS,
  1346.                 (WPARAM)wParam, 0);
  1347.             break;
  1348.         case WM_CLOSE:
  1349.         case WM_COMMAND:
  1350.             pcmi = (CleanupMgrInfo *)GetWindowLongPtr (hDlg, DWLP_USER);
  1351.             if (pcmi != NULL)
  1352.                 pcmi->bAbortScan = TRUE;
  1353.             break;
  1354.         default:
  1355.             return FALSE;
  1356.     }
  1357.     return TRUE;
  1358. }
  1359. BOOL
  1360. PASCAL
  1361. MessagePump(
  1362.     HWND hDialogWnd
  1363.     )
  1364. {
  1365.     MSG Msg;
  1366.     BOOL fGotMessage;
  1367.     if ((fGotMessage = PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))) 
  1368.     {
  1369.         if (!IsDialogMessage(hDialogWnd, &Msg)) 
  1370.         {
  1371.             TranslateMessage(&Msg);
  1372.             DispatchMessage(&Msg);
  1373.         }
  1374.     }
  1375.     return fGotMessage;
  1376. }
  1377. void
  1378. ScanAbortThread(
  1379.     CleanupMgrInfo *pcmi
  1380.     )
  1381. {
  1382.     if ((pcmi->hAbortScanWnd = CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_SCAN_ABORT),
  1383.         NULL, ScanAbortDlgProc, (LPARAM)pcmi)) == NULL)
  1384.     {
  1385.         return;
  1386.     }   
  1387.     ShowWindow(pcmi->hAbortScanWnd, SW_SHOW);
  1388.     //
  1389.     //Keep spinning till the Scan is stopped
  1390.     //
  1391.     while (!(pcmi->bAbortScan))
  1392.     {
  1393.         MessagePump(pcmi->hAbortScanWnd);
  1394.     }
  1395.     //
  1396.     //Destroy the Abort Scan dialog
  1397.     //
  1398.     if (pcmi->hAbortScanWnd != NULL)
  1399.     {
  1400.         DestroyWindow(pcmi->hAbortScanWnd);
  1401.         pcmi->hAbortScanWnd = NULL;
  1402.     }
  1403. }
  1404. INT_PTR CALLBACK
  1405. PurgeAbortDlgProc(
  1406.     HWND hDlg,
  1407.     UINT Message,
  1408.     WPARAM wParam,
  1409.     LPARAM lParam
  1410.     )
  1411. {
  1412.     CleanupMgrInfo  *pcmi;
  1413.     DWORD           dwCurrent;
  1414.     switch(Message)
  1415.     {
  1416.         case WM_INITDIALOG:
  1417.             SetWindowLongPtr (hDlg, DWLP_USER, 0L);
  1418.             //   
  1419.             //Get the CleanupMgrInfo
  1420.             //
  1421.             pcmi = (CleanupMgrInfo *)lParam;    
  1422.             if (pcmi == NULL)
  1423.             {   
  1424.                 //Error - passed in invalid CleanupMgrInfo info
  1425.                 return FALSE;
  1426.             }       
  1427.             //
  1428.             //Save pointer to CleanupMgrInfo object
  1429.             //
  1430.             SetWindowLongPtr(hDlg, DWLP_USER, lParam);
  1431.             TCHAR * psz;
  1432.             psz = SHFormatMessage( MSG_PURGE_ABORT_TEXT, pcmi->szVolName, pcmi->szRoot[0]);
  1433.             SetDlgItemText (hDlg, IDC_PURGE_TEXT, psz);
  1434.             LocalFree(psz);
  1435.             //
  1436.             //Set the limits on the progress bar
  1437.             //
  1438.             if (pcmi->cbProgressDivider.QuadPart != 0)
  1439.                 dwCurrent = (DWORD)(pcmi->cbSpaceToPurge.QuadPart / pcmi->cbProgressDivider.QuadPart);
  1440.             else
  1441.                 dwCurrent = (DWORD)(pcmi->cbSpaceToPurge.QuadPart);
  1442.             SendDlgItemMessage(hDlg, IDC_ABORT_PURGE_PROGRESS, PBM_SETRANGE,
  1443.                 0, MAKELPARAM(0, dwCurrent));
  1444.             PulseEvent(pcmi->hAbortPurgeEvent);
  1445.             break;
  1446.         case WMAPP_UPDATESTATUS:
  1447.             if (lParam != NULL)
  1448.                 SetDlgItemText(hDlg, IDC_PURGE_STATUS_TEXT, (LPTSTR)lParam);
  1449.             else
  1450.                 SetDlgItemText(hDlg, IDC_PURGE_STATUS_TEXT, TEXT(""));
  1451.             break;
  1452.         case WMAPP_UPDATEPROGRESS:
  1453.             pcmi = (CleanupMgrInfo *)GetWindowLongPtr (hDlg, DWLP_USER);
  1454.             if (pcmi != NULL)
  1455.             {
  1456.                 //
  1457.                 //BUGBUG:
  1458.                 //
  1459.                 if (pcmi->cbProgressDivider.QuadPart != 0)
  1460.                     dwCurrent = (DWORD)((pcmi->cbTotalPurgedSoFar.QuadPart +
  1461.                         pcmi->cbCurrentClientPurgedSoFar.QuadPart) /
  1462.                         pcmi->cbProgressDivider.QuadPart);
  1463.                 else
  1464.                     dwCurrent = (DWORD)(pcmi->cbTotalPurgedSoFar.QuadPart +
  1465.                         pcmi->cbCurrentClientPurgedSoFar.QuadPart);
  1466.                 SendDlgItemMessage(hDlg, IDC_ABORT_PURGE_PROGRESS, PBM_SETPOS,
  1467.                     (WPARAM)dwCurrent, 0);
  1468.             }
  1469.             break;
  1470.         case WM_CLOSE:
  1471.         case WM_COMMAND:
  1472.             pcmi = (CleanupMgrInfo *)GetWindowLongPtr (hDlg, DWLP_USER);
  1473.             if (pcmi != NULL)
  1474.                 pcmi->bAbortPurge = TRUE;
  1475.             break;
  1476.         default:
  1477.             return FALSE;
  1478.     }
  1479.     return TRUE;
  1480. }
  1481. void
  1482. PurgeAbortThread(
  1483.     CleanupMgrInfo *pcmi
  1484.     )
  1485. {
  1486.     if ((pcmi->hAbortPurgeWnd = CreateDialogParam(g_hInstance, MAKEINTRESOURCE(IDD_PURGE_ABORT),
  1487.         NULL, PurgeAbortDlgProc, (LPARAM)pcmi)) == NULL)
  1488.     {
  1489.         return;
  1490.     }   
  1491.     ShowWindow(pcmi->hAbortPurgeWnd, SW_SHOW);
  1492.     //
  1493.     //Keep spinning till the Purge is stopped
  1494.     //
  1495.     while (!(pcmi->bAbortPurge))
  1496.     {
  1497.         MessagePump(pcmi->hAbortPurgeWnd);
  1498.     }
  1499.     //
  1500.     //Destroy the Abort Purge dialog
  1501.     //
  1502.     if (pcmi->hAbortPurgeWnd != NULL)
  1503.     {
  1504.         DestroyWindow(pcmi->hAbortPurgeWnd);
  1505.         pcmi->hAbortPurgeWnd = NULL;
  1506.     }
  1507. }
  1508. /*
  1509. **------------------------------------------------------------------------------
  1510. ** End of File
  1511. **------------------------------------------------------------------------------
  1512. */