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.

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