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.

448 lines
14 KiB

  1. #include "priv.h"
  2. #include "nsc.h"
  3. #include "nsctask.h"
  4. #define PRIORITY_ENUM ITSAT_DEFAULT_PRIORITY
  5. #define PRIORITY_ICON PRIORITY_ENUM + 1 //needs to be slightly higher priority
  6. #define PRIORITY_OVERLAY ITSAT_DEFAULT_PRIORITY
  7. /////////////////////////////////////////////////////////////////////////
  8. // COPY AND PASTE ALERT
  9. // this code is mostly copied and pasted from browseui/icotask.cpp
  10. // see lamadio and/or davemi for why these aren't combined or shared
  11. /////////////////////////////////////////////////////////////////////////
  12. // {7DB7F689-BBDB-483f-A8A9-C6E963E8D274}
  13. EXTERN_C const GUID TASKID_BackgroundEnum = { 0x7db7f689, 0xbbdb, 0x483f, { 0xa8, 0xa9, 0xc6, 0xe9, 0x63, 0xe8, 0xd2, 0x74 } };
  14. // {EB30900C-1AC4-11d2-8383-00C04FD918D0}
  15. EXTERN_C const GUID TASKID_IconExtraction = { 0xeb30900c, 0x1ac4, 0x11d2, { 0x83, 0x83, 0x0, 0xc0, 0x4f, 0xd9, 0x18, 0xd0 } };
  16. // {EB30900D-1AC4-11d2-8383-00C04FD918D0}
  17. EXTERN_C const GUID TASKID_OverlayExtraction = { 0xeb30900d, 0x1ac4, 0x11d2, { 0x83, 0x83, 0x0, 0xc0, 0x4f, 0xd9, 0x18, 0xd0 } };
  18. class CNscIconTask : public CRunnableTask
  19. {
  20. public:
  21. CNscIconTask(LPITEMIDLIST pidl, PFNNSCICONTASKBALLBACK pfn, CNscTree *pns, UINT_PTR uId, UINT uSynchId);
  22. // IRunnableTask
  23. STDMETHODIMP RunInitRT(void);
  24. protected:
  25. virtual ~CNscIconTask();
  26. virtual void _Extract(IShellFolder *psf, LPCITEMIDLIST pidlItem);
  27. BOOL _bOverlayTask;
  28. LPITEMIDLIST _pidl;
  29. PFNNSCICONTASKBALLBACK _pfnIcon;
  30. CNscTree *_pns;
  31. UINT_PTR _uId;
  32. UINT _uSynchId;
  33. };
  34. CNscIconTask::CNscIconTask(LPITEMIDLIST pidl, PFNNSCICONTASKBALLBACK pfn, CNscTree *pns, UINT_PTR uId, UINT uSynchId):
  35. _pidl(pidl), _pfnIcon(pfn), _uId(uId), _uSynchId(uSynchId), CRunnableTask(RTF_DEFAULT)
  36. {
  37. _pns = pns;
  38. if (_pns)
  39. _pns->AddRef();
  40. }
  41. CNscIconTask::~CNscIconTask()
  42. {
  43. if (_pns)
  44. _pns->Release();
  45. ILFree(_pidl);
  46. }
  47. // IRunnableTask methods (override)
  48. STDMETHODIMP CNscIconTask::RunInitRT(void)
  49. {
  50. IShellFolder* psf;
  51. LPCITEMIDLIST pidlItem;
  52. // We need to rebind because shell folders may not be thread safe.
  53. if (SUCCEEDED(IEBindToParentFolder(_pidl, &psf, &pidlItem)))
  54. {
  55. _Extract(psf, pidlItem);
  56. psf->Release();
  57. }
  58. return S_OK;
  59. }
  60. void CNscIconTask::_Extract(IShellFolder *psf, LPCITEMIDLIST pidlItem)
  61. {
  62. int iIcon = -1, iIconOpen = -1;
  63. #ifdef IE5_36825
  64. HRESULT hr = E_FAIL;
  65. IShellIcon *psi;
  66. if (SUCCEEDED(psf->QueryInterface(IID_PPV_ARG(IShellIcon, &psi))))
  67. {
  68. hr = psi->GetIconOf(pidlItem, 0, &iIcon);
  69. if (hr == S_OK)
  70. {
  71. ULONG ulAttrs = SFGAO_FOLDER;
  72. psf->GetAttributesOf(1, &pidlItem, &ulAttrs);
  73. if (!(ulAttrs & SFGAO_FOLDER) || FAILED(psi->GetIconOf(pidlItem, GIL_OPENICON, &iIconOpen)))
  74. iIconOpen = iIcon;
  75. }
  76. psi->Release();
  77. }
  78. if (hr != S_OK)
  79. {
  80. #endif
  81. // slow way...
  82. iIcon = IEMapPIDLToSystemImageListIndex(psf, pidlItem, &iIconOpen);
  83. #ifdef IE5_36825
  84. }
  85. #endif
  86. // REARCHITECT : This is no good. We are attempted to see if the content is offline. That should
  87. // be done by using IQueryInfo::xxx(). This should go in the InternetShortcut object.
  88. // IShellFolder2::GetItemData or can also be used.
  89. //
  90. // See if it is a link. If it is not, then it can't be in the wininet cache and can't
  91. // be pinned (sticky cache entry) or greyed (unavailable when offline)
  92. DWORD dwFlags = 0;
  93. BOOL fAvailable;
  94. BOOL fSticky;
  95. // GetLinkInfo() will fail if the SFGAO_FOLDER or SFGAO_BROWSER bits aren't set.
  96. if (pidlItem && SUCCEEDED(GetLinkInfo(psf, pidlItem, &fAvailable, &fSticky)))
  97. {
  98. if (!fAvailable)
  99. {
  100. dwFlags |= NSCICON_GREYED;
  101. }
  102. if (fSticky)
  103. {
  104. dwFlags |= NSCICON_PINNED;
  105. }
  106. }
  107. else
  108. {
  109. //item is not a link
  110. dwFlags |= NSCICON_DONTREFETCH;
  111. }
  112. _pfnIcon(_pns, _uId, iIcon, iIconOpen, dwFlags, _uSynchId);
  113. }
  114. // takes ownership of pidl
  115. HRESULT AddNscIconTask(IShellTaskScheduler* pts, LPITEMIDLIST pidl, PFNNSCICONTASKBALLBACK pfn, CNscTree *pns, UINT_PTR uId, UINT uSynchId)
  116. {
  117. HRESULT hr;
  118. CNscIconTask* pTask = new CNscIconTask(pidl, pfn, pns, uId, uSynchId);
  119. if (pTask)
  120. {
  121. hr = pts->AddTask(SAFECAST(pTask, IRunnableTask*), TASKID_IconExtraction,
  122. ITSAT_DEFAULT_LPARAM, PRIORITY_ICON);
  123. pTask->Release();
  124. }
  125. else
  126. {
  127. hr = E_OUTOFMEMORY;
  128. ILFree(pidl);
  129. }
  130. return hr;
  131. }
  132. class CNscOverlayTask : public CNscIconTask
  133. {
  134. public:
  135. CNscOverlayTask(LPITEMIDLIST pidl, PFNNSCOVERLAYTASKBALLBACK pfn, CNscTree *pns, UINT_PTR uId, UINT uSynchId);
  136. protected:
  137. virtual void _Extract(IShellFolder *psf, LPCITEMIDLIST pidlItem);
  138. PFNNSCOVERLAYTASKBALLBACK _pfnOverlay;
  139. };
  140. CNscOverlayTask::CNscOverlayTask(LPITEMIDLIST pidl, PFNNSCOVERLAYTASKBALLBACK pfn, CNscTree *pns, UINT_PTR uId, UINT uSynchId) :
  141. CNscIconTask(pidl, NULL, pns, uId, uSynchId), _pfnOverlay(pfn)
  142. {
  143. }
  144. void CNscOverlayTask::_Extract(IShellFolder *psf, LPCITEMIDLIST pidlItem)
  145. {
  146. IShellIconOverlay *psio;
  147. if (SUCCEEDED(psf->QueryInterface(IID_PPV_ARG(IShellIconOverlay, &psio))))
  148. {
  149. int iOverlayIndex = 0;
  150. if (psio->GetOverlayIndex(pidlItem, &iOverlayIndex) == S_OK && iOverlayIndex > 0)
  151. {
  152. _pfnOverlay(_pns, _uId, iOverlayIndex, _uSynchId);
  153. }
  154. psio->Release();
  155. }
  156. }
  157. // takes ownership of pidl
  158. HRESULT AddNscOverlayTask(IShellTaskScheduler* pts, LPITEMIDLIST pidl, PFNNSCOVERLAYTASKBALLBACK pfn, CNscTree *pns, UINT_PTR uId, UINT uSynchId)
  159. {
  160. HRESULT hr;
  161. CNscOverlayTask *pTask = new CNscOverlayTask(pidl, pfn, pns, uId, uSynchId);
  162. if (pTask)
  163. {
  164. hr = pts->AddTask(SAFECAST(pTask, IRunnableTask*), TASKID_OverlayExtraction,
  165. ITSAT_DEFAULT_LPARAM, PRIORITY_OVERLAY);
  166. pTask->Release();
  167. }
  168. else
  169. {
  170. hr = E_OUTOFMEMORY;
  171. ILFree(pidl); // we own it, clean up here
  172. }
  173. return hr;
  174. }
  175. class CNscEnumTask : public CRunnableTask
  176. {
  177. public:
  178. CNscEnumTask(PFNNSCENUMTASKBALLBACK pfn,
  179. CNscTree *pns, UINT_PTR uId, DWORD dwSig, DWORD grfFlags, HDPA hdpaOrder,
  180. DWORD dwOrderSig, BOOL fForceExpand, UINT uDepth, BOOL fUpdate, BOOL fUpdatePidls);
  181. HRESULT Init(LPCITEMIDLIST pidl, LPCITEMIDLIST pidlExpandingTo);
  182. // IRunnableTask
  183. STDMETHODIMP RunInitRT(void);
  184. STDMETHODIMP InternalResumeRT(void);
  185. private:
  186. virtual ~CNscEnumTask();
  187. LPITEMIDLIST _pidl;
  188. PFNNSCENUMTASKBALLBACK _pfn;
  189. CNscTree * _pns;
  190. UINT_PTR _uId;
  191. DWORD _dwSig;
  192. DWORD _grfFlags;
  193. HDPA _hdpaOrder;
  194. LPITEMIDLIST _pidlExpandingTo;
  195. DWORD _dwOrderSig;
  196. BOOL _fForceExpand;
  197. BOOL _fUpdate;
  198. BOOL _fUpdatePidls;
  199. UINT _uDepth;
  200. HDPA _hdpa;
  201. IShellFolder * _psf;
  202. IEnumIDList * _penum;
  203. static DWORD s_dwMaxItems;
  204. };
  205. DWORD CNscEnumTask::s_dwMaxItems = 0;
  206. CNscEnumTask::CNscEnumTask(PFNNSCENUMTASKBALLBACK pfn, CNscTree *pns,
  207. UINT_PTR uId, DWORD dwSig, DWORD grfFlags, HDPA hdpaOrder,
  208. DWORD dwOrderSig, BOOL fForceExpand, UINT uDepth,
  209. BOOL fUpdate, BOOL fUpdatePidls) :
  210. CRunnableTask(RTF_SUPPORTKILLSUSPEND), _pfn(pfn), _uId(uId), _dwSig(dwSig), _grfFlags(grfFlags),
  211. _hdpaOrder(hdpaOrder), _dwOrderSig(dwOrderSig), _fForceExpand(fForceExpand), _uDepth(uDepth),
  212. _fUpdate(fUpdate), _fUpdatePidls(fUpdatePidls)
  213. {
  214. _pns = pns;
  215. if (_pns)
  216. _pns->AddRef();
  217. }
  218. HRESULT CNscEnumTask::Init(LPCITEMIDLIST pidl, LPCITEMIDLIST pidlExpandingTo)
  219. {
  220. if (pidlExpandingTo)
  221. SHILClone(pidlExpandingTo, &_pidlExpandingTo); // failure OK
  222. return SHILClone(pidl, &_pidl);
  223. }
  224. CNscEnumTask::~CNscEnumTask()
  225. {
  226. if (_pns)
  227. _pns->Release();
  228. ILFree(_pidl);
  229. ILFree(_pidlExpandingTo);
  230. OrderList_Destroy(&_hdpaOrder, TRUE); // calls DPA_Destroy(_hdpaOrder)
  231. ATOMICRELEASE(_psf);
  232. ATOMICRELEASE(_penum);
  233. if (_hdpa)
  234. OrderList_Destroy(&_hdpa, TRUE); // calls DPA_Destroy(hdpa)
  235. }
  236. BOOL OrderList_AppendCustom(HDPA hdpa, LPITEMIDLIST pidl, int nOrder, DWORD dwAttrib)
  237. {
  238. PORDERITEM poi = OrderItem_Create(pidl, nOrder);
  239. if (poi)
  240. {
  241. poi->lParam = dwAttrib;
  242. if (-1 != DPA_AppendPtr(hdpa, poi))
  243. return TRUE;
  244. OrderItem_Free(poi, FALSE); //don't free pidl because caller will do it
  245. }
  246. return FALSE;
  247. }
  248. // IRunnableTask methods (override)
  249. STDMETHODIMP CNscEnumTask::RunInitRT(void)
  250. {
  251. if (!s_dwMaxItems)
  252. {
  253. DWORD dwDefaultLimit = 100; // Default value for the limit
  254. DWORD dwSize = sizeof(s_dwMaxItems);
  255. SHRegGetUSValue(TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"),
  256. TEXT("PartialExpandLimit"), NULL, &s_dwMaxItems, &dwSize,
  257. FALSE, &dwDefaultLimit, sizeof(dwDefaultLimit));
  258. if (!s_dwMaxItems)
  259. s_dwMaxItems = dwDefaultLimit;
  260. }
  261. HRESULT hr = E_OUTOFMEMORY;
  262. _hdpa = DPA_Create(2);
  263. if (_hdpa)
  264. {
  265. // We need to rebind because shell folders may not be thread safe.
  266. hr = IEBindToObject(_pidl, &_psf);
  267. if (SUCCEEDED(hr))
  268. {
  269. hr = _psf->EnumObjects(NULL, _grfFlags, &_penum);
  270. if (S_OK != hr)
  271. {
  272. // Callback function takes ownership of the pidls and hdpa
  273. _pfn(_pns, _pidl, _uId, _dwSig, _hdpa, _pidlExpandingTo, _dwOrderSig, _uDepth, _fUpdate, _fUpdatePidls);
  274. _pidl = NULL;
  275. _pidlExpandingTo = NULL;
  276. _hdpa = NULL;
  277. if (SUCCEEDED(hr))
  278. hr = E_FAIL;
  279. }
  280. }
  281. }
  282. return hr;
  283. }
  284. #define FILE_JUNCTION_FOLDER_FLAGS (SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_STREAM)
  285. STDMETHODIMP CNscEnumTask::InternalResumeRT(void)
  286. {
  287. HRESULT hr = S_OK;
  288. ULONG celt;
  289. LPITEMIDLIST pidlTemp;
  290. while (S_OK == _penum->Next(1, &pidlTemp, &celt))
  291. {
  292. // filter out zip files (they are both folders and files but we treat them as files)
  293. // on downlevel SFGAO_STREAM is the same as SFGAO_HASSTORAGE so we'll let zip files slide through (oh well)
  294. // better than not adding filesystem folders (that have storage)
  295. if (!(_grfFlags & SHCONTF_NONFOLDERS) && IsOS(OS_WHISTLERORGREATER) &&
  296. (SHGetAttributes(_psf, pidlTemp, FILE_JUNCTION_FOLDER_FLAGS) & FILE_JUNCTION_FOLDER_FLAGS) == FILE_JUNCTION_FOLDER_FLAGS)
  297. {
  298. ILFree(pidlTemp);
  299. }
  300. else if (!OrderList_AppendCustom(_hdpa, pidlTemp, -1, 0))
  301. {
  302. hr = E_OUTOFMEMORY;
  303. ILFree(pidlTemp);
  304. break;
  305. }
  306. if (!_fForceExpand && (DPA_GetPtrCount(_hdpa) > (int)s_dwMaxItems))
  307. {
  308. hr = E_ABORT;
  309. break;
  310. }
  311. // we were told to either suspend or quit...
  312. if (WaitForSingleObject(_hDone, 0) == WAIT_OBJECT_0)
  313. {
  314. return (_lState == IRTIR_TASK_SUSPENDED) ? E_PENDING : E_FAIL;
  315. }
  316. }
  317. if (hr == S_OK)
  318. {
  319. ORDERINFO oinfo;
  320. oinfo.psf = _psf;
  321. oinfo.dwSortBy = OI_SORTBYNAME; // merge depends on by name.
  322. if (_hdpaOrder && DPA_GetPtrCount(_hdpaOrder) > 0)
  323. {
  324. OrderList_Merge(_hdpa, _hdpaOrder, -1, (LPARAM)&oinfo, NULL, NULL);
  325. oinfo.dwSortBy = OI_SORTBYORDINAL;
  326. }
  327. else
  328. oinfo.dwSortBy = OI_SORTBYNAME;
  329. DPA_Sort(_hdpa, OrderItem_Compare, (LPARAM)&oinfo);
  330. OrderList_Reorder(_hdpa);
  331. // Callback function takes ownership of the pidls and hdpa
  332. _pfn(_pns, _pidl, _uId, _dwSig, _hdpa, _pidlExpandingTo, _dwOrderSig, _uDepth, _fUpdate, _fUpdatePidls);
  333. _pidl = NULL;
  334. _pidlExpandingTo = NULL;
  335. _hdpa = NULL;
  336. }
  337. return S_OK; // return S_OK even if we failed
  338. }
  339. HRESULT AddNscEnumTask(IShellTaskScheduler* pts, LPCITEMIDLIST pidl, PFNNSCENUMTASKBALLBACK pfn,
  340. CNscTree *pns, UINT_PTR uId, DWORD dwSig, DWORD grfFlags, HDPA hdpaOrder,
  341. LPCITEMIDLIST pidlExpandingTo, DWORD dwOrderSig,
  342. BOOL fForceExpand, UINT uDepth, BOOL fUpdate, BOOL fUpdatePidls)
  343. {
  344. HRESULT hr;
  345. CNscEnumTask *pTask = new CNscEnumTask(pfn, pns, uId, dwSig, grfFlags,
  346. hdpaOrder, dwOrderSig, fForceExpand, uDepth,
  347. fUpdate, fUpdatePidls);
  348. if (pTask)
  349. {
  350. hr = pTask->Init(pidl, pidlExpandingTo);
  351. if (SUCCEEDED(hr))
  352. {
  353. hr = pts->AddTask(SAFECAST(pTask, IRunnableTask*), TASKID_BackgroundEnum,
  354. ITSAT_DEFAULT_LPARAM, PRIORITY_ENUM);
  355. }
  356. pTask->Release();
  357. }
  358. else
  359. {
  360. OrderList_Destroy(&hdpaOrder, TRUE); // calls DPA_Destroy(hdpaOrder)
  361. hr = E_OUTOFMEMORY;
  362. }
  363. return hr;
  364. }
  365. #ifdef DEBUG
  366. #define TF_NSC 0x00002000
  367. void DumpOrderItem(IShellFolder *psf, PORDERITEM poi)
  368. {
  369. if (poi)
  370. {
  371. TCHAR szDebugName[MAX_URL_STRING] = TEXT("Desktop");
  372. DisplayNameOf(psf, poi->pidl, SHGDN_FORPARSING, szDebugName, ARRAYSIZE(szDebugName));
  373. TraceMsg(TF_NSC, "OrderItem (%d, %s)\n", poi->nOrder, szDebugName);
  374. }
  375. }
  376. void DumpOrderList(IShellFolder *psf, HDPA hdpa)
  377. {
  378. if (psf && hdpa)
  379. {
  380. TraceMsg(TF_NSC, "OrderList dump: #of items:%d\n", DPA_GetPtrCount(hdpa));
  381. for (int i = 0; i < DPA_GetPtrCount(hdpa); i++)
  382. {
  383. PORDERITEM poi = (PORDERITEM)DPA_GetPtr(hdpa, i);
  384. DumpOrderItem(psf, poi);
  385. }
  386. }
  387. }
  388. #endif