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.

612 lines
18 KiB

  1. //////////////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // EmptyVolumeCache.cpp
  4. //
  5. // Copyright (C) 1998, 1999 Microsoft Corporation. All rights reserved.
  6. //
  7. // Abstract :
  8. //
  9. // This is the implementation of IEmptyVolumeCache
  10. //
  11. // History :
  12. //
  13. // 10/12/1999 jchauvin/luish Created
  14. //
  15. //////////////////////////////////////////////////////////////////////////////////////////////
  16. #include <assert.h>
  17. #include "AppMan.h"
  18. #include "AppManAdmin.h"
  19. #include "emptyvc.h"
  20. #include "resource.h"
  21. #include "ApplicationManager.h"
  22. #include "AppManDebug.h"
  23. #include "ExceptionHandler.h"
  24. #include "ExceptionHandler.h"
  25. #include "Lock.h"
  26. #include "StructIdentifiers.h"
  27. #include "Global.h"
  28. #include "RegistryKey.h"
  29. #ifdef DBG_MODULE
  30. #undef DBG_MODULE
  31. #endif
  32. #define DBG_MODULE DBG_EMPTYVOLUMECACHE
  33. //////////////////////////////////////////////////////////////////////////////////////////////
  34. //
  35. //////////////////////////////////////////////////////////////////////////////////////////////
  36. CEmptyVolumeCache::CEmptyVolumeCache(void)
  37. {
  38. FUNCTION("CEmptyVolumeCache::CEmptyVolumeCache (void)");
  39. }
  40. //////////////////////////////////////////////////////////////////////////////////////////////
  41. //
  42. //////////////////////////////////////////////////////////////////////////////////////////////
  43. CEmptyVolumeCache::CEmptyVolumeCache(CApplicationManagerRoot * lpParent)
  44. {
  45. FUNCTION("CEmptyVolumeCache::CEmptyVolumeCache (CApplicationManagerRoot *pParent)");
  46. HRESULT hResult = S_OK;
  47. ///////////////////////////////////////////////////////////////////////////////////////
  48. try
  49. {
  50. assert(NULL != lpParent);
  51. m_lpoParentObject = lpParent;
  52. m_oInformationManager.Initialize();
  53. }
  54. ///////////////////////////////////////////////////////////////////////////////////////
  55. catch(CAppManExceptionHandler * pException)
  56. {
  57. hResult = pException->GetResultCode();
  58. delete pException;
  59. }
  60. catch(...)
  61. {
  62. hResult = E_UNEXPECTED;
  63. }
  64. ///////////////////////////////////////////////////////////////////////////////////////
  65. }
  66. //////////////////////////////////////////////////////////////////////////////////////////////
  67. //
  68. //////////////////////////////////////////////////////////////////////////////////////////////
  69. CEmptyVolumeCache::~CEmptyVolumeCache(void)
  70. {
  71. FUNCTION("CEmptyVolumeCache::~CEmptyVolumeCache (void)");
  72. }
  73. //////////////////////////////////////////////////////////////////////////////////////////////
  74. //
  75. //////////////////////////////////////////////////////////////////////////////////////////////
  76. STDMETHODIMP CEmptyVolumeCache::QueryInterface(REFIID RefIID, LPVOID * lppVoidObject)
  77. {
  78. FUNCTION("CEmptyVolumeCache::QueryInterface (REFIID RefIID, LPVOID * lppVoidObject)");
  79. if (NULL == m_lpoParentObject)
  80. {
  81. return E_NOINTERFACE;
  82. }
  83. return m_lpoParentObject->QueryInterface(RefIID, lppVoidObject);
  84. }
  85. //////////////////////////////////////////////////////////////////////////////////////////////
  86. //
  87. //////////////////////////////////////////////////////////////////////////////////////////////
  88. STDMETHODIMP_(ULONG) CEmptyVolumeCache::AddRef(void)
  89. {
  90. FUNCTION("CEmptyVolumeCache::AddRef (void)");
  91. if (NULL != m_lpoParentObject)
  92. {
  93. return m_lpoParentObject->AddRef();
  94. }
  95. return 0;
  96. }
  97. //////////////////////////////////////////////////////////////////////////////////////////////
  98. //
  99. //////////////////////////////////////////////////////////////////////////////////////////////
  100. STDMETHODIMP_(ULONG) CEmptyVolumeCache::Release(void)
  101. {
  102. FUNCTION("CEmptyVolumeCache::Release (void)");
  103. if (NULL != m_lpoParentObject)
  104. {
  105. return m_lpoParentObject->Release();
  106. }
  107. return 0;
  108. }
  109. //////////////////////////////////////////////////////////////////////////////////////////////
  110. //
  111. //////////////////////////////////////////////////////////////////////////////////////////////
  112. STDMETHODIMP CEmptyVolumeCache::Initialize(HKEY /*hRegKey*/, LPCWSTR lpwszVolume, LPWSTR * lppwszDisplayName, LPWSTR * lppwszDescription, DWORD * lpdwFlags)
  113. {
  114. FUNCTION("CEmptyVolumeCache::Initialize (HKEY hRegKey, LPCWSTR lpwszVolume, LPWSTR * lppwszDisplayName, LPWSTR * lppwszDescription, DWORD * lpdwFlags)");
  115. HRESULT hResult = S_OK;
  116. ///////////////////////////////////////////////////////////////////////////////////////
  117. try
  118. {
  119. CRegistryKey oRegistryKey;
  120. DWORD dwSize;
  121. DWORD dwType;
  122. CHAR cBuffer[20];
  123. //
  124. // Now Get Day Threshold from Registry
  125. //
  126. oRegistryKey.OpenKey(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\VolumeCaches\\Delete Game Manager Files", KEY_READ);
  127. dwSize = sizeof(cBuffer);
  128. hResult = oRegistryKey.GetValue("DiskCleanerDayThreshold", &dwType, (LPBYTE) cBuffer, &dwSize);
  129. m_dwDiskCleanerDayThreshold = *((LPDWORD) cBuffer);
  130. //
  131. // Check to make sure sub key exists and correct type and size, else use default
  132. //
  133. if (FAILED(hResult)||(dwType != REG_DWORD)||(dwSize != sizeof(DWORD)))
  134. {
  135. m_dwDiskCleanerDayThreshold = DISKCLEANER_DAY_THRESHOLD;
  136. }
  137. //
  138. // Now convert Day Threshold into String
  139. //
  140. _ltow(m_dwDiskCleanerDayThreshold, m_wszDiskCleanerDayTH, 10);
  141. //
  142. // Break Strings into several parts for easier localization, and because string table is
  143. // limited to 1024 per string
  144. //
  145. GetResourceStringW(IDS_DISKCLEANERNAME1, m_wszDiskCleanerName, sizeof(m_wszDiskCleanerName));
  146. GetResourceStringW(IDS_DISKCLEANERNAME2, m_wszDiskCleanerName2, sizeof(m_wszDiskCleanerName2));
  147. wcscat(m_wszDiskCleanerName,m_wszDiskCleanerDayTH); //Append Day Threshold
  148. wcscat(m_wszDiskCleanerName,m_wszDiskCleanerName2); //Append Rest of String;
  149. GetResourceStringW(IDS_DISKCLEANERDESC1, m_wszDiskCleanerDesc, sizeof(m_wszDiskCleanerDesc));
  150. GetResourceStringW(IDS_DISKCLEANERDESC2, m_wszDiskCleanerDesc2, sizeof(m_wszDiskCleanerDesc2));
  151. wcscat(m_wszDiskCleanerDesc,m_wszDiskCleanerDayTH); //Append Day Threshold
  152. wcscat(m_wszDiskCleanerDesc,m_wszDiskCleanerDesc2); //Append Rest of String;
  153. *lppwszDisplayName = (LPWSTR) m_wszDiskCleanerName;
  154. *lppwszDescription = (LPWSTR) m_wszDiskCleanerDesc;
  155. //
  156. // Set Volume number and make sure we are not enabled by default.
  157. //
  158. m_dwVolume = VolumeStringToNumber(lpwszVolume);
  159. //
  160. // *pdwFlags = EVCF_DONTSHOWIFZERO | EVCF_ENABLEBYDEFAULT | EVCF_ENABLEBYDEFAULT_AUTO;
  161. //
  162. *lpdwFlags = EVCF_DONTSHOWIFZERO;
  163. }
  164. ///////////////////////////////////////////////////////////////////////////////////////
  165. catch(CAppManExceptionHandler * pException)
  166. {
  167. hResult = pException->GetResultCode();
  168. delete pException;
  169. }
  170. catch(...)
  171. {
  172. hResult = E_UNEXPECTED;
  173. }
  174. ///////////////////////////////////////////////////////////////////////////////////////
  175. return hResult;
  176. }
  177. //////////////////////////////////////////////////////////////////////////////////////////////
  178. //
  179. //////////////////////////////////////////////////////////////////////////////////////////////
  180. STDMETHODIMP CEmptyVolumeCache::GetSpaceUsed(DWORDLONG * lpdwSpaceUsed, IEmptyVolumeCacheCallBack * lpCallBack)
  181. {
  182. FUNCTION("CEmptyVolumeCache::GetSpaceUsed(DWORDLONG * lpdwSpaceUsed, IEmptyVolumeCacheCallBack * lpCallBack)");
  183. HRESULT hResult = S_OK;
  184. try
  185. {
  186. DWORD dwKilobytes;
  187. DWORDLONG dwlSpaceUtilization;
  188. GetSpaceUtilization(m_dwVolume, m_dwDiskCleanerDayThreshold, (LPDWORD) &dwKilobytes, lpCallBack);
  189. dwlSpaceUtilization = (DWORDLONG)(dwKilobytes)*(DWORDLONG)1024;
  190. (*lpdwSpaceUsed) = dwlSpaceUtilization;
  191. }
  192. ///////////////////////////////////////////////////////////////////////////////////////
  193. catch(CAppManExceptionHandler * pException)
  194. {
  195. hResult = pException->GetResultCode();
  196. delete pException;
  197. }
  198. catch(...)
  199. {
  200. hResult = E_UNEXPECTED;
  201. }
  202. ///////////////////////////////////////////////////////////////////////////////////////
  203. return hResult;
  204. }
  205. //////////////////////////////////////////////////////////////////////////////////////////////
  206. //
  207. //////////////////////////////////////////////////////////////////////////////////////////////
  208. STDMETHODIMP CEmptyVolumeCache::Purge(DWORDLONG dwSpaceToFree, IEmptyVolumeCacheCallBack * lpCallBack)
  209. {
  210. FUNCTION("CEmptyVolumeCache::Purge(DWORDLONG dwSpaceToFree, IEmptyVolumeCacheCallBack * lpCallBack)");
  211. HRESULT hResult = S_OK;
  212. ///////////////////////////////////////////////////////////////////////////////////////
  213. try
  214. {
  215. DWORD dwKilobytes;
  216. dwKilobytes = (DWORD) (dwSpaceToFree / 1024);
  217. hResult = CleanDisk(m_dwVolume, m_dwDiskCleanerDayThreshold, dwKilobytes, lpCallBack);
  218. if (FAILED(hResult))
  219. {
  220. THROW(hResult);
  221. }
  222. }
  223. ///////////////////////////////////////////////////////////////////////////////////////
  224. catch(CAppManExceptionHandler * pException)
  225. {
  226. hResult = pException->GetResultCode();
  227. delete pException;
  228. }
  229. catch(...)
  230. {
  231. hResult = E_UNEXPECTED;
  232. }
  233. ///////////////////////////////////////////////////////////////////////////////////////
  234. return hResult;
  235. }
  236. //////////////////////////////////////////////////////////////////////////////////////////////
  237. //
  238. //////////////////////////////////////////////////////////////////////////////////////////////
  239. STDMETHODIMP CEmptyVolumeCache::ShowProperties(HWND /*hwnd*/)
  240. {
  241. return S_OK;
  242. }
  243. //////////////////////////////////////////////////////////////////////////////////////////////
  244. //
  245. //////////////////////////////////////////////////////////////////////////////////////////////
  246. STDMETHODIMP CEmptyVolumeCache::Deactivate(DWORD * /*pdwFlags*/)
  247. {
  248. return S_OK;
  249. }
  250. //////////////////////////////////////////////////////////////////////////////////////////////
  251. //
  252. //////////////////////////////////////////////////////////////////////////////////////////////
  253. HRESULT CEmptyVolumeCache::GetSpaceUtilization(DWORD dwDeviceIndex, DWORD dwDays, LPDWORD lpdwKilobytes, IEmptyVolumeCacheCallBack * lpCallBack)
  254. {
  255. FUNCTION("CEmptyVolumeCache::GetSpaceUtilization(DWORD dwDeviceIndex, DWORD dwDays, LPDWORD lpdwKilobytes, IEmptyVolumeCacheCallBack * lpCallBack)");
  256. HRESULT hResult = S_OK;
  257. DWORD dwKilobytesAvailable = 0;
  258. ///////////////////////////////////////////////////////////////////////////////////////
  259. try
  260. {
  261. DEVICE_RECORD sDeviceRecord;
  262. APPLICATION_DATA sApplicationData;
  263. DWORD dwElapsedDays;
  264. SYSTEMTIME stLastUsedDate;
  265. //
  266. // Record the initial state
  267. //
  268. if (FAILED(m_oInformationManager.GetDeviceInfoWithIndex(dwDeviceIndex, &sDeviceRecord)))
  269. {
  270. THROW(E_UNEXPECTED);
  271. }
  272. //
  273. // Go through each application to determine removable diskspace consumed by game apps
  274. // that have been last accessed over X days ago, where X = DiskCleanerDayThreshold value
  275. // from registry. These are candidates for downsizing.
  276. // Note: X default value = 120 days. Also, pinned apps are not considered candidates for
  277. // downsizing, regardless of age.
  278. //
  279. if (S_OK == m_oInformationManager.GetOldestApplicationDataByDeviceWithIndex(dwDeviceIndex, &sApplicationData))
  280. {
  281. do
  282. {
  283. //
  284. // Get the age of the application
  285. //
  286. stLastUsedDate = sApplicationData.sAgingInfo.stLastUsedDate;
  287. dwElapsedDays = ElapsedDays(&stLastUsedDate);
  288. //
  289. // Determine amount that can be freed sApplicationRecord
  290. //
  291. if ((dwElapsedDays >= dwDays)&&(APP_CATEGORY_ENTERTAINMENT & sApplicationData.sBaseInfo.dwCategory)&&(sApplicationData.sBaseInfo.dwPinState == 0))
  292. {
  293. dwKilobytesAvailable += sApplicationData.sBaseInfo.dwRemovableKilobytes;
  294. hResult = lpCallBack->ScanProgress(dwKilobytesAvailable*1024, 0, NULL);
  295. if(FAILED(hResult))
  296. {
  297. THROW(E_UNEXPECTED);
  298. }
  299. }
  300. }
  301. while ((dwElapsedDays >= dwDays)&&(S_OK == m_oInformationManager.GetNextOldestApplicationDataByDeviceWithIndex(dwDeviceIndex, &sApplicationData)));
  302. }
  303. //
  304. // Now pass back the available kilobytes
  305. //
  306. *lpdwKilobytes = dwKilobytesAvailable;
  307. }
  308. ///////////////////////////////////////////////////////////////////////////////////////
  309. catch(CAppManExceptionHandler * pException)
  310. {
  311. hResult = pException->GetResultCode();
  312. delete pException;
  313. }
  314. catch(...)
  315. {
  316. hResult = E_UNEXPECTED;
  317. }
  318. ///////////////////////////////////////////////////////////////////////////////////////
  319. hResult = lpCallBack->ScanProgress(dwKilobytesAvailable * 1024, EVCCBF_LASTNOTIFICATION, NULL);
  320. if(FAILED(hResult))
  321. {
  322. hResult = E_UNEXPECTED;
  323. }
  324. return hResult;
  325. }
  326. //////////////////////////////////////////////////////////////////////////////////////////////
  327. //
  328. //////////////////////////////////////////////////////////////////////////////////////////////
  329. HRESULT CEmptyVolumeCache::CleanDisk(DWORD dwDeviceIndex, DWORD dwDays, DWORD dwKilobytesToFree, IEmptyVolumeCacheCallBack * lpCallBack)
  330. {
  331. FUNCTION("CEmptyVolumeCache::CleanDisk(DWORD dwDeviceIndex, DWORD dwDays, DWORD dwKilobytesToFree, IEmptyVolumeCacheCallBack * lpCallBack)");
  332. HRESULT hResult = S_OK;
  333. ///////////////////////////////////////////////////////////////////////////////////////
  334. try
  335. {
  336. DEVICE_SPACE_INFO sDeviceSpaceInfo;
  337. APPLICATION_DATA sApplicationData;
  338. DWORD dwKilobytesFreed;
  339. DWORD dwElapsedDays;
  340. DWORDLONG dwlMBFreed;
  341. DWORDLONG dwlMBToFree;
  342. SYSTEMTIME stLastUsedDate;
  343. if (FAILED(m_oInformationManager.GetDeviceSpaceInfoWithIndex(dwDeviceIndex, &sDeviceSpaceInfo)))
  344. {
  345. THROW(E_UNEXPECTED);
  346. }
  347. //
  348. // Record the initial state
  349. //
  350. dwlMBToFree = dwKilobytesToFree * 1024;
  351. dwlMBFreed = 0;
  352. //
  353. // Downsize removable diskspace consumed by game apps that have been last accessed over
  354. // X days ago, where X = DiskCleanerDayThreshold value from registry.
  355. // Note: X default value = 120 days. Also, pinned apps are not downsized,
  356. // regardless of age.
  357. //
  358. if (S_OK == m_oInformationManager.GetOldestApplicationDataByDeviceWithIndex(dwDeviceIndex, &sApplicationData))
  359. {
  360. do
  361. {
  362. //
  363. // Get the age of the application
  364. //
  365. stLastUsedDate = sApplicationData.sAgingInfo.stLastUsedDate;
  366. dwElapsedDays = ElapsedDays(&stLastUsedDate);
  367. //
  368. // Determine amount that can be freed sApplicationRecord
  369. //
  370. if ((dwElapsedDays >= dwDays)&&(APP_CATEGORY_ENTERTAINMENT & sApplicationData.sBaseInfo.dwCategory)&&(sApplicationData.sBaseInfo.dwPinState == 0))
  371. {
  372. m_oInformationManager.DownsizeApplication(sApplicationData.sBaseInfo.dwRemovableKilobytes, &sApplicationData);
  373. dwKilobytesFreed = sApplicationData.sBaseInfo.dwRemovableKilobytes;
  374. dwlMBFreed += (DWORDLONG)dwKilobytesFreed*(DWORDLONG)1024; //dwlMBFreed is cumulative up to that point
  375. hResult = lpCallBack->PurgeProgress(dwlMBFreed,dwlMBToFree-dwlMBFreed, 0,NULL);
  376. if (FAILED(hResult))
  377. {
  378. THROW(E_UNEXPECTED);
  379. }
  380. }
  381. }
  382. while ((dwElapsedDays >= dwDays)&&(S_OK == m_oInformationManager.GetNextOldestApplicationDataByDeviceWithIndex(dwDeviceIndex, &sApplicationData)));
  383. hResult = lpCallBack->PurgeProgress(dwlMBFreed,dwlMBToFree-dwlMBFreed, EVCCBF_LASTNOTIFICATION,NULL);
  384. if (FAILED(hResult))
  385. {
  386. THROW(E_UNEXPECTED);
  387. }
  388. }
  389. }
  390. ///////////////////////////////////////////////////////////////////////////////////////
  391. catch(CAppManExceptionHandler * pException)
  392. {
  393. hResult = pException->GetResultCode();
  394. delete pException;
  395. }
  396. catch(...)
  397. {
  398. hResult = E_UNEXPECTED;
  399. }
  400. ///////////////////////////////////////////////////////////////////////////////////////
  401. return hResult;
  402. }
  403. //////////////////////////////////////////////////////////////////////////////////////////////
  404. //
  405. // Miscellaneous functions
  406. //
  407. //////////////////////////////////////////////////////////////////////////////////////////////
  408. DWORD CEmptyVolumeCache::VolumeStringToNumber(LPCWSTR lpszVolume)
  409. {
  410. FUNCTION("CEmptyVolumeCache::VolumeStringToNumber(LPCWSTR lpszVolume)");
  411. WORD wDrive;
  412. DWORD dwDrive;
  413. //
  414. // First get the first DWORD which makes up the drive label (i.e. c:\)
  415. //
  416. wDrive = *(WORD *) lpszVolume;
  417. //
  418. // Now convert the character to uppercase
  419. //
  420. dwDrive = toupper((INT) wDrive);
  421. //
  422. // Now Subtract the ASCII index off to have a drive number from 0 - 25.
  423. //
  424. dwDrive -= 65;
  425. return dwDrive;
  426. }
  427. //////////////////////////////////////////////////////////////////////////////////////////////
  428. //
  429. //////////////////////////////////////////////////////////////////////////////////////////////
  430. DWORD CEmptyVolumeCache::ElapsedDays(SYSTEMTIME * lpLastUsedDate)
  431. {
  432. FUNCTION("CEmptyVolumeCache::ElapsedDays(SYSTEMTIME * lpLastUsedDate)");
  433. SYSTEMTIME stTodaysDate;
  434. FILETIME ftTodaysDate, ftLastUsedDate;
  435. DWORDLONG dwlTodaysDate, dwlLastUsedDate;
  436. DWORD dwElapsedDays;
  437. GetLocalTime(&stTodaysDate);
  438. //
  439. // Convert from systemtime to filetime
  440. //
  441. SystemTimeToFileTime(&stTodaysDate,&ftTodaysDate);
  442. SystemTimeToFileTime(lpLastUsedDate, &ftLastUsedDate);
  443. //
  444. // Copy to a DWORDLONG element
  445. //
  446. memcpy((void *)&dwlTodaysDate,(void *)&ftTodaysDate,sizeof(DWORDLONG));
  447. memcpy((void *)&dwlLastUsedDate,(void *)&ftLastUsedDate,sizeof(DWORDLONG));
  448. // Conversion: 100 nsec to days
  449. //
  450. // 10000000 (100 nsec) 60 sec 60 min 24 hours 864000000000 (100 nsec)
  451. // ------------------- x ------ x ------- x -------- = -----------------------
  452. // sec min hour day day
  453. //
  454. if (dwlTodaysDate <= dwlLastUsedDate)
  455. {
  456. dwElapsedDays = 0;
  457. }
  458. else
  459. {
  460. dwElapsedDays = (DWORD)((dwlTodaysDate - dwlLastUsedDate) / (DWORDLONG) 864000000000);
  461. }
  462. return dwElapsedDays;
  463. }