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.

527 lines
15 KiB

  1. // Author: Pritvinath Obla
  2. // Date: 10 July 1997
  3. #include "priv.h"
  4. #include "util.h"
  5. #include <emptyvc.h>
  6. #include <mluisupp.h> // for MLLoadString
  7. #include "resource.h" // for the string ID's
  8. class CInternetCacheCleaner : public IEmptyVolumeCache2
  9. {
  10. private:
  11. //
  12. // Data
  13. //
  14. ULONG m_cRef; // reference count
  15. DWORDLONG m_dwlSpaceUsed;
  16. TCHAR m_szCacheDir[MAX_PATH + 1];
  17. //
  18. // Functions
  19. //
  20. HRESULT GetInternetCacheSize(
  21. DWORDLONG *pdwlSpaceUsed,
  22. IEmptyVolumeCacheCallBack *picb
  23. );
  24. HRESULT DelInternetCacheFiles(
  25. DWORD dwPercentToFree,
  26. IEmptyVolumeCacheCallBack *picb
  27. );
  28. public:
  29. //
  30. // Constructor and Destructor
  31. //
  32. CInternetCacheCleaner(void);
  33. ~CInternetCacheCleaner(void);
  34. //
  35. // IUnknown interface members
  36. //
  37. STDMETHODIMP QueryInterface(REFIID, void **);
  38. STDMETHODIMP_(ULONG) AddRef(void);
  39. STDMETHODIMP_(ULONG) Release(void);
  40. //
  41. // IEmptyVolumeCache interface methods
  42. //
  43. STDMETHODIMP Initialize(
  44. HKEY hkRegKey,
  45. LPCWSTR pcwszVolume,
  46. LPWSTR *ppwszDisplayName,
  47. LPWSTR *ppwszDescription,
  48. DWORD *pdwFlags
  49. );
  50. STDMETHODIMP GetSpaceUsed(
  51. DWORDLONG *pdwlSpaceUsed,
  52. IEmptyVolumeCacheCallBack *picb
  53. );
  54. STDMETHODIMP Purge(
  55. DWORDLONG dwlSpaceToFree,
  56. IEmptyVolumeCacheCallBack *picb
  57. );
  58. STDMETHODIMP ShowProperties(
  59. HWND hwnd
  60. );
  61. STDMETHODIMP Deactivate(
  62. DWORD *pdwFlags
  63. );
  64. //
  65. // IEmptyVolumeCache2 interface methods
  66. //
  67. STDMETHODIMP InitializeEx(
  68. HKEY hkRegKey,
  69. LPCWSTR pcwszVolume,
  70. LPCWSTR pcwszKeyName,
  71. LPWSTR *ppwszDisplayName,
  72. LPWSTR *ppwszDescription,
  73. LPWSTR *ppwszBtnText,
  74. DWORD *pdwFlags
  75. );
  76. };
  77. //
  78. //------------------------------------------------------------------------------
  79. // CInternetCacheCleaner_CreateInstance
  80. //
  81. // Purpose: CreateInstance function for IClassFactory
  82. //------------------------------------------------------------------------------
  83. //
  84. STDAPI CInternetCacheCleaner_CreateInstance(
  85. IUnknown *punkOuter,
  86. IUnknown **ppunk,
  87. LPCOBJECTINFO poi
  88. )
  89. {
  90. *ppunk = NULL;
  91. CInternetCacheCleaner *lpICC = new CInternetCacheCleaner();
  92. if (lpICC == NULL)
  93. return E_OUTOFMEMORY;
  94. *ppunk = SAFECAST(lpICC, IEmptyVolumeCache *);
  95. return S_OK;
  96. }
  97. CInternetCacheCleaner::CInternetCacheCleaner() : m_cRef(1)
  98. {
  99. DllAddRef();
  100. m_dwlSpaceUsed = 0;
  101. *m_szCacheDir = '\0';
  102. }
  103. CInternetCacheCleaner::~CInternetCacheCleaner()
  104. {
  105. DllRelease();
  106. }
  107. STDMETHODIMP CInternetCacheCleaner::QueryInterface(REFIID riid, LPVOID *ppv)
  108. {
  109. if (IsEqualIID(riid, IID_IUnknown) ||
  110. IsEqualIID(riid, IID_IEmptyVolumeCache2) ||
  111. IsEqualIID(riid, IID_IEmptyVolumeCache))
  112. {
  113. *ppv = SAFECAST(this, IEmptyVolumeCache2 *);
  114. }
  115. else
  116. {
  117. *ppv = NULL;
  118. return E_NOINTERFACE;
  119. }
  120. AddRef();
  121. return NOERROR;
  122. }
  123. STDMETHODIMP_(ULONG) CInternetCacheCleaner::AddRef()
  124. {
  125. return ++m_cRef;
  126. }
  127. STDMETHODIMP_(ULONG) CInternetCacheCleaner::Release()
  128. {
  129. //
  130. // Decrement and check
  131. //
  132. if (--m_cRef)
  133. return m_cRef;
  134. //
  135. // No references left to this object
  136. //
  137. delete this;
  138. return 0;
  139. }
  140. //
  141. //------------------------------------------------------------------------------
  142. // CInternetCacheCleaner::InitializeEx
  143. //
  144. // Purpose: Initializes the Internet Cache Cleaner and returns the
  145. // specified IEmptyVolumeCache flags to the cache manager
  146. //------------------------------------------------------------------------------
  147. //
  148. STDMETHODIMP CInternetCacheCleaner::InitializeEx(
  149. HKEY hkRegKey,
  150. LPCWSTR pcwszVolume,
  151. LPCWSTR pcwszKeyName,
  152. LPWSTR *ppwszDisplayName,
  153. LPWSTR *ppwszDescription,
  154. LPWSTR *ppwszBtnText,
  155. DWORD *pdwFlags
  156. )
  157. {
  158. *ppwszBtnText = (LPWSTR)CoTaskMemAlloc( 128*sizeof(WCHAR) );
  159. if ( !*ppwszBtnText )
  160. return E_OUTOFMEMORY;
  161. MLLoadString( IDS_CACHECLN_BTNTEXT, *ppwszBtnText, 128 );
  162. return Initialize(hkRegKey, pcwszVolume, ppwszDisplayName, ppwszDescription, pdwFlags );
  163. }
  164. //
  165. //------------------------------------------------------------------------------
  166. // CInternetCacheCleaner::Initialize
  167. //
  168. // Purpose: Initializes the Internet Cache Cleaner and returns the
  169. // specified IEmptyVolumeCache flags to the cache manager
  170. //------------------------------------------------------------------------------
  171. //
  172. STDMETHODIMP CInternetCacheCleaner::Initialize(
  173. HKEY hkRegKey,
  174. LPCWSTR pcwszVolume,
  175. LPWSTR *ppwszDisplayName,
  176. LPWSTR *ppwszDescription,
  177. DWORD *pdwFlags
  178. )
  179. {
  180. #ifdef UNICODE
  181. // We can't use the registry values on NT because they can't be multi-local localized. As
  182. // a result we must set the out pointers with values read from resources.
  183. *ppwszDisplayName = (LPWSTR)CoTaskMemAlloc( 512*sizeof(WCHAR) );
  184. if ( !*ppwszDisplayName )
  185. return E_OUTOFMEMORY;
  186. *ppwszDescription = (LPWSTR)CoTaskMemAlloc( 512*sizeof(WCHAR) );
  187. if ( !*ppwszDescription )
  188. return E_OUTOFMEMORY;
  189. MLLoadString( IDS_CACHECLN_DISPLAY, *ppwszDisplayName, 512 );
  190. MLLoadString( IDS_CACHECLN_DESCRIPTION, *ppwszDescription, 512 );
  191. #else
  192. //
  193. // Let cleanmgr read the default DisplayName and Description
  194. // from hkRegKey and use them
  195. //
  196. *ppwszDisplayName = NULL;
  197. *ppwszDescription = NULL;
  198. #endif
  199. *pdwFlags = 0; // initialize the [out] parameter
  200. //
  201. // Check if the Internet Cache Folder is in pcwzVolume
  202. //
  203. GetCacheLocation(m_szCacheDir, sizeof(m_szCacheDir));
  204. if (StrCmpNI(pcwszVolume, m_szCacheDir, 3))
  205. {
  206. //
  207. // Different drives; return S_FALSE so that this cleaner
  208. // doesn't show up in cleanmgr's UI
  209. //
  210. return S_FALSE;
  211. }
  212. //
  213. // Enable this cleaner by default both in cleanup and tuneup modes
  214. //
  215. *pdwFlags = EVCF_ENABLEBYDEFAULT |
  216. EVCF_ENABLEBYDEFAULT_AUTO |
  217. EVCF_HASSETTINGS;
  218. #if 0
  219. /***
  220. // Since GetInternetCacheSize returns only an approx. size,
  221. // we would never get a value of 0 even if the cache is empty
  222. // Should enable this check once wininet.dll exports a GetCacheSize API
  223. //
  224. // Check if there is any disk space to free at all
  225. // If not, return S_FALSE so that this cleaner doesn't show up in
  226. // cleanmgr's UI
  227. //
  228. DWORDLONG dwlSpaceUsed;
  229. if (SUCCEEDED(GetInternetCacheSize(&dwlSpaceUsed, NULL)) &&
  230. dwlSpaceUsed == 0)
  231. {
  232. return S_FALSE;
  233. }
  234. ***/
  235. #endif
  236. return S_OK;
  237. }
  238. //
  239. //------------------------------------------------------------------------------
  240. // CInternetCacheCleaner::GetSpaceUsed
  241. //
  242. // Purpose: Return the total amount of space this internet cache cleaner
  243. // can free up
  244. //------------------------------------------------------------------------------
  245. //
  246. STDMETHODIMP CInternetCacheCleaner::GetSpaceUsed(
  247. DWORDLONG *pdwlSpaceUsed,
  248. IEmptyVolumeCacheCallBack *picb
  249. )
  250. {
  251. HRESULT hr;
  252. hr = GetInternetCacheSize(pdwlSpaceUsed, picb);
  253. m_dwlSpaceUsed = *pdwlSpaceUsed;
  254. //
  255. // Send the last notification to the cleanup manager
  256. //
  257. if (picb != NULL)
  258. {
  259. picb->ScanProgress(*pdwlSpaceUsed, EVCCBF_LASTNOTIFICATION, NULL);
  260. }
  261. if (hr != E_ABORT)
  262. {
  263. if (FAILED(hr))
  264. {
  265. //
  266. // *pdwlSpaceUsed is only a guesstimate; so return S_FALSE
  267. //
  268. hr = S_FALSE;
  269. }
  270. else
  271. {
  272. //
  273. // Return S_OK once wininet exports a GetCacheSize API;
  274. // till then use FindFirstUrlCacheEntry/FindNextUrlCacheEntry
  275. // to get approx. size of the cache
  276. //
  277. hr = S_FALSE;
  278. }
  279. }
  280. return hr;
  281. }
  282. //
  283. //------------------------------------------------------------------------------
  284. // CInternetCacheCleaner::Purge
  285. //
  286. // Purpose: Delete the internet cache files
  287. //------------------------------------------------------------------------------
  288. //
  289. STDMETHODIMP CInternetCacheCleaner::Purge(
  290. DWORDLONG dwlSpaceToFree,
  291. IEmptyVolumeCacheCallBack *picb
  292. )
  293. {
  294. HRESULT hr;
  295. DWORD dwPercentToFree = 100; // Optimize the most common scenario:
  296. // In most cases, dwlSpaceToFree will be
  297. // equal to m_dwlSpaceUsed
  298. if (dwlSpaceToFree != m_dwlSpaceUsed)
  299. {
  300. dwPercentToFree = m_dwlSpaceUsed ?
  301. DWORD((dwlSpaceToFree * 100) / m_dwlSpaceUsed) :
  302. 100;
  303. }
  304. hr = DelInternetCacheFiles(dwPercentToFree, picb);
  305. //
  306. // Send the last notification to the cleanup manager
  307. //
  308. if (picb != NULL)
  309. {
  310. picb->PurgeProgress(dwlSpaceToFree, 0,
  311. EVCCBF_LASTNOTIFICATION, NULL);
  312. }
  313. if (hr != E_ABORT)
  314. {
  315. hr = S_OK; // cannot return anything else
  316. }
  317. return hr;
  318. }
  319. //
  320. //------------------------------------------------------------------------------
  321. // CInternetCacheCleaner::ShowProperties
  322. //
  323. // Purpose: Launch the cache viewer to list the internet cache files
  324. //------------------------------------------------------------------------------
  325. //
  326. STDMETHODIMP CInternetCacheCleaner::ShowProperties(
  327. HWND hwnd
  328. )
  329. {
  330. DWORD dwAttrib;
  331. if (*m_szCacheDir == '\0') // Internet cache dir is not yet initialized
  332. {
  333. GetCacheLocation(m_szCacheDir, sizeof(m_szCacheDir));
  334. }
  335. dwAttrib = GetFileAttributes(m_szCacheDir);
  336. if (dwAttrib != 0xffffffff && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY))
  337. {
  338. SHELLEXECUTEINFO sei;
  339. //
  340. // Launch the cache viewer
  341. //
  342. sei.cbSize = sizeof(SHELLEXECUTEINFO);
  343. sei.hwnd = hwnd;
  344. sei.lpVerb = NULL;
  345. sei.lpFile = m_szCacheDir;
  346. sei.lpParameters = NULL;
  347. sei.lpDirectory = NULL;
  348. sei.nShow = SW_SHOWNORMAL;
  349. sei.fMask = 0;
  350. ShellExecuteEx(&sei);
  351. }
  352. //
  353. // The user may or may not delete files directly from the cachevu folder
  354. // Since there is no way of knowing this, don't return S_OK which would
  355. // trigger cleanmgr to call GetSpaceUsed again
  356. //
  357. return S_OK;
  358. }
  359. //
  360. //------------------------------------------------------------------------------
  361. // CInternetCacheCleaner::Deactivate
  362. //
  363. // Purpose: Deactivates the Internet Cache Cleaner...Not implemented
  364. //------------------------------------------------------------------------------
  365. //
  366. STDMETHODIMP CInternetCacheCleaner::Deactivate(
  367. DWORD *pdwFlags
  368. )
  369. {
  370. *pdwFlags = 0;
  371. return S_OK;
  372. }
  373. //
  374. //------------------------------------------------------------------------------
  375. // CInternetCacheCleaner::GetInternetCacheSize
  376. //
  377. // Purpose: Find the size of the internet cache by calling into wininet APIs
  378. //
  379. // Notes: The current implementation is temporary; once wininet exports
  380. // a real API for getting the cache size, use that
  381. //------------------------------------------------------------------------------
  382. //
  383. HRESULT CInternetCacheCleaner::GetInternetCacheSize(
  384. DWORDLONG *pdwlSpaceUsed,
  385. IEmptyVolumeCacheCallBack *picb // not used
  386. )
  387. {
  388. HRESULT hr = S_OK;
  389. DWORD dwLastErr;
  390. LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntryInfo;
  391. HANDLE hCacheEntryInfo;
  392. DWORD dwCacheEntryInfoSize;
  393. *pdwlSpaceUsed = 0;
  394. if ((lpCacheEntryInfo = (LPINTERNET_CACHE_ENTRY_INFOA) LocalAlloc(LPTR,
  395. MAX_CACHE_ENTRY_INFO_SIZE)) == NULL)
  396. {
  397. return E_OUTOFMEMORY;
  398. }
  399. dwCacheEntryInfoSize = MAX_CACHE_ENTRY_INFO_SIZE;
  400. if ((hCacheEntryInfo = FindFirstUrlCacheEntryA(NULL, lpCacheEntryInfo,
  401. &dwCacheEntryInfoSize)) == NULL)
  402. {
  403. hr = HRESULT_FROM_WIN32(GetLastError());
  404. }
  405. if (SUCCEEDED(hr))
  406. {
  407. do
  408. {
  409. if (!(lpCacheEntryInfo->CacheEntryType & (STICKY_CACHE_ENTRY | COOKIE_CACHE_ENTRY)))
  410. {
  411. ULARGE_INTEGER uliFileSize;
  412. uliFileSize.HighPart = lpCacheEntryInfo->dwSizeHigh;
  413. uliFileSize.LowPart = lpCacheEntryInfo->dwSizeLow;
  414. *pdwlSpaceUsed += QUAD_PART(uliFileSize);
  415. }
  416. dwCacheEntryInfoSize = MAX_CACHE_ENTRY_INFO_SIZE;
  417. } while (FindNextUrlCacheEntryA(hCacheEntryInfo, lpCacheEntryInfo,
  418. &dwCacheEntryInfoSize));
  419. if ((dwLastErr = GetLastError()) != ERROR_NO_MORE_ITEMS)
  420. {
  421. hr = HRESULT_FROM_WIN32(dwLastErr);
  422. }
  423. }
  424. if (lpCacheEntryInfo != NULL)
  425. {
  426. LocalFree(lpCacheEntryInfo);
  427. lpCacheEntryInfo = NULL;
  428. }
  429. return hr;
  430. }
  431. //
  432. //------------------------------------------------------------------------------
  433. // CInternetCacheCleaner::DelInternetCacheFiles
  434. //
  435. // Purpose: Delete the internet cache files
  436. //------------------------------------------------------------------------------
  437. //
  438. HRESULT CInternetCacheCleaner::DelInternetCacheFiles(
  439. DWORD dwPercentToFree,
  440. IEmptyVolumeCacheCallBack *picb // not used
  441. )
  442. {
  443. HRESULT hr = S_OK;
  444. if (*m_szCacheDir == '\0') // Internet cache dir is not yet initialized
  445. {
  446. hr = GetCacheLocation(m_szCacheDir, sizeof(m_szCacheDir));
  447. }
  448. if (SUCCEEDED(hr))
  449. {
  450. FreeUrlCacheSpace(m_szCacheDir, dwPercentToFree, STICKY_CACHE_ENTRY);
  451. }
  452. return hr;
  453. }