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.

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