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.

345 lines
9.7 KiB

  1. #include <shellprv.h>
  2. #include "enumidlist.h"
  3. CEnumIDListBase::CEnumIDListBase() : _cRef(1)
  4. {
  5. }
  6. CEnumIDListBase::~CEnumIDListBase()
  7. {
  8. }
  9. STDMETHODIMP CEnumIDListBase::QueryInterface(REFIID riid, void **ppv)
  10. {
  11. static const QITAB qit[] = {
  12. QITABENT(CEnumIDListBase, IEnumIDList), // IID_IEnumIDList
  13. QITABENT(CEnumIDListBase, IObjectWithSite), // IID_IObjectWithSite
  14. { 0 },
  15. };
  16. return QISearch(this, qit, riid, ppv);
  17. }
  18. STDMETHODIMP_(ULONG) CEnumIDListBase::AddRef()
  19. {
  20. return InterlockedIncrement(&_cRef);
  21. }
  22. STDMETHODIMP_(ULONG) CEnumIDListBase::Release()
  23. {
  24. ASSERT( 0 != _cRef );
  25. ULONG cRef = InterlockedDecrement(&_cRef);
  26. if ( 0 == cRef )
  27. {
  28. delete this;
  29. }
  30. return cRef;
  31. }
  32. class CEnumArray : public CEnumIDListBase
  33. {
  34. public:
  35. CEnumArray();
  36. HRESULT Init(const LPCITEMIDLIST rgpidl[], UINT cidl, UINT ulIndex);
  37. HRESULT InitFromPaths(LPCTSTR pszPaths);
  38. HRESULT InitFromCSIDLArray(const LPCTSTR rgcsidl[], UINT ccsidls, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  39. // IEnumIDList
  40. STDMETHODIMP Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched);
  41. STDMETHODIMP Skip(ULONG celt);
  42. STDMETHODIMP Reset();
  43. STDMETHODIMP Clone(IEnumIDList **ppenum);
  44. protected:
  45. virtual ~CEnumArray();
  46. LPITEMIDLIST *_ppidl;
  47. BOOL _InitFolderParent(LPITEMIDLIST rgItems[], UINT cMaxItems, UINT *pcItems, LPCITEMIDLIST pidlFolder, LPITEMIDLIST *ppidlParent);
  48. LPITEMIDLIST _ILLogical(LPCITEMIDLIST pidl);
  49. BOOL _ShouldEnumCSIDL(int csidl);
  50. private:
  51. LONG _cRef;
  52. ULONG _ulIndex;
  53. UINT _cItems;
  54. };
  55. CEnumArray::CEnumArray() : CEnumIDListBase()
  56. {
  57. }
  58. CEnumArray::~CEnumArray()
  59. {
  60. if (_ppidl)
  61. FreeIDListArray(_ppidl, _cItems);
  62. }
  63. HRESULT CEnumArray::Init(const LPCITEMIDLIST rgpidl[], UINT cidl, UINT ulIndex)
  64. {
  65. _ulIndex = ulIndex;
  66. HRESULT hr = CloneIDListArray(cidl, rgpidl, &_cItems, &_ppidl);
  67. if (S_FALSE == hr)
  68. hr = S_OK; // S_FALSE to S_OK
  69. return hr;
  70. }
  71. HRESULT CEnumArray::InitFromCSIDLArray(const LPCTSTR rgcsidl[], UINT ccsidls, LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlItem)
  72. {
  73. LPITEMIDLIST rgItems[32] = {0}; // reasonable max size, grow as needed
  74. UINT cItems = 0;
  75. LPITEMIDLIST pidlParent = NULL; // pidlFolder's pidlParent (filesystem or logical pidl)
  76. LPITEMIDLIST pidlParentLogical = NULL; // pidlFolder's pidlParent (logical pidl -- if exists)
  77. // Initialize pidlFolder's parent pidl.
  78. if (_InitFolderParent(rgItems, ARRAYSIZE(rgItems), &cItems, pidlFolder, &pidlParent))
  79. {
  80. // Retrieve pidlFolder's logical parent pidl.
  81. pidlParentLogical = _ILLogical(pidlParent);
  82. }
  83. // Initialize pidlItem.
  84. if (pidlItem &&
  85. (!pidlParent || !ILIsEqual(pidlItem, pidlParent)) &&
  86. (!pidlParentLogical || !ILIsEqual(pidlItem, pidlParentLogical)))
  87. {
  88. if (rgItems[cItems] = ILClone(pidlItem))
  89. {
  90. cItems++;
  91. }
  92. }
  93. // Initialize CSIDLs.
  94. for (UINT i = 0; (i < ccsidls) && (cItems < ARRAYSIZE(rgItems)); i++)
  95. {
  96. LPITEMIDLIST pidl;
  97. if (IS_INTRESOURCE(rgcsidl[i]))
  98. {
  99. int csidl = LOWORD((UINT_PTR)rgcsidl[i]);
  100. if (_ShouldEnumCSIDL(csidl))
  101. SHGetSpecialFolderLocation(NULL, csidl, &pidl);
  102. else
  103. pidl = NULL;
  104. }
  105. else
  106. {
  107. SHParseDisplayName((LPTSTR)rgcsidl[i], NULL, &pidl, 0, NULL);
  108. }
  109. if (pidl)
  110. {
  111. DWORD dwAttribs = SFGAO_NONENUMERATED;
  112. if ((pidlFolder && ILIsEqual(pidlFolder, pidl)) || // if pidl is not myself
  113. (pidlParent && ILIsEqual(pidlParent, pidl)) || // if pidl is not my parent
  114. (pidlParentLogical && ILIsEqual(pidlParentLogical, pidl)) || // (need to check logical parent too)
  115. (pidlItem && ILIsEqual(pidlItem, pidl)) || // if pidl is not pidlItem
  116. FAILED(SHGetNameAndFlags(pidl, 0, NULL, 0, &dwAttribs)) || // if pidl is not SFGAO_NONENUMERATED
  117. (SFGAO_NONENUMERATED & dwAttribs))
  118. {
  119. ILFree(pidl);
  120. }
  121. else
  122. {
  123. rgItems[cItems++] = pidl; // then add pidl
  124. }
  125. }
  126. }
  127. // Initialize CEnumArray with collected pidls.
  128. HRESULT hr = Init(rgItems, cItems, 0);
  129. // Cleanup.
  130. for (i = 0; i < cItems; i++)
  131. {
  132. ILFree(rgItems[i]);
  133. }
  134. ILFree(pidlParentLogical);
  135. return hr;
  136. }
  137. BOOL CEnumArray::_InitFolderParent(LPITEMIDLIST rgItems[], UINT cMaxItems, UINT *pcItems, LPCITEMIDLIST pidlFolder, LPITEMIDLIST *ppidlParent)
  138. {
  139. ASSERT(*pcItems == 0); // Currently we expect to add the parent pidl as the FIRST entry.
  140. ASSERT(cMaxItems > 0); // Sanity check.
  141. // If there is a pidlFolder and it's NOT the Desktop pidl, add its parent
  142. // as the first entry in the rgItems array. Note that the reason we
  143. // exclude the Desktop pidl from having its parent added to the array is
  144. // because its parent is itself, and we don't want the folder we're
  145. // currently in appearing in rgItems since we're already there!
  146. if (pidlFolder && !ILIsEmpty(pidlFolder))
  147. {
  148. *ppidlParent = ILCloneParent(pidlFolder);
  149. if (*ppidlParent)
  150. {
  151. rgItems[*pcItems] = *ppidlParent;
  152. (*pcItems)++;
  153. }
  154. }
  155. else
  156. {
  157. *ppidlParent = NULL;
  158. }
  159. return (*ppidlParent != NULL);
  160. }
  161. // Description:
  162. // _ILLogical() will return NULL in three cases:
  163. // 1. out of memory
  164. // 2. pidl has no logical pidl equivalent
  165. // 3. pidl is SAME as logical pidl equivalent
  166. // (thus we already have the logical pidl)
  167. //
  168. // Note:
  169. // ILFree() must be called on returned pidls.
  170. //
  171. LPITEMIDLIST CEnumArray::_ILLogical(LPCITEMIDLIST pidl)
  172. {
  173. LPITEMIDLIST pidlLogical = SHLogILFromFSIL(pidl);
  174. if (pidlLogical && ILIsEqual(pidl, pidlLogical))
  175. {
  176. // If the pidl argument is logical, then we already
  177. // have the logical pidl so don't return another one.
  178. ILFree(pidlLogical);
  179. pidlLogical = NULL;
  180. }
  181. return pidlLogical;
  182. }
  183. STDMETHODIMP CEnumArray::Next(ULONG celt, LPITEMIDLIST *ppidl, ULONG *pceltFetched)
  184. {
  185. HRESULT hr = S_FALSE;
  186. if (_ppidl && (_ulIndex < _cItems))
  187. {
  188. hr = SHILClone(_ppidl[_ulIndex++], ppidl);
  189. }
  190. if (pceltFetched)
  191. *pceltFetched = (hr == S_OK) ? 1 : 0;
  192. return hr;
  193. }
  194. STDMETHODIMP CEnumArray::Skip(ULONG celt)
  195. {
  196. _ulIndex = min(_cItems, _ulIndex + celt);
  197. return S_OK;
  198. }
  199. STDMETHODIMP CEnumArray::Reset()
  200. {
  201. _ulIndex = 0;
  202. return S_OK;
  203. }
  204. HRESULT _CreateIEnumIDListOnIDLists(const LPCITEMIDLIST rgpidl[], UINT cItems, UINT ulIndex, IEnumIDList **ppenum)
  205. {
  206. HRESULT hr = E_OUTOFMEMORY;
  207. *ppenum = NULL;
  208. CEnumArray *p = new CEnumArray();
  209. if (p)
  210. {
  211. hr = p->Init(rgpidl, cItems, ulIndex);
  212. if (SUCCEEDED(hr))
  213. {
  214. hr = p->QueryInterface(IID_PPV_ARG(IEnumIDList, ppenum));
  215. }
  216. p->Release();
  217. }
  218. return hr;
  219. }
  220. STDMETHODIMP CEnumArray::Clone(IEnumIDList **ppenum)
  221. {
  222. return _CreateIEnumIDListOnIDLists(_ppidl, _cItems, _ulIndex, ppenum);
  223. }
  224. // Depending on the current state of the world, certain we may not want
  225. // to allow certain CSIDLs to be enumerated (i.e. we want to hide them).
  226. //
  227. BOOL CEnumArray::_ShouldEnumCSIDL(int csidl)
  228. {
  229. BOOL bEnum;
  230. switch (csidl)
  231. {
  232. case CSIDL_COMMON_DOCUMENTS:
  233. case CSIDL_COMMON_MUSIC:
  234. case CSIDL_COMMON_PICTURES:
  235. case CSIDL_COMMON_VIDEO:
  236. bEnum = SHShowSharedFolders();
  237. break;
  238. default:
  239. bEnum = TRUE;
  240. break;
  241. }
  242. return bEnum;
  243. }
  244. STDAPI CreateIEnumIDListOnIDLists(const LPCITEMIDLIST rgpidl[], UINT cItems, IEnumIDList **ppenum)
  245. {
  246. return _CreateIEnumIDListOnIDLists(rgpidl, cItems, 0, ppenum);
  247. }
  248. STDAPI CreateIEnumIDListOnCSIDLs(LPCITEMIDLIST pidlFolder, const LPCTSTR rgcsidl[], UINT cItems, IEnumIDList **ppenum)
  249. {
  250. return CreateIEnumIDListOnCSIDLs2(pidlFolder, NULL, rgcsidl, cItems, ppenum);
  251. }
  252. STDAPI CreateIEnumIDListOnCSIDLs2(LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlItem, const LPCTSTR rgcsidl[], UINT cItems, IEnumIDList **ppenum)
  253. {
  254. HRESULT hr = E_OUTOFMEMORY;
  255. *ppenum = NULL;
  256. CEnumArray *p = new CEnumArray();
  257. if (p)
  258. {
  259. hr = p->InitFromCSIDLArray(rgcsidl, cItems, pidlFolder, pidlItem);
  260. if (SUCCEEDED(hr))
  261. {
  262. hr = p->QueryInterface(IID_PPV_ARG(IEnumIDList, ppenum));
  263. }
  264. p->Release();
  265. }
  266. return hr;
  267. }
  268. STDAPI CreateIEnumIDListPaths(LPCTSTR pszPaths, IEnumIDList **ppenum)
  269. {
  270. *ppenum = NULL;
  271. HRESULT hr = E_FAIL;
  272. LPITEMIDLIST rgItems[32] = {0};
  273. TCHAR szPath[MAX_PATH];
  274. LPCTSTR pszNext = pszPaths;
  275. int cItems = 0;
  276. while ((cItems < ARRAYSIZE(rgItems)) && (pszNext = NextPath(pszNext, szPath, ARRAYSIZE(szPath))))
  277. {
  278. PathRemoveBackslash(szPath);
  279. TCHAR szExpanded[MAX_PATH];
  280. if (SHExpandEnvironmentStrings(szPath, szExpanded, ARRAYSIZE(szExpanded)))
  281. {
  282. if (SUCCEEDED(SHParseDisplayName(szExpanded, NULL, &rgItems[cItems], 0, NULL)))
  283. {
  284. cItems++;
  285. }
  286. }
  287. }
  288. if (cItems > 0)
  289. {
  290. hr = _CreateIEnumIDListOnIDLists(rgItems, cItems, 0, ppenum);
  291. for (int i = 0; i < cItems; i++)
  292. ILFree(rgItems[i]);
  293. }
  294. return hr;
  295. }