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.

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