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.

357 lines
8.2 KiB

  1. #include "shellprv.h"
  2. #include "idltree.h"
  3. BOOL CIDLData::Init(IDLDATAF flags, INT_PTR data)
  4. {
  5. _flags = flags;
  6. _data = data;
  7. return TRUE;
  8. }
  9. HRESULT CIDLData::GetData(IDLDATAF flags, INT_PTR *pdata)
  10. {
  11. if (flags & _flags)
  12. {
  13. // we have a match
  14. *pdata = _data;
  15. return S_OK;
  16. }
  17. return E_FAIL;
  18. }
  19. BOOL CIDLNode::Init(LPCITEMIDLIST pidl, CIDLNode *pinParent)
  20. {
  21. _pidl = ILCloneFirst(pidl);
  22. _pinParent = pinParent;
  23. return _pidl != NULL;
  24. }
  25. CIDLNode::~CIDLNode()
  26. {
  27. ILFree(_pidl);
  28. if (_psf)
  29. _psf->Release();
  30. }
  31. BOOL CIDLNode::_InitSF()
  32. {
  33. // TODO MAYBE LATER - add per thread cacheing instead.
  34. // this way we can insure nonviolation of apartments
  35. if (!_psf)
  36. {
  37. if (_pinParent)
  38. _pinParent->_BindToFolder(_pidl, &_psf);
  39. else
  40. SHGetDesktopFolder(&_psf);
  41. _cUsage++;
  42. }
  43. return (_psf != NULL);
  44. }
  45. HRESULT CIDLNode::_BindToFolder(LPCITEMIDLIST pidl, IShellFolder **ppsf)
  46. {
  47. if (_InitSF())
  48. {
  49. _cUsage++;
  50. return _psf->BindToObject(pidl, NULL, IID_PPV_ARG(IShellFolder, ppsf));
  51. }
  52. return E_UNEXPECTED;
  53. }
  54. BOOL CIDLNode::_IsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  55. {
  56. int iRet = ShortFromResult(IShellFolder_CompareIDs(_psf, SHCIDS_CANONICALONLY, pidl1, pidl2));
  57. return (iRet == 0);
  58. }
  59. CLinkedNode<CIDLNode> *CIDLNode::_GetKid(LPCITEMIDLIST pidl)
  60. {
  61. CLinkedWalk<CIDLNode> lw(&_listKids);
  62. // WARNING - need to avoid a real allocation - ZekeL - 27-SEP-2000
  63. // when we are just doing a seek
  64. // it creates weird state problems
  65. LPITEMIDLIST pidlStack = (LPITEMIDLIST)alloca(pidl->mkid.cb + sizeof(pidl->mkid.cb));
  66. memcpy(pidlStack, pidl, pidl->mkid.cb);
  67. (_ILNext(pidlStack))->mkid.cb = 0;
  68. while (lw.Step())
  69. {
  70. if (_IsEqual(lw.That()->_pidl, pidlStack))
  71. {
  72. return lw.Node();
  73. }
  74. }
  75. return NULL;
  76. }
  77. #define IsValidIDLNODE(pin) IS_VALID_WRITE_BUFFER(pin, BYTE, SIZEOF(CIDLNode))
  78. #define _IsEmptyNode(pin) (!(pin)->_pinKids && !(pin)->_pidDatas)
  79. void CIDLNode::_FreshenKids(void)
  80. {
  81. CLinkedWalk<CIDLNode> lw(&_listKids);
  82. LONG cMostUsage = 0;
  83. while (lw.Step())
  84. {
  85. CIDLNode *pin = lw.That();
  86. LONG cUsage = pin->_cUsage;
  87. pin->_cUsage = 0;
  88. ASSERT(IsValidIDLNODE(pin));
  89. pin->_FreshenKids();
  90. ASSERT(IsValidIDLNODE(pin));
  91. if (!cUsage && pin->_IsEmpty())
  92. {
  93. lw.Delete();
  94. }
  95. if (cUsage > cMostUsage && !lw.IsFirst())
  96. {
  97. // simple sorting algorithm
  98. // we just want most used at the top
  99. // move it from its current spot
  100. // to the beginning of the list
  101. CLinkedNode<CIDLNode> *p = lw.Remove();
  102. _listKids.Insert(p);
  103. }
  104. cMostUsage = max(cUsage, cMostUsage);
  105. }
  106. }
  107. HRESULT CIDLNode::GetNode(BOOL fCreate, LPCITEMIDLIST pidlChild, CIDLNode **ppin, IDLDATAF *pflagsFound)
  108. {
  109. HRESULT hr = E_FAIL;
  110. if (ILIsEmpty(pidlChild))
  111. {
  112. // this is just a request for self
  113. *ppin = this;
  114. if (pflagsFound)
  115. *pflagsFound = IDLDATAF_MATCH_RECURSIVE;
  116. hr = S_OK;
  117. }
  118. else
  119. {
  120. // search through kids looking for this child
  121. *ppin = NULL;
  122. CLinkedNode<CIDLNode> *pKid = _GetKid(pidlChild);
  123. if (!pKid && fCreate)
  124. {
  125. // we need to allocations during fCreate
  126. // so that memory failures dont affect Remove
  127. if (_InitSF())
  128. {
  129. // we dont have it, and they want it anyway
  130. pKid = new CLinkedNode<CIDLNode>;
  131. // we give our pidl ref away to avoid allocations
  132. if (pKid)
  133. {
  134. if (pKid->that.Init(pidlChild, this))
  135. _listKids.Insert(pKid);
  136. else
  137. {
  138. delete pKid;
  139. pKid = NULL;
  140. }
  141. }
  142. }
  143. }
  144. // let the child take care of setting
  145. if (pKid)
  146. {
  147. pKid->that._cUsage++;
  148. pidlChild = _ILNext(pidlChild);
  149. hr = pKid->that.GetNode(fCreate, pidlChild, ppin, pflagsFound);
  150. }
  151. if (FAILED(hr) && !fCreate && pflagsFound)
  152. {
  153. // just return this as second best
  154. *ppin = this;
  155. ASSERT(!ILIsEmpty(pidlChild));
  156. if (ILIsEmpty(_ILNext(pidlChild)))
  157. *pflagsFound = IDLDATAF_MATCH_RECURSIVE & ~IDLDATAF_MATCH_EXACT;
  158. else
  159. *pflagsFound = IDLDATAF_MATCH_RECURSIVE & ~IDLDATAF_MATCH_IMMEDIATE;
  160. hr = S_FALSE;
  161. }
  162. }
  163. return hr;
  164. }
  165. HRESULT CIDLNode::IDList(LPITEMIDLIST *ppidl)
  166. {
  167. CIDLNode *pin = this;
  168. *ppidl = NULL;
  169. while (pin && pin->_pidl)
  170. {
  171. *ppidl = ILAppendID(*ppidl, &pin->_pidl->mkid, FALSE);
  172. pin = pin->_pinParent;
  173. }
  174. return *ppidl ? S_OK : E_FAIL;
  175. }
  176. HRESULT CIDLNode::_AddData(IDLDATAF flags, INT_PTR data)
  177. {
  178. // assuming unique/no collisions of Datas
  179. CLinkedNode<CIDLData> *p = new CLinkedNode<CIDLData>;
  180. if (p)
  181. {
  182. p->that.Init(flags, data);
  183. _listDatas.Insert(p);
  184. }
  185. return p ? S_OK : E_FAIL;
  186. }
  187. HRESULT CIDLNode::_RemoveData(INT_PTR data)
  188. {
  189. HRESULT hr = E_FAIL;
  190. CLinkedWalk<CIDLData> lw(&_listDatas);
  191. while (lw.Step())
  192. {
  193. if (lw.That()->_data == data)
  194. {
  195. lw.Delete();
  196. hr = S_OK;
  197. break;
  198. }
  199. }
  200. return hr;
  201. }
  202. HRESULT CIDLTree::Create(CIDLTree **pptree)
  203. {
  204. HRESULT hr = E_OUTOFMEMORY;
  205. *pptree = new CIDLTree();
  206. if (*pptree)
  207. {
  208. hr = SHILClone(&c_idlDesktop, &((*pptree)->_pidl));
  209. if (FAILED(hr))
  210. {
  211. delete *pptree;
  212. *pptree = NULL;
  213. }
  214. }
  215. return hr;
  216. }
  217. HRESULT CIDLTree::AddData(IDLDATAF flags, LPCITEMIDLIST pidlIndex, INT_PTR data)
  218. {
  219. CIDLNode *pin;
  220. if (SUCCEEDED(GetNode(TRUE, pidlIndex, &pin)))
  221. {
  222. return pin->_AddData(flags, data);
  223. }
  224. return E_UNEXPECTED;
  225. }
  226. HRESULT CIDLTree::RemoveData(LPCITEMIDLIST pidlIndex, INT_PTR data)
  227. {
  228. CIDLNode *pin;
  229. if (SUCCEEDED(GetNode(FALSE, pidlIndex, &pin)))
  230. {
  231. return pin->_RemoveData(data);
  232. }
  233. return E_UNEXPECTED;
  234. }
  235. CIDLNode *CIDLTree::_MatchNode(LPCITEMIDLIST pidlMatch, IDLMATCHF *pflags)
  236. {
  237. CIDLNode *pin;
  238. IDLMATCHF flagsFound;
  239. HRESULT hr = GetNode(FALSE, pidlMatch, &pin, &flagsFound);
  240. if (SUCCEEDED(hr) && (flagsFound & (*pflags)))
  241. {
  242. *pflags &= flagsFound;
  243. }
  244. else
  245. pin = NULL;
  246. return pin;
  247. }
  248. HRESULT CIDLTree::MatchOne(IDLMATCHF flags, LPCITEMIDLIST pidlMatch, INT_PTR *pdata, LPITEMIDLIST *ppidl)
  249. {
  250. CIDLNode *pin = _MatchNode(pidlMatch, &flags);
  251. if (pin)
  252. {
  253. CIDLMatchMany mm(flags, pin);
  254. return mm.Next(pdata, ppidl);
  255. }
  256. return E_FAIL;
  257. }
  258. HRESULT CIDLTree::MatchMany(IDLMATCHF flags, LPCITEMIDLIST pidlMatch, CIDLMatchMany **ppmatch)
  259. {
  260. CIDLNode *pin = _MatchNode(pidlMatch, &flags);
  261. if (pin)
  262. {
  263. *ppmatch = new CIDLMatchMany(flags, pin);
  264. return *ppmatch ? S_OK : E_FAIL;
  265. }
  266. *ppmatch = NULL;
  267. return E_FAIL;
  268. }
  269. HRESULT CIDLTree::Freshen(void)
  270. {
  271. _FreshenKids();
  272. return S_OK;
  273. }
  274. HRESULT CIDLMatchMany::Next(INT_PTR *pdata, LPITEMIDLIST *ppidl)
  275. {
  276. HRESULT hr = E_FAIL;
  277. while (_pin && (_flags & IDLDATAF_MATCH_RECURSIVE))
  278. {
  279. if (_lw.Step())
  280. {
  281. hr = _lw.That()->GetData(_flags, pdata);
  282. if (SUCCEEDED(hr) && ppidl)
  283. {
  284. hr = _pin->IDList(ppidl);
  285. }
  286. if (SUCCEEDED(hr))
  287. break;
  288. }
  289. else
  290. {
  291. _pin = _pin->_pinParent;
  292. if (_pin)
  293. {
  294. _lw.Init(&_pin->_listDatas);
  295. // adjust the flags as you go up the parent chain.
  296. if (_flags & IDLDATAF_MATCH_EXACT)
  297. _flags &= ~IDLDATAF_MATCH_EXACT;
  298. else if (_flags & IDLDATAF_MATCH_IMMEDIATE)
  299. _flags &= ~IDLDATAF_MATCH_IMMEDIATE;
  300. }
  301. }
  302. }
  303. return hr;
  304. }