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.

1526 lines
37 KiB

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include "iface.h"
  4. #include "augisf.h"
  5. #include "menuisf.h"
  6. //=================================================================
  7. // Implementation of an IShellFolder that wraps a collection of
  8. // other IShellFolders. We call this an augmented IShellFolder
  9. // object.
  10. //
  11. //=================================================================
  12. // The CAugmentedISF wraps all the pidls so it can identify which pidl
  13. // belongs to which IShellFolder object.
  14. typedef struct tagIDWRAP
  15. {
  16. // Real pidl goes on the end
  17. UINT nID; // Refers to a specific IShellFolder object
  18. UINT cbOriginal; // the original size of the pidl. we need this because we dword align the pidl before wrapping it
  19. } IDWRAP, * PIDWRAP;
  20. #define IDWrap_GetWrap(pidl) ((PIDWRAP)(((LPBYTE)pidl) + (pidl)->mkid.cb - SIZEOF(IDWRAP)))
  21. #define IDWrap_GetID(pidl) (IDWrap_GetWrap(pidl)->nID)
  22. #define IDWrap_GetOriginalSize(pidl) (IDWrap_GetWrap(pidl)->cbOriginal)
  23. /*----------------------------------------------------------
  24. The CAugmentedISF object holds an array of CISFElems, each of which
  25. refers to an IShellFolder which will be enumerated.
  26. */
  27. class CISFElem
  28. {
  29. public:
  30. CISFElem * Clone(void);
  31. HRESULT AcquireEnumerator(DWORD dwFlags);
  32. IShellFolder * GetPSF() { return _psf; };
  33. IEnumIDList * GetEnumerator() { return _pei; };
  34. void GetNameSpaceID(GUID * rguid);
  35. HRESULT SetPidl(LPCITEMIDLIST pidl);
  36. LPCITEMIDLIST GetPidl() { return _pidl; };
  37. DWORD GetFlags() { return _dwFlags; };
  38. void SetRegister(UINT uReg) { _uRegister = uReg; };
  39. UINT GetRegister() { return _uRegister; };
  40. CISFElem(const GUID * pguid, IShellFolder * psf, DWORD dwFlags);
  41. ~CISFElem();
  42. protected:
  43. GUID _guid; // Unique ID
  44. IShellFolder * _psf;
  45. IEnumIDList * _pei; // Used by CAugSIFEnum only
  46. LPITEMIDLIST _pidl;
  47. DWORD _dwFlags;
  48. UINT _uRegister;
  49. friend BOOL IsValidPCISFElem(CISFElem * pel);
  50. };
  51. //
  52. // CAugmentedISF enumerator
  53. //
  54. class CAugISFEnum : public IEnumIDList
  55. {
  56. public:
  57. // *** IUnknown methods ***
  58. STDMETHOD(QueryInterface) (REFIID riid, LPVOID * ppvObj);
  59. STDMETHOD_(ULONG,AddRef) () ;
  60. STDMETHOD_(ULONG,Release) ();
  61. // *** IEnumIDList methods ***
  62. STDMETHOD(Next) (ULONG celt,
  63. LPITEMIDLIST *rgelt,
  64. ULONG *pceltFetched);
  65. STDMETHOD(Skip) (ULONG celt);
  66. STDMETHOD(Reset) ();
  67. STDMETHOD(Clone) (IEnumIDList **ppenum);
  68. // Other methods
  69. HRESULT Init(HDPA hdpaISF, DWORD dwEnumFlags);
  70. CAugISFEnum();
  71. ~CAugISFEnum();
  72. protected:
  73. IEnumIDList * _GetObjectEnumerator(int nID);
  74. UINT _cRef;
  75. int _iCurISF; // current item in _hdpaISF
  76. HDPA _hdpaISF;
  77. };
  78. /*----------------------------------------------------------
  79. Pidl wrapping routine
  80. */
  81. LPITEMIDLIST AugISF_WrapPidl( LPCITEMIDLIST pidl, int nID )
  82. {
  83. LPITEMIDLIST pidlRet = NULL;
  84. // get the size of the pidl
  85. // round up to dword align.
  86. UINT cbPidlSize = (pidl->mkid.cb + 3) & ~3;
  87. ASSERT(cbPidlSize >= pidl->mkid.cb);
  88. UINT cbSize = SIZEOF(IDWRAP) + cbPidlSize + SIZEOF(DWORD); // pidl plus terminator
  89. LPBYTE p = (LPBYTE)SHAlloc(cbSize);
  90. if (p)
  91. {
  92. ZeroMemory(p, cbSize);
  93. memcpy(p, pidl, pidl->mkid.cb);
  94. IDWRAP* pidw = (IDWRAP*) (p + cbPidlSize);
  95. pidw->nID = nID;
  96. pidw->cbOriginal = pidl->mkid.cb;
  97. // now make the cb be the whole pidl (not including the final null)
  98. pidlRet = (LPITEMIDLIST)p;
  99. pidlRet->mkid.cb = (USHORT) (cbPidlSize + SIZEOF(IDWRAP));
  100. }
  101. return pidlRet;
  102. }
  103. // GetIDListWrapCount and GetNameSpaceCount are not used anywhere
  104. #if 0
  105. /*----------------------------------------------------------
  106. Purpose: IAugmentedShellFolder2::GetIDListWrapCount
  107. */
  108. STDMETHODIMP CAugmentedISF::GetNameSpaceCount( OUT LONG* pcNamespaces )
  109. {
  110. if( NULL == pcNamespaces )
  111. return E_INVALIDARG ;
  112. *pcNamespaces = (NULL != _hdpa) ? DPA_GetPtrCount( _hdpa ) : 0 ;
  113. return S_OK ;
  114. }
  115. /*----------------------------------------------------------
  116. Purpose: IAugmentedShellFolder2::GetIDListWrapCount
  117. */
  118. STDMETHODIMP CAugmentedISF::GetIDListWrapCount(
  119. LPCITEMIDLIST pidlWrap,
  120. OUT LONG * pcPidls )
  121. {
  122. if( NULL == pidlWrap || NULL == pcPidls )
  123. return E_INVALIDARG ;
  124. PIDWRAP pWrap = IDWrap_GetWrap(pidlWrap) ;
  125. *pcPidls = 0 ;
  126. if( NULL != _hdpa &&
  127. DPA_GetPtrCount( _hdpa ) > (int)pWrap->nID &&
  128. pWrap->cbOriginal < pidlWrap->mkid.cb + sizeof(IDWRAP) )
  129. *pcPidls = 1 ;
  130. return S_OK ;
  131. }
  132. #endif
  133. /*----------------------------------------------------------
  134. Purpose: IAugmentedShellFolder2::UnWrapIDList
  135. */
  136. STDMETHODIMP CAugmentedISF::UnWrapIDList(
  137. LPCITEMIDLIST pidl,
  138. LONG cPidls,
  139. IShellFolder ** ppsf,
  140. LPITEMIDLIST * ppidlFolder,
  141. LPITEMIDLIST * ppidl,
  142. LONG * pcFetched )
  143. {
  144. HRESULT hres = E_INVALIDARG;
  145. ASSERT(IS_VALID_PIDL(pidl));
  146. if( pcFetched )
  147. *pcFetched = 0 ;
  148. if (pidl)
  149. {
  150. UINT nId = IDWrap_GetID(pidl);
  151. CISFElem * pel = (CISFElem *)DPA_GetPtr(_hdpa, nId);
  152. if (pel)
  153. {
  154. LPITEMIDLIST pidlNew = ILClone(GetNativePidl(pidl, nId));
  155. LPITEMIDLIST pidlFolderNew = ILClone(pel->GetPidl());
  156. if (pidlNew && pidlFolderNew)
  157. {
  158. if ( ppsf )
  159. {
  160. *ppsf = pel->GetPSF();
  161. (*ppsf)->AddRef();
  162. }
  163. *ppidl = pidlNew;
  164. *ppidlFolder = pidlFolderNew;
  165. if( pcFetched )
  166. *pcFetched = 1 ;
  167. hres = (cPidls == 1) ? S_OK : S_FALSE ;
  168. }
  169. else
  170. {
  171. ILFree(pidlNew);
  172. ILFree(pidlFolderNew);
  173. hres = E_OUTOFMEMORY;
  174. }
  175. }
  176. else
  177. hres = E_FAIL;
  178. }
  179. return hres;
  180. }
  181. /*----------------------------------------------------------
  182. Purpose: CAugmentedISF::TranslatePidl
  183. */
  184. LPITEMIDLIST CAugmentedISF::TranslatePidl( LPCITEMIDLIST pidlNS, LPCITEMIDLIST pidl, LPARAM nID )
  185. {
  186. LPITEMIDLIST pidlRet = NULL;
  187. // Is this not empty and an immediate child?
  188. if (ILIsParent(pidlNS, pidl, TRUE))
  189. {
  190. LPCITEMIDLIST pidlChild;
  191. LPITEMIDLIST pidlNew;
  192. TCHAR szFullName[MAX_PATH];
  193. LPITEMIDLIST pidlFull = NULL;
  194. // HACKHACK (lamadio): You cannot use SHGetRealIDL for augisf encapsulated
  195. // IShellFolders. This routine QIs for INeedRealShellFolder, which IAugISF
  196. // doesnot forward. The fstree code does not handle aggregation, so this
  197. // cannot be forwarded anyway. This code can be cleaned up when we rewrite
  198. // the fstree stuff... Sep.4.1997
  199. if (SUCCEEDED(SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szFullName, SIZECHARS(szFullName), NULL))
  200. && (pidlFull = ILCreateFromPath(szFullName)) != NULL)
  201. {
  202. pidlChild = ILFindLastID(pidlFull);
  203. pidlNew = ILClone(pidlFull);
  204. }
  205. else
  206. {
  207. pidlChild = ILFindLastID(pidl);
  208. pidlNew = ILClone(pidl);
  209. }
  210. // Yes; create a new full pidl where the last element is wrapped
  211. if (pidlNew)
  212. {
  213. ILRemoveLastID(pidlNew);
  214. LPITEMIDLIST pidlWrap = AugISF_WrapPidl( pidlChild, (int)nID );
  215. if (pidlWrap)
  216. {
  217. pidlRet = ILCombine(pidlNew, pidlWrap);
  218. ILFree(pidlWrap);
  219. }
  220. ILFree(pidlNew);
  221. }
  222. ILFree(pidlFull); //Checks for a NULL pidl
  223. }
  224. else
  225. pidlRet = (LPITEMIDLIST)pidl;
  226. return pidlRet;
  227. }
  228. /*----------------------------------------------------------
  229. Purpose: CAugmentedISF::GetNativePidl
  230. Clones and returns a copy of the native ('source') pidl
  231. contained in the specified wrap.
  232. */
  233. LPITEMIDLIST CAugmentedISF::GetNativePidl(LPCITEMIDLIST pidl, LPARAM lParam /*int nID*/ )
  234. {
  235. ASSERT(IS_VALID_PIDL(pidl));
  236. UNREFERENCED_PARAMETER( lParam ) ; // only one source ID in the wrap!
  237. LPITEMIDLIST pidlNew = ILClone(pidl);
  238. if (pidlNew)
  239. {
  240. // Take off our trailing wrap signature
  241. pidlNew->mkid.cb = IDWrap_GetOriginalSize(pidl);
  242. ASSERT(sizeof(IDWRAP) >= sizeof(USHORT));
  243. USHORT * pu = (USHORT *)_ILNext(pidlNew);
  244. *pu = 0;
  245. }
  246. return pidlNew;
  247. }
  248. CISFElem::CISFElem(const GUID * pguid, IShellFolder * psf, DWORD dwFlags) : _dwFlags(dwFlags)
  249. {
  250. ASSERT(IS_VALID_CODE_PTR(psf, IShellFolder));
  251. ASSERT(NULL == pguid || IS_VALID_READ_PTR(pguid, GUID));
  252. if (pguid)
  253. CopyMemory(&_guid, pguid, sizeof(_guid));
  254. _psf = psf;
  255. _psf->AddRef();
  256. }
  257. CISFElem::~CISFElem()
  258. {
  259. ASSERT(IS_VALID_CODE_PTR(_psf, IShellFolder));
  260. _psf->Release();
  261. if (_pei)
  262. _pei->Release();
  263. Pidl_Set(&_pidl, NULL);
  264. }
  265. CISFElem * CISFElem::Clone(void)
  266. {
  267. CISFElem * pelem = new CISFElem(&_guid, _psf, _dwFlags);
  268. if (pelem)
  269. {
  270. // If this fails, we're punting and going ahead anyway
  271. pelem->SetPidl(_pidl);
  272. }
  273. return pelem;
  274. }
  275. void CISFElem::GetNameSpaceID(GUID * pguid)
  276. {
  277. ASSERT(IS_VALID_WRITE_PTR(pguid, GUID));
  278. CopyMemory(pguid, &_guid, sizeof(_guid));
  279. }
  280. HRESULT CISFElem::SetPidl(LPCITEMIDLIST pidl)
  281. {
  282. HRESULT hres = S_OK;
  283. Pidl_Set(&_pidl, pidl);
  284. if (pidl && NULL == _pidl)
  285. hres = E_OUTOFMEMORY;
  286. return hres;
  287. }
  288. /*----------------------------------------------------------
  289. Purpose: Gets an enumerator for the IShellFolder and caches it.
  290. */
  291. HRESULT CISFElem::AcquireEnumerator(DWORD dwFlags)
  292. {
  293. return IShellFolder_EnumObjects(_psf, NULL, dwFlags, &_pei);
  294. }
  295. //
  296. // CAugmentedISF object
  297. //
  298. #undef SUPERCLASS
  299. #ifdef DEBUG
  300. BOOL IsValidPCISFElem(CISFElem * pel)
  301. {
  302. return (IS_VALID_WRITE_PTR(pel, CISFElem) &&
  303. IS_VALID_CODE_PTR(pel->_psf, IShellFolder) &&
  304. (NULL == pel->_pidl || IS_VALID_PIDL(pel->_pidl)));
  305. }
  306. #endif
  307. // Constructor
  308. CAugmentedISF::CAugmentedISF() :
  309. _cRef(1)
  310. {
  311. DllAddRef();
  312. }
  313. /*----------------------------------------------------------
  314. Purpose: Callback to destroy each element
  315. */
  316. int CISFElem_DestroyCB(LPVOID pv, LPVOID pvData)
  317. {
  318. CISFElem * pel = (CISFElem *)pv;
  319. ASSERT(NULL == pel || IS_VALID_STRUCT_PTR(pel, CISFElem));
  320. if (pel)
  321. delete pel;
  322. return TRUE;
  323. }
  324. /*----------------------------------------------------------
  325. Purpose: Callback to set the owner of each element
  326. */
  327. int CISFElem_SetOwnerCB(LPVOID pv, LPVOID pvData)
  328. {
  329. CISFElem * pel = (CISFElem *)pv;
  330. ASSERT(IS_VALID_STRUCT_PTR(pel, CISFElem));
  331. IShellFolder * psf = pel->GetPSF();
  332. if (psf)
  333. {
  334. IUnknown_SetOwner(psf, (IUnknown *)pvData);
  335. // don't need to release psf
  336. }
  337. return TRUE;
  338. }
  339. typedef struct {
  340. HRESULT hres;
  341. HWND hwnd;
  342. const IID * piid;
  343. void ** ppvObj;
  344. } CVODATA;
  345. /*----------------------------------------------------------
  346. Purpose: Callback to call CreateViewObject
  347. */
  348. int CISFElem_CreateViewObjectCB(LPVOID pv, LPVOID pvData)
  349. {
  350. CISFElem * pel = (CISFElem *)pv;
  351. CVODATA * pdata = (CVODATA *)pvData;
  352. ASSERT(IS_VALID_STRUCT_PTR(pel, CISFElem));
  353. ASSERT(IS_VALID_WRITE_PTR(pdata, CVODATA));
  354. IShellFolder * psf = pel->GetPSF();
  355. if (psf)
  356. {
  357. pdata->hres = psf->CreateViewObject(pdata->hwnd, *(pdata->piid), pdata->ppvObj);
  358. if (SUCCEEDED(pdata->hres))
  359. return FALSE; // stop on first success
  360. // don't need to release psf
  361. }
  362. return TRUE;
  363. }
  364. // Destructor
  365. CAugmentedISF::~CAugmentedISF()
  366. {
  367. SetOwner(NULL);
  368. DPA_DestroyCallback(_hdpa, CISFElem_DestroyCB, NULL);
  369. _hdpa = NULL;
  370. DllRelease();
  371. }
  372. STDMETHODIMP_(ULONG) CAugmentedISF::AddRef()
  373. {
  374. _cRef++;
  375. return _cRef;
  376. }
  377. STDMETHODIMP_(ULONG) CAugmentedISF::Release()
  378. {
  379. ASSERT(_cRef > 0);
  380. _cRef--;
  381. if (_cRef > 0)
  382. return _cRef;
  383. delete this;
  384. return 0;
  385. }
  386. STDMETHODIMP CAugmentedISF::QueryInterface(REFIID riid, void **ppvObj)
  387. {
  388. static const QITAB qit[] = {
  389. QITABENT(CAugmentedISF, IShellFolder),
  390. QITABENT(CAugmentedISF, IAugmentedShellFolder),
  391. QITABENT(CAugmentedISF, IAugmentedShellFolder2),
  392. QITABENT(CAugmentedISF, IShellService),
  393. QITABENT(CAugmentedISF, ITranslateShellChangeNotify),
  394. { 0 },
  395. };
  396. return QISearch(this, qit, riid, ppvObj);
  397. }
  398. /*----------------------------------------------------------
  399. Purpose: IShellService::SetOwner method
  400. */
  401. STDMETHODIMP CAugmentedISF::SetOwner(IUnknown* punk)
  402. {
  403. HRESULT hres = S_OK;
  404. ASSERT(NULL == punk || IS_VALID_CODE_PTR(punk, IUnknown));
  405. if (_hdpa && _punkOwner)
  406. DPA_EnumCallback(_hdpa, CISFElem_SetOwnerCB, NULL);
  407. ATOMICRELEASE(_punkOwner);
  408. if (punk)
  409. {
  410. hres = punk->QueryInterface(IID_IUnknown, (LPVOID *)&_punkOwner);
  411. if (_hdpa)
  412. DPA_EnumCallback(_hdpa, CISFElem_SetOwnerCB, (void *)_punkOwner);
  413. }
  414. return hres;
  415. }
  416. /*----------------------------------------------------------
  417. Purpose: IShellFolder::EnumObjects method
  418. */
  419. STDMETHODIMP CAugmentedISF::EnumObjects(HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST * ppenumIDList)
  420. {
  421. HRESULT hres = E_FAIL;
  422. if (_hdpa)
  423. {
  424. *ppenumIDList = new CAugISFEnum();
  425. if (*ppenumIDList)
  426. {
  427. hres = ((CAugISFEnum *)(*ppenumIDList))->Init(_hdpa, grfFlags);
  428. if (FAILED(hres))
  429. {
  430. delete *ppenumIDList;
  431. *ppenumIDList = NULL;
  432. }
  433. }
  434. else
  435. hres = E_OUTOFMEMORY;
  436. }
  437. return hres;
  438. }
  439. /*----------------------------------------------------------
  440. Purpose: IShellFolder::BindToObject method
  441. */
  442. STDMETHODIMP CAugmentedISF::BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved,
  443. REFIID riid, LPVOID * ppvOut)
  444. {
  445. HRESULT hres = E_FAIL;
  446. ASSERT(IS_VALID_PIDL(pidl));
  447. ASSERT(IS_VALID_WRITE_PTR(ppvOut, LPVOID));
  448. *ppvOut = NULL;
  449. UINT id = IDWrap_GetID(pidl);
  450. IShellFolder * psf = _GetObjectPSF(id);
  451. if (psf)
  452. {
  453. LPITEMIDLIST pidlReal = GetNativePidl(pidl, id);
  454. if (pidlReal)
  455. {
  456. hres = psf->BindToObject(pidlReal, pbcReserved, riid, ppvOut);
  457. ILFree(pidlReal);
  458. }
  459. else
  460. hres = E_OUTOFMEMORY;
  461. psf->Release();
  462. }
  463. return hres;
  464. }
  465. /*----------------------------------------------------------
  466. Purpose: IShellFolder::BindToStorage method
  467. */
  468. STDMETHODIMP CAugmentedISF::BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved,
  469. REFIID riid, LPVOID * ppvObj)
  470. {
  471. TraceMsg(TF_WARNING, "Called unimplemented CAugmentedISF::BindToStorage");
  472. return E_NOTIMPL;
  473. }
  474. /*----------------------------------------------------------
  475. Purpose: IShellFolder::CompareIDs method
  476. */
  477. STDMETHODIMP CAugmentedISF::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  478. {
  479. HRESULT hres = 0;
  480. int nID1 = IDWrap_GetID(pidl1);
  481. int nID2 = IDWrap_GetID(pidl2);
  482. if (nID1 == nID2)
  483. {
  484. IShellFolder * psf = _GetObjectPSF(nID1);
  485. if (psf)
  486. {
  487. LPITEMIDLIST pidlReal1 = GetNativePidl(pidl1, nID1);
  488. if (pidlReal1)
  489. {
  490. LPITEMIDLIST pidlReal2 = GetNativePidl(pidl2, nID2);
  491. if (pidlReal2)
  492. {
  493. hres = psf->CompareIDs(lParam, pidlReal1, pidlReal2);
  494. ILFree(pidlReal2);
  495. }
  496. ILFree(pidlReal1);
  497. }
  498. psf->Release();
  499. }
  500. }
  501. else
  502. {
  503. //In this situation, we want to see if one of these items wants to be sorted
  504. // below the other.
  505. CISFElem * pel1 = (CISFElem *)DPA_GetPtr(_hdpa, nID1);
  506. CISFElem * pel2 = (CISFElem *)DPA_GetPtr(_hdpa, nID2);
  507. DWORD dwel1 = 0;
  508. DWORD dwel2 = 0;
  509. if (pel1)
  510. dwel1 = pel1->GetFlags();
  511. if (pel2)
  512. dwel2 = pel2->GetFlags();
  513. // if both want their items sorted below the other, punt and do neither.
  514. if ((dwel1 & ASFF_SORTDOWN) ^ (dwel2 & ASFF_SORTDOWN))
  515. hres = ResultFromShort((dwel1 & ASFF_SORTDOWN)? 1 : -1);
  516. else
  517. hres = (nID1 - nID2);
  518. }
  519. return hres;
  520. }
  521. /*----------------------------------------------------------
  522. Purpose: IShellFolder::CreateViewObject method
  523. */
  524. STDMETHODIMP CAugmentedISF::CreateViewObject (HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
  525. {
  526. HRESULT hres = E_FAIL;
  527. if (_hdpa)
  528. {
  529. CVODATA cvodata;
  530. cvodata.hres = E_FAIL;
  531. cvodata.hwnd = hwndOwner;
  532. cvodata.piid = &riid;
  533. cvodata.ppvObj = ppvOut;
  534. // Whoever responds first wins
  535. DPA_EnumCallback(_hdpa, CISFElem_CreateViewObjectCB, (void *)&cvodata);
  536. hres = cvodata.hres;
  537. }
  538. return hres;
  539. }
  540. /*----------------------------------------------------------
  541. Purpose: IShellFolder::GetAttributesOf method
  542. */
  543. STDMETHODIMP CAugmentedISF::GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl,
  544. ULONG * pfInOut)
  545. {
  546. HRESULT hres = E_FAIL;
  547. ASSERT(IS_VALID_READ_PTR(apidl, LPCITEMIDLIST));
  548. ASSERT(IS_VALID_WRITE_PTR(pfInOut, ULONG));
  549. ULONG fInOut = *pfInOut;
  550. *pfInOut &= 0;
  551. // We only handle one pidl
  552. if (1 == cidl && apidl)
  553. {
  554. UINT id = IDWrap_GetID(*apidl);
  555. IShellFolder * psf = _GetObjectPSF(id);
  556. if (psf)
  557. {
  558. LPITEMIDLIST pidlReal = GetNativePidl(*apidl, id);
  559. if (pidlReal)
  560. {
  561. hres = psf->GetAttributesOf(1, (LPCITEMIDLIST *)&pidlReal, &fInOut);
  562. *pfInOut = fInOut;
  563. ILFree(pidlReal);
  564. }
  565. else
  566. hres = E_OUTOFMEMORY;
  567. psf->Release();
  568. }
  569. }
  570. return hres;
  571. }
  572. /*----------------------------------------------------------
  573. Purpose: IShellFolder::GetUIObjectOf method
  574. */
  575. STDMETHODIMP CAugmentedISF::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
  576. REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
  577. {
  578. HRESULT hres = E_FAIL;
  579. ASSERT(IS_VALID_READ_PTR(apidl, LPCITEMIDLIST));
  580. *ppvOut = NULL;
  581. // We only handle one pidl
  582. if (1 == cidl && apidl)
  583. {
  584. UINT id = IDWrap_GetID(*apidl);
  585. IShellFolder * psf = _GetObjectPSF(id);
  586. if (psf)
  587. {
  588. LPITEMIDLIST pidlReal = GetNativePidl(*apidl, id);
  589. if (pidlReal)
  590. {
  591. hres = psf->GetUIObjectOf(hwndOwner, 1, (LPCITEMIDLIST *)&pidlReal, riid, prgfInOut, ppvOut);
  592. ILFree(pidlReal);
  593. }
  594. else
  595. hres = E_OUTOFMEMORY;
  596. psf->Release();
  597. }
  598. }
  599. return hres;
  600. }
  601. /*----------------------------------------------------------
  602. Purpose: IShellFolder::GetDisplayNameOf method
  603. */
  604. STDMETHODIMP CAugmentedISF::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags,
  605. LPSTRRET pstrret)
  606. {
  607. HRESULT hres = E_FAIL;
  608. ASSERT(NULL == pidl || IS_VALID_PIDL(pidl));
  609. ASSERT(IS_VALID_WRITE_PTR(pstrret, STRRET));
  610. if (pidl)
  611. {
  612. UINT id = IDWrap_GetID(pidl);
  613. IShellFolder * psf = _GetObjectPSF(id);
  614. if (psf)
  615. {
  616. LPITEMIDLIST pidlReal = GetNativePidl(pidl, id);
  617. if (pidlReal)
  618. {
  619. hres = psf->GetDisplayNameOf(pidlReal, uFlags, pstrret);
  620. ILFree(pidlReal);
  621. }
  622. else
  623. hres = E_OUTOFMEMORY;
  624. psf->Release();
  625. }
  626. else
  627. hres = E_FAIL;
  628. }
  629. return hres;
  630. }
  631. /*----------------------------------------------------------
  632. Purpose: IShellFolder::SetNameOf method
  633. */
  634. STDMETHODIMP CAugmentedISF::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl,
  635. LPCOLESTR lpszName, DWORD uFlags,
  636. LPITEMIDLIST * ppidlOut)
  637. {
  638. HRESULT hres = E_FAIL;
  639. ASSERT(NULL == pidl || IS_VALID_PIDL(pidl));
  640. if (pidl)
  641. {
  642. UINT id = IDWrap_GetID(pidl);
  643. IShellFolder * psf = _GetObjectPSF(id);
  644. if (psf)
  645. {
  646. LPITEMIDLIST pidlReal = GetNativePidl(pidl, id);
  647. if (pidlReal)
  648. {
  649. LPITEMIDLIST pidlOut = NULL;
  650. hres = psf->SetNameOf(hwndOwner, pidlReal,
  651. lpszName, uFlags,
  652. &pidlOut);
  653. // Do they want a pidl back?
  654. if (SUCCEEDED(hres) && ppidlOut)
  655. {
  656. *ppidlOut = AugISF_WrapPidl( pidlOut, id );
  657. if (!*ppidlOut)
  658. hres = E_OUTOFMEMORY;
  659. }
  660. ILFree(pidlOut);
  661. ILFree(pidlReal);
  662. }
  663. else
  664. hres = E_OUTOFMEMORY;
  665. psf->Release();
  666. }
  667. else
  668. hres = E_FAIL;
  669. }
  670. return hres;
  671. }
  672. /*----------------------------------------------------------
  673. Purpose: IShellFolder::ParseDisplayName method
  674. */
  675. STDMETHODIMP CAugmentedISF::ParseDisplayName(HWND hwndOwner,
  676. LPBC pbcReserved, LPOLESTR lpszDisplayName,
  677. ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes)
  678. {
  679. TraceMsg(TF_WARNING, "Called unimplemented CAugmentedISF::ParseDisplayNameOf");
  680. return E_NOTIMPL;
  681. }
  682. /*----------------------------------------------------------
  683. Purpose: IAugmentedShellFolder::AddNameSpace
  684. */
  685. STDMETHODIMP CAugmentedISF::AddNameSpace(const GUID * pguid,
  686. IShellFolder * psf, LPCITEMIDLIST pidl, DWORD dwFlags)
  687. {
  688. HRESULT hres = E_INVALIDARG;
  689. ASSERT(IS_VALID_CODE_PTR(psf, IShellFolder));
  690. ASSERT(NULL == pguid || IS_VALID_READ_PTR(pguid, GUID));
  691. ASSERT(NULL == pidl || IS_VALID_PIDL(pidl));
  692. if (NULL == _hdpa)
  693. {
  694. _hdpa = DPA_Create(4);
  695. }
  696. if (psf && _hdpa)
  697. {
  698. hres = S_OK; // Assume success
  699. CISFElem * pel = new CISFElem(pguid, psf, dwFlags);
  700. if (pel)
  701. {
  702. hres = pel->SetPidl(pidl);
  703. if (SUCCEEDED(hres))
  704. {
  705. if (DPA_ERR == DPA_AppendPtr(_hdpa, pel))
  706. hres = E_OUTOFMEMORY;
  707. }
  708. if (FAILED(hres))
  709. delete pel;
  710. }
  711. else
  712. hres = E_OUTOFMEMORY;
  713. }
  714. return hres;
  715. }
  716. /*----------------------------------------------------------
  717. Purpose: IAugmentedShellFolder::GetNameSpaceID
  718. */
  719. STDMETHODIMP CAugmentedISF::GetNameSpaceID(LPCITEMIDLIST pidl, GUID * pguidOut)
  720. {
  721. HRESULT hres = E_INVALIDARG;
  722. ASSERT(IS_VALID_PIDL(pidl));
  723. ASSERT(IS_VALID_WRITE_PTR(pguidOut, GUID));
  724. if (pidl && pguidOut)
  725. {
  726. UINT id = IDWrap_GetID(pidl);
  727. hres = E_FAIL;
  728. if (_hdpa)
  729. {
  730. CISFElem * pel = (CISFElem *)DPA_GetPtr(_hdpa, id);
  731. if (pel)
  732. {
  733. pel->GetNameSpaceID(pguidOut);
  734. hres = S_OK;
  735. }
  736. }
  737. }
  738. return hres;
  739. }
  740. /*----------------------------------------------------------
  741. Purpose: IAugmentedShellFolder::QueryNameSpace
  742. */
  743. STDMETHODIMP CAugmentedISF::QueryNameSpace(DWORD dwID, GUID * pguidOut,
  744. IShellFolder ** ppsf)
  745. {
  746. HRESULT hres = E_FAIL;
  747. ASSERT(NULL == pguidOut || IS_VALID_WRITE_PTR(pguidOut, GUID));
  748. ASSERT(NULL == ppsf || IS_VALID_WRITE_PTR(ppsf, IShellFolder));
  749. if (_hdpa)
  750. {
  751. CISFElem * pel = (CISFElem *)DPA_GetPtr(_hdpa, dwID);
  752. if (pel)
  753. {
  754. if (ppsf)
  755. {
  756. IShellFolder * psf = pel->GetPSF();
  757. psf->AddRef();
  758. *ppsf = psf;
  759. }
  760. if (pguidOut)
  761. pel->GetNameSpaceID(pguidOut);
  762. hres = S_OK;
  763. }
  764. }
  765. return hres;
  766. }
  767. /*----------------------------------------------------------
  768. Purpose: IAugmentedShellFolder::EnumNameSpace
  769. */
  770. STDMETHODIMP CAugmentedISF::EnumNameSpace(DWORD uNameSpace, DWORD * pdwID)
  771. {
  772. HRESULT hres = E_FAIL;
  773. if (_hdpa)
  774. {
  775. DWORD celem = DPA_GetPtrCount(_hdpa);
  776. if (-1 == uNameSpace)
  777. hres = celem;
  778. else
  779. {
  780. if (uNameSpace >= celem)
  781. hres = E_FAIL;
  782. else
  783. {
  784. // For now, simply use the index given
  785. *pdwID = uNameSpace;
  786. hres = S_OK;
  787. }
  788. }
  789. }
  790. return hres;
  791. }
  792. /*----------------------------------------------------------
  793. Purpose: ITranslateShellChangeNotify::TranslateIDs
  794. */
  795. STDMETHODIMP CAugmentedISF::TranslateIDs(LONG *plEvent,
  796. LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2,
  797. LPITEMIDLIST * ppidlOut1, LPITEMIDLIST * ppidlOut2,
  798. LONG *plEvent2, LPITEMIDLIST *ppidlOut1Event2,
  799. LPITEMIDLIST *ppidlOut2Event2)
  800. {
  801. HRESULT hres = S_OK;
  802. *plEvent2 = (LONG)-1;
  803. *ppidlOut1Event2 = NULL;
  804. *ppidlOut2Event2 = NULL;
  805. *ppidlOut1 = (LPITEMIDLIST)pidl1;
  806. *ppidlOut2 = (LPITEMIDLIST)pidl2;
  807. if (_hdpa)
  808. {
  809. int cElem = DPA_GetPtrCount(_hdpa);
  810. int i;
  811. // Go thru all the namespaces and find which one should
  812. // translate this notification
  813. for (i = 0; i < cElem; i++)
  814. {
  815. CISFElem * pel = (CISFElem *)DPA_FastGetPtr(_hdpa, i);
  816. if (pel)
  817. {
  818. LPCITEMIDLIST pidlNS = pel->GetPidl();
  819. if (pidlNS)
  820. {
  821. if (pidl1)
  822. {
  823. *ppidlOut1 = TranslatePidl(pidlNS, pidl1, i);
  824. if (NULL == *ppidlOut1)
  825. hres = E_OUTOFMEMORY;
  826. }
  827. if (SUCCEEDED(hres) && pidl2)
  828. {
  829. *ppidlOut2 = TranslatePidl(pidlNS, pidl2, i);
  830. if (NULL == *ppidlOut2)
  831. hres = E_OUTOFMEMORY;
  832. }
  833. if (FAILED(hres))
  834. {
  835. if (*ppidlOut1 != pidl1)
  836. Pidl_Set(ppidlOut1, NULL);
  837. if (*ppidlOut2 != pidl2)
  838. Pidl_Set(ppidlOut2, NULL);
  839. break;
  840. }
  841. else
  842. {
  843. if (*ppidlOut1 != pidl1 || *ppidlOut2 != pidl2)
  844. break;
  845. }
  846. }
  847. }
  848. }
  849. }
  850. return hres;
  851. }
  852. /*----------------------------------------------------------
  853. Purpose: ITranslateShellChangeNotify::IsChildID
  854. */
  855. STDMETHODIMP CAugmentedISF::IsChildID(LPCITEMIDLIST pidlKid, BOOL fImmediate)
  856. {
  857. HRESULT hres = S_FALSE;
  858. //At this point we should have a translated pidl
  859. if (pidlKid)
  860. {
  861. // Weirdness: If fImmediate is TRUE, then this is a Wrapped pidl. If it's
  862. // false, then it's not, and we need to check to see if it's a Real FS Child.
  863. if (fImmediate)
  864. {
  865. LPCITEMIDLIST pidlRelKid = ILFindLastID(pidlKid);
  866. if (pidlRelKid)
  867. {
  868. int nID = IDWrap_GetID(pidlRelKid);
  869. CISFElem * pel = (CISFElem *)DPA_GetPtr(_hdpa, nID);
  870. if (pel && pel->GetPidl())
  871. {
  872. if (ILIsParent(pel->GetPidl(), pidlKid, TRUE))
  873. hres = S_OK;
  874. }
  875. }
  876. }
  877. else
  878. {
  879. int cElem = DPA_GetPtrCount(_hdpa);
  880. int i;
  881. for (i = 0; i < cElem; i++)
  882. {
  883. CISFElem * pel = (CISFElem *)DPA_GetPtr(_hdpa, i);
  884. if (pel && pel->GetPidl())
  885. {
  886. if (ILIsParent(pel->GetPidl(), pidlKid, FALSE))
  887. {
  888. hres = S_OK;
  889. break;
  890. }
  891. }
  892. }
  893. }
  894. }
  895. return hres;
  896. }
  897. /*----------------------------------------------------------
  898. Purpose: ITranslateShellChangeNotify::IsEqualID
  899. */
  900. STDMETHODIMP CAugmentedISF::IsEqualID(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  901. {
  902. int cElem = DPA_GetPtrCount(_hdpa);
  903. int i;
  904. for (i = 0; i < cElem; i++)
  905. {
  906. CISFElem * pel = (CISFElem *)DPA_FastGetPtr(_hdpa, i);
  907. if (pel)
  908. {
  909. if (pidl1)
  910. {
  911. if (ILIsEqual(pel->GetPidl(),pidl1))
  912. return S_OK;
  913. }
  914. else if (pidl2)
  915. {
  916. if (ILIsParent(pidl2, pel->GetPidl(), FALSE))
  917. return S_OK;
  918. }
  919. }
  920. }
  921. return S_FALSE;
  922. }
  923. /*----------------------------------------------------------
  924. Purpose: ITranslateShellChangeNotify::Register
  925. Registers all pidls contained to the passed in window
  926. */
  927. STDMETHODIMP CAugmentedISF::Register(HWND hwnd, UINT uMsg, long lEvents)
  928. {
  929. HRESULT hres = NOERROR;
  930. if (_hdpa)
  931. {
  932. int cElem = DPA_GetPtrCount(_hdpa);
  933. int i;
  934. for (i = 0; i < cElem; i++)
  935. {
  936. CISFElem * pel = (CISFElem *)DPA_FastGetPtr(_hdpa, i);
  937. // Has this namespace been registered yet?
  938. if (pel && 0 == pel->GetRegister())
  939. {
  940. // No; register it
  941. LPCITEMIDLIST pidlNS = pel->GetPidl();
  942. if (pidlNS)
  943. {
  944. pel->SetRegister(RegisterNotify(hwnd, uMsg, pidlNS, lEvents,
  945. SHCNRF_ShellLevel | SHCNRF_InterruptLevel, TRUE));
  946. }
  947. }
  948. }
  949. }
  950. else
  951. hres = E_FAIL;
  952. return hres;
  953. }
  954. /*----------------------------------------------------------
  955. Purpose: ITranslateShellChangeNotify::Unregister
  956. */
  957. STDMETHODIMP CAugmentedISF::Unregister()
  958. {
  959. HRESULT hres = NOERROR;
  960. if (_hdpa)
  961. {
  962. int cElem = DPA_GetPtrCount(_hdpa);
  963. int i;
  964. for (i = 0; i < cElem; i++)
  965. {
  966. CISFElem * pel = (CISFElem *)DPA_FastGetPtr(_hdpa, i);
  967. UINT uReg;
  968. if (pel && (uReg = pel->GetRegister()) != 0)
  969. {
  970. // SHChangeNotifyDeregister will flush messages
  971. // which will send a notify which will come back here...
  972. pel->SetRegister(0);
  973. SHChangeNotifyDeregister(uReg);
  974. }
  975. }
  976. }
  977. else
  978. hres = E_FAIL;
  979. return hres;
  980. }
  981. /*----------------------------------------------------------
  982. Purpose: Returns the psf associated with the ID.
  983. */
  984. IShellFolder * CAugmentedISF::_GetObjectPSF(int nID)
  985. {
  986. IShellFolder * psf = NULL;
  987. if (_hdpa)
  988. {
  989. CISFElem * pel = (CISFElem *)DPA_GetPtr(_hdpa, nID);
  990. if (pel)
  991. {
  992. psf = pel->GetPSF();
  993. ASSERT(IS_VALID_CODE_PTR(psf, IShellFolder));
  994. psf->AddRef();
  995. }
  996. }
  997. return psf;
  998. }
  999. //
  1000. // CAugISF Enumerator object
  1001. //
  1002. #undef SUPERCLASS
  1003. // Constructor
  1004. CAugISFEnum::CAugISFEnum() :
  1005. _cRef(1)
  1006. {
  1007. }
  1008. // Destructor
  1009. CAugISFEnum::~CAugISFEnum()
  1010. {
  1011. if (_hdpaISF)
  1012. {
  1013. DPA_DestroyCallback(_hdpaISF, CISFElem_DestroyCB, NULL);
  1014. _hdpaISF = NULL;
  1015. }
  1016. }
  1017. HRESULT CAugISFEnum::Init(HDPA hdpaISF, DWORD dwEnumFlags)
  1018. {
  1019. HRESULT hres = S_OK;
  1020. ASSERT(IS_VALID_HANDLE(hdpaISF, DPA));
  1021. // Clone the DPA
  1022. _hdpaISF = DPA_Clone(hdpaISF, NULL);
  1023. if (_hdpaISF)
  1024. {
  1025. // Clone the elements too
  1026. int cElem = DPA_GetPtrCount(_hdpaISF);
  1027. int i;
  1028. // If something fails in the loop, at least try to enumerate
  1029. // other namespaces.
  1030. for (i = 0; i < cElem; i++)
  1031. {
  1032. CISFElem * pel = (CISFElem *)DPA_FastGetPtr(_hdpaISF, i);
  1033. if (pel)
  1034. {
  1035. CISFElem * pelNew = pel->Clone();
  1036. if (pelNew)
  1037. {
  1038. // Get the enumerator
  1039. if (SUCCEEDED(pelNew->AcquireEnumerator(dwEnumFlags)))
  1040. DPA_SetPtr(_hdpaISF, i, pelNew);
  1041. else
  1042. {
  1043. TraceMsg(TF_WARNING, "CAugISFEnum::Init. Namespace %d has no enumerator.", i);
  1044. // Remove it from the list to enumerate, and continue
  1045. DPA_DeletePtr(_hdpaISF, i);
  1046. cElem--;
  1047. i--;
  1048. delete pelNew;
  1049. }
  1050. }
  1051. }
  1052. }
  1053. }
  1054. else
  1055. hres = E_OUTOFMEMORY;
  1056. return hres;
  1057. }
  1058. STDMETHODIMP CAugISFEnum::QueryInterface(REFIID riid, LPVOID * ppvObj)
  1059. {
  1060. static const QITAB qit[] = {
  1061. QITABENT(CAugISFEnum, IEnumIDList),
  1062. { 0 },
  1063. };
  1064. return QISearch(this, qit, riid, ppvObj);
  1065. }
  1066. STDMETHODIMP_(ULONG) CAugISFEnum::AddRef()
  1067. {
  1068. return ++_cRef;
  1069. }
  1070. STDMETHODIMP_(ULONG) CAugISFEnum::Release()
  1071. {
  1072. if (--_cRef > 0) {
  1073. return _cRef;
  1074. }
  1075. delete this;
  1076. return 0;
  1077. }
  1078. /*----------------------------------------------------------
  1079. Purpose: IEnumIDList::Next method
  1080. This will call the current enumerator for the next
  1081. object. The object's pidl is wrapped in an IDWRAP
  1082. (which is stamped with the identifier of the specific
  1083. IShellFolder the object belongs to) and handed back.
  1084. If the current enumerator has no more items to return,
  1085. this function will call the next enumerator for its
  1086. first item, and returns that. The subsequent call
  1087. will pick up from there.
  1088. */
  1089. STDMETHODIMP CAugISFEnum::Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
  1090. {
  1091. ULONG celtFetched = 0;
  1092. HRESULT hres = S_FALSE;
  1093. if (celt > 0)
  1094. {
  1095. IEnumIDList * pei = _GetObjectEnumerator(_iCurISF);
  1096. if (pei)
  1097. {
  1098. LPITEMIDLIST pidl;
  1099. hres = pei->Next(1, &pidl, &celtFetched);
  1100. if (SUCCEEDED(hres))
  1101. {
  1102. // End of enumeration for this object?
  1103. if (S_FALSE == hres)
  1104. {
  1105. // Yes; go to next ISF object
  1106. _iCurISF++;
  1107. hres = Next(celt, rgelt, &celtFetched);
  1108. }
  1109. else
  1110. {
  1111. // No; now wrap the pidl.
  1112. rgelt[0] = AugISF_WrapPidl( pidl, _iCurISF );
  1113. if (rgelt[0])
  1114. {
  1115. celtFetched = 1;
  1116. hres = S_OK;
  1117. }
  1118. else
  1119. hres = E_OUTOFMEMORY;
  1120. ILFree(pidl);
  1121. }
  1122. }
  1123. pei->Release();
  1124. }
  1125. }
  1126. if (pceltFetched)
  1127. *pceltFetched = celtFetched;
  1128. return hres;
  1129. }
  1130. STDMETHODIMP CAugISFEnum::Skip(ULONG celt)
  1131. {
  1132. return E_NOTIMPL;
  1133. }
  1134. STDMETHODIMP CAugISFEnum::Reset()
  1135. {
  1136. if (_hdpaISF)
  1137. {
  1138. // Reset all the enumerators
  1139. int cel = DPA_GetPtrCount(_hdpaISF);
  1140. int i;
  1141. for (i = 0; i < cel; i++)
  1142. {
  1143. CISFElem * pel = (CISFElem *)DPA_FastGetPtr(_hdpaISF, i);
  1144. if (pel)
  1145. {
  1146. IEnumIDList * pei = pel->GetEnumerator();
  1147. if (pei)
  1148. {
  1149. pei->Reset();
  1150. // Don't Release b/c GetEnumerator doesn't AddRef
  1151. }
  1152. }
  1153. }
  1154. }
  1155. _iCurISF = 0;
  1156. return S_OK;
  1157. }
  1158. STDMETHODIMP CAugISFEnum::Clone(IEnumIDList **ppenum)
  1159. {
  1160. *ppenum = NULL;
  1161. return E_NOTIMPL;
  1162. }
  1163. /*----------------------------------------------------------
  1164. Purpose: Returns the enumerator associated with the ID.
  1165. */
  1166. IEnumIDList * CAugISFEnum::_GetObjectEnumerator(int nID)
  1167. {
  1168. IEnumIDList * pei = NULL;
  1169. if (_hdpaISF)
  1170. {
  1171. CISFElem * pel = (CISFElem *)DPA_GetPtr(_hdpaISF, nID);
  1172. if (pel)
  1173. {
  1174. pei = pel->GetEnumerator();
  1175. ASSERT(IS_VALID_CODE_PTR(pei, IEnumIDList));
  1176. pei->AddRef();
  1177. }
  1178. }
  1179. return pei;
  1180. }
  1181. /*----------------------------------------------------------
  1182. Purpose: Create-instance function for class factory
  1183. */
  1184. STDAPI CAugmentedISF_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  1185. {
  1186. // aggregation checking is handled in class factory
  1187. HRESULT hres;
  1188. CAugmentedISF* pObj;
  1189. hres = E_OUTOFMEMORY;
  1190. pObj = new CAugmentedISF();
  1191. if (pObj)
  1192. {
  1193. *ppunk = SAFECAST(pObj, IShellFolder *);
  1194. hres = S_OK;
  1195. }
  1196. return hres;
  1197. }