Leaked source code of windows server 2003
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.

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