Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1743 lines
61 KiB

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