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.

1509 lines
38 KiB

  1. #include "shellprv.h"
  2. #include "cowsite.h"
  3. #include "enumidlist.h"
  4. typedef enum
  5. {
  6. MAYBEBOOL_MAYBE = 0,
  7. MAYBEBOOL_TRUE,
  8. MAYBEBOOL_FALSE,
  9. } MAYBEBOOL;
  10. #define _GetBindWindow(p) NULL
  11. class CShellItem : public IShellItem
  12. , public IPersistIDList
  13. , public IParentAndItem
  14. {
  15. public:
  16. CShellItem();
  17. // IUnknown
  18. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  19. STDMETHODIMP_(ULONG) AddRef();
  20. STDMETHODIMP_(ULONG) Release();
  21. // IShellItem
  22. STDMETHODIMP BindToHandler(IBindCtx *pbc, REFGUID rguidHandler, REFIID riid, void **ppv);
  23. STDMETHODIMP GetParent(IShellItem **ppsi);
  24. STDMETHODIMP GetDisplayName(SIGDN sigdnName, LPOLESTR *ppszName);
  25. STDMETHODIMP GetAttributes(SFGAOF sfgaoMask, SFGAOF *psfgaoFlags);
  26. STDMETHODIMP Compare(IShellItem *psi, SICHINTF hint, int *piOrder);
  27. // IPersist
  28. STDMETHODIMP GetClassID(LPCLSID lpClassID) {*lpClassID = CLSID_ShellItem; return S_OK;}
  29. // IPersistIDList
  30. STDMETHODIMP SetIDList(LPCITEMIDLIST pidl);
  31. STDMETHODIMP GetIDList(LPITEMIDLIST *ppidl);
  32. // IParentAndItem
  33. STDMETHODIMP SetParentAndItem(LPCITEMIDLIST pidlParent, IShellFolder *psf, LPCITEMIDLIST pidlChild);
  34. STDMETHODIMP GetParentAndItem(LPITEMIDLIST *ppidlParent, IShellFolder **ppsf, LPITEMIDLIST *ppidlChild);
  35. #if 0
  36. // IPersistStream
  37. STDMETHODIMP IsDirty(void);
  38. STDMETHODIMP Load(IStream *pStm);
  39. STDMETHODIMP Save(IStream *pStm, BOOL fClearDirty);
  40. STDMETHODIMP GetSizeMax(ULARGE_INTEGER *pcbSize);
  41. // implement or we cant ask for the IShellFolder in GetParentAndItem()
  42. // IMarshal
  43. STDMETHODIMP GetUnmarshalClass(
  44. REFIID riid,
  45. void *pv,
  46. DWORD dwDestContext,
  47. void *pvDestContext,
  48. DWORD mshlflags,
  49. CLSID *pCid);
  50. STDMETHODIMP GetMarshalSizeMax(
  51. REFIID riid,
  52. void *pv,
  53. DWORD dwDestContext,
  54. void *pvDestContext,
  55. DWORD mshlflags,
  56. DWORD *pSize);
  57. STDMETHODIMP MarshalInterface(
  58. IStream *pStm,
  59. REFIID riid,
  60. void *pv,
  61. dwDestContext,
  62. void *pvDestContext,
  63. DWORD mshlflags);
  64. STDMETHODIMP UnmarshalInterface(
  65. IStream *pStm,
  66. REFIID riid,
  67. void **ppv);
  68. STDMETHODIMP ReleaseMarshalData(IStream *pStm);
  69. STDMETHODIMP DisconnectObject(DWORD dwReserved);
  70. #endif // 0
  71. private: // methods
  72. ~CShellItem();
  73. void _Reset(void);
  74. // BindToHandler() helpers
  75. HRESULT _BindToParent(REFIID riid, void **ppv);
  76. HRESULT _BindToSelf(REFIID riid, void **ppv);
  77. // GetAttributes() helpers
  78. inline BOOL _IsAttrib(SFGAOF sfgao);
  79. // GetDisplayName() helpers
  80. BOOL _SupportedName(SIGDN sigdnName, SHGDNF *pflags);
  81. HRESULT _FixupName(SIGDN sigdnName, LPOLESTR *ppszName);
  82. void _FixupAttributes(IShellFolder *psf, SFGAOF sfgaoMask);
  83. LONG _cRef;
  84. LPITEMIDLIST _pidlSelf;
  85. LPCITEMIDLIST _pidlChild;
  86. LPITEMIDLIST _pidlParent;
  87. IShellFolder *_psfSelf;
  88. IShellFolder *_psfParent;
  89. BOOL _fInited;
  90. SFGAOF _sfgaoTried;
  91. SFGAOF _sfgaoKnown;
  92. };
  93. CShellItem::CShellItem() : _cRef(1)
  94. {
  95. ASSERT(!_pidlSelf);
  96. ASSERT(!_pidlChild);
  97. ASSERT(!_pidlParent);
  98. ASSERT(!_psfSelf);
  99. ASSERT(!_psfParent);
  100. }
  101. CShellItem::~CShellItem()
  102. {
  103. _Reset();
  104. }
  105. void CShellItem::_Reset(void)
  106. {
  107. ATOMICRELEASE(_psfSelf);
  108. ATOMICRELEASE(_psfParent);
  109. ILFree(_pidlSelf);
  110. ILFree(_pidlParent);
  111. _pidlSelf = NULL;
  112. _pidlParent = NULL;
  113. _pidlChild = NULL; // alias into _pidlParent
  114. }
  115. STDMETHODIMP CShellItem::QueryInterface(REFIID riid, void **ppv)
  116. {
  117. static const QITAB qit[] =
  118. {
  119. QITABENT(CShellItem, IShellItem),
  120. QITABENT(CShellItem, IPersistIDList),
  121. QITABENT(CShellItem, IParentAndItem),
  122. { 0 },
  123. };
  124. return QISearch(this, qit, riid, ppv);
  125. }
  126. STDMETHODIMP_(ULONG) CShellItem::AddRef()
  127. {
  128. return InterlockedIncrement(&_cRef);
  129. }
  130. STDMETHODIMP_(ULONG) CShellItem::Release()
  131. {
  132. if (InterlockedDecrement(&_cRef))
  133. return _cRef;
  134. delete this;
  135. return 0;
  136. }
  137. STDMETHODIMP CShellItem::SetIDList(LPCITEMIDLIST pidl)
  138. {
  139. if (!pidl)
  140. {
  141. RIPMSG(0, "Tried to Call SetIDList with a NULL pidl");
  142. return E_INVALIDARG;
  143. }
  144. _Reset();
  145. HRESULT hr = SHILClone(pidl, &_pidlSelf);
  146. if (SUCCEEDED(hr))
  147. {
  148. // possible this item is the desktop in which case
  149. // there is no parent.
  150. if (ILIsEmpty(_pidlSelf))
  151. {
  152. _pidlParent = NULL;
  153. _pidlChild = _pidlSelf;
  154. }
  155. else
  156. {
  157. _pidlParent = ILCloneParent(_pidlSelf);
  158. _pidlChild = ILFindLastID(_pidlSelf);
  159. if (NULL == _pidlParent)
  160. {
  161. hr = E_OUTOFMEMORY;
  162. }
  163. }
  164. }
  165. return hr;
  166. }
  167. STDMETHODIMP CShellItem::GetIDList(LPITEMIDLIST *ppidl)
  168. {
  169. HRESULT hr = E_UNEXPECTED;
  170. if (_pidlSelf)
  171. {
  172. hr = SHILClone(_pidlSelf, ppidl);
  173. }
  174. return hr;
  175. }
  176. HRESULT CShellItem::_BindToParent(REFIID riid, void **ppv)
  177. {
  178. ASSERT(_pidlChild); // we should already have a child setup
  179. if (!_psfParent && _pidlParent && _pidlSelf) // check pidlParent to check in case the item is the desktop
  180. {
  181. HRESULT hr;
  182. LPCITEMIDLIST pidlChild;
  183. hr = SHBindToIDListParent(_pidlSelf, IID_PPV_ARG(IShellFolder, &_psfParent), &pidlChild);
  184. #ifdef DEBUG
  185. if (SUCCEEDED(hr))
  186. {
  187. ASSERT(pidlChild == _pidlChild);
  188. }
  189. #endif // DEBUG
  190. }
  191. if (_psfParent)
  192. {
  193. return _psfParent->QueryInterface(riid, ppv);
  194. }
  195. return E_FAIL;
  196. }
  197. HRESULT CShellItem::_BindToSelf(REFIID riid, void **ppv)
  198. {
  199. HRESULT hr = E_FAIL;
  200. if (!_psfSelf)
  201. {
  202. hr = BindToHandler(NULL, BHID_SFObject, IID_PPV_ARG(IShellFolder, &_psfSelf));
  203. }
  204. if (_psfSelf)
  205. {
  206. hr = _psfSelf->QueryInterface(riid, ppv);
  207. }
  208. return hr;
  209. }
  210. HRESULT _CreateLinkTargetItem(IShellItem *psi, IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppv)
  211. {
  212. SFGAOF flags = SFGAO_LINK;
  213. if (SUCCEEDED(psi->GetAttributes(flags, &flags)) && (flags & SFGAO_LINK))
  214. {
  215. // this is indeed a link
  216. // get the target and
  217. IShellLink *psl;
  218. HRESULT hr = psi->BindToHandler(pbc, BHID_SFUIObject, IID_PPV_ARG(IShellLink, &psl));
  219. if (SUCCEEDED(hr))
  220. {
  221. DWORD slr = 0;
  222. HWND hwnd = _GetBindWindow(pbc);
  223. if (pbc)
  224. {
  225. BIND_OPTS2 bo;
  226. bo.cbStruct = sizeof(BIND_OPTS2); // Requires size filled in.
  227. if (SUCCEEDED(pbc->GetBindOptions(&bo)))
  228. {
  229. // these are the flags to pass to resolve
  230. slr = bo.dwTrackFlags;
  231. }
  232. }
  233. hr = psl->Resolve(hwnd, slr);
  234. if (S_OK == hr)
  235. {
  236. LPITEMIDLIST pidl;
  237. hr = psl->GetIDList(&pidl);
  238. if (SUCCEEDED(hr))
  239. {
  240. IShellItem *psiTarget;
  241. hr = SHCreateShellItem(NULL, NULL, pidl, &psiTarget);
  242. if (SUCCEEDED(hr))
  243. {
  244. hr = psiTarget->QueryInterface(riid, ppv);
  245. psiTarget->Release();
  246. }
  247. ILFree(pidl);
  248. }
  249. }
  250. else if (SUCCEEDED(hr))
  251. hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  252. psl->Release();
  253. }
  254. return hr;
  255. }
  256. return E_INVALIDARG;
  257. }
  258. BOOL _IsWebfolders(IShellItem *psi);
  259. HRESULT _CreateStorageHelper(IShellItem *psi, IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppv);
  260. HRESULT _CreateStream(IShellItem *psi, IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppv);
  261. HRESULT _CreateEnumHelper(IShellItem *psi, IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppv);
  262. HRESULT _CreateHelperInstance(IShellItem *psi, IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppv)
  263. {
  264. IItemHandler *pih;
  265. HRESULT hr = SHCoCreateInstance(NULL, &rbhid, NULL, IID_PPV_ARG(IItemHandler, &pih));
  266. if (SUCCEEDED(hr))
  267. {
  268. hr = pih->SetItem(psi);
  269. if (SUCCEEDED(hr))
  270. {
  271. hr = pih->QueryInterface(riid, ppv);
  272. }
  273. pih->Release();
  274. }
  275. return hr;
  276. }
  277. enum
  278. {
  279. BNF_OBJECT = 0x0001,
  280. BNF_UIOBJECT = 0x0002,
  281. BNF_VIEWOBJECT = 0x0004,
  282. BNF_USE_RIID = 0x0008,
  283. BNF_REFLEXIVE = 0x0010,
  284. };
  285. typedef DWORD BNF;
  286. typedef HRESULT (* PFNCREATEHELPER)(IShellItem *psi, IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppv);
  287. typedef struct
  288. {
  289. const GUID *pbhid;
  290. BNF bnf;
  291. const IID *piid;
  292. PFNCREATEHELPER pfn;
  293. } BINDNONSENSE;
  294. #define BINDHANDLER(bhid, flags, piid, pfn) { &bhid, flags, piid, pfn},
  295. #define SFBINDHANDLER(bhid, flags, piid) BINDHANDLER(bhid, flags, piid, NULL)
  296. #define BINDHELPER(bhid, flags, pfn) BINDHANDLER(bhid, flags, NULL, pfn)
  297. const BINDNONSENSE c_bnList[] =
  298. {
  299. SFBINDHANDLER(BHID_SFObject, BNF_OBJECT | BNF_USE_RIID, NULL)
  300. SFBINDHANDLER(BHID_SFUIObject, BNF_UIOBJECT | BNF_USE_RIID, NULL)
  301. SFBINDHANDLER(BHID_SFViewObject, BNF_VIEWOBJECT | BNF_USE_RIID, NULL)
  302. BINDHELPER(BHID_LinkTargetItem, 0, _CreateLinkTargetItem)
  303. BINDHELPER(BHID_LocalCopyHelper, 0, _CreateHelperInstance)
  304. BINDHELPER(BHID_Storage, BNF_OBJECT | BNF_USE_RIID, _CreateStorageHelper)
  305. BINDHELPER(BHID_Stream, BNF_OBJECT | BNF_USE_RIID, NULL)
  306. BINDHELPER(BHID_StorageEnum, 0, _CreateEnumHelper)
  307. };
  308. HRESULT _GetBindNonsense(const GUID *pbhid, const IID *piid, BINDNONSENSE *pbn)
  309. {
  310. HRESULT hr = MK_E_NOOBJECT;
  311. for (int i = 0; i < ARRAYSIZE(c_bnList); i++)
  312. {
  313. if (IsEqualGUID(*pbhid, *(c_bnList[i].pbhid)))
  314. {
  315. *pbn = c_bnList[i];
  316. hr = S_OK;
  317. if (pbn->bnf & BNF_USE_RIID)
  318. {
  319. pbn->piid = piid;
  320. }
  321. if (pbn->piid && IsEqualGUID(*(pbn->piid), *piid))
  322. pbn->bnf |= BNF_REFLEXIVE;
  323. break;
  324. }
  325. }
  326. return hr;
  327. }
  328. // the SafeBC functions will use the pbc passed in or
  329. // create a new one if necessary. either way, if
  330. // the *ppbc is returned non-NULL then it is ref'd
  331. STDAPI SHSafeRegisterObjectParam(LPCWSTR psz, IUnknown *punk, IBindCtx *pbcIn, IBindCtx **ppbc)
  332. {
  333. IBindCtx *pbc = pbcIn;
  334. if (!pbc)
  335. CreateBindCtx(0, &pbc);
  336. else
  337. pbc->AddRef();
  338. *ppbc = NULL;
  339. HRESULT hr;
  340. if (pbc)
  341. {
  342. hr = pbc->RegisterObjectParam((LPOLESTR)psz, punk);
  343. if (SUCCEEDED(hr))
  344. {
  345. // pass our ref to the caller
  346. *ppbc = pbc;
  347. }
  348. else
  349. {
  350. pbc->Release();
  351. }
  352. }
  353. else
  354. {
  355. hr = E_OUTOFMEMORY;
  356. }
  357. return hr;
  358. }
  359. STDMETHODIMP CShellItem::BindToHandler(IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppv)
  360. {
  361. // look up handler for bind flags
  362. // use the flags to determine BTO GUIO BTS CVO
  363. BINDNONSENSE bn = {0};
  364. HRESULT hr = _GetBindNonsense(&rbhid, &riid, &bn);
  365. *ppv = NULL;
  366. if (SUCCEEDED(hr))
  367. {
  368. hr = E_NOINTERFACE;
  369. if (_pidlParent && (bn.bnf & (BNF_OBJECT | BNF_UIOBJECT)))
  370. {
  371. IShellFolder *psf;
  372. if (SUCCEEDED(_BindToParent(IID_PPV_ARG(IShellFolder, &psf))))
  373. {
  374. if (bn.bnf & BNF_OBJECT)
  375. {
  376. hr = psf->BindToObject(_pidlChild, pbc, *(bn.piid), ppv);
  377. }
  378. if (FAILED(hr) && (bn.bnf & BNF_UIOBJECT))
  379. {
  380. HWND hwnd = _GetBindWindow(pbc);
  381. hr = psf->GetUIObjectOf(hwnd, 1, &_pidlChild, *(bn.piid), NULL, ppv);
  382. }
  383. psf->Release();
  384. }
  385. }
  386. // if don't have a parent pidl then we are the desktop.
  387. if (FAILED(hr) && (NULL == _pidlParent) && (bn.bnf & BNF_OBJECT))
  388. {
  389. IShellFolder *psf;
  390. if (SUCCEEDED(SHGetDesktopFolder(&psf)))
  391. {
  392. hr = psf->QueryInterface(riid,ppv);
  393. psf->Release();
  394. }
  395. }
  396. if (FAILED(hr) && (bn.bnf & BNF_VIEWOBJECT))
  397. {
  398. IShellFolder *psf;
  399. if (SUCCEEDED(_BindToSelf(IID_PPV_ARG(IShellFolder, &psf))))
  400. {
  401. HWND hwnd = _GetBindWindow(pbc);
  402. hr = psf->CreateViewObject(hwnd, *(bn.piid), ppv);
  403. psf->Release();
  404. }
  405. }
  406. if (SUCCEEDED(hr))
  407. {
  408. if (!(bn.bnf & BNF_REFLEXIVE))
  409. {
  410. IUnknown *punk = (IUnknown *)*ppv;
  411. hr = punk->QueryInterface(riid, ppv);
  412. punk->Release();
  413. }
  414. // else riid is the same as bn.piid
  415. }
  416. else if (bn.pfn)
  417. {
  418. hr = bn.pfn(this, pbc, rbhid, riid, ppv);
  419. }
  420. }
  421. return hr;
  422. }
  423. STDMETHODIMP CShellItem::GetParent(IShellItem **ppsi)
  424. {
  425. HRESULT hr = MK_E_NOOBJECT;
  426. if (_pidlParent)
  427. {
  428. if (!ILIsEmpty(_pidlSelf))
  429. {
  430. CShellItem *psi = new CShellItem();
  431. if (psi)
  432. {
  433. // may already have the _psf Parent here so be nice
  434. // to have a way to do this in a set.
  435. hr = psi->SetIDList(_pidlParent);
  436. if (SUCCEEDED(hr))
  437. hr = psi->QueryInterface(IID_PPV_ARG(IShellItem, ppsi));
  438. psi->Release();
  439. }
  440. else
  441. hr = E_OUTOFMEMORY;
  442. }
  443. }
  444. return hr;
  445. }
  446. BOOL CShellItem::_IsAttrib(SFGAOF sfgao)
  447. {
  448. HRESULT hr = GetAttributes(sfgao, &sfgao);
  449. return hr == S_OK;
  450. }
  451. #define SHGDNF_MASK 0xFFFF // bottom word
  452. BOOL CShellItem::_SupportedName(SIGDN sigdn, SHGDNF *pflags)
  453. {
  454. *pflags = (sigdn & SHGDNF_MASK);
  455. // block this completely
  456. // to avoid doing any binding at all
  457. if (sigdn == SIGDN_FILESYSPATH && !_IsAttrib(SFGAO_FILESYSTEM))
  458. return FALSE;
  459. return TRUE;
  460. }
  461. HRESULT CShellItem::_FixupName(SIGDN sigdnName, LPOLESTR *ppszName)
  462. {
  463. HRESULT hr = S_OK;
  464. if (sigdnName == SIGDN_URL && !UrlIsW(*ppszName, URLIS_URL))
  465. {
  466. WCHAR sz[MAX_URL_STRING];
  467. DWORD cch = ARRAYSIZE(sz);
  468. if (SUCCEEDED(UrlCreateFromPathW(*ppszName, sz, &cch, 0)))
  469. {
  470. CoTaskMemFree(*ppszName);
  471. hr = SHStrDupW(sz, ppszName);
  472. }
  473. }
  474. return hr;
  475. }
  476. STDMETHODIMP CShellItem::GetDisplayName(SIGDN sigdnName, LPOLESTR *ppszName)
  477. {
  478. SHGDNF flags;
  479. if (_SupportedName(sigdnName, &flags))
  480. {
  481. IShellFolder *psf;
  482. HRESULT hr = _BindToParent(IID_PPV_ARG(IShellFolder, &psf));
  483. if (SUCCEEDED(hr))
  484. {
  485. STRRET str;
  486. hr = IShellFolder_GetDisplayNameOf(psf, _pidlChild, flags, &str, 0);
  487. if (SUCCEEDED(hr))
  488. {
  489. hr = StrRetToStrW(&str, _pidlChild, ppszName);
  490. if (SUCCEEDED(hr) && (int)flags != (int)sigdnName)
  491. {
  492. hr = _FixupName(sigdnName, ppszName);
  493. }
  494. }
  495. psf->Release();
  496. }
  497. return hr;
  498. }
  499. return E_INVALIDARG;
  500. }
  501. void CShellItem::_FixupAttributes(IShellFolder *psf, SFGAOF sfgaoMask)
  502. {
  503. // APPCOMPAT: The following if statement and its associated body is an APP HACK for pagis pro
  504. // folder. Which specifies SFGAO_FOLDER and SFGAO_FILESYSTEM but it doesn't specify SFGAO_STORAGEANCESTOR
  505. // This APP HACK basically checks for this condition and provides SFGAO_STORAGEANCESTOR bit.
  506. if (_sfgaoKnown & SFGAO_FOLDER)
  507. {
  508. if ((!(_sfgaoKnown & SFGAO_FILESYSANCESTOR) && (sfgaoMask & SFGAO_FILESYSANCESTOR))
  509. || ((_sfgaoKnown & SFGAO_CANMONIKER) && !(_sfgaoKnown & SFGAO_STORAGEANCESTOR) && (sfgaoMask & SFGAO_STORAGEANCESTOR)))
  510. {
  511. OBJCOMPATFLAGS ocf = SHGetObjectCompatFlags(psf, NULL);
  512. if (ocf & OBJCOMPATF_NEEDSFILESYSANCESTOR)
  513. {
  514. _sfgaoKnown |= SFGAO_FILESYSANCESTOR;
  515. }
  516. if (ocf & OBJCOMPATF_NEEDSSTORAGEANCESTOR)
  517. {
  518. // switch SFGAO_CANMONIKER -> SFGAO_STORAGEANCESTOR
  519. _sfgaoKnown |= SFGAO_STORAGEANCESTOR;
  520. _sfgaoKnown &= ~SFGAO_CANMONIKER;
  521. }
  522. }
  523. }
  524. }
  525. STDMETHODIMP CShellItem::GetAttributes(SFGAOF sfgaoMask, SFGAOF *psfgaoFlags)
  526. {
  527. HRESULT hr = S_OK;
  528. // see if we cached this bits before...
  529. if ((sfgaoMask & _sfgaoTried) != sfgaoMask)
  530. {
  531. IShellFolder *psf;
  532. hr = _BindToParent(IID_PPV_ARG(IShellFolder, &psf));
  533. if (SUCCEEDED(hr))
  534. {
  535. // we cache all the bits except VALIDATE
  536. _sfgaoTried |= (sfgaoMask & ~SFGAO_VALIDATE);
  537. SFGAOF sfgao = sfgaoMask;
  538. hr = psf->GetAttributesOf(1, &_pidlChild, &sfgao);
  539. if (SUCCEEDED(hr))
  540. {
  541. // we cache all the bits except VALIDATE
  542. _sfgaoKnown |= (sfgao & ~SFGAO_VALIDATE);
  543. _FixupAttributes(psf, sfgaoMask);
  544. }
  545. psf->Release();
  546. }
  547. }
  548. *psfgaoFlags = _sfgaoKnown & sfgaoMask;
  549. if (SUCCEEDED(hr))
  550. {
  551. // we return S_OK
  552. // only if the bits set match
  553. // exactly the bits requested
  554. if (*psfgaoFlags == sfgaoMask)
  555. hr = S_OK;
  556. else
  557. hr = S_FALSE;
  558. }
  559. return hr;
  560. }
  561. STDMETHODIMP CShellItem::Compare(IShellItem *psi, SICHINTF hint, int *piOrder)
  562. {
  563. *piOrder = 0;
  564. HRESULT hr = IsSameObject(SAFECAST(this, IShellItem *), psi) ? S_OK : E_FAIL;
  565. if (FAILED(hr))
  566. {
  567. IShellFolder *psf;
  568. hr = _BindToParent(IID_PPV_ARG(IShellFolder, &psf));
  569. if (SUCCEEDED(hr))
  570. {
  571. IParentAndItem *pfai;
  572. hr = psi->QueryInterface(IID_PPV_ARG(IParentAndItem, &pfai));
  573. if (SUCCEEDED(hr))
  574. {
  575. IShellFolder *psfOther;
  576. LPITEMIDLIST pidlParent, pidlChild;
  577. hr = pfai->GetParentAndItem(&pidlParent, &psfOther, &pidlChild);
  578. if (SUCCEEDED(hr))
  579. {
  580. if (IsSameObject(psf, psfOther) || ILIsEqual(_pidlParent, pidlParent))
  581. {
  582. hr = psf->CompareIDs(hint & 0xf0000000, _pidlChild, pidlChild);
  583. }
  584. else
  585. {
  586. // these items have a different parent
  587. // compare the absolute pidls
  588. LPITEMIDLIST pidlOther;
  589. hr = SHGetIDListFromUnk(psi, &pidlOther);
  590. if (SUCCEEDED(hr))
  591. {
  592. IShellFolder *psfDesktop;
  593. hr = SHGetDesktopFolder(&psfDesktop);
  594. if (SUCCEEDED(hr))
  595. {
  596. hr = psfDesktop->CompareIDs(hint & 0xf0000000, _pidlSelf, pidlOther);
  597. psfDesktop->Release();
  598. }
  599. ILFree(pidlOther);
  600. }
  601. }
  602. if (SUCCEEDED(hr))
  603. {
  604. *piOrder = ShortFromResult(hr);
  605. if (*piOrder)
  606. hr = S_FALSE;
  607. else
  608. hr = S_OK;
  609. }
  610. psfOther->Release();
  611. ILFree(pidlParent);
  612. ILFree(pidlChild);
  613. }
  614. pfai->Release();
  615. }
  616. psf->Release();
  617. }
  618. }
  619. return hr;
  620. }
  621. // IParentAndItem
  622. STDMETHODIMP CShellItem::SetParentAndItem(LPCITEMIDLIST pidlParent, IShellFolder *psfParent, LPCITEMIDLIST pidlChild)
  623. {
  624. // require to have a Parent if making this call. If don't then use SetIDList
  625. if (!pidlParent && !psfParent)
  626. {
  627. RIPMSG(0, "Tried to Call SetParent without a parent");
  628. return E_INVALIDARG;
  629. }
  630. LPITEMIDLIST pidlFree = NULL;
  631. if ((NULL == pidlParent) && psfParent)
  632. {
  633. if (SUCCEEDED(SHGetIDListFromUnk(psfParent, &pidlFree)))
  634. {
  635. pidlParent = pidlFree;
  636. }
  637. }
  638. if (!ILIsEmpty(_ILNext(pidlChild)))
  639. {
  640. // if more than on item in the child pidl don't use the parent IShellFolder*
  641. // could revist and bind from this parent to get a new parent so don't have
  642. // to BindObject through the entire pidl path.
  643. psfParent = NULL;
  644. }
  645. HRESULT hr = E_FAIL;
  646. if (pidlParent)
  647. {
  648. _Reset();
  649. hr = SHILCombine(pidlParent, pidlChild, &_pidlSelf);
  650. if (SUCCEEDED(hr))
  651. {
  652. // setup pidls so _pidlChild is a single item.
  653. if (_pidlParent = ILCloneParent(_pidlSelf))
  654. {
  655. _pidlChild = ILFindLastID(_pidlSelf);
  656. PPUNK_SET(&_psfParent, psfParent);
  657. #ifdef DEBUG
  658. if (psfParent)
  659. {
  660. LPITEMIDLIST pidlD;
  661. if (SUCCEEDED(SHGetIDListFromUnk(psfParent, &pidlD)))
  662. {
  663. ASSERT(ILIsEqual(pidlD, pidlParent));
  664. ILFree(pidlD);
  665. }
  666. }
  667. #endif //DEBUG
  668. }
  669. else
  670. {
  671. hr = E_OUTOFMEMORY;
  672. }
  673. }
  674. }
  675. ILFree(pidlFree); // maybe NULL
  676. return hr;
  677. }
  678. STDMETHODIMP CShellItem::GetParentAndItem(LPITEMIDLIST *ppidlParent, IShellFolder **ppsf, LPITEMIDLIST *ppidl)
  679. {
  680. if (ppsf)
  681. {
  682. _BindToParent(IID_PPV_ARG(IShellFolder, ppsf));
  683. }
  684. if (ppidlParent)
  685. {
  686. if (_pidlParent)
  687. {
  688. *ppidlParent = ILClone(_pidlParent);
  689. }
  690. else
  691. {
  692. *ppidlParent = NULL;
  693. }
  694. }
  695. if (ppidl)
  696. *ppidl = ILClone(_pidlChild);
  697. HRESULT hr = S_OK;
  698. if ((ppidlParent && !*ppidlParent)
  699. || (ppsf && !*ppsf)
  700. || (ppidl && !*ppidl))
  701. {
  702. // this is failure
  703. // but we dont know what failed
  704. if (ppsf && *ppsf)
  705. {
  706. (*ppsf)->Release();
  707. *ppsf = NULL;
  708. }
  709. if (ppidlParent)
  710. {
  711. ILFree(*ppidlParent);
  712. *ppidlParent = NULL;
  713. }
  714. if (ppidl)
  715. {
  716. ILFree(*ppidl);
  717. *ppidl = NULL;
  718. }
  719. hr = E_OUTOFMEMORY;
  720. }
  721. return hr;
  722. }
  723. STDAPI CShellItem_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppv)
  724. {
  725. CShellItem *psi = new CShellItem();
  726. if (psi)
  727. {
  728. HRESULT hr = psi->QueryInterface(riid, ppv);
  729. psi->Release();
  730. return hr;
  731. }
  732. return E_OUTOFMEMORY;
  733. }
  734. class CShellItemEnum : IEnumShellItems, public CObjectWithSite
  735. {
  736. public:
  737. CShellItemEnum();
  738. STDMETHODIMP Initialize(LPCITEMIDLIST pidlFolder,IShellFolder *psf, DWORD dwFlags,UINT cidl,LPCITEMIDLIST *apidl);
  739. // IUnknown methods
  740. STDMETHODIMP QueryInterface(REFIID riid, void **ppvOut);
  741. STDMETHODIMP_(ULONG) AddRef();
  742. STDMETHODIMP_(ULONG) Release();
  743. STDMETHODIMP Next(ULONG celt, IShellItem **rgelt, ULONG *pceltFetched);
  744. STDMETHODIMP Skip(ULONG celt);
  745. STDMETHODIMP Reset();
  746. STDMETHODIMP Clone(IEnumShellItems **ppenum);
  747. private:
  748. virtual ~CShellItemEnum();
  749. HRESULT _EnsureEnum();
  750. LONG _cRef;
  751. DWORD _dwFlags;
  752. IShellFolder *_psf;
  753. IEnumIDList *_penum;
  754. LPITEMIDLIST _pidlFolder;
  755. };
  756. STDMETHODIMP CShellItemEnum::QueryInterface(REFIID riid, void **ppv)
  757. {
  758. static const QITAB qit[] =
  759. {
  760. QITABENT(CShellItemEnum, IEnumShellItems),
  761. QITABENT(CShellItemEnum, IObjectWithSite),
  762. { 0 },
  763. };
  764. return QISearch(this, qit, riid, ppv);
  765. }
  766. STDMETHODIMP_(ULONG) CShellItemEnum::AddRef()
  767. {
  768. return InterlockedIncrement(&_cRef);
  769. }
  770. STDMETHODIMP_(ULONG) CShellItemEnum::Release()
  771. {
  772. if (InterlockedDecrement(&_cRef))
  773. return _cRef;
  774. delete this;
  775. return 0;
  776. }
  777. STDMETHODIMP CShellItemEnum::Next(ULONG celt, IShellItem **rgelt, ULONG *pceltFetched)
  778. {
  779. HRESULT hr = _EnsureEnum();
  780. if (FAILED(hr))
  781. return hr;
  782. ULONG uTemp;
  783. if (!pceltFetched)
  784. pceltFetched = &uTemp;
  785. *pceltFetched = 0;
  786. while (celt--)
  787. {
  788. LPITEMIDLIST pidl;
  789. ULONG cFetched;
  790. hr = _penum->Next(1, &pidl, &cFetched);
  791. if (S_OK == hr)
  792. {
  793. hr = SHCreateShellItem(_pidlFolder, _psf, pidl, &rgelt[*pceltFetched]);
  794. if (SUCCEEDED(hr))
  795. (*pceltFetched)++;
  796. ILFree(pidl);
  797. }
  798. if (S_OK != hr)
  799. break;
  800. }
  801. if (SUCCEEDED(hr))
  802. {
  803. hr = *pceltFetched ? S_OK : S_FALSE;
  804. }
  805. else
  806. {
  807. for (UINT i = 0; i < *pceltFetched; i++)
  808. {
  809. ATOMICRELEASE(rgelt[i]);
  810. }
  811. *pceltFetched = 0;
  812. }
  813. return hr;
  814. }
  815. STDMETHODIMP CShellItemEnum::Skip(ULONG celt)
  816. {
  817. HRESULT hr = _EnsureEnum();
  818. if (SUCCEEDED(hr))
  819. hr = _penum->Skip(celt);
  820. return hr;
  821. }
  822. STDMETHODIMP CShellItemEnum::Reset()
  823. {
  824. HRESULT hr = _EnsureEnum();
  825. if (SUCCEEDED(hr))
  826. hr = _penum->Reset();
  827. return hr;
  828. }
  829. STDMETHODIMP CShellItemEnum::Clone(IEnumShellItems **ppenum)
  830. {
  831. return E_NOTIMPL;
  832. }
  833. HRESULT CShellItemEnum::_EnsureEnum()
  834. {
  835. if (_penum)
  836. return S_OK;
  837. HRESULT hr = E_FAIL;
  838. if (_psf)
  839. {
  840. HWND hwnd = NULL;
  841. IUnknown_GetWindow(_punkSite, &hwnd);
  842. // if didn't get an enum in Initialize then enumerate the
  843. // entire folder.
  844. hr = _psf->EnumObjects(hwnd, _dwFlags, &_penum);
  845. }
  846. return hr;
  847. }
  848. CShellItemEnum::CShellItemEnum()
  849. : _cRef(1)
  850. {
  851. ASSERT(NULL == _psf);
  852. ASSERT(NULL == _penum);
  853. ASSERT(NULL == _pidlFolder);
  854. }
  855. STDMETHODIMP CShellItemEnum::Initialize(LPCITEMIDLIST pidlFolder, IShellFolder *psf, DWORD dwFlags, UINT cidl, LPCITEMIDLIST *apidl)
  856. {
  857. HRESULT hr = E_FAIL;
  858. _dwFlags = dwFlags;
  859. _psf = psf;
  860. _psf->AddRef();
  861. if (NULL == _pidlFolder)
  862. {
  863. hr = SHGetIDListFromUnk(_psf, &_pidlFolder);
  864. }
  865. else
  866. {
  867. hr = SHILClone(pidlFolder, &_pidlFolder);
  868. }
  869. if (SUCCEEDED(hr) && cidl)
  870. {
  871. ASSERT(apidl);
  872. // if want to enum with other flags or combos need to implement the filter
  873. ASSERT(_dwFlags == (SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN));
  874. hr = CreateIEnumIDListOnIDLists(apidl, cidl, &_penum);
  875. }
  876. // on error let our destructor do the cleanup
  877. return hr;
  878. }
  879. CShellItemEnum::~CShellItemEnum()
  880. {
  881. ATOMICRELEASE(_penum);
  882. ATOMICRELEASE(_psf);
  883. ILFree(_pidlFolder);
  884. }
  885. HRESULT _CreateShellItemEnum(LPCITEMIDLIST pidlFolder,IShellFolder *psf,IBindCtx *pbc, REFGUID rbhid,
  886. UINT cidl, LPCITEMIDLIST *apidl,
  887. REFIID riid, void **ppv)
  888. {
  889. DWORD dwFlags;
  890. HRESULT hr = E_FAIL;
  891. LPCITEMIDLIST *pidlEnum = NULL;
  892. UINT mycidl = 0;
  893. LPITEMIDLIST *myppidl = NULL;;
  894. if (IsEqualGUID(rbhid, BHID_StorageEnum))
  895. dwFlags = SHCONTF_STORAGE;
  896. else
  897. dwFlags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN;
  898. CShellItemEnum *psie = new CShellItemEnum();
  899. if (psie)
  900. {
  901. hr = psie->Initialize(pidlFolder, psf, dwFlags, cidl, apidl);
  902. if (SUCCEEDED(hr))
  903. {
  904. hr = psie->QueryInterface(riid, ppv);
  905. }
  906. psie->Release();
  907. }
  908. else
  909. {
  910. hr = E_OUTOFMEMORY;
  911. }
  912. return hr;
  913. }
  914. HRESULT _CreateEnumHelper(IShellItem *psi, IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppv)
  915. {
  916. HRESULT hr = E_FAIL;
  917. IShellFolder *psf;
  918. ASSERT(psi);
  919. if (psi)
  920. {
  921. hr = psi->BindToHandler(NULL, BHID_SFObject, IID_PPV_ARG(IShellFolder, &psf));
  922. if (SUCCEEDED(hr))
  923. {
  924. hr = _CreateShellItemEnum(NULL,psf,pbc,rbhid,0,NULL,riid,ppv);
  925. psf->Release();
  926. }
  927. }
  928. return hr;
  929. }
  930. class CShellItemArray : public IShellItemArray
  931. {
  932. public:
  933. CShellItemArray();
  934. ~CShellItemArray();
  935. HRESULT Initialize(LPCITEMIDLIST pidlParent,IShellFolder *psf,UINT cidl,LPCITEMIDLIST *ppidl);
  936. // IUnknown
  937. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  938. STDMETHODIMP_(ULONG) AddRef(void) ;
  939. STDMETHODIMP_(ULONG) Release(void);
  940. // IShellItemArray
  941. STDMETHODIMP BindToHandler(
  942. IBindCtx *pbc,
  943. REFGUID rbhid,
  944. REFIID riid,
  945. void **ppvOut);
  946. STDMETHODIMP GetAttributes(
  947. SIATTRIBFLAGS dwAttribFlags,
  948. SFGAOF sfgaoMask,
  949. SFGAOF *psfgaoAttribs);
  950. STDMETHODIMP GetCount(DWORD *pdwNumItems);
  951. STDMETHODIMP GetItemAt(DWORD dwIndex,IShellItem **ppsi);
  952. STDMETHODIMP EnumItems(IEnumShellItems **ppenumShellItems);
  953. private:
  954. HRESULT _CloneIDListArray(UINT cidl, LPCITEMIDLIST *apidl, UINT *pcidl, LPITEMIDLIST **papidl);
  955. IShellFolder *_pshf;
  956. LPITEMIDLIST _pidlParent;
  957. LPITEMIDLIST *_ppidl;
  958. UINT _cidl;
  959. LONG _cRef;
  960. IDataObject *_pdo; // cached data object.
  961. DWORD _dwAttribAndCacheResults;
  962. DWORD _dwAttribAndCacheMask;
  963. DWORD _dwAttribCompatCacheResults;
  964. DWORD _dwAttribCompatCacheMask;
  965. BOOL _fItemPidlsRagged; // set to true if have any rugged pidls.
  966. };
  967. CShellItemArray::CShellItemArray()
  968. {
  969. ASSERT(0 == _cidl);
  970. ASSERT(NULL == _ppidl);
  971. ASSERT(NULL == _pshf);
  972. ASSERT(NULL == _pdo);
  973. _fItemPidlsRagged = TRUE;
  974. _cRef = 1;
  975. }
  976. CShellItemArray::~CShellItemArray()
  977. {
  978. ATOMICRELEASE(_pdo);
  979. ATOMICRELEASE(_pshf);
  980. ILFree(_pidlParent); // may be null
  981. if (NULL != _ppidl)
  982. {
  983. FreeIDListArray(_ppidl,_cidl);
  984. }
  985. }
  986. HRESULT CShellItemArray::Initialize(LPCITEMIDLIST pidlParent, IShellFolder *psf, UINT cidl, LPCITEMIDLIST *ppidl)
  987. {
  988. if ((cidl > 1) && !ppidl || !psf)
  989. {
  990. return E_INVALIDARG;
  991. }
  992. if (pidlParent)
  993. {
  994. _pidlParent = ILClone(pidlParent); // proceed on alloc failure, just won't use.
  995. }
  996. _pshf = psf;
  997. _pshf->AddRef();
  998. HRESULT hr = S_OK;
  999. if (cidl)
  1000. {
  1001. // if there are items then make a copy
  1002. hr = _CloneIDListArray(cidl, ppidl, &_cidl, &_ppidl);
  1003. }
  1004. // on error rely on destructor to do the cleanup
  1005. return hr;
  1006. }
  1007. // IUnknown
  1008. STDMETHODIMP CShellItemArray::QueryInterface(REFIID riid, void **ppv)
  1009. {
  1010. static const QITAB qit[] =
  1011. {
  1012. QITABENT(CShellItemArray, IShellItemArray),
  1013. { 0 },
  1014. };
  1015. return QISearch(this, qit, riid, ppv);
  1016. }
  1017. STDMETHODIMP_(ULONG) CShellItemArray::AddRef()
  1018. {
  1019. return InterlockedIncrement(&_cRef);
  1020. }
  1021. STDMETHODIMP_(ULONG) CShellItemArray::Release()
  1022. {
  1023. if (InterlockedDecrement(&_cRef))
  1024. return _cRef;
  1025. delete this;
  1026. return 0;
  1027. }
  1028. STDMETHODIMP CShellItemArray::BindToHandler(IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppvOut)
  1029. {
  1030. HRESULT hr = E_FAIL;
  1031. if (_pshf)
  1032. {
  1033. // currently only allow bind to IDataObject and
  1034. // cache the result.
  1035. if (BHID_DataObject == rbhid)
  1036. {
  1037. if (NULL == _pdo)
  1038. {
  1039. _pshf->GetUIObjectOf(NULL, _cidl, (LPCITEMIDLIST *)_ppidl, IID_PPV_ARG_NULL(IDataObject, &_pdo));
  1040. }
  1041. if (_pdo)
  1042. {
  1043. hr = _pdo->QueryInterface(riid, ppvOut);
  1044. }
  1045. }
  1046. else
  1047. {
  1048. hr = E_NOINTERFACE;
  1049. }
  1050. }
  1051. return hr;
  1052. }
  1053. // This should probably take a flag that does an or'ing of attributes but this
  1054. // currrently isn't implemented. Do have comments on what the changes would be.
  1055. HRESULT CShellItemArray::GetAttributes(SIATTRIBFLAGS dwAttribFlags, SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs)
  1056. {
  1057. DWORD dwAttrib;
  1058. HRESULT hr = E_FAIL;
  1059. if (dwAttribFlags > (dwAttribFlags & SIATTRIBFLAGS_MASK))
  1060. {
  1061. ASSERT(dwAttribFlags <= (dwAttribFlags & SIATTRIBFLAGS_MASK));
  1062. return E_INVALIDARG;
  1063. }
  1064. if (SIATTRIBFLAGS_OR == dwAttribFlags)
  1065. {
  1066. ASSERT(SIATTRIBFLAGS_OR != dwAttribFlags); // or'ing is currently not implemented.
  1067. return E_INVALIDARG;
  1068. }
  1069. if (_pshf)
  1070. {
  1071. DWORD dwAttribMask = sfgaoMask;
  1072. DWORD *pdwCacheMask = NULL;
  1073. DWORD *pdwCacheResults = NULL;
  1074. // setup to point to proper Cached values.
  1075. switch(dwAttribFlags)
  1076. {
  1077. case SIATTRIBFLAGS_AND:
  1078. pdwCacheMask = &_dwAttribAndCacheMask;
  1079. pdwCacheResults = &_dwAttribAndCacheResults;
  1080. break;
  1081. case SIATTRIBFLAGS_APPCOMPAT:
  1082. pdwCacheMask = &_dwAttribCompatCacheMask;
  1083. pdwCacheResults = &_dwAttribCompatCacheResults;
  1084. break;
  1085. default:
  1086. ASSERT(0); // i don't know how to handle this flag.
  1087. break;
  1088. }
  1089. dwAttribMask &= ~(*pdwCacheMask); // only ask for the bits we don't already have.
  1090. dwAttrib = dwAttribMask;
  1091. if (dwAttrib)
  1092. {
  1093. if (0 == _cidl)
  1094. {
  1095. dwAttrib = 0;
  1096. }
  1097. else
  1098. {
  1099. // if know this is not a ragged pidl and calling with the APPCOMPAT flag
  1100. // then calls GetAttributesOf for all the items in one call to the
  1101. // shellFolder.
  1102. if (!_fItemPidlsRagged && (SIATTRIBFLAGS_APPCOMPAT == dwAttribFlags))
  1103. {
  1104. hr = _pshf->GetAttributesOf(_cidl, (LPCITEMIDLIST *)_ppidl, &dwAttrib);
  1105. }
  1106. else
  1107. {
  1108. LPITEMIDLIST *pCurItem = _ppidl;
  1109. UINT itemCount = _cidl;
  1110. DWORD dwAttribLoopResult = -1; // set all result bits for and, if going to or set to zero
  1111. while (itemCount--)
  1112. {
  1113. DWORD dwAttribTemp = dwAttrib;
  1114. IShellFolder *psfNew;
  1115. LPCITEMIDLIST pidlChild;
  1116. hr = SHBindToFolderIDListParent(_pshf, *pCurItem, IID_PPV_ARG(IShellFolder, &psfNew), &pidlChild);
  1117. if (SUCCEEDED(hr))
  1118. {
  1119. hr = psfNew->GetAttributesOf(1, &pidlChild, &dwAttribTemp);
  1120. psfNew->Release();
  1121. }
  1122. if (FAILED(hr))
  1123. {
  1124. break;
  1125. }
  1126. dwAttribLoopResult &= dwAttribTemp; // could also do an or'ing here
  1127. if (0 == dwAttribLoopResult) // if no attribs set and doing an and we can stop.
  1128. {
  1129. break;
  1130. }
  1131. ++pCurItem;
  1132. }
  1133. dwAttrib = dwAttribLoopResult; // update the attrib
  1134. }
  1135. }
  1136. }
  1137. else
  1138. {
  1139. hr = S_OK;
  1140. }
  1141. if (SUCCEEDED(hr))
  1142. {
  1143. // remember those bits that we just got +
  1144. // those that we computed before
  1145. *pdwCacheResults = dwAttrib | (*pdwCacheResults & *pdwCacheMask);
  1146. // we know these are now valid, keep track of those +
  1147. // if they gave us more than we asked for, cache them too
  1148. *pdwCacheMask |= dwAttribMask | dwAttrib;
  1149. // don't return anything that wasn't asked for. defview code relies on this.
  1150. *psfgaoAttribs = (*pdwCacheResults & sfgaoMask);
  1151. }
  1152. }
  1153. return hr;
  1154. }
  1155. STDMETHODIMP CShellItemArray::GetCount(DWORD *pdwNumItems)
  1156. {
  1157. *pdwNumItems = _cidl;
  1158. return S_OK;
  1159. }
  1160. // way to get zero based index ShellItem without having to
  1161. // go through enumerator overhead.
  1162. STDMETHODIMP CShellItemArray::GetItemAt(DWORD dwIndex, IShellItem **ppsi)
  1163. {
  1164. *ppsi = NULL;
  1165. if (dwIndex >= _cidl)
  1166. {
  1167. return E_FAIL;
  1168. }
  1169. ASSERT(_ppidl);
  1170. LPITEMIDLIST pidl = *(_ppidl + dwIndex);
  1171. // if GetItemAt is called a lot may want to
  1172. // a) get the pshf pidl to pass to SHCreateshellItem so doesn't have to create each time
  1173. // b) see if always asking for first item and is so maybe cache the shellItem
  1174. return SHCreateShellItem(NULL, _pshf, pidl, ppsi);
  1175. }
  1176. STDMETHODIMP CShellItemArray::EnumItems(IEnumShellItems **ppenumShellItems)
  1177. {
  1178. return _CreateShellItemEnum(_pidlParent, _pshf, NULL, GUID_NULL, _cidl,
  1179. (LPCITEMIDLIST *) _ppidl, IID_PPV_ARG(IEnumShellItems, ppenumShellItems));
  1180. }
  1181. HRESULT CShellItemArray::_CloneIDListArray(UINT cidl, LPCITEMIDLIST *apidl, UINT *pcidl, LPITEMIDLIST **papidl)
  1182. {
  1183. HRESULT hr;
  1184. LPITEMIDLIST *ppidl;
  1185. *papidl = NULL;
  1186. _fItemPidlsRagged = FALSE;
  1187. if (cidl && apidl)
  1188. {
  1189. ppidl = (LPITEMIDLIST *)LocalAlloc(LPTR, cidl * sizeof(*ppidl));
  1190. if (ppidl)
  1191. {
  1192. LPITEMIDLIST *apidlFrom = (LPITEMIDLIST *) apidl;
  1193. LPITEMIDLIST *apidlTo = ppidl;
  1194. hr = S_OK;
  1195. for (UINT i = 0; i < cidl ; i++)
  1196. {
  1197. hr = SHILClone(*apidlFrom, apidlTo);
  1198. if (FAILED(hr))
  1199. {
  1200. FreeIDListArray(ppidl, i);
  1201. ppidl = NULL;
  1202. break;
  1203. }
  1204. // if more than one item in list then set singeItemPidls to false
  1205. if (!ILIsEmpty(_ILNext(*apidlTo)))
  1206. {
  1207. _fItemPidlsRagged = TRUE;
  1208. }
  1209. ++apidlFrom;
  1210. ++apidlTo;
  1211. }
  1212. }
  1213. else
  1214. hr = E_OUTOFMEMORY;
  1215. }
  1216. else
  1217. {
  1218. ppidl = NULL;
  1219. hr = S_FALSE; // success by empty
  1220. }
  1221. if (SUCCEEDED(hr))
  1222. {
  1223. *papidl = ppidl;
  1224. *pcidl = cidl;
  1225. }
  1226. else
  1227. {
  1228. _fItemPidlsRagged = TRUE;
  1229. }
  1230. return hr;
  1231. }
  1232. SHSTDAPI SHCreateShellItemArray(LPCITEMIDLIST pidlParent, IShellFolder *psf, UINT cidl,
  1233. LPCITEMIDLIST *ppidl, IShellItemArray **ppsiItemArray)
  1234. {
  1235. HRESULT hr = E_OUTOFMEMORY;
  1236. CShellItemArray *pItemArray = new CShellItemArray();
  1237. if (pItemArray)
  1238. {
  1239. hr = pItemArray->Initialize(pidlParent, psf, cidl, ppidl);
  1240. if (FAILED(hr))
  1241. {
  1242. pItemArray->Release();
  1243. pItemArray = NULL;
  1244. }
  1245. }
  1246. *ppsiItemArray = pItemArray;
  1247. return hr;
  1248. }