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.

1162 lines
29 KiB

  1. #include "local.h"
  2. #include "resource.h"
  3. #include "cachesrch.h"
  4. #include "sfview.h"
  5. #include <shlwapi.h>
  6. #include <limits.h>
  7. #include "chcommon.h"
  8. #include "cafolder.h"
  9. #include <mluisupp.h>
  10. #define DM_HSFOLDER 0
  11. // these are common flags to ShChangeNotify
  12. #ifndef UNIX
  13. #define CHANGE_FLAGS (0)
  14. #else
  15. #define CHANGE_FLAGS SHCNF_FLUSH
  16. #endif
  17. static void _GetFileTypeInternal(LPCEIPIDL pidl, LPUTSTR pszStr, UINT cchStr);
  18. //
  19. // Column definition for the Cache Folder DefView
  20. //
  21. enum {
  22. ICOLC_URL_SHORTNAME = 0,
  23. ICOLC_URL_NAME,
  24. ICOLC_URL_TYPE,
  25. ICOLC_URL_SIZE,
  26. ICOLC_URL_EXPIRES,
  27. ICOLC_URL_MODIFIED,
  28. ICOLC_URL_ACCESSED,
  29. ICOLC_URL_LASTSYNCED,
  30. ICOLC_URL_MAX // Make sure this is the last enum item
  31. };
  32. typedef struct _COLSPEC
  33. {
  34. short int iCol;
  35. short int ids; // Id of string for title
  36. short int cchCol; // Number of characters wide to make column
  37. short int iFmt; // The format of the column;
  38. } COLSPEC;
  39. const COLSPEC s_CacheFolder_cols[] = {
  40. {ICOLC_URL_SHORTNAME, IDS_SHORTNAME_COL, 18, LVCFMT_LEFT},
  41. {ICOLC_URL_NAME, IDS_NAME_COL, 30, LVCFMT_LEFT},
  42. {ICOLC_URL_TYPE, IDS_TYPE_COL, 15, LVCFMT_LEFT},
  43. {ICOLC_URL_SIZE, IDS_SIZE_COL, 8, LVCFMT_RIGHT},
  44. {ICOLC_URL_EXPIRES, IDS_EXPIRES_COL, 18, LVCFMT_LEFT},
  45. {ICOLC_URL_MODIFIED, IDS_MODIFIED_COL, 18, LVCFMT_LEFT},
  46. {ICOLC_URL_ACCESSED, IDS_ACCESSED_COL, 18, LVCFMT_LEFT},
  47. {ICOLC_URL_LASTSYNCED, IDS_LASTSYNCED_COL, 18, LVCFMT_LEFT}
  48. };
  49. //////////////////////////////////////////////////////////////////////
  50. LPCEIPIDL _CreateBuffCacheFolderPidl(DWORD dwSize, LPINTERNET_CACHE_ENTRY_INFO pcei)
  51. {
  52. DWORD dwTotalSize = 0;
  53. dwTotalSize = sizeof(CEIPIDL) + dwSize - sizeof(INTERNET_CACHE_ENTRY_INFO);
  54. #if defined(UNIX)
  55. dwTotalSize = ALIGN4(dwTotalSize);
  56. #endif
  57. LPCEIPIDL pceip = (LPCEIPIDL)OleAlloc(dwTotalSize);
  58. if (pceip)
  59. {
  60. memset(pceip, 0, dwTotalSize);
  61. pceip->cb = (USHORT)(dwTotalSize - sizeof(USHORT));
  62. pceip->usSign = CEIPIDL_SIGN;
  63. _CopyCEI(&pceip->cei, pcei, dwSize);
  64. }
  65. return pceip;
  66. }
  67. HRESULT CacheFolderView_MergeMenu(UINT idMenu, LPQCMINFO pqcm)
  68. {
  69. HMENU hmenu = LoadMenu(MLGetHinst(), MAKEINTRESOURCE(idMenu));
  70. if (hmenu)
  71. {
  72. MergeMenuHierarchy(pqcm->hmenu, hmenu, pqcm->idCmdFirst, pqcm->idCmdLast);
  73. DestroyMenu(hmenu);
  74. }
  75. return S_OK;
  76. }
  77. HRESULT CacheFolderView_DidDragDrop(IDataObject *pdo, DWORD dwEffect)
  78. {
  79. if (dwEffect & DROPEFFECT_MOVE)
  80. {
  81. CCacheItem *pCItem;
  82. BOOL fBulkDelete;
  83. if (SUCCEEDED(pdo->QueryInterface(IID_ICache, (void **)&pCItem)))
  84. {
  85. fBulkDelete = pCItem->_cItems > LOTS_OF_FILES;
  86. for (UINT i = 0; i < pCItem->_cItems; i++)
  87. {
  88. if (DeleteUrlCacheEntry(CPidlToSourceUrl((LPCEIPIDL)pCItem->_ppidl[i])))
  89. {
  90. if (!fBulkDelete)
  91. {
  92. _GenerateEvent(SHCNE_DELETE, pCItem->_pCFolder->_pidl, pCItem->_ppidl[i], NULL);
  93. }
  94. }
  95. }
  96. if (fBulkDelete)
  97. {
  98. _GenerateEvent(SHCNE_UPDATEDIR, pCItem->_pCFolder->_pidl, NULL, NULL);
  99. }
  100. SHChangeNotifyHandleEvents();
  101. pCItem->Release();
  102. return S_OK;
  103. }
  104. }
  105. return E_FAIL;
  106. }
  107. // There are copies of exactly this function in SHELL32
  108. // Add the File Type page
  109. HRESULT CacheFolderView_OnAddPropertyPages(DWORD pv, SFVM_PROPPAGE_DATA * ppagedata)
  110. {
  111. IShellPropSheetExt * pspse;
  112. HRESULT hr = CoCreateInstance(CLSID_FileTypes, NULL, CLSCTX_INPROC_SERVER,
  113. IID_PPV_ARG(IShellPropSheetExt, &pspse));
  114. if (SUCCEEDED(hr))
  115. {
  116. hr = pspse->AddPages(ppagedata->pfn, ppagedata->lParam);
  117. pspse->Release();
  118. }
  119. return hr;
  120. }
  121. HRESULT CacheFolderView_OnGetSortDefaults(int * piDirection, int * plParamSort)
  122. {
  123. *plParamSort = (int)ICOLC_URL_ACCESSED;
  124. if (piDirection)
  125. *piDirection = 1;
  126. return S_OK;
  127. }
  128. HRESULT CALLBACK CCacheFolder::_sViewCallback(IShellView *psv, IShellFolder *psf,
  129. HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  130. {
  131. CCacheFolder *pfolder = NULL;
  132. HRESULT hr = S_OK;
  133. switch (uMsg)
  134. {
  135. case DVM_GETHELPTEXT:
  136. {
  137. TCHAR szText[MAX_PATH];
  138. UINT id = LOWORD(wParam);
  139. UINT cchBuf = HIWORD(wParam);
  140. LPTSTR pszBuf = (LPTSTR)lParam;
  141. MLLoadString(id + IDS_MH_FIRST, szText, ARRAYSIZE(szText));
  142. // we know for a fact that this parameter is really a TCHAR
  143. if ( IsOS( OS_NT ))
  144. {
  145. SHTCharToUnicode( szText, (LPWSTR) pszBuf, cchBuf );
  146. }
  147. else
  148. {
  149. SHTCharToAnsi( szText, (LPSTR) pszBuf, cchBuf );
  150. }
  151. break;
  152. }
  153. case SFVM_GETNOTIFY:
  154. hr = psf->QueryInterface(CLSID_CacheFolder, (void **)&pfolder);
  155. if (SUCCEEDED(hr))
  156. {
  157. *(LPCITEMIDLIST*)wParam = pfolder->_pidl; // evil alias
  158. pfolder->Release();
  159. }
  160. else
  161. wParam = 0;
  162. *(LONG*)lParam = SHCNE_DELETE | SHCNE_UPDATEDIR;
  163. break;
  164. case DVM_DIDDRAGDROP:
  165. hr = CacheFolderView_DidDragDrop((IDataObject *)lParam, (DWORD)wParam);
  166. break;
  167. case DVM_INITMENUPOPUP:
  168. hr = S_OK;
  169. break;
  170. case DVM_INVOKECOMMAND:
  171. _ArrangeFolder(hwnd, (UINT)wParam);
  172. break;
  173. case DVM_COLUMNCLICK:
  174. ShellFolderView_ReArrange(hwnd, (UINT)wParam);
  175. hr = S_OK;
  176. break;
  177. case DVM_MERGEMENU:
  178. hr = CacheFolderView_MergeMenu(MENU_CACHE, (LPQCMINFO)lParam);
  179. break;
  180. case DVM_DEFVIEWMODE:
  181. *(FOLDERVIEWMODE *)lParam = FVM_DETAILS;
  182. break;
  183. case SFVM_ADDPROPERTYPAGES:
  184. hr = CacheFolderView_OnAddPropertyPages((DWORD)wParam, (SFVM_PROPPAGE_DATA *)lParam);
  185. break;
  186. case SFVM_GETSORTDEFAULTS:
  187. hr = CacheFolderView_OnGetSortDefaults((int *)wParam, (int *)lParam);
  188. break;
  189. case SFVM_UPDATESTATUSBAR:
  190. ResizeStatusBar(hwnd, FALSE);
  191. // We did not set any text; let defview do it
  192. hr = E_NOTIMPL;
  193. break;
  194. case SFVM_SIZE:
  195. ResizeStatusBar(hwnd, FALSE);
  196. break;
  197. case SFVM_GETPANE:
  198. if (wParam == PANE_ZONE)
  199. *(DWORD*)lParam = 1;
  200. else
  201. *(DWORD*)lParam = PANE_NONE;
  202. break;
  203. case SFVM_WINDOWCREATED:
  204. ResizeStatusBar(hwnd, TRUE);
  205. break;
  206. case SFVM_GETZONE:
  207. *(DWORD*)lParam = URLZONE_INTERNET; // Internet by default
  208. break;
  209. default:
  210. hr = E_FAIL;
  211. }
  212. return hr;
  213. }
  214. HRESULT CacheFolderView_CreateInstance(CCacheFolder *pHCFolder, void **ppv)
  215. {
  216. CSFV csfv;
  217. csfv.cbSize = sizeof(csfv);
  218. csfv.pshf = (IShellFolder *)pHCFolder;
  219. csfv.psvOuter = NULL;
  220. csfv.pidl = pHCFolder->_pidl;
  221. csfv.lEvents = SHCNE_DELETE; // SHCNE_DISKEVENTS | SHCNE_ASSOCCHANGED | SHCNE_GLOBALEVENTS;
  222. csfv.pfnCallback = CCacheFolder::_sViewCallback;
  223. csfv.fvm = (FOLDERVIEWMODE)0; // Have defview restore the folder view mode
  224. return SHCreateShellFolderViewEx(&csfv, (IShellView**)ppv);
  225. }
  226. CCacheFolderEnum::CCacheFolderEnum(DWORD grfFlags, CCacheFolder *pHCFolder) : _cRef(1)
  227. {
  228. DllAddRef();
  229. _grfFlags = grfFlags,
  230. _pCFolder = pHCFolder;
  231. pHCFolder->AddRef();
  232. ASSERT(_hEnum == NULL);
  233. }
  234. CCacheFolderEnum::~CCacheFolderEnum()
  235. {
  236. ASSERT(_cRef == 0); // we should always have a zero ref count here
  237. TraceMsg(DM_HSFOLDER, "hcfe - ~CCacheFolderEnum() called.");
  238. _pCFolder->Release();
  239. if (_pceiWorking)
  240. {
  241. LocalFree(_pceiWorking);
  242. _pceiWorking = NULL;
  243. }
  244. if (_hEnum)
  245. {
  246. FindCloseUrlCache(_hEnum);
  247. _hEnum = NULL;
  248. }
  249. DllRelease();
  250. }
  251. HRESULT CCacheFolderEnum_CreateInstance(DWORD grfFlags, CCacheFolder *pHCFolder, IEnumIDList **ppeidl)
  252. {
  253. TraceMsg(DM_HSFOLDER, "hcfe - CreateInstance() called.");
  254. *ppeidl = NULL; // null the out param
  255. CCacheFolderEnum *pHCFE = new CCacheFolderEnum(grfFlags, pHCFolder);
  256. if (!pHCFE)
  257. return E_OUTOFMEMORY;
  258. *ppeidl = pHCFE;
  259. return S_OK;
  260. }
  261. HRESULT CCacheFolderEnum::QueryInterface(REFIID riid, void **ppv)
  262. {
  263. static const QITAB qit[] = {
  264. QITABENT(CCacheFolderEnum, IEnumIDList),
  265. { 0 },
  266. };
  267. return QISearch(this, qit, riid, ppv);
  268. }
  269. ULONG CCacheFolderEnum::AddRef(void)
  270. {
  271. return InterlockedIncrement(&_cRef);
  272. }
  273. ULONG CCacheFolderEnum::Release(void)
  274. {
  275. if (InterlockedDecrement(&_cRef))
  276. return _cRef;
  277. delete this;
  278. return 0;
  279. }
  280. //
  281. // IEnumIDList Methods
  282. //
  283. HRESULT CCacheFolderEnum::Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
  284. {
  285. HRESULT hr = S_FALSE;
  286. DWORD dwBuffSize;
  287. DWORD dwError;
  288. LPTSTR pszSearchPattern = NULL;
  289. TraceMsg(DM_HSFOLDER, "hcfe - Next() called.");
  290. if (0 == (SHCONTF_NONFOLDERS & _grfFlags))
  291. {
  292. dwError = 0xFFFFFFFF;
  293. goto exitPoint;
  294. }
  295. if (_pceiWorking == NULL)
  296. {
  297. _pceiWorking = (LPINTERNET_CACHE_ENTRY_INFO)LocalAlloc(LPTR, MAX_URLCACHE_ENTRY);
  298. if (_pceiWorking == NULL)
  299. {
  300. dwError = ERROR_NOT_ENOUGH_MEMORY;
  301. goto exitPoint;
  302. }
  303. }
  304. // Set up things to enumerate history items, if appropriate, otherwise,
  305. // we'll just pass in NULL and enumerate all items as before.
  306. TryAgain:
  307. dwBuffSize = MAX_URLCACHE_ENTRY;
  308. dwError = S_OK;
  309. if (!_hEnum) // _hEnum maintains our state as we iterate over all the cache entries
  310. {
  311. _hEnum = FindFirstUrlCacheEntry(pszSearchPattern, _pceiWorking, &dwBuffSize);
  312. if (!_hEnum)
  313. dwError = GetLastError();
  314. }
  315. else if (!FindNextUrlCacheEntry(_hEnum, _pceiWorking, &dwBuffSize))
  316. {
  317. dwError = GetLastError();
  318. }
  319. if (S_OK == dwError)
  320. {
  321. LPCEIPIDL pcei = NULL;
  322. if ((_pceiWorking->CacheEntryType & URLHISTORY_CACHE_ENTRY) == URLHISTORY_CACHE_ENTRY)
  323. goto TryAgain;
  324. pcei = _CreateBuffCacheFolderPidl(dwBuffSize, _pceiWorking);
  325. if (pcei)
  326. {
  327. _GetFileTypeInternal(pcei, pcei->szTypeName, ARRAYSIZE(pcei->szTypeName));
  328. rgelt[0] = (LPITEMIDLIST)pcei;
  329. if (pceltFetched)
  330. *pceltFetched = 1;
  331. }
  332. else
  333. {
  334. dwError = ERROR_NOT_ENOUGH_MEMORY;
  335. }
  336. }
  337. exitPoint:
  338. if (dwError != S_OK)
  339. {
  340. if (_hEnum)
  341. {
  342. FindCloseUrlCache(_hEnum);
  343. _hEnum = NULL;
  344. }
  345. if (pceltFetched)
  346. *pceltFetched = 0;
  347. rgelt[0] = NULL;
  348. hr = S_FALSE;
  349. }
  350. else
  351. {
  352. hr = S_OK;
  353. }
  354. return hr;
  355. }
  356. HRESULT CCacheFolderEnum::Skip(ULONG celt)
  357. {
  358. TraceMsg(DM_HSFOLDER, "hcfe - Skip() called.");
  359. return E_NOTIMPL;
  360. }
  361. HRESULT CCacheFolderEnum::Reset()
  362. {
  363. TraceMsg(DM_HSFOLDER, "hcfe - Reset() called.");
  364. return E_NOTIMPL;
  365. }
  366. HRESULT CCacheFolderEnum::Clone(IEnumIDList **ppenum)
  367. {
  368. TraceMsg(DM_HSFOLDER, "hcfe - Clone() called.");
  369. return E_NOTIMPL;
  370. }
  371. //////////////////////////////////////////////////////////////////////////////
  372. //
  373. // CCacheFolder Object
  374. //
  375. //////////////////////////////////////////////////////////////////////////////
  376. CCacheFolder::CCacheFolder() : _cRef(1)
  377. {
  378. ASSERT(_pidl == NULL);
  379. DllAddRef();
  380. }
  381. CCacheFolder::~CCacheFolder()
  382. {
  383. ASSERT(_cRef == 0); // should always have zero
  384. TraceMsg(DM_HSFOLDER, "hcf - ~CCacheFolder() called.");
  385. if (_pidl)
  386. ILFree(_pidl);
  387. if (_pshfSys)
  388. _pshfSys->Release();
  389. DllRelease();
  390. }
  391. HRESULT CCacheFolder::QueryInterface(REFIID iid, void **ppv)
  392. {
  393. static const QITAB qitCache[] = {
  394. QITABENT(CCacheFolder, IShellFolder2),
  395. QITABENTMULTI(CCacheFolder, IShellFolder, IShellFolder2),
  396. QITABENT(CCacheFolder, IShellIcon),
  397. QITABENT(CCacheFolder, IPersistFolder2),
  398. QITABENTMULTI(CCacheFolder, IPersistFolder, IPersistFolder2),
  399. QITABENTMULTI(CCacheFolder, IPersist, IPersistFolder2),
  400. { 0 },
  401. };
  402. if (iid == CLSID_CacheFolder)
  403. {
  404. *ppv = (void *)(CCacheFolder *)this; // unrefed
  405. AddRef();
  406. return S_OK;
  407. }
  408. HRESULT hr = QISearch(this, qitCache, iid, ppv);
  409. if (FAILED(hr) && !IsOS(OS_WHISTLERORGREATER))
  410. {
  411. if (iid == IID_IShellView)
  412. {
  413. // this is a total hack... return our view object from this folder
  414. //
  415. // the desktop.ini file for "Temporary Internet Files" has UICLSID={guid of this object}
  416. // this lets us implment only ths IShellView for this folder, leaving the IShellFolder
  417. // to the default file system. this enables operations on the pidls that are stored in
  418. // this folder that would otherwise faile since our IShellFolder is not as complete
  419. // as the default (this is the same thing the font folder does).
  420. //
  421. // to support this with defview we would either have to do a complete wrapper object
  422. // for the view implemenation, or add this hack that hands out the view object, this
  423. // assumes we know the order of calls that the shell makes to create this object
  424. // and get the IShellView implementation
  425. //
  426. hr = CacheFolderView_CreateInstance(this, ppv);
  427. }
  428. }
  429. return hr;
  430. }
  431. STDMETHODIMP CCacheFolder::_GetDetail(LPCITEMIDLIST pidl, UINT iColumn, LPTSTR pszStr, UINT cchStr)
  432. {
  433. switch (iColumn) {
  434. case ICOLC_URL_SHORTNAME:
  435. _GetCacheItemTitle((LPCEIPIDL)pidl, pszStr, cchStr);
  436. break;
  437. case ICOLC_URL_NAME:
  438. StrCpyN(pszStr, CPidlToSourceUrl((LPCEIPIDL)pidl), cchStr);
  439. break;
  440. case ICOLC_URL_TYPE:
  441. ualstrcpyn(pszStr, ((LPCEIPIDL)pidl)->szTypeName, cchStr);
  442. break;
  443. case ICOLC_URL_SIZE:
  444. StrFormatKBSize(((LPCEIPIDL)pidl)->cei.dwSizeLow, pszStr, cchStr);
  445. break;
  446. case ICOLC_URL_EXPIRES:
  447. FileTimeToDateTimeStringInternal(&((LPCEIPIDL)pidl)->cei.ExpireTime, pszStr, cchStr, FALSE);
  448. break;
  449. case ICOLC_URL_ACCESSED:
  450. FileTimeToDateTimeStringInternal(&((LPCEIPIDL)pidl)->cei.LastAccessTime, pszStr, cchStr, FALSE);
  451. break;
  452. case ICOLC_URL_MODIFIED:
  453. FileTimeToDateTimeStringInternal(&((LPCEIPIDL)pidl)->cei.LastModifiedTime, pszStr, cchStr, FALSE);
  454. break;
  455. case ICOLC_URL_LASTSYNCED:
  456. FileTimeToDateTimeStringInternal(&((LPCEIPIDL)pidl)->cei.LastSyncTime, pszStr, cchStr, FALSE);
  457. break;
  458. }
  459. return S_OK;
  460. }
  461. HRESULT CCacheFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pdi)
  462. {
  463. HRESULT hr = E_FAIL;
  464. if (pidl == NULL)
  465. {
  466. if (iColumn < ICOLC_URL_MAX)
  467. {
  468. TCHAR szTemp[128];
  469. MLLoadString(s_CacheFolder_cols[iColumn].ids, szTemp, ARRAYSIZE(szTemp));
  470. pdi->fmt = s_CacheFolder_cols[iColumn].iFmt;
  471. pdi->cxChar = s_CacheFolder_cols[iColumn].cchCol;
  472. hr = StringToStrRet(szTemp, &pdi->str);
  473. }
  474. else
  475. {
  476. // enum done
  477. hr = E_FAIL;
  478. }
  479. }
  480. else if (!IS_VALID_CEIPIDL(pidl))
  481. {
  482. if (_pshfSys)
  483. {
  484. // delegate to the filesystem
  485. hr = _pshfSys->GetDetailsOf(pidl, iColumn, pdi);
  486. }
  487. }
  488. else
  489. {
  490. TCHAR szTemp[MAX_URL_STRING];
  491. hr = _GetDetail(pidl, iColumn, szTemp, ARRAYSIZE(szTemp));
  492. if (SUCCEEDED(hr))
  493. {
  494. hr = StringToStrRet(szTemp, &pdi->str);
  495. }
  496. }
  497. return hr;
  498. }
  499. HRESULT CCacheFolder::_GetFileSysFolder(IShellFolder2 **ppsf)
  500. {
  501. *ppsf = NULL;
  502. IPersistFolder *ppf;
  503. HRESULT hr = CoCreateInstance(CLSID_ShellFSFolder, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IPersistFolder, &ppf));
  504. if (SUCCEEDED(hr))
  505. {
  506. hr = ppf->Initialize(this->_pidl);
  507. if (SUCCEEDED(hr))
  508. {
  509. hr = ppf->QueryInterface(IID_PPV_ARG(IShellFolder2, ppsf));
  510. }
  511. ppf->Release();
  512. }
  513. return hr;
  514. }
  515. // IShellFolder
  516. HRESULT CCacheFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  517. {
  518. HRESULT hr = E_FAIL;
  519. if (!IS_VALID_CEIPIDL(pidl))
  520. {
  521. if (_pshfSys)
  522. {
  523. hr = _pshfSys->BindToObject(pidl, pbc, riid, ppv);
  524. }
  525. }
  526. else
  527. {
  528. hr = E_NOTIMPL;
  529. *ppv = NULL;
  530. }
  531. return hr;
  532. }
  533. HRESULT CCacheFolder::ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR pszDisplayName,
  534. ULONG *pchEaten, LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  535. {
  536. HRESULT hr = E_FAIL;
  537. if (_pshfSys)
  538. {
  539. hr = _pshfSys->ParseDisplayName(hwnd, pbc, pszDisplayName, pchEaten, ppidl, pdwAttributes);
  540. }
  541. else
  542. *ppidl = NULL;
  543. return hr;
  544. }
  545. // IPersist
  546. HRESULT CCacheFolder::GetClassID(CLSID *pclsid)
  547. {
  548. *pclsid = CLSID_CacheFolder;
  549. return S_OK;
  550. }
  551. STDAPI CacheFolder_CreateInstance(IUnknown* punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  552. {
  553. *ppunk = NULL; // null the out param
  554. if (punkOuter)
  555. return CLASS_E_NOAGGREGATION;
  556. CCacheFolder *pcache = new CCacheFolder();
  557. if (pcache)
  558. {
  559. *ppunk = SAFECAST(pcache, IShellFolder2*);
  560. return S_OK;
  561. }
  562. return E_OUTOFMEMORY;
  563. }
  564. ULONG CCacheFolder::AddRef()
  565. {
  566. return InterlockedIncrement(&_cRef);
  567. }
  568. ULONG CCacheFolder::Release()
  569. {
  570. if (InterlockedDecrement(&_cRef))
  571. return _cRef;
  572. delete this;
  573. return 0;
  574. }
  575. // IShellFolder
  576. HRESULT CCacheFolder::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
  577. {
  578. return CCacheFolderEnum_CreateInstance(grfFlags, this, ppenumIDList);
  579. }
  580. HRESULT CCacheFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  581. {
  582. return BindToObject(pidl, pbc, riid, ppv);
  583. }
  584. // unalligned verison
  585. #if defined(UNIX) || !defined(_X86_)
  586. // defined in hsfolder.cpp
  587. extern UINT ULCompareFileTime(UNALIGNED const FILETIME *pft1, UNALIGNED const FILETIME *pft2);
  588. #else
  589. #define ULCompareFileTime(pft1, pft2) CompareFileTime(pft1, pft2)
  590. #endif
  591. HRESULT CCacheFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  592. {
  593. BOOL fRealigned1;
  594. HRESULT hr = AlignPidl(&pidl1, &fRealigned1);
  595. if (SUCCEEDED(hr))
  596. {
  597. BOOL fRealigned2;
  598. hr = AlignPidl(&pidl2, &fRealigned2);
  599. if (SUCCEEDED(hr))
  600. {
  601. hr = _CompareAlignedIDs(lParam, (LPCEIPIDL)pidl1, (LPCEIPIDL)pidl2);
  602. if (fRealigned2)
  603. FreeRealignedPidl(pidl2);
  604. }
  605. if (fRealigned1)
  606. FreeRealignedPidl(pidl1);
  607. }
  608. return hr;
  609. }
  610. int _CompareSize(LPCEIPIDL pcei1, LPCEIPIDL pcei2)
  611. {
  612. // check only the low for now
  613. if (pcei1->cei.dwSizeLow == pcei2->cei.dwSizeLow)
  614. {
  615. return 0;
  616. }
  617. else if (pcei1->cei.dwSizeLow > pcei2->cei.dwSizeLow)
  618. {
  619. return 1;
  620. }
  621. return -1;
  622. }
  623. HRESULT CCacheFolder::_CompareAlignedIDs(LPARAM lParam, LPCEIPIDL pidl1, LPCEIPIDL pidl2)
  624. {
  625. int iRet = 0;
  626. if (NULL == pidl1 || NULL == pidl2)
  627. return E_INVALIDARG;
  628. // At this point, both pidls have resolved to leaf (history or cache)
  629. if (!IS_VALID_CEIPIDL(pidl1) || !IS_VALID_CEIPIDL(pidl2))
  630. return E_FAIL;
  631. switch (lParam & SHCIDS_COLUMNMASK) {
  632. case ICOLC_URL_SHORTNAME:
  633. iRet = StrCmpI(_FindURLFileName(CPidlToSourceUrl(pidl1)),
  634. _FindURLFileName(CPidlToSourceUrl(pidl2)));
  635. break;
  636. case ICOLC_URL_NAME:
  637. iRet = _CompareCFolderPidl(pidl1, pidl2);
  638. break;
  639. case ICOLC_URL_TYPE:
  640. iRet = ualstrcmp(pidl1->szTypeName, pidl2->szTypeName);
  641. break;
  642. case ICOLC_URL_SIZE:
  643. iRet = _CompareSize(pidl1, pidl2);
  644. break;
  645. case ICOLC_URL_MODIFIED:
  646. iRet = ULCompareFileTime(&pidl1->cei.LastModifiedTime,
  647. &pidl2->cei.LastModifiedTime);
  648. break;
  649. case ICOLC_URL_ACCESSED:
  650. iRet = ULCompareFileTime(&pidl1->cei.LastAccessTime,
  651. &pidl2->cei.LastAccessTime);
  652. break;
  653. case ICOLC_URL_EXPIRES:
  654. iRet = ULCompareFileTime(&pidl1->cei.ExpireTime,
  655. &pidl2->cei.ExpireTime);
  656. break;
  657. case ICOLC_URL_LASTSYNCED:
  658. iRet = ULCompareFileTime(&pidl1->cei.LastSyncTime,
  659. &pidl2->cei.LastSyncTime);
  660. break;
  661. default:
  662. iRet = -1;
  663. }
  664. return ResultFromShort((SHORT)iRet);
  665. }
  666. HRESULT CCacheFolder::CreateViewObject(HWND hwnd, REFIID riid, void **ppv)
  667. {
  668. HRESULT hr = E_NOINTERFACE;
  669. *ppv = NULL;
  670. if (riid == IID_IShellView)
  671. {
  672. hr = CacheFolderView_CreateInstance(this, ppv);
  673. }
  674. else if (riid == IID_IContextMenu)
  675. {
  676. // this creates the "Arrange Icons" cascased menu in the background of folder view
  677. CFolderArrangeMenu *p = new CFolderArrangeMenu(MENU_CACHE);
  678. if (p)
  679. {
  680. hr = p->QueryInterface(riid, ppv);
  681. p->Release();
  682. }
  683. else
  684. hr = E_OUTOFMEMORY;
  685. }
  686. else if (riid == IID_IShellDetails)
  687. {
  688. CDetailsOfFolder *p = new CDetailsOfFolder(hwnd, this);
  689. if (p)
  690. {
  691. hr = p->QueryInterface(riid, ppv);
  692. p->Release();
  693. }
  694. else
  695. hr = E_OUTOFMEMORY;
  696. }
  697. return hr;
  698. }
  699. // Right now, we will allow TIF Drag in Browser Only, even though
  700. // it will not be Zone Checked at the Drop.
  701. //#define BROWSERONLY_NOTIFDRAG
  702. HRESULT CCacheFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl,
  703. ULONG * prgfInOut)
  704. {
  705. ULONG rgfInOut;
  706. HRESULT hr = E_UNEXPECTED;
  707. // Make sure each pidl in the array is dword aligned.
  708. if (apidl && IS_VALID_CEIPIDL(apidl[0]))
  709. {
  710. BOOL fRealigned;
  711. hr = AlignPidlArray(apidl, cidl, &apidl, &fRealigned);
  712. if (SUCCEEDED(hr))
  713. {
  714. rgfInOut = SFGAO_FILESYSTEM | SFGAO_CANDELETE | SFGAO_HASPROPSHEET;
  715. #ifdef BROWSERONLY_NOTIFDRAG
  716. if (PLATFORM_INTEGRATED == WhichPlatform())
  717. #endif // BROWSERONLY_NOTIFDRAG
  718. {
  719. SetFlag(rgfInOut, SFGAO_CANCOPY);
  720. }
  721. // all items can be deleted
  722. if (SUCCEEDED(hr))
  723. rgfInOut |= SFGAO_CANDELETE;
  724. *prgfInOut = rgfInOut;
  725. if (fRealigned)
  726. FreeRealignedPidlArray(apidl, cidl);
  727. }
  728. }
  729. else if (_pshfSys)
  730. {
  731. hr = _pshfSys->GetAttributesOf(cidl, apidl, prgfInOut);
  732. }
  733. if (FAILED(hr))
  734. *prgfInOut = 0;
  735. return hr;
  736. }
  737. HRESULT CCacheFolder::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl,
  738. REFIID riid, UINT * prgfInOut, void **ppv)
  739. {
  740. HRESULT hr = E_NOINTERFACE;
  741. *ppv = NULL; // null the out param
  742. // Make sure all pidls in the array are dword aligned.
  743. if (apidl && IS_VALID_CEIPIDL(apidl[0]))
  744. {
  745. BOOL fRealigned;
  746. hr = AlignPidlArray(apidl, cidl, &apidl, &fRealigned);
  747. if (SUCCEEDED(hr))
  748. {
  749. if ((riid == IID_IShellLinkA) ||
  750. (riid == IID_IShellLinkW) ||
  751. (riid == IID_IExtractIconA) ||
  752. (riid == IID_IExtractIconW) ||
  753. (riid == IID_IQueryInfo))
  754. {
  755. LPCTSTR pszURL = CPidlToSourceUrl((LPCEIPIDL)apidl[0]);
  756. hr = _GetShortcut(pszURL, riid, ppv);
  757. }
  758. else if ((riid == IID_IContextMenu) ||
  759. (riid == IID_IDataObject) ||
  760. (riid == IID_IExtractIconA) ||
  761. (riid == IID_IExtractIconW))
  762. {
  763. hr = CCacheItem_CreateInstance(this, hwnd, cidl, apidl, riid, ppv);
  764. }
  765. else
  766. {
  767. hr = E_FAIL;
  768. }
  769. if (fRealigned)
  770. FreeRealignedPidlArray(apidl, cidl);
  771. }
  772. }
  773. else if (_pshfSys)
  774. {
  775. // delegate to the filesystem
  776. hr = _pshfSys->GetUIObjectOf(hwnd, cidl, apidl, riid, prgfInOut, ppv);
  777. }
  778. return hr;
  779. }
  780. HRESULT CCacheFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
  781. {
  782. if (pSort)
  783. {
  784. *pSort = 0;
  785. }
  786. if (pDisplay)
  787. {
  788. *pDisplay = 0;
  789. }
  790. return S_OK;
  791. }
  792. HRESULT CCacheFolder::_GetInfoTip(LPCITEMIDLIST pidl, DWORD dwFlags, WCHAR **ppwszTip)
  793. {
  794. *ppwszTip = NULL;
  795. return E_FAIL;
  796. }
  797. HRESULT CCacheFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, STRRET *pstr)
  798. {
  799. BOOL fRealigned;
  800. HRESULT hr = E_FAIL;
  801. if (!IS_VALID_CEIPIDL(pidl))
  802. {
  803. if (_pshfSys)
  804. {
  805. // delegate to the filesystem
  806. hr = _pshfSys->GetDisplayNameOf(pidl, uFlags, pstr);
  807. }
  808. }
  809. else if (SUCCEEDED(AlignPidl(&pidl, &fRealigned)))
  810. {
  811. hr = GetDisplayNameOfCEI(pidl, uFlags, pstr);
  812. if (fRealigned)
  813. FreeRealignedPidl(pidl);
  814. }
  815. return hr;
  816. }
  817. HRESULT CCacheFolder::GetDisplayNameOfCEI(LPCITEMIDLIST pidl, DWORD uFlags, STRRET *pstr)
  818. {
  819. TCHAR szTemp[MAX_URL_STRING];
  820. szTemp[0] = 0;
  821. LPCTSTR pszTitle = _FindURLFileName(CEI_SOURCEURLNAME((LPCEIPIDL)pidl));
  822. // _GetURLTitle could return the real title or just an URL.
  823. // We use _URLTitleIsURL to make sure we don't unescape any titles.
  824. if (pszTitle && *pszTitle)
  825. {
  826. StrCpyN(szTemp, pszTitle, ARRAYSIZE(szTemp));
  827. }
  828. else
  829. {
  830. LPCTSTR pszUrl = _StripHistoryUrlToUrl(CPidlToSourceUrl((LPCEIPIDL)pidl));
  831. if (pszUrl)
  832. StrCpyN(szTemp, pszUrl, ARRAYSIZE(szTemp));
  833. }
  834. if (!(uFlags & SHGDN_FORPARSING))
  835. {
  836. DWORD cchBuf = ARRAYSIZE(szTemp);
  837. PrepareURLForDisplayUTF8(szTemp, szTemp, &cchBuf, TRUE);
  838. SHELLSTATE ss;
  839. SHGetSetSettings(&ss, SSF_SHOWEXTENSIONS, FALSE);
  840. if (!ss.fShowExtensions)
  841. PathRemoveExtension(szTemp);
  842. }
  843. return StringToStrRet(szTemp, pstr);
  844. }
  845. HRESULT CCacheFolder::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl,
  846. LPCOLESTR pszName, DWORD uFlags, LPITEMIDLIST *ppidlOut)
  847. {
  848. if (ppidlOut)
  849. *ppidlOut = NULL; // null the out param
  850. return E_FAIL;
  851. }
  852. //
  853. // IShellIcon Methods...
  854. //
  855. HRESULT CCacheFolder::GetIconOf(LPCITEMIDLIST pidl, UINT flags, LPINT lpIconIndex)
  856. {
  857. BOOL fRealigned;
  858. HRESULT hr = E_FAIL;
  859. if (!IS_VALID_CEIPIDL(pidl))
  860. {
  861. if (_pshfSys)
  862. {
  863. IShellIcon* pshi;
  864. hr = _pshfSys->QueryInterface(IID_PPV_ARG(IShellIcon, &pshi));
  865. if (SUCCEEDED(hr))
  866. {
  867. hr = pshi->GetIconOf(pidl, flags, lpIconIndex);
  868. pshi->Release();
  869. }
  870. }
  871. }
  872. else if (SUCCEEDED(AlignPidl(&pidl, &fRealigned)))
  873. {
  874. SHFILEINFO shfi;
  875. LPCTSTR pszIconFile = CEI_LOCALFILENAME((LPCEIPIDL)pidl);
  876. if (SHGetFileInfo(pszIconFile, 0, &shfi, sizeof(shfi),
  877. SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_SMALLICON))
  878. {
  879. *lpIconIndex = shfi.iIcon;
  880. hr = S_OK;
  881. }
  882. if (fRealigned)
  883. FreeRealignedPidl(pidl);
  884. }
  885. return hr;
  886. }
  887. // IPersist
  888. HRESULT CCacheFolder::Initialize(LPCITEMIDLIST pidlInit)
  889. {
  890. ILFree(_pidl);
  891. if (_pshfSys)
  892. {
  893. _pshfSys->Release();
  894. _pshfSys = NULL;
  895. }
  896. HRESULT hr;
  897. if (IsCSIDLFolder(CSIDL_INTERNET_CACHE, pidlInit))
  898. {
  899. hr = SHILClone(pidlInit, &_pidl);
  900. if (SUCCEEDED(hr))
  901. {
  902. hr = _GetFileSysFolder(&_pshfSys);
  903. // On a pre-Win2k shell, CLSID_ShellFSFolder will not be registered. However, it does not
  904. // impact the operation of the cache folder. So rather than propogate a failure return value to
  905. // the shell, we treat that case as success.
  906. if (FAILED(hr))
  907. {
  908. // This is a pre-Win2k shell. Return S_OK.
  909. hr = S_OK;
  910. }
  911. }
  912. }
  913. else
  914. {
  915. hr = E_FAIL;
  916. }
  917. return hr;
  918. }
  919. //
  920. // IPersistFolder2 Methods...
  921. //
  922. HRESULT CCacheFolder::GetCurFolder(LPITEMIDLIST *ppidl)
  923. {
  924. if (_pidl)
  925. return SHILClone(_pidl, ppidl);
  926. *ppidl = NULL;
  927. return S_FALSE; // success but empty
  928. }
  929. void _GetFileTypeInternal(LPCEIPIDL pidl, LPUTSTR pszuStr, UINT cchStr)
  930. {
  931. SHFILEINFO shInfo;
  932. LPTSTR pszStr;
  933. if (TSTR_ALIGNED(pszuStr) == FALSE)
  934. {
  935. //
  936. // If pszuStr is in fact unaligned, allocate some scratch
  937. // space on the stack for the output copy of this string.
  938. //
  939. pszStr = (LPTSTR)_alloca(cchStr * sizeof(TCHAR));
  940. }
  941. else
  942. {
  943. pszStr = (LPTSTR)pszuStr;
  944. }
  945. if (SHGetFileInfo(CEI_LOCALFILENAME((LPCEIPIDL)pidl), FILE_ATTRIBUTE_NORMAL,
  946. &shInfo, sizeof(shInfo),
  947. SHGFI_USEFILEATTRIBUTES | SHGFI_TYPENAME)
  948. && shInfo.szTypeName[0])
  949. {
  950. StrCpyN(pszStr, shInfo.szTypeName, cchStr);
  951. }
  952. else
  953. {
  954. LPTSTR psz = PathFindExtension(CEI_LOCALFILENAME((LPCEIPIDL)pidl));
  955. DWORD dw;
  956. ASSERT((pszStr && (cchStr>0)));
  957. *pszStr = 0;
  958. if (psz && *psz)
  959. {
  960. psz++;
  961. StrCpyN(pszStr, psz, cchStr);
  962. CharUpper(pszStr);
  963. StrCatBuff(pszStr, TEXT(" "), cchStr);
  964. }
  965. dw = lstrlen(pszStr);
  966. MLLoadString(IDS_FILE_TYPE, pszStr+dw, cchStr-dw);
  967. }
  968. if (TSTR_ALIGNED(pszuStr) == FALSE)
  969. {
  970. // If pszuStr was unaligned then copy the output string from
  971. // the scratch space on the stack to the supplied output buffer
  972. ualstrcpyn(pszuStr, pszStr, cchStr);
  973. }
  974. }