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.

3393 lines
114 KiB

  1. //-------------------------------------------------------------------------//
  2. //
  3. // AugMisf.cpp - Augmented Merge IShellFolder class implementation.
  4. //
  5. //-------------------------------------------------------------------------//
  6. #include "priv.h"
  7. #include "augmisf.h"
  8. #include "resource.h"
  9. #include "mluisupp.h"
  10. #define TF_AUGM 0x10000000
  11. //-------------------------------------------------------------------------//
  12. // BUGBUG: Shell allocator bullchit, inserted here because SHRealloc
  13. // isn't imported into browseui, this module's hosting executable.
  14. // If we get SHRealloc, the following block can be removed:
  15. #define _EXPL_SHELL_ALLOCATOR_
  16. #ifdef _EXPL_SHELL_ALLOCATOR_
  17. #define SHRealloc( pv, cb ) shrealloc( pv, cb )
  18. void* shrealloc( void* pv, size_t cb )
  19. {
  20. IMalloc* pMalloc ;
  21. void* pvRet = NULL ;
  22. if( SUCCEEDED( SHGetMalloc( &pMalloc ) ) ) {
  23. pvRet = pMalloc->Realloc( pv, cb ) ;
  24. ATOMICRELEASE( pMalloc ) ;
  25. }
  26. return pvRet ;
  27. }
  28. #endif _EXPL_SHELL_ALLOCATOR_
  29. BOOL AffectAllUsers(HWND hwnd);
  30. // id - verb mappings for IContextMenu impl
  31. const struct
  32. {
  33. UINT id;
  34. LPCSTR pszVerb;
  35. } c_sIDVerbMap[] =
  36. {
  37. {SMIDM_DELETE, "delete"},
  38. {SMIDM_RENAME, "rename"},
  39. {SMIDM_PROPERTIES, "properties"},
  40. //{SMIDM_OPEN, "open"},
  41. //{SMIDM_EXPLORE, "explore"},
  42. };
  43. // augmisf context menu
  44. class CAugMergeISFContextMenu : public IContextMenu2
  45. {
  46. public:
  47. // *** IUnknown methods ***
  48. STDMETHOD (QueryInterface)(REFIID, void**);
  49. STDMETHOD_(ULONG, AddRef)();
  50. STDMETHOD_(ULONG, Release)();
  51. // *** IContextMenu methods ***
  52. STDMETHOD(QueryContextMenu)(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags);
  53. STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO lpici);
  54. STDMETHOD(GetCommandString)(UINT_PTR idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax);
  55. // *** IContextMenu2 methods ***
  56. STDMETHOD(HandleMenuMsg)(UINT uMsg, WPARAM wParam, LPARAM lParam);
  57. protected:
  58. CAugMergeISFContextMenu(IShellFolder *psfCommon, LPCITEMIDLIST pidlCommon,
  59. IShellFolder *psfUser, LPCITEMIDLIST pidlUser, LPITEMIDLIST pidl,
  60. HWND hwnd, UINT * prgfInOut);
  61. ~CAugMergeISFContextMenu();
  62. friend class CAugmentedMergeISF;
  63. friend CAugMergeISFContextMenu* CreateMergeISFContextMenu(
  64. IShellFolder *psfCommon, LPCITEMIDLIST pidlCommon,
  65. IShellFolder *psfUser, LPCITEMIDLIST pidlUser, LPITEMIDLIST pidl,
  66. HWND hwnd, UINT * prgfInOut);
  67. protected:
  68. LPITEMIDLIST _pidlItem;
  69. IShellFolder * _psfCommon;
  70. IShellFolder * _psfUser;
  71. IContextMenu * _pcmCommon;
  72. IContextMenu * _pcmUser;
  73. LPITEMIDLIST _pidlCommon;
  74. LPITEMIDLIST _pidlUser;
  75. UINT _idFirst;
  76. LONG _cRef;
  77. HWND _hwnd;
  78. };
  79. CAugMergeISFContextMenu* CreateMergeISFContextMenu(
  80. IShellFolder *psfCommon, LPCITEMIDLIST pidlCommon,
  81. IShellFolder *psfUser, LPCITEMIDLIST pidlUser, LPITEMIDLIST pidl,
  82. HWND hwnd, UINT * prgfInOut)
  83. {
  84. CAugMergeISFContextMenu* pcm = new CAugMergeISFContextMenu(psfCommon, pidlCommon,
  85. psfUser, pidlUser,
  86. pidl, hwnd, prgfInOut);
  87. if (pcm)
  88. {
  89. if (!pcm->_pidlItem)
  90. {
  91. delete pcm;
  92. pcm = NULL;
  93. }
  94. }
  95. return pcm;
  96. }
  97. CAugMergeISFContextMenu::CAugMergeISFContextMenu(IShellFolder *psfCommon, LPCITEMIDLIST pidlCommon,
  98. IShellFolder *psfUser, LPCITEMIDLIST pidlUser,
  99. LPITEMIDLIST pidl, HWND hwnd, UINT * prgfInOut)
  100. {
  101. _cRef = 1;
  102. HRESULT hres;
  103. _hwnd = hwnd;
  104. _psfCommon = psfCommon;
  105. if (_psfCommon)
  106. {
  107. _psfCommon->AddRef();
  108. hres = _psfCommon->GetUIObjectOf(hwnd, 1, (LPCITEMIDLIST*)&pidl, IID_IContextMenu, prgfInOut, (void **)&_pcmCommon);
  109. ASSERT(SUCCEEDED(hres) || !_pcmCommon);
  110. _pidlCommon = ILClone(pidlCommon);
  111. }
  112. _psfUser = psfUser;
  113. if (_psfUser)
  114. {
  115. _psfUser->AddRef();
  116. hres = _psfUser->GetUIObjectOf(hwnd, 1, (LPCITEMIDLIST*)&pidl, IID_IContextMenu, prgfInOut, (void **)&_pcmUser);
  117. ASSERT(SUCCEEDED(hres) || !_pcmUser);
  118. _pidlUser = ILClone(pidlUser);
  119. }
  120. _pidlItem = ILClone(pidl);
  121. ASSERT(_psfCommon || _psfUser);
  122. }
  123. CAugMergeISFContextMenu::~CAugMergeISFContextMenu()
  124. {
  125. ATOMICRELEASE(_psfCommon);
  126. ATOMICRELEASE(_pcmCommon);
  127. ATOMICRELEASE(_psfUser);
  128. ATOMICRELEASE(_pcmUser);
  129. ILFree(_pidlCommon);
  130. ILFree(_pidlUser);
  131. ILFree(_pidlItem);
  132. }
  133. STDMETHODIMP CAugMergeISFContextMenu::QueryInterface(REFIID riid, LPVOID *ppvOut)
  134. {
  135. static const QITAB qit[] = {
  136. QITABENTMULTI(CAugMergeISFContextMenu, IContextMenu, IContextMenu2),
  137. QITABENT(CAugMergeISFContextMenu, IContextMenu2),
  138. { 0 },
  139. };
  140. return QISearch(this, qit, riid, ppvOut);
  141. }
  142. STDMETHODIMP_(ULONG) CAugMergeISFContextMenu::AddRef()
  143. {
  144. return InterlockedIncrement(&_cRef);
  145. }
  146. STDMETHODIMP_(ULONG) CAugMergeISFContextMenu::Release()
  147. {
  148. ASSERT( 0 != _cRef );
  149. ULONG cRef = InterlockedDecrement(&_cRef);
  150. if ( 0 == cRef )
  151. {
  152. delete this;
  153. }
  154. return cRef;
  155. }
  156. HRESULT CAugMergeISFContextMenu::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
  157. {
  158. HRESULT hres = E_INVALIDARG;
  159. if (hmenu)
  160. {
  161. HMENU hmContext = LoadMenuPopup(MENU_SM_CONTEXTMENU);
  162. if (hmContext)
  163. {
  164. if (!_psfCommon || !_psfUser)
  165. {
  166. DeleteMenu(hmContext, SMIDM_OPENCOMMON, MF_BYCOMMAND);
  167. DeleteMenu(hmContext, SMIDM_EXPLORECOMMON, MF_BYCOMMAND);
  168. }
  169. _idFirst = idCmdFirst;
  170. Shell_MergeMenus(hmenu, hmContext, -1, idCmdFirst, idCmdLast, MM_ADDSEPARATOR);
  171. DestroyMenu(hmContext);
  172. // Make it look "Shell Like"
  173. SetMenuDefaultItem(hmenu, 0, MF_BYPOSITION);
  174. hres = S_OK;
  175. }
  176. else
  177. hres = E_OUTOFMEMORY;
  178. }
  179. return hres;
  180. }
  181. HRESULT CAugMergeISFContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
  182. {
  183. UINT id = -1;
  184. HRESULT hres = E_FAIL;
  185. CMINVOKECOMMANDINFO ici = *pici;
  186. if (pici->cbSize < SIZEOF(CMINVOKECOMMANDINFO))
  187. return E_INVALIDARG;
  188. if (HIWORD(pici->lpVerb))
  189. {
  190. for (int i=0; i < ARRAYSIZE(c_sIDVerbMap); i++)
  191. {
  192. if (lstrcmpiA(pici->lpVerb, c_sIDVerbMap[i].pszVerb) == 0)
  193. {
  194. id = c_sIDVerbMap[i].id;
  195. break;
  196. }
  197. }
  198. }
  199. else
  200. id = (UINT) PtrToUlong( pici->lpVerb ); // Win64: should be ok since MAKEINTRESOURCE assumed
  201. switch (id)
  202. {
  203. case -1:
  204. hres = E_INVALIDARG;
  205. break;
  206. case SMIDM_OPEN:
  207. case SMIDM_EXPLORE:
  208. case SMIDM_OPENCOMMON:
  209. case SMIDM_EXPLORECOMMON:
  210. {
  211. IShellFolder * psf;
  212. LPITEMIDLIST pidl;
  213. if (id == SMIDM_OPEN || id == SMIDM_EXPLORE)
  214. {
  215. if (_psfUser)
  216. {
  217. psf = _psfUser;
  218. pidl = _pidlUser;
  219. }
  220. else
  221. {
  222. psf = _psfCommon;
  223. pidl = _pidlCommon;
  224. }
  225. }
  226. else
  227. {
  228. psf = _psfCommon;
  229. pidl = _pidlCommon;
  230. }
  231. if (psf && pidl)
  232. {
  233. SHELLEXECUTEINFO shei = {0};
  234. shei.lpIDList = ILCombine(pidl, _pidlItem);
  235. if (shei.lpIDList)
  236. {
  237. shei.cbSize = sizeof(shei);
  238. shei.fMask = SEE_MASK_IDLIST;
  239. shei.nShow = SW_SHOWNORMAL;
  240. if (id == SMIDM_EXPLORE || id == SMIDM_EXPLORECOMMON)
  241. shei.lpVerb = TEXT("explore");
  242. else
  243. shei.lpVerb = TEXT("open");
  244. hres = ShellExecuteEx(&shei) ? S_OK : E_FAIL;
  245. ILFree((LPITEMIDLIST)shei.lpIDList);
  246. }
  247. }
  248. }
  249. break;
  250. case SMIDM_PROPERTIES:
  251. {
  252. IContextMenu * pcm = _pcmUser ? _pcmUser : _pcmCommon;
  253. if (pcm)
  254. {
  255. ici.lpVerb = "properties";
  256. hres = pcm->InvokeCommand(&ici);
  257. }
  258. }
  259. break;
  260. case SMIDM_DELETE:
  261. ici.lpVerb = "delete";
  262. hres = S_OK;
  263. if (_pcmUser)
  264. {
  265. hres = _pcmUser->InvokeCommand(&ici);
  266. }
  267. else if (_pcmCommon)
  268. {
  269. ici.fMask |= CMIC_MASK_FLAG_NO_UI;
  270. if (AffectAllUsers(_hwnd))
  271. hres = _pcmCommon->InvokeCommand(&ici);
  272. else
  273. hres = E_FAIL;
  274. }
  275. break;
  276. case SMIDM_RENAME:
  277. ASSERT(0);
  278. hres = E_NOTIMPL; // sftbar picks this off
  279. break;
  280. }
  281. return hres;
  282. }
  283. HRESULT CAugMergeISFContextMenu::GetCommandString(UINT_PTR idCmd, UINT uType, UINT* pwReserved, LPSTR pszName, UINT cchMax)
  284. {
  285. HRESULT hres = E_NOTIMPL;
  286. // if hiword in not null then a string is passed to us. we don't handle that case (yet?)
  287. if (!HIWORD(idCmd) && (uType == GCS_VERBA || uType == GCS_VERBW))
  288. {
  289. hres = E_INVALIDARG;
  290. for (int i = 0; hres != S_OK && i < ARRAYSIZE(c_sIDVerbMap); i++)
  291. {
  292. if (c_sIDVerbMap[i].id == idCmd)
  293. {
  294. if (uType == GCS_VERBA)
  295. {
  296. hres = StringCchCopyA(pszName, cchMax, c_sIDVerbMap[i].pszVerb);
  297. }
  298. else
  299. {
  300. SHAnsiToUnicode(c_sIDVerbMap[i].pszVerb, (LPWSTR)pszName, cchMax);
  301. hres = S_OK;
  302. }
  303. }
  304. }
  305. }
  306. return hres;
  307. }
  308. // we need IContextMenu2 although HandleMenuMsg is not impl because of the way sftbar
  309. // works -- it caches only IContextMenu2 so if we don't have ICM2 sftbar will think
  310. // that it does not have context menu so it will eat the messages intended for the hmenu
  311. // that way, with context menu up, if user presses esc it will kill start menu sub menu
  312. // not the context menu.
  313. HRESULT CAugMergeISFContextMenu::HandleMenuMsg(UINT uMsg, WPARAM wParam, LPARAM lParam)
  314. {
  315. return E_NOTIMPL;
  316. }
  317. //-------------------------------------------------------------------------//
  318. // Augmented Merge Shell Folder's pidl wrapper package consists of a versioned
  319. // header followed by n 'source namespace' pidl wrappers.
  320. // Each individual pidl wrapper consists of a header containing a
  321. // collection lookup index followed by the source pidl itself. The
  322. // source pidl's mkid.cb member is used to seek the next pidl wrap in
  323. // the package.
  324. //-------------------------------------------------------------------------//
  325. //-------------------------------------------------------------------------//
  326. //--- Augmented Merge Shell Folder's pidl wrapper header
  327. typedef struct tagAUGM_IDWRAP {
  328. USHORT cb ; // pidl wrap length
  329. USHORT Reserved ; // reserved.
  330. ULONG tag ; // AugMergeISF pidl signature
  331. ULONG version ; // AugMergeISF pidl version
  332. ULONG cSrcs ; // Number of source namespace objects backing this composite pidl
  333. } AUGM_IDWRAP;
  334. typedef UNALIGNED AUGM_IDWRAP *PAUGM_IDWRAP;
  335. //--- Source pidl header. One or more of these records will be concatenated
  336. // within the wrap following the wrap header.
  337. typedef struct tagAUGM_IDSRC {
  338. UINT nID ; // source namespace index
  339. BYTE pidl[0] ; // source pidl
  340. } AUGM_IDSRC;
  341. typedef UNALIGNED AUGM_IDSRC *PAUGM_IDSRC;
  342. //-------------------------------------------------------------------------//
  343. // Constants
  344. //-------------------------------------------------------------------------//
  345. #define AUGM_WRAPTAG MAKELONG( MAKEWORD('A','u'), MAKEWORD('g','M') )
  346. #define AUGM_WRAPVERSION_1_0 MAKELONG( 1, 0 )
  347. #define AUGM_WRAPCURRENTVERSION AUGM_WRAPVERSION_1_0
  348. #define INVALID_NAMESPACE_INDEX ((UINT)-1)
  349. #define CB_IDLIST_TERMINATOR sizeof(USHORT)
  350. //-------------------------------------------------------------------------//
  351. // Augmented Merge shell folder pidl wrap utilities
  352. //-------------------------------------------------------------------------//
  353. //-------------------------------------------------------------------------//
  354. // Resolves the wrap header from the indicated pidl.
  355. #define AugMergeISF_GetWrap( p ) ((PAUGM_IDWRAP)(p))
  356. //-------------------------------------------------------------------------//
  357. // Determines whether the indicated pidl is an Augmented Merge
  358. // shell folder pidl wrapper.
  359. HRESULT AugMergeISF_IsWrap(
  360. IN LPCITEMIDLIST pidlTest,
  361. IN ULONG nVersion = AUGM_WRAPCURRENTVERSION )
  362. {
  363. ASSERT(IS_VALID_PIDL( pidlTest ));
  364. if (pidlTest)
  365. {
  366. PAUGM_IDWRAP pWrap = AugMergeISF_GetWrap( pidlTest ) ;
  367. return (pWrap->cb >= sizeof(AUGM_IDWRAP) &&
  368. pWrap->tag == AUGM_WRAPTAG &&
  369. pWrap->version == nVersion) ?
  370. S_OK : E_UNEXPECTED ; //BUGBUG: better error code for version mismatch?
  371. }
  372. else
  373. {
  374. return E_INVALIDARG;
  375. }
  376. }
  377. //-------------------------------------------------------------------------//
  378. // Retrieves the number of source namespace pidls in the wrap.
  379. // If the pidl was not wrapped, the return value is -1.
  380. ULONG AugMergeISF_GetSourceCount( IN LPCITEMIDLIST pidl )
  381. {
  382. ASSERT(SUCCEEDED(AugMergeISF_IsWrap(pidl)));
  383. return AugMergeISF_GetWrap(pidl)->cSrcs;
  384. }
  385. //-------------------------------------------------------------------------//
  386. // Creates an IDLIST wrapper object based on the indicated source pidl.
  387. HRESULT AugMergeISF_CreateWrap(
  388. IN LPCITEMIDLIST pidlSrc,
  389. IN UINT nSrcID,
  390. OUT LPITEMIDLIST* ppidlWrap )
  391. {
  392. ASSERT( ppidlWrap ) ;
  393. ASSERT( IS_VALID_PIDL( pidlSrc ) && INVALID_NAMESPACE_INDEX != nSrcID ) ;
  394. *ppidlWrap = NULL ;
  395. // Allocate a header and terminator
  396. LPBYTE pBuf = NULL ;
  397. WORD cbAlloc = sizeof(AUGM_IDWRAP) +
  398. sizeof(AUGM_IDSRC) + pidlSrc->mkid.cb +
  399. // we need two terminators, one for pidlSrc and one for the wrap
  400. // the one for pidlSrc is necessary for the ILClone to work
  401. // because it gets confused with the nSrcID that follows the pidl
  402. CB_IDLIST_TERMINATOR +
  403. CB_IDLIST_TERMINATOR ;
  404. if( NULL == (pBuf = (LPBYTE)IEILCreate( cbAlloc )) )
  405. return E_OUTOFMEMORY ;
  406. // Initialize wrap header members
  407. PAUGM_IDWRAP pWrap = AugMergeISF_GetWrap( pBuf ) ;
  408. pWrap->cb = cbAlloc - CB_IDLIST_TERMINATOR ;
  409. pWrap->tag = AUGM_WRAPTAG ;
  410. pWrap->version = AUGM_WRAPCURRENTVERSION ;
  411. if( pidlSrc )
  412. {
  413. PAUGM_IDSRC pSrc = (PAUGM_IDSRC)(pBuf + sizeof(AUGM_IDWRAP)) ;
  414. pSrc->nID = nSrcID ;
  415. memcpy( pSrc->pidl, pidlSrc, pidlSrc->mkid.cb ) ;
  416. pWrap->cSrcs = 1 ;
  417. }
  418. *ppidlWrap = (LPITEMIDLIST)pWrap ;
  419. return S_OK ;
  420. }
  421. BOOL WrappedPidlContainsSrcID(LPCITEMIDLIST pidlWrap, UINT uSrcID)
  422. {
  423. ASSERT(SUCCEEDED(AugMergeISF_IsWrap(pidlWrap)));
  424. PAUGM_IDWRAP pWrap = AugMergeISF_GetWrap( pidlWrap ) ;
  425. if( pWrap->cSrcs > 0 )
  426. {
  427. LPBYTE p = ((LPBYTE)pWrap) + sizeof(AUGM_IDWRAP) ; // position of first pidl header.
  428. PAUGM_IDSRC pSrc = (PAUGM_IDSRC)p ;
  429. // offset to next pidl header, needs terminator so that ILClone below can work
  430. UINT cbPidl= ((LPITEMIDLIST)pSrc->pidl)->mkid.cb + CB_IDLIST_TERMINATOR;
  431. if (pSrc->nID != uSrcID && pWrap->cSrcs > 1)
  432. {
  433. pSrc = (PAUGM_IDSRC)(p + sizeof(AUGM_IDSRC) + cbPidl) ;
  434. }
  435. if (pSrc->nID == uSrcID)
  436. return TRUE;
  437. }
  438. return FALSE;
  439. }
  440. HRESULT AugMergeISF_WrapRemovePidl(
  441. IN LPITEMIDLIST pidlWrap,
  442. IN UINT nSrcID,
  443. OUT LPITEMIDLIST* ppidlRet )
  444. {
  445. ASSERT( IS_VALID_WRITE_PTR( ppidlRet, LPITEMIDLIST )) ;
  446. *ppidlRet = NULL ;
  447. HRESULT hr = AugMergeISF_IsWrap(pidlWrap);
  448. if (SUCCEEDED(hr))
  449. {
  450. PAUGM_IDWRAP pWrap = AugMergeISF_GetWrap( pidlWrap ) ;
  451. ASSERT(pWrap->cSrcs > 1);
  452. LPBYTE p = ((LPBYTE)pWrap) + sizeof(AUGM_IDWRAP) ; // position of first pidl header.
  453. PAUGM_IDSRC pSrc = (PAUGM_IDSRC)p ;
  454. // offset to next pidl header, needs terminator so that ILClone below can work
  455. UINT cbPidl= ((LPITEMIDLIST)pSrc->pidl)->mkid.cb + CB_IDLIST_TERMINATOR;
  456. // We want to look for the Other SrcID. So we loop while the source id we're removing is
  457. // equal. When it's not equal, we've got the ID.
  458. if (pSrc->nID == nSrcID)
  459. {
  460. pSrc = (PAUGM_IDSRC)(p + sizeof(AUGM_IDSRC) + cbPidl) ;
  461. }
  462. if (pSrc->nID != nSrcID)
  463. {
  464. hr = AugMergeISF_CreateWrap((LPITEMIDLIST)pSrc->pidl, pSrc->nID, ppidlRet);
  465. ILFree(pidlWrap);
  466. }
  467. else
  468. {
  469. hr = E_FAIL;
  470. }
  471. }
  472. return hr;
  473. }
  474. //-------------------------------------------------------------------------//
  475. // Adds a source pidl to the indicated pidl wrap.
  476. HRESULT AugMergeISF_WrapAddPidl(
  477. IN LPCITEMIDLIST pidlSrc,
  478. IN UINT nSrcID,
  479. IN OUT LPITEMIDLIST* ppidlWrap )
  480. {
  481. ASSERT (ppidlWrap && IS_VALID_PIDL( *ppidlWrap ));
  482. ASSERT (IS_VALID_PIDL( pidlSrc ));
  483. ASSERT (INVALID_NAMESPACE_INDEX != nSrcID );
  484. HRESULT hr ;
  485. if (FAILED((hr = AugMergeISF_IsWrap(*ppidlWrap))))
  486. return hr ;
  487. // AHHHHHHHHHHH Rewrite this.
  488. if (WrappedPidlContainsSrcID(*ppidlWrap, nSrcID))
  489. {
  490. if (AugMergeISF_GetSourceCount(*ppidlWrap) > 1)
  491. {
  492. hr = AugMergeISF_WrapRemovePidl((LPITEMIDLIST)*ppidlWrap, nSrcID, ppidlWrap);
  493. }
  494. else
  495. {
  496. ILFree(*ppidlWrap);
  497. return AugMergeISF_CreateWrap(pidlSrc, nSrcID, ppidlWrap);
  498. }
  499. if (FAILED(hr))
  500. {
  501. return hr;
  502. }
  503. }
  504. // Retrieve wrap header
  505. PAUGM_IDWRAP pWrap = (PAUGM_IDWRAP)*ppidlWrap ;
  506. // Reallocate a block large enough to contain our new record.
  507. WORD offTerm0 = pWrap->cb, // offset to end of existing wrap
  508. offTerm1 = offTerm0 + sizeof(AUGM_IDSRC) + pidlSrc->mkid.cb, // offset to end of next record
  509. cbRealloc= offTerm1 + 2*CB_IDLIST_TERMINATOR ; // total bytes to reallocate
  510. LPBYTE pRealloc ;
  511. if( NULL == (pRealloc = (LPBYTE)SHRealloc( pWrap, cbRealloc )) )
  512. return E_OUTOFMEMORY ;
  513. // Adjust our pointers if memory moved
  514. pWrap = (PAUGM_IDWRAP)pRealloc ;
  515. // Initialize new record in the wrap
  516. UNALIGNED AUGM_IDSRC* pSrc = (PAUGM_IDSRC)(pRealloc + offTerm0 ) ;
  517. pSrc->nID = nSrcID ;
  518. memcpy( pSrc->pidl, pidlSrc, pidlSrc->mkid.cb ) ;
  519. // Terminate new record
  520. ZeroMemory( pRealloc + offTerm1, 2*CB_IDLIST_TERMINATOR ) ;
  521. // Update our header
  522. pWrap->cb = cbRealloc - CB_IDLIST_TERMINATOR ;
  523. pWrap->cSrcs++ ;
  524. *ppidlWrap = (LPITEMIDLIST)pWrap ;
  525. return S_OK ;
  526. }
  527. //-------------------------------------------------------------------------//
  528. // Private pidl enumeration block (GetFirst/GetNext)
  529. typedef struct tagAUGM_IDWRAP_ENUM
  530. {
  531. ULONG cbStruct ; // structure size
  532. PAUGM_IDWRAP pWrap ; // wrap header.
  533. PAUGM_IDSRC pSrcNext ; // pointer to next src header
  534. } AUGM_IDWRAP_ENUM, *PAUGM_IDWRAP_ENUM ;
  535. //-------------------------------------------------------------------------//
  536. // Begins enumeration of source pidls in the indicated pidl wrap.
  537. HANDLE AugMergeISF_EnumFirstSrcPidl(
  538. IN LPCITEMIDLIST pidlWrap,
  539. OUT UINT* pnSrcID,
  540. OUT LPITEMIDLIST* ppidlRet )
  541. {
  542. ASSERT( IS_VALID_WRITE_PTR( ppidlRet, LPITEMIDLIST ) && IS_VALID_WRITE_PTR( pnSrcID, UINT ) ) ;
  543. PAUGM_IDWRAP_ENUM pEnum = NULL ;
  544. *ppidlRet = NULL ;
  545. *pnSrcID = (UINT)-1 ;
  546. HRESULT hr = AugMergeISF_IsWrap(pidlWrap);
  547. if(SUCCEEDED(hr))
  548. {
  549. PAUGM_IDWRAP pWrap = AugMergeISF_GetWrap( pidlWrap ) ;
  550. if( pWrap->cSrcs > 0 )
  551. {
  552. LPBYTE p = ((LPBYTE)pWrap) + sizeof(AUGM_IDWRAP) ; // position of first pidl header.
  553. PAUGM_IDSRC pSrc = (PAUGM_IDSRC)p ;
  554. // offset to next pidl header, needs terminator so that ILClone below can work
  555. UINT cbPidl= ((LPITEMIDLIST)pSrc->pidl)->mkid.cb + CB_IDLIST_TERMINATOR;
  556. if( NULL != (pEnum = new AUGM_IDWRAP_ENUM) )
  557. {
  558. pEnum->cbStruct = sizeof(*pEnum) ;
  559. pEnum->pWrap = pWrap ;
  560. pEnum->pSrcNext = (PAUGM_IDSRC)(p + sizeof(AUGM_IDSRC) + cbPidl) ;
  561. *pnSrcID = pSrc->nID ;
  562. *ppidlRet = ILClone( (LPITEMIDLIST)pSrc->pidl ) ;
  563. if ( NULL == *ppidlRet )
  564. {
  565. delete pEnum;
  566. pEnum = NULL;
  567. }
  568. }
  569. }
  570. }
  571. return pEnum ;
  572. }
  573. //-------------------------------------------------------------------------//
  574. // Continues source pidl enumeration
  575. BOOL AugMergeISF_EnumNextSrcPidl(
  576. IN HANDLE hEnum,
  577. OUT UINT* pnSrcID,
  578. OUT LPITEMIDLIST* ppidlRet )
  579. {
  580. PAUGM_IDWRAP_ENUM pEnum = (PAUGM_IDWRAP_ENUM)hEnum ;
  581. HRESULT hr = E_UNEXPECTED ;
  582. ASSERT( IS_VALID_WRITE_PTR( pEnum, AUGM_IDWRAP_ENUM ) ) ;
  583. ASSERT( sizeof(*pEnum) == pEnum->cbStruct ) ;
  584. ASSERT( sizeof(*pEnum) == pEnum->cbStruct );
  585. *ppidlRet = NULL ;
  586. *pnSrcID = (UINT)-1 ;
  587. if (SUCCEEDED((hr = AugMergeISF_IsWrap((LPCITEMIDLIST)pEnum->pWrap))))
  588. {
  589. if ((LPBYTE)(pEnum->pWrap) + pEnum->pWrap->cb <= (LPBYTE)pEnum->pSrcNext)
  590. hr = S_FALSE ;
  591. else
  592. {
  593. UNALIGNED AUGM_IDSRC* pualSrcNext = pEnum->pSrcNext;
  594. *pnSrcID = pualSrcNext->nID;
  595. *ppidlRet = ILClone((LPITEMIDLIST)pualSrcNext->pidl);
  596. pEnum->pSrcNext = (PAUGM_IDSRC)(
  597. ((LPBYTE)pualSrcNext) +
  598. sizeof(AUGM_IDSRC) +
  599. ((LPITEMIDLIST)pualSrcNext->pidl)->mkid.cb +
  600. CB_IDLIST_TERMINATOR);
  601. hr = S_OK ;
  602. return TRUE ;
  603. }
  604. }
  605. return FALSE ;
  606. }
  607. //-------------------------------------------------------------------------//
  608. // Terminates source pidl enumeration
  609. void AugMergeISF_EndEnumSrcPidls(
  610. IN OUT HANDLE& hEnum )
  611. {
  612. PAUGM_IDWRAP_ENUM pEnum = (PAUGM_IDWRAP_ENUM)hEnum ;
  613. ASSERT( IS_VALID_WRITE_PTR( pEnum, AUGM_IDWRAP_ENUM ) &&
  614. sizeof(*pEnum) == pEnum->cbStruct );
  615. delete pEnum ;
  616. hEnum = NULL ;
  617. }
  618. //-------------------------------------------------------------------------//
  619. // Allocates and returns a copy of the specified source pidl
  620. // from the wrapped pidl.
  621. HRESULT AugMergeISF_GetSrcPidl(
  622. IN LPCITEMIDLIST pidlWrap,
  623. IN UINT nSrcID,
  624. OUT LPITEMIDLIST* ppidlRet )
  625. {
  626. ASSERT( ppidlRet ) ;
  627. *ppidlRet = NULL ;
  628. HANDLE hEnum ;
  629. BOOL bEnum ;
  630. UINT nSrcIDEnum ;
  631. LPITEMIDLIST pidlEnum ;
  632. for( hEnum = AugMergeISF_EnumFirstSrcPidl( pidlWrap, &nSrcIDEnum, &pidlEnum ), bEnum = TRUE ;
  633. hEnum && bEnum ;
  634. bEnum = AugMergeISF_EnumNextSrcPidl( hEnum, &nSrcIDEnum, &pidlEnum ) )
  635. {
  636. if( nSrcIDEnum == nSrcID )
  637. {
  638. *ppidlRet = pidlEnum ;
  639. AugMergeISF_EndEnumSrcPidls(hEnum);
  640. return S_OK ;
  641. }
  642. ILFree( pidlEnum ) ;
  643. }
  644. AugMergeISF_EndEnumSrcPidls( hEnum ) ;
  645. return E_FAIL ;
  646. }
  647. #ifdef DEBUG
  648. BOOL IsValidWrappedPidl(LPCITEMIDLIST pidlWrap)
  649. {
  650. BOOL fValid = FALSE;
  651. if (pidlWrap == NULL)
  652. return FALSE;
  653. if (FAILED(AugMergeISF_IsWrap(pidlWrap)))
  654. return FALSE;
  655. HANDLE hEnum ;
  656. UINT nSrcIDEnum ;
  657. LPITEMIDLIST pidlEnum ;
  658. hEnum = AugMergeISF_EnumFirstSrcPidl( pidlWrap, &nSrcIDEnum, &pidlEnum );
  659. do
  660. {
  661. fValid = IS_VALID_PIDL(pidlEnum);
  662. ILFree(pidlEnum);
  663. }
  664. while( fValid && AugMergeISF_EnumNextSrcPidl( hEnum, &nSrcIDEnum, &pidlEnum ));
  665. AugMergeISF_EndEnumSrcPidls( hEnum ) ;
  666. return fValid;
  667. }
  668. #endif
  669. //-------------------------------------------------------------------------//
  670. int AugmEnumCompare(void *pv1, void *pv2, LPARAM lParam)
  671. {
  672. CAugISFEnumItem* paugmEnum1 = (CAugISFEnumItem*)pv1;
  673. CAugISFEnumItem* paugmEnum2 = (CAugISFEnumItem*)pv2;
  674. int iRet = -1;
  675. if (paugmEnum1 && paugmEnum2)
  676. {
  677. // Are these two items of different types?
  678. if (BOOLIFY(paugmEnum1->_rgfAttrib & SFGAO_FOLDER) ^ BOOLIFY(paugmEnum2->_rgfAttrib & SFGAO_FOLDER))
  679. {
  680. // Yes. Then Folders sort before items.
  681. iRet = BOOLIFY(paugmEnum1->_rgfAttrib & SFGAO_FOLDER) ? 1 : -1;
  682. }
  683. else // They are of the same type. Then compare by name
  684. {
  685. iRet = lstrcmpi(paugmEnum1->_pszDisplayName, paugmEnum2->_pszDisplayName);
  686. }
  687. }
  688. return iRet;
  689. }
  690. LPVOID AugmEnumMerge(UINT uMsg, void * pv1, void * pv2, LPARAM lParam)
  691. {
  692. void * pvRet = pv1;
  693. switch (uMsg)
  694. {
  695. case DPAMM_MERGE:
  696. {
  697. HANDLE hEnum;
  698. UINT nSrcID;
  699. LPITEMIDLIST pidl;
  700. CAugISFEnumItem* paugmeDest = (CAugISFEnumItem*)pv1;
  701. CAugISFEnumItem* paugmeSrc = (CAugISFEnumItem*)pv2;
  702. ASSERT(paugmeDest && paugmeSrc);
  703. hEnum = AugMergeISF_EnumFirstSrcPidl(paugmeSrc->_pidlWrap, &nSrcID, &pidl);
  704. if (hEnum)
  705. {
  706. // add pidl from src to dest
  707. AugMergeISF_WrapAddPidl(pidl, nSrcID, &paugmeDest->_pidlWrap);
  708. // no longer need hEnum
  709. AugMergeISF_EndEnumSrcPidls(hEnum);
  710. // this was copied to paugmeDest->_pidlWrap
  711. ILFree(pidl);
  712. }
  713. }
  714. break;
  715. case DPAMM_INSERT:
  716. {
  717. CAugISFEnumItem* paugmNew = new CAugISFEnumItem;
  718. CAugISFEnumItem* paugmSrc = (CAugISFEnumItem*)pv1;
  719. if (paugmNew)
  720. {
  721. paugmNew->_pidlWrap = ILClone(paugmSrc->_pidlWrap);
  722. if (paugmNew->_pidlWrap)
  723. {
  724. paugmNew->SetDisplayName(paugmSrc->_pszDisplayName);
  725. paugmNew->_rgfAttrib = paugmSrc->_rgfAttrib;
  726. }
  727. else
  728. {
  729. delete paugmNew;
  730. paugmNew = NULL;
  731. }
  732. }
  733. pvRet = paugmNew;
  734. }
  735. break;
  736. default:
  737. ASSERT(0);
  738. }
  739. return pvRet;
  740. }
  741. typedef struct
  742. {
  743. LPTSTR pszDisplayName;
  744. BOOL fFolder;
  745. } AUGMISFSEARCHFORPIDL;
  746. int CALLBACK AugMISFSearchForOnePidlByDisplayName(LPVOID p1, LPVOID p2, LPARAM lParam)
  747. {
  748. AUGMISFSEARCHFORPIDL* pSearchFor = (AUGMISFSEARCHFORPIDL*)p1;
  749. CAugISFEnumItem* paugmEnum = (CAugISFEnumItem*)p2;
  750. // Are they of different types?
  751. if (BOOLIFY(paugmEnum->_rgfAttrib & SFGAO_FOLDER) ^ pSearchFor->fFolder)
  752. {
  753. // Yes.
  754. return pSearchFor->fFolder ? 1 : -1;
  755. }
  756. else // They are of the same type. Then compare by name
  757. {
  758. return StrCmpI(pSearchFor->pszDisplayName, paugmEnum->_pszDisplayName);
  759. }
  760. }
  761. //-------------------------------------------------------------------------------------------------//
  762. // DPA utilities
  763. #define DPA_GETPTRCOUNT( hdpa ) ((NULL != (hdpa)) ? DPA_GetPtrCount((hdpa)) : 0)
  764. #define DPA_GETPTR( hdpa, i, type ) ((NULL != (hdpa)) ? (type*)DPA_GetPtr((hdpa), i) : (type*)NULL)
  765. #define DPA_DESTROY( hdpa, pfn ) { if( NULL != hdpa ) \
  766. { DPA_DestroyCallback( hdpa, pfn, NULL ) ; \
  767. hdpa = NULL ; }}
  768. //-------------------------------------------------------------------------------------------------//
  769. // Forwards...
  770. class CEnum ;
  771. class CChildObject ;
  772. //-------------------------------------------------------------------------------------------------//
  773. // Augmented Merge Shell Folder source namespace descriptor.
  774. //
  775. // Objects of class CNamespace are created by CAugmentedMergeISF in
  776. // the AddNameSpace() method impl, and are maintained in the collection
  777. // CAugmentedMergeISF::_hdpaNamespaces.
  778. //
  779. class CNamespace
  780. //-------------------------------------------------------------------------------------------------//
  781. {
  782. public:
  783. CNamespace( const GUID * pguidUIObject, IShellFolder* psf, LPCITEMIDLIST pidl, ULONG dwAttrib ) ;
  784. ~CNamespace() ;
  785. IShellFolder* ShellFolder() { return _psf ; }
  786. REFGUID Guid() { return _guid ; }
  787. ULONG Attrib() const { return _dwAttrib ; }
  788. LPITEMIDLIST GetPidl() const { return _pidl; }
  789. void Assign( const GUID * pguidUIObject, IShellFolder* psf, LPCITEMIDLIST pidl, ULONG dwAttrib ) ;
  790. void Unassign() ;
  791. HRESULT RegisterNotify( HWND, UINT, ULONG ) ;
  792. HRESULT UnregisterNotify() ;
  793. BOOL SetOwner( IUnknown *punk ) ;
  794. protected:
  795. IShellFolder* _psf ; // IShellFolder interface pointer
  796. GUID _guid ; // optional GUID for specialized UI handling
  797. LPITEMIDLIST _pidl ; // optional pidl
  798. ULONG _dwAttrib ; // optional flags
  799. UINT _uChangeReg ; // Shell change notify registration ID.
  800. } ;
  801. //-------------------------------------------------------------------------------------------------//
  802. inline CNamespace::CNamespace( const GUID * pguidUIObject, IShellFolder* psf, LPCITEMIDLIST pidl, ULONG dwAttrib )
  803. : _psf(NULL),
  804. _pidl(NULL),
  805. _guid(GUID_NULL),
  806. _dwAttrib(0),
  807. _uChangeReg(0)
  808. {
  809. Assign( pguidUIObject, psf, pidl, dwAttrib ) ;
  810. }
  811. //-------------------------------------------------------------------------------------------------//
  812. inline CNamespace::~CNamespace() {
  813. UnregisterNotify() ;
  814. Unassign() ;
  815. }
  816. //-------------------------------------------------------------------------------------------------//
  817. // Assigns data members.
  818. void CNamespace::Assign( const GUID * pguidUIObject, IShellFolder* psf, LPCITEMIDLIST pidl, ULONG dwAttrib )
  819. {
  820. Unassign() ;
  821. if( NULL != (_psf = psf) )
  822. _psf->AddRef() ;
  823. _pidl = ILClone( pidl ) ;
  824. _guid = pguidUIObject ? *pguidUIObject : GUID_NULL ;
  825. _dwAttrib = dwAttrib ;
  826. }
  827. //-------------------------------------------------------------------------------------------------//
  828. // Unassigns data members.
  829. void CNamespace::Unassign()
  830. {
  831. ATOMICRELEASE( _psf ) ;
  832. ILFree( _pidl ) ;
  833. _pidl = NULL ;
  834. _guid = GUID_NULL ;
  835. _dwAttrib = 0L ;
  836. }
  837. //-------------------------------------------------------------------------------------------------//
  838. // Register change notification for the namespace
  839. HRESULT CNamespace::RegisterNotify( HWND hwnd, UINT uMsg, ULONG lEvents )
  840. {
  841. if( 0 == _uChangeReg )
  842. _uChangeReg = ::RegisterNotify(hwnd,
  843. uMsg,
  844. _pidl,
  845. lEvents,
  846. SHCNRF_ShellLevel | SHCNRF_InterruptLevel | SHCNRF_RecursiveInterrupt,
  847. TRUE);
  848. return 0 != _uChangeReg ? S_OK : E_FAIL ;
  849. }
  850. //-------------------------------------------------------------------------------------------------//
  851. // Unregister change notification for the namespace
  852. HRESULT CNamespace::UnregisterNotify()
  853. {
  854. if( 0 != _uChangeReg )
  855. {
  856. UINT uID = _uChangeReg;
  857. _uChangeReg = 0;
  858. ::SHChangeNotifyDeregister(uID);
  859. }
  860. return S_OK;
  861. }
  862. //-------------------------------------------------------------------------------------------------//
  863. inline BOOL CNamespace::SetOwner(IUnknown *punkOwner)
  864. {
  865. if (_psf)
  866. {
  867. IUnknown_SetOwner(_psf, punkOwner);
  868. return TRUE ;
  869. }
  870. return FALSE ;
  871. }
  872. //-------------------------------------------------------------------------//
  873. CAugmentedMergeISF::CAugmentedMergeISF() : _cRef(1)
  874. {
  875. ASSERT(_hdpaNamespaces == NULL);
  876. ASSERT(_punkOwner == NULL);
  877. ASSERT(_pdt == NULL);
  878. DllAddRef() ;
  879. }
  880. //-------------------------------------------------------------------------//
  881. CAugmentedMergeISF::~CAugmentedMergeISF()
  882. {
  883. SetOwner(NULL);
  884. FreeNamespaces();
  885. DllRelease();
  886. }
  887. //-------------------------------------------------------------------------//
  888. // CAugmentedMergeISF global CreateInstance method for da class factory
  889. //-------------------------------------------------------------------------//
  890. STDAPI CAugmentedISF2_CreateInstance( IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi )
  891. {
  892. // aggregation checking is handled in class factory
  893. CAugmentedMergeISF* pObj;
  894. if( NULL == (pObj = new CAugmentedMergeISF) )
  895. return E_OUTOFMEMORY ;
  896. *ppunk = SAFECAST( pObj, IAugmentedShellFolder2 * ) ;
  897. return S_OK;
  898. }
  899. //-------------------------------------------------------------------------//
  900. // CAugmentedMergeISF - IUnknown methods
  901. //-------------------------------------------------------------------------//
  902. //-------------------------------------------------------------------------//
  903. STDMETHODIMP CAugmentedMergeISF::QueryInterface(REFIID riid, void **ppvObj)
  904. {
  905. static const QITAB qit[] = {
  906. QITABENTMULTI( CAugmentedMergeISF, IShellFolder, IAugmentedShellFolder ),
  907. QITABENT( CAugmentedMergeISF, IAugmentedShellFolder ),
  908. QITABENT( CAugmentedMergeISF, IAugmentedShellFolder2 ),
  909. QITABENT( CAugmentedMergeISF, IShellFolder2 ),
  910. QITABENT( CAugmentedMergeISF, IShellService ),
  911. QITABENT( CAugmentedMergeISF, ITranslateShellChangeNotify ),
  912. QITABENT( CAugmentedMergeISF, IDropTarget ),
  913. { 0 },
  914. };
  915. return QISearch( this, qit, riid, ppvObj ) ;
  916. }
  917. //-------------------------------------------------------------------------//
  918. STDMETHODIMP_(ULONG) CAugmentedMergeISF::AddRef()
  919. {
  920. return InterlockedIncrement(&_cRef);
  921. }
  922. //-------------------------------------------------------------------------//
  923. STDMETHODIMP_(ULONG) CAugmentedMergeISF::Release()
  924. {
  925. ASSERT( 0 != _cRef );
  926. ULONG cRef = InterlockedDecrement(&_cRef);
  927. if ( 0 == cRef )
  928. {
  929. delete this;
  930. }
  931. return cRef;
  932. }
  933. //-------------------------------------------------------------------------//
  934. // CAugmentedMergeISF - IShellFolder methods
  935. //-------------------------------------------------------------------------//
  936. //-------------------------------------------------------------------------//
  937. STDMETHODIMP CAugmentedMergeISF::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
  938. {
  939. HRESULT hr = E_FAIL;
  940. if (_hdpaNamespaces)
  941. {
  942. // BUGBUG (lamadio): This does not work if you have 2 enumerators. But,
  943. // when asking for a new enumerator, we should flush the cache.
  944. FreeObjects();
  945. *ppenumIDList = new CEnum(this, grfFlags);
  946. if (NULL == *ppenumIDList)
  947. return E_OUTOFMEMORY ;
  948. hr = S_OK ;
  949. }
  950. return hr;
  951. }
  952. //-------------------------------------------------------------------------//
  953. STDMETHODIMP CAugmentedMergeISF::BindToObject( LPCITEMIDLIST pidlWrap, LPBC pbc, REFIID riid, LPVOID *ppvOut )
  954. {
  955. ASSERT(IS_VALID_PIDL( pidlWrap ) && NULL != ppvOut);
  956. *ppvOut = NULL ;
  957. if (SUCCEEDED(AugMergeISF_IsWrap(pidlWrap)))
  958. {
  959. PAUGM_IDWRAP pWrap = AugMergeISF_GetWrap( pidlWrap ) ;
  960. ASSERT(IsValidWrappedPidl(pidlWrap));
  961. ASSERT( pWrap ) ;
  962. ASSERT( pWrap->cSrcs > 0 ) ; // should never, never happen
  963. HANDLE hEnum ;
  964. BOOL bEnum ;
  965. UINT nIDSrc = -1 ;
  966. DEBUG_CODE(int iNumBound = 0);
  967. LPITEMIDLIST pidlSrc ;
  968. HRESULT hr = E_UNEXPECTED ;
  969. CNamespace* pSrc = NULL ;
  970. CAugmentedMergeISF* pISF ;
  971. if (NULL == (pISF = new CAugmentedMergeISF))
  972. return E_OUTOFMEMORY ;
  973. for (hEnum = AugMergeISF_EnumFirstSrcPidl( pidlWrap, &nIDSrc, &pidlSrc ), bEnum = TRUE ;
  974. hEnum && bEnum ;
  975. bEnum = AugMergeISF_EnumNextSrcPidl( hEnum, &nIDSrc, &pidlSrc))
  976. {
  977. if (SUCCEEDED((hr = QueryNameSpace(nIDSrc, (PVOID*)&pSrc))) && pSrc)
  978. {
  979. IShellFolder *psf;
  980. hr = S_FALSE;
  981. if (SUCCEEDED(pSrc->ShellFolder()->BindToObject(pidlSrc, NULL, IID_IShellFolder, (void **)&psf)))
  982. {
  983. LPCITEMIDLIST pidlParent = pSrc->GetPidl();
  984. LPITEMIDLIST pidlFull = ILCombine(pidlParent, pidlSrc);
  985. hr = pISF->AddNameSpace(NULL, psf, pidlFull, pSrc->Attrib());
  986. #ifdef DEBUG
  987. if (SUCCEEDED(hr))
  988. iNumBound++;
  989. #endif
  990. ILFree(pidlFull);
  991. psf->Release();
  992. }
  993. ASSERT(SUCCEEDED(hr));
  994. }
  995. ILFree(pidlSrc);
  996. }
  997. // If this hits, then something is terribly wrong. Either we were unable to bind to the
  998. // ShellFolders, or the add failed. This could be caused by a bad wrapped pidl.
  999. ASSERT(iNumBound > 0);
  1000. AugMergeISF_EndEnumSrcPidls( hEnum ) ;
  1001. hr = pISF->QueryInterface(riid, ppvOut);
  1002. pISF->Release();
  1003. return hr ;
  1004. }
  1005. return E_UNEXPECTED ;
  1006. }
  1007. //-------------------------------------------------------------------------//
  1008. STDMETHODIMP CAugmentedMergeISF::BindToStorage( LPCITEMIDLIST, LPBC, REFIID, void ** )
  1009. {
  1010. return E_NOTIMPL ;
  1011. }
  1012. //-------------------------------------------------------------------------//
  1013. STDMETHODIMP CAugmentedMergeISF::CompareIDs(
  1014. LPARAM lParam,
  1015. LPCITEMIDLIST pidl1,
  1016. LPCITEMIDLIST pidl2)
  1017. {
  1018. IShellFolder *psf1 = NULL, *psf2 = NULL;
  1019. LPITEMIDLIST pidlItem1 = NULL, pidlItem2 = NULL;
  1020. int iRet = 0 ;
  1021. HRESULT hr1, hr2, hr ;
  1022. hr1 = GetDefNamespace( pidl1, ASFF_DEFNAMESPACE_DISPLAYNAME, &psf1, &pidlItem1 ) ;
  1023. hr2 = GetDefNamespace( pidl2, ASFF_DEFNAMESPACE_DISPLAYNAME, &psf2, &pidlItem2 ) ;
  1024. if( SUCCEEDED( hr1 ) && SUCCEEDED( hr2 ) )
  1025. {
  1026. ULONG dwAttrib1 = SFGAO_FOLDER, dwAttrib2 = SFGAO_FOLDER;
  1027. // Same namespace? Just forward the request.
  1028. if( psf1 == psf2 )
  1029. {
  1030. hr = psf1->CompareIDs( lParam, pidlItem1, pidlItem2 ) ;
  1031. ILFree( pidlItem1 ) ;
  1032. ILFree( pidlItem2 ) ;
  1033. return hr ;
  1034. }
  1035. hr1 = psf1->GetAttributesOf( 1, (LPCITEMIDLIST*)&pidlItem1, &dwAttrib1 ) ;
  1036. hr2 = psf2->GetAttributesOf( 1, (LPCITEMIDLIST*)&pidlItem2, &dwAttrib2 ) ;
  1037. if( SUCCEEDED( hr1 ) && SUCCEEDED( hr2 ) )
  1038. {
  1039. // Comparison heuristics:
  1040. // (1) folders take precedence over nonfolders, (2) alphanum comparison
  1041. if( 0 != (dwAttrib1 & SFGAO_FOLDER) &&
  1042. 0 == (dwAttrib2 & SFGAO_FOLDER) )
  1043. iRet = -1 ;
  1044. else if( 0 == (dwAttrib1 & SFGAO_FOLDER) &&
  1045. 0 != (dwAttrib2 & SFGAO_FOLDER) )
  1046. iRet = 1 ;
  1047. else
  1048. {
  1049. STRRET strName1, strName2;
  1050. HRESULT hres1 = E_FAIL;
  1051. HRESULT hres2 = E_FAIL;
  1052. TCHAR szName1[MAX_PATH], szName2[MAX_PATH];
  1053. hr1 = psf1->GetDisplayNameOf(pidlItem1, SHGDN_FORPARSING | SHGDN_INFOLDER, &strName1);
  1054. hr2 = psf2->GetDisplayNameOf(pidlItem2, SHGDN_FORPARSING | SHGDN_INFOLDER, &strName2);
  1055. if (SUCCEEDED(hr1) && SUCCEEDED(hr2))
  1056. {
  1057. // must call StrRetToBuf because it frees StrRet strings if allocated
  1058. hres1 = StrRetToBuf(&strName1, pidlItem1, szName1, ARRAYSIZE(szName1));
  1059. hres2 = StrRetToBuf(&strName2, pidlItem2, szName2, ARRAYSIZE(szName2));
  1060. }
  1061. // if the names match we return -1 because they are different pidls with
  1062. // the same name
  1063. if (SUCCEEDED(hr1) && SUCCEEDED(hr2) && SUCCEEDED(hres1) && SUCCEEDED(hres2))
  1064. {
  1065. iRet = lstrcmp(szName1, szName2); // Comparisons are by name with items of the same type.
  1066. }
  1067. }
  1068. }
  1069. }
  1070. hr = FAILED( hr1 ) ? hr1 :
  1071. FAILED( hr2 ) ? hr2 :
  1072. S_OK ;
  1073. if( pidlItem1 )
  1074. ILFree( pidlItem1 ) ;
  1075. if( pidlItem2 )
  1076. ILFree( pidlItem2 ) ;
  1077. return MAKE_HRESULT( HRESULT_SEVERITY( hr ), HRESULT_FACILITY( hr ), iRet ) ;
  1078. }
  1079. //-------------------------------------------------------------------------//
  1080. STDMETHODIMP CAugmentedMergeISF::CreateViewObject(
  1081. HWND hwndOwner,
  1082. REFIID riid,
  1083. LPVOID * ppvOut )
  1084. {
  1085. HRESULT hr ;
  1086. CNamespace *pSrc, *pSrc0 ;
  1087. pSrc = pSrc0 = NULL ;
  1088. // TODO: Handle IDropTarget here, delegate for all others.
  1089. if (IsEqualIID(riid, IID_IDropTarget))
  1090. {
  1091. hr = QueryInterface(riid, ppvOut);
  1092. if (SUCCEEDED(hr))
  1093. _hwnd = hwndOwner;
  1094. return hr;
  1095. }
  1096. // Search for default namespace for CreateViewObj()
  1097. if( FAILED( (hr = GetDefNamespace( ASFF_DEFNAMESPACE_VIEWOBJ, (PVOID*)&pSrc, NULL, (PVOID*)&pSrc0 )) ) )
  1098. return hr ;
  1099. if( NULL == pSrc )
  1100. pSrc = pSrc0 ;
  1101. if( NULL != pSrc )
  1102. {
  1103. ASSERT( pSrc->ShellFolder() ) ;
  1104. hr = pSrc->ShellFolder()->CreateViewObject( hwndOwner, riid, ppvOut ) ;
  1105. }
  1106. return hr ;
  1107. }
  1108. //-------------------------------------------------------------------------//
  1109. STDMETHODIMP CAugmentedMergeISF::GetAttributesOf(
  1110. UINT cidl,
  1111. LPCITEMIDLIST * apidl,
  1112. ULONG * rgfInOut )
  1113. {
  1114. IShellFolder* pISF ;
  1115. LPITEMIDLIST pidlItem ;
  1116. HRESULT hr ;
  1117. if( cidl > 1 ) // support 1 only.
  1118. return E_NOTIMPL ;
  1119. if( !apidl )
  1120. return E_INVALIDARG ;
  1121. // Forward to default namespace for item attributes
  1122. if( FAILED( (hr = GetDefNamespace(
  1123. apidl[0], ASFF_DEFNAMESPACE_ATTRIB, &pISF, &pidlItem )) ) )
  1124. return hr ;
  1125. hr = pISF->GetAttributesOf( 1, (LPCITEMIDLIST*)&pidlItem, rgfInOut ) ;
  1126. ILFree( pidlItem ) ;
  1127. return hr ;
  1128. }
  1129. //-------------------------------------------------------------------------//
  1130. STDMETHODIMP CAugmentedMergeISF::GetUIObjectOf(
  1131. HWND hwndOwner,
  1132. UINT cidl,
  1133. LPCITEMIDLIST * apidl,
  1134. REFIID riid,
  1135. UINT * prgfInOut,
  1136. LPVOID * ppvOut )
  1137. {
  1138. IShellFolder* pISF ;
  1139. LPITEMIDLIST pidlItem ;
  1140. HRESULT hr ;
  1141. if (cidl > 1) // support 1 only.
  1142. return E_NOTIMPL ;
  1143. if (!apidl)
  1144. return E_INVALIDARG ;
  1145. if (IsEqualGUID(riid, IID_IContextMenu))
  1146. {
  1147. hr = _GetContextMenu(hwndOwner, cidl, apidl, prgfInOut, ppvOut);
  1148. }
  1149. else
  1150. {
  1151. // Forward to default namespace for UI object
  1152. if (FAILED((hr = GetDefNamespace(apidl[0], ASFF_DEFNAMESPACE_UIOBJ, &pISF, &pidlItem))))
  1153. return hr ;
  1154. hr = pISF->GetUIObjectOf(hwndOwner, 1, (LPCITEMIDLIST*)&pidlItem, riid, prgfInOut, ppvOut);
  1155. ILFree(pidlItem);
  1156. }
  1157. return hr ;
  1158. }
  1159. //-------------------------------------------------------------------------//
  1160. STDMETHODIMP CAugmentedMergeISF::GetDisplayNameOf(
  1161. LPCITEMIDLIST pidl,
  1162. DWORD grfFlags,
  1163. LPSTRRET pstrName )
  1164. {
  1165. IShellFolder* pISF ;
  1166. LPITEMIDLIST pidlItem ;
  1167. HRESULT hr ;
  1168. // Forward to default namespace for display name
  1169. if (FAILED((hr = GetDefNamespace(
  1170. pidl, ASFF_DEFNAMESPACE_DISPLAYNAME, &pISF, &pidlItem))))
  1171. return hr ;
  1172. if (SUCCEEDED((hr = pISF->GetDisplayNameOf(pidlItem, grfFlags, pstrName))))
  1173. {
  1174. // STRRET_OFFSET has no meaning in context of the pidl wrapper.
  1175. // We can either calculate the offset into the wrapper, or allocate
  1176. // a wide char for the name. For expedience, we'll allocate the name.
  1177. if (pstrName->uType == STRRET_OFFSET)
  1178. {
  1179. UINT cch = lstrlenA( STRRET_OFFPTR( pidlItem, pstrName ) ) ;
  1180. LPWSTR pwszName = (LPWSTR)SHAlloc( (cch + 1) * sizeof(WCHAR));
  1181. if (NULL != pwszName)
  1182. {
  1183. SHAnsiToUnicode( STRRET_OFFPTR( pidlItem, pstrName ), pwszName, cch+1 );
  1184. pwszName[cch] = (WCHAR)0 ;
  1185. }
  1186. pstrName->pOleStr = pwszName ;
  1187. pstrName->uType = STRRET_WSTR ;
  1188. }
  1189. #ifdef DEBUG
  1190. // If the trace flags are set, and this is not comming from an internal query,
  1191. // Then append the location where this name came from
  1192. if (g_qwTraceFlags & TF_AUGM && _fInternalGDNO == FALSE)
  1193. {
  1194. if (pstrName->uType == STRRET_WSTR)
  1195. {
  1196. LPWSTR wszOldName = pstrName->pOleStr;
  1197. UINT cch = lstrlenW(wszOldName);
  1198. UINT cchWithExtra = cch + 50;
  1199. pstrName->pOleStr = (LPWSTR)SHAlloc( cchWithExtra * sizeof(WCHAR));
  1200. if (pstrName->pOleStr)
  1201. {
  1202. StringCchCopyW(pstrName->pOleStr, cchWithExtra, wszOldName);
  1203. if (AugMergeISF_GetSourceCount(pidl) > 1)
  1204. StringCchCatW(pstrName->pOleStr, cchWithExtra, L" (Merged)");
  1205. else if (WrappedPidlContainsSrcID(pidl, 0))
  1206. StringCchCatW(pstrName->pOleStr, cchWithExtra, L" (1)");
  1207. else
  1208. StringCchCatW(pstrName->pOleStr, cchWithExtra, L" (2)");
  1209. SHFree(wszOldName);
  1210. }
  1211. else
  1212. {
  1213. pstrName->pOleStr = wszOldName;
  1214. }
  1215. }
  1216. else if (pstrName->uType == STRRET_CSTR)
  1217. {
  1218. if (AugMergeISF_GetSourceCount(pidl) > 1)
  1219. StringCchCatA(pstrName->cStr, ARRAYSIZE(pstrName->cStr), " (Merged)");
  1220. else if (WrappedPidlContainsSrcID(pidl, 0))
  1221. StringCchCatA(pstrName->cStr, ARRAYSIZE(pstrName->cStr), " (1)");
  1222. else
  1223. StringCchCatA(pstrName->cStr, ARRAYSIZE(pstrName->cStr), " (2)");
  1224. }
  1225. }
  1226. #endif
  1227. }
  1228. ILFree( pidlItem ) ;
  1229. return hr ;
  1230. }
  1231. //-------------------------------------------------------------------------//
  1232. STDMETHODIMP CAugmentedMergeISF::ParseDisplayName(
  1233. HWND hwndOwner,
  1234. LPBC pbcReserved,
  1235. LPOLESTR pwszName,
  1236. ULONG * pchEaten,
  1237. LPITEMIDLIST * ppidl,
  1238. ULONG * pdwAttrib )
  1239. {
  1240. int iIndex;
  1241. LPITEMIDLIST pidl;
  1242. *ppidl = NULL;
  1243. // This ParseDisplayName should iterate through all our delegates until one works.
  1244. for (iIndex = NamespaceCount() - 1; iIndex >=0 ; iIndex--)
  1245. {
  1246. CNamespace* pSrc = Namespace(iIndex) ;
  1247. if (pSrc)
  1248. {
  1249. if (SUCCEEDED(pSrc->ShellFolder()->ParseDisplayName(hwndOwner, pbcReserved, pwszName, pchEaten,
  1250. &pidl, pdwAttrib)))
  1251. {
  1252. ASSERT(pidl); // Make sure a valid pidl comes out.
  1253. if (*ppidl == NULL)
  1254. AugMergeISF_CreateWrap(pidl, iIndex, ppidl);
  1255. else
  1256. AugMergeISF_WrapAddPidl(pidl, iIndex, ppidl);
  1257. ILFree(pidl);
  1258. }
  1259. }
  1260. }
  1261. return *ppidl? S_OK : E_FAIL;
  1262. }
  1263. //-------------------------------------------------------------------------//
  1264. STDMETHODIMP CAugmentedMergeISF::SetNameOf(
  1265. HWND hwndOwner,
  1266. LPCITEMIDLIST pidl,
  1267. LPCOLESTR pwszName,
  1268. DWORD uFlags,
  1269. LPITEMIDLIST *ppidlOut )
  1270. {
  1271. CNamespace* pnsCommon;
  1272. CNamespace* pnsUser;
  1273. LPITEMIDLIST pidlItem;
  1274. HRESULT hres;
  1275. UINT uiUser;
  1276. UINT uiCommon;
  1277. hres = _GetNamespaces(pidl, &pnsCommon, &uiCommon, &pnsUser, &uiUser, &pidlItem, NULL);
  1278. if (SUCCEEDED(hres))
  1279. {
  1280. LPITEMIDLIST pidlNew = NULL;
  1281. UINT uiNamespace = INVALID_NAMESPACE_INDEX;
  1282. if (pnsUser)
  1283. {
  1284. hres = pnsUser->ShellFolder()->SetNameOf(hwndOwner, pidlItem, pwszName, uFlags, &pidlNew);
  1285. uiNamespace = uiUser;
  1286. }
  1287. else if (pnsCommon)
  1288. {
  1289. hres = E_FAIL;
  1290. if (AffectAllUsers(hwndOwner))
  1291. {
  1292. hres = pnsCommon->ShellFolder()->SetNameOf(hwndOwner, pidlItem, pwszName, uFlags, &pidlNew);
  1293. uiNamespace = uiCommon;
  1294. }
  1295. }
  1296. if (ppidlOut)
  1297. {
  1298. *ppidlOut = NULL;
  1299. // wrap the pidl
  1300. if (SUCCEEDED(hres) && pidlNew)
  1301. AugMergeISF_CreateWrap(pidlNew, uiNamespace, ppidlOut);
  1302. }
  1303. ILFree(pidlNew);
  1304. ILFree(pidlItem);
  1305. }
  1306. return hres;
  1307. }
  1308. //-------------------------------------------------------------------------//
  1309. // IAugmentedShellFolder methods
  1310. //-------------------------------------------------------------------------//
  1311. //-------------------------------------------------------------------------//
  1312. // Adds a source namespace to the Augmented Merge shell folder object.
  1313. STDMETHODIMP CAugmentedMergeISF::AddNameSpace(
  1314. const GUID * pguidObject,
  1315. IShellFolder * psf,
  1316. LPCITEMIDLIST pidl,
  1317. DWORD dwFlags )
  1318. {
  1319. ASSERT (IS_VALID_CODE_PTR(psf, IShellFolder*));
  1320. ASSERT (IS_VALID_PIDL(pidl));
  1321. // Check for duplicate via full display name
  1322. for( int i=0, max = NamespaceCount() ; i < max; i++ )
  1323. {
  1324. CNamespace* pSrc = Namespace( i ) ;
  1325. if (pSrc)
  1326. {
  1327. if (ILIsEqual(pSrc->GetPidl(), pidl))
  1328. {
  1329. // Found! Reassign attributes
  1330. pSrc->Assign( pguidObject, psf, pidl, dwFlags ) ;
  1331. return S_OK ;
  1332. }
  1333. }
  1334. }
  1335. // No match; safe to append it to collection, creating DPA if necessary.
  1336. if( NULL == _hdpaNamespaces &&
  1337. NULL == (_hdpaNamespaces= DPA_Create( 2 )) )
  1338. return E_OUTOFMEMORY ;
  1339. CNamespace *pSrc = new CNamespace( pguidObject, psf, pidl, dwFlags );
  1340. if( NULL == pSrc )
  1341. return E_OUTOFMEMORY ;
  1342. return DPA_AppendPtr( _hdpaNamespaces, pSrc ) >= 0 ? S_OK : E_FAIL;
  1343. }
  1344. //-------------------------------------------------------------------------//
  1345. // Retrieves the primary namespace iid for the wrapped pidl.
  1346. STDMETHODIMP CAugmentedMergeISF::GetNameSpaceID(
  1347. LPCITEMIDLIST pidl,
  1348. GUID * pguidOut )
  1349. {
  1350. HRESULT hr ;
  1351. if (FAILED((hr = AugMergeISF_IsWrap( pidl ))))
  1352. return hr ;
  1353. // BUGBUG: need to enumerate wrapped source pidls
  1354. return E_NOTIMPL ;
  1355. }
  1356. //-------------------------------------------------------------------------//
  1357. // Retrieves a pointer to a source namespace descriptor associated with
  1358. // the specified lookup index.
  1359. STDMETHODIMP CAugmentedMergeISF::QueryNameSpace( ULONG nID, PVOID* ppSrc )
  1360. {
  1361. if (!ppSrc)
  1362. return E_INVALIDARG;
  1363. *ppSrc = NULL;
  1364. LONG cSrcs;
  1365. if ((cSrcs = NamespaceCount()) <=0)
  1366. return E_FAIL;
  1367. if(nID >= (ULONG)cSrcs)
  1368. return E_INVALIDARG;
  1369. if (NULL == (*ppSrc = Namespace(nID)))
  1370. return E_UNEXPECTED;
  1371. return S_OK;
  1372. }
  1373. //-------------------------------------------------------------------------//
  1374. // Retrieves data for the namespace identified by dwID.
  1375. STDMETHODIMP CAugmentedMergeISF::QueryNameSpace(
  1376. ULONG nID,
  1377. GUID * pguidOut,
  1378. IShellFolder ** ppsf )
  1379. {
  1380. CNamespace* pSrc = NULL ;
  1381. HRESULT hr = QueryNameSpace( nID, (PVOID*)&pSrc ) ;
  1382. if( pguidOut )
  1383. *pguidOut = NULL != pSrc ? pSrc->Guid() : GUID_NULL ;
  1384. if( ppsf )
  1385. {
  1386. if( (*ppsf = (NULL != pSrc) ? pSrc->ShellFolder() : NULL) != NULL )
  1387. (*ppsf)->AddRef() ;
  1388. }
  1389. return hr ;
  1390. }
  1391. //-------------------------------------------------------------------------//
  1392. STDMETHODIMP CAugmentedMergeISF::EnumNameSpace(
  1393. DWORD uNameSpace,
  1394. DWORD * pdwID )
  1395. {
  1396. return E_NOTIMPL ;
  1397. }
  1398. //-------------------------------------------------------------------------//
  1399. // IAugmentedShellFolder2 methods
  1400. //-------------------------------------------------------------------------//
  1401. //GetNameSpaceCount and GetIDListWrapCount are not used anywhere
  1402. #if 0
  1403. //-------------------------------------------------------------------------//
  1404. STDMETHODIMP CAugmentedMergeISF::GetNameSpaceCount( OUT LONG* pcNamespaces )
  1405. {
  1406. if( !pcNamespaces )
  1407. return E_INVALIDARG ;
  1408. *pcNamespaces = (LONG)NamespaceCount() ;
  1409. return S_OK ;
  1410. }
  1411. //-------------------------------------------------------------------------//
  1412. STDMETHODIMP CAugmentedMergeISF::GetIDListWrapCount(
  1413. LPCITEMIDLIST pidlWrap,
  1414. OUT LONG * pcPidls)
  1415. {
  1416. if( NULL == pidlWrap || NULL == pcPidls )
  1417. return E_INVALIDARG ;
  1418. *pcPidls = 0 ;
  1419. HRESULT hr ;
  1420. if (SUCCEEDED((hr = AugMergeISF_IsWrap(pidlWrap))))
  1421. {
  1422. PAUGM_IDWRAP pWrap = AugMergeISF_GetWrap(pidlWrap);
  1423. *pcPidls = pWrap->cSrcs;
  1424. hr = S_OK;
  1425. }
  1426. return hr;
  1427. }
  1428. #endif // #if 0
  1429. //-------------------------------------------------------------------------//
  1430. STDMETHODIMP CAugmentedMergeISF::UnWrapIDList(
  1431. LPCITEMIDLIST pidlWrap,
  1432. LONG cPidls,
  1433. IShellFolder** apsf,
  1434. LPITEMIDLIST* apidlFolder,
  1435. LPITEMIDLIST* apidlItems,
  1436. LONG* pcFetched )
  1437. {
  1438. HRESULT hr ;
  1439. HANDLE hEnum ;
  1440. BOOL bEnum = TRUE ;
  1441. UINT nSrcID ;
  1442. LPITEMIDLIST pidlItem ;
  1443. LONG cFetched = 0;
  1444. if (NULL == pidlWrap || cPidls <= 0)
  1445. return E_INVALIDARG ;
  1446. if (FAILED((hr = AugMergeISF_IsWrap(pidlWrap))))
  1447. return hr ;
  1448. // Enumerate pidls in wrap
  1449. for (hEnum = AugMergeISF_EnumFirstSrcPidl( pidlWrap, &nSrcID, &pidlItem);
  1450. cFetched < cPidls && hEnum && bEnum ;
  1451. bEnum = AugMergeISF_EnumNextSrcPidl( hEnum, &nSrcID, &pidlItem))
  1452. {
  1453. // Retrieve namespace data
  1454. CNamespace* pSrc ;
  1455. if (SUCCEEDED((hr = QueryNameSpace(nSrcID, (PVOID*)&pSrc))))
  1456. {
  1457. if (apsf)
  1458. {
  1459. apsf[cFetched] = pSrc->ShellFolder() ;
  1460. if (apsf[cFetched])
  1461. apsf[cFetched]->AddRef();
  1462. }
  1463. if (apidlFolder)
  1464. apidlFolder[cFetched] = ILClone(pSrc->GetPidl());
  1465. if (apidlItems)
  1466. {
  1467. apidlItems[cFetched] = pidlItem;
  1468. pidlItem = NULL; // paranoia -- just making sure we, somehow, don't free this guy at the end of the for loop
  1469. }
  1470. cFetched++ ;
  1471. }
  1472. else
  1473. {
  1474. ILFree( pidlItem ) ;
  1475. }
  1476. }
  1477. ILFree(pidlItem); // AugMergeISF_EnumNextSrcPidl is called (if there are 2 wrapped pidls and we ask for only one)
  1478. // right before we exit the for loop so we have to free pidl if allocated.
  1479. if (hEnum)
  1480. AugMergeISF_EndEnumSrcPidls( hEnum );
  1481. if( pcFetched )
  1482. *pcFetched = cFetched ;
  1483. return cFetched == cPidls ? S_OK : S_FALSE ;
  1484. }
  1485. //-------------------------------------------------------------------------//
  1486. STDMETHODIMP CAugmentedMergeISF::SetOwner( IUnknown* punkOwner )
  1487. {
  1488. HRESULT hr = S_OK ;
  1489. int cSrcs = NamespaceCount() ;
  1490. if( cSrcs > 0 )
  1491. DPA_EnumCallback( _hdpaNamespaces, SetOwnerProc, NULL ) ;
  1492. ATOMICRELEASE( _punkOwner ) ;
  1493. if( punkOwner )
  1494. {
  1495. hr = punkOwner->QueryInterface(IID_IUnknown, (LPVOID *)&_punkOwner ) ;
  1496. if( cSrcs )
  1497. DPA_EnumCallback( _hdpaNamespaces, SetOwnerProc, (void *)_punkOwner);
  1498. }
  1499. return hr ;
  1500. }
  1501. //-------------------------------------------------------------------------//
  1502. int CAugmentedMergeISF::SetOwnerProc( LPVOID pv, LPVOID pvParam )
  1503. {
  1504. CNamespace* pSrc = (CNamespace*) pv ;
  1505. ASSERT( pSrc ) ;
  1506. return pSrc->SetOwner( (IUnknown*)pvParam ) ;
  1507. }
  1508. //-------------------------------------------------------------------------//
  1509. // ITranslateShellChangeNotify methods
  1510. //-------------------------------------------------------------------------//
  1511. LPITEMIDLIST ILCombineBase(LPCITEMIDLIST pidlContainingBase, LPCITEMIDLIST pidlRel)
  1512. {
  1513. // This routine differs from ILCombine in that it takes the First pidl's base, and
  1514. // cats on the last id of the second pidl. We need this so Wrapped pidls
  1515. // end up with the same base, and we get a valid full pidl.
  1516. LPITEMIDLIST pidlRet = NULL;
  1517. LPITEMIDLIST pidlBase = ILClone(pidlContainingBase);
  1518. if (pidlBase)
  1519. {
  1520. ILRemoveLastID(pidlBase);
  1521. pidlRet = ILCombine(pidlBase, pidlRel);
  1522. ILFree(pidlBase);
  1523. }
  1524. return pidlRet;
  1525. }
  1526. BOOL IsFolderEvent(LONG lEvent)
  1527. {
  1528. return lEvent == SHCNE_MKDIR || lEvent == SHCNE_RMDIR || lEvent == SHCNE_RENAMEFOLDER;
  1529. }
  1530. #ifdef DEBUG
  1531. void CAugmentedMergeISF::DumpObjects()
  1532. {
  1533. if (g_dwDumpFlags & TF_AUGM)
  1534. {
  1535. ASSERT(_hdpaObjects);
  1536. int iObjectCount = DPA_GetPtrCount(_hdpaObjects);
  1537. TraceMsg(TF_AUGM, "CAugMISF::DumpObjects: Number of items: %d", iObjectCount);
  1538. CNamespace* pns = (CNamespace *)DPA_FastGetPtr(_hdpaNamespaces, 0);
  1539. if (pns)
  1540. DebugDumpPidl(TF_AUGM, TEXT("CAugMISF::DumpObjects Namespace 1"), pns->GetPidl());
  1541. pns = (CNamespace *)DPA_FastGetPtr(_hdpaNamespaces, 1);
  1542. if (pns)
  1543. DebugDumpPidl(TF_AUGM, TEXT("CAugMISF::DumpObjects Namespace 2"), pns->GetPidl());
  1544. for (int i = 0; i < iObjectCount; i++)
  1545. {
  1546. CAugISFEnumItem* pEnumItem = (CAugISFEnumItem*)DPA_FastGetPtr(_hdpaObjects, i);
  1547. TraceMsg(TF_ALWAYS, "CAugMISF::DumpObjects: %s, Folder: %s Merged: %s",
  1548. pEnumItem->_pszDisplayName,
  1549. BOOLIFY(pEnumItem->_rgfAttrib & SFGAO_FOLDER) ? TEXT("Yes") : TEXT("No"),
  1550. (AugMergeISF_GetSourceCount(pEnumItem->_pidlWrap) > 1)? TEXT("Yes") : TEXT("No"));
  1551. }
  1552. }
  1553. }
  1554. #endif
  1555. BOOL GetRealPidlFromSimple(LPCITEMIDLIST pidlSimple, LPITEMIDLIST* ppidlReal)
  1556. {
  1557. // Similar to SHGetRealIDL in Function, but SHGetRealIDL does SHGDN_FORPARSING | INFOLDER.
  1558. // I need the parsing name. I can't rev SHGetRealIDL very easily, so here's this one!
  1559. TCHAR szFullName[MAX_PATH];
  1560. if (SUCCEEDED(SHGetNameAndFlags(pidlSimple, SHGDN_FORPARSING, szFullName, SIZECHARS(szFullName), NULL)))
  1561. {
  1562. *ppidlReal = ILCreateFromPath(szFullName);
  1563. }
  1564. if (*ppidlReal == NULL) // Unable to create? Then use the simple pidl. This is because it does not exist any more
  1565. { // For say, a Delete Notify
  1566. *ppidlReal = ILClone(pidlSimple);
  1567. }
  1568. return *ppidlReal != NULL;
  1569. }
  1570. //-------------------------------------------------------------------------------------------------//
  1571. STDMETHODIMP CAugmentedMergeISF::TranslateIDs(
  1572. LONG *plEvent,
  1573. LPCITEMIDLIST pidl1,
  1574. LPCITEMIDLIST pidl2,
  1575. LPITEMIDLIST * ppidlOut1,
  1576. LPITEMIDLIST * ppidlOut2,
  1577. LONG *plEvent2, LPITEMIDLIST *ppidlOut1Event2,
  1578. LPITEMIDLIST *ppidlOut2Event2)
  1579. {
  1580. HRESULT hres = E_FAIL;
  1581. switch (*plEvent)
  1582. {
  1583. case SHCNE_EXTENDED_EVENT:
  1584. case SHCNE_ASSOCCHANGED:
  1585. case SHCNE_UPDATEIMAGE:
  1586. return S_OK;
  1587. case SHCNE_UPDATEDIR:
  1588. FreeObjects();
  1589. return S_OK;
  1590. }
  1591. ASSERT(ppidlOut1);
  1592. ASSERT(ppidlOut2);
  1593. LONG lEvent = *plEvent;
  1594. *plEvent2 = (LONG)-1;
  1595. *ppidlOut1Event2 = NULL;
  1596. *ppidlOut2Event2 = NULL;
  1597. *ppidlOut1 = (LPITEMIDLIST)pidl1;
  1598. *ppidlOut2 = (LPITEMIDLIST)pidl2;
  1599. if (!plEvent)
  1600. return E_FAIL;
  1601. // If they are already wrapped, don't wrap twice.
  1602. if ((pidl1 && SUCCEEDED(AugMergeISF_IsWrap(ILFindLastID(pidl1)))) ||
  1603. (pidl2 && SUCCEEDED(AugMergeISF_IsWrap(ILFindLastID(pidl2)))))
  1604. {
  1605. // We don't want to wrap twice.
  1606. return E_FAIL;
  1607. }
  1608. if (!_hdpaNamespaces)
  1609. return E_FAIL;
  1610. if (!_hdpaObjects)
  1611. return E_FAIL;
  1612. CAugISFEnumItem* pEnumItem;
  1613. int iIndex;
  1614. int iShellFolder1 = -1;
  1615. int iShellFolder2 = -1;
  1616. IShellFolder* psf1 = NULL;
  1617. IShellFolder* psf2 = NULL;
  1618. LPITEMIDLIST pidlReal1 = NULL;
  1619. LPITEMIDLIST pidlReal2 = NULL;
  1620. LPITEMIDLIST pidlRealRel1 = NULL;
  1621. LPITEMIDLIST pidlRealRel2 = NULL;
  1622. BOOL fFolder = IsFolderEvent(*plEvent);
  1623. // Get the information about these Simple pidls: Are they our Children? If so, what namespace?
  1624. BOOL fChild1 = IsChildIDInternal(pidl1, TRUE, &iShellFolder1);
  1625. BOOL fChild2 = IsChildIDInternal(pidl2, TRUE, &iShellFolder2);
  1626. // Is either a child?
  1627. if (!(fChild1 || fChild2))
  1628. return hres;
  1629. // Ok, pidl1 is a child, can we get the Real pidl from the simple one?
  1630. if (pidl1 && !GetRealPidlFromSimple(pidl1, &pidlReal1))
  1631. goto Cleanup;
  1632. // Ok, pidl2 is a child, can we get the Real pidl from the simple one?
  1633. if (pidl2 && !GetRealPidlFromSimple(pidl2, &pidlReal2))
  1634. goto Cleanup;
  1635. // These are for code clarity later on. We deal with Relative pidls from here until the very end,
  1636. // when we combine the base of the in pidls with the outgoing wrapped pidls.
  1637. if (pidlReal1)
  1638. pidlRealRel1 = ILFindLastID(pidlReal1);
  1639. if (pidlReal2)
  1640. pidlRealRel2 = ILFindLastID(pidlReal2);
  1641. // Is Pidl1 in our namespaces?
  1642. if (iShellFolder1 != -1)
  1643. {
  1644. // Yes, lets get the non-refcounted shell folder that know's about this pidl.
  1645. CNamespace * pns = (CNamespace *)DPA_GetPtr(_hdpaNamespaces, iShellFolder1);
  1646. psf1 = pns->ShellFolder(); // Non ref counted.
  1647. }
  1648. // Is Pidl2 in our namespaces?
  1649. if (iShellFolder2 != -1)
  1650. {
  1651. // Yes, lets get the non-refcounted shell folder that know's about this pidl.
  1652. CNamespace * pns = (CNamespace *)DPA_GetPtr(_hdpaNamespaces, iShellFolder2);
  1653. psf2 = pns->ShellFolder(); // Non ref counted.
  1654. }
  1655. hres = S_OK;
  1656. DEBUG_CODE(_fInternalGDNO = TRUE);
  1657. switch(*plEvent)
  1658. {
  1659. case 0: // Just look up the pidls and return.
  1660. {
  1661. DWORD rgfAttrib = SFGAO_FOLDER;
  1662. if (iShellFolder1 != -1)
  1663. {
  1664. psf1->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlRealRel1, &rgfAttrib);
  1665. if (S_OK == _SearchForPidl(psf1, pidlRealRel1, BOOLIFY(rgfAttrib & SFGAO_FOLDER), &iIndex, &pEnumItem))
  1666. {
  1667. *ppidlOut1 = ILCombineBase(pidlReal1, pEnumItem->_pidlWrap);
  1668. if (!*ppidlOut1)
  1669. hres = E_OUTOFMEMORY;
  1670. }
  1671. }
  1672. rgfAttrib = SFGAO_FOLDER;
  1673. if (iShellFolder2 != -1 && SUCCEEDED(hres))
  1674. {
  1675. psf2->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlRealRel2, &rgfAttrib);
  1676. if (S_OK == _SearchForPidl(psf2, pidlRealRel2, BOOLIFY(rgfAttrib & SFGAO_FOLDER), &iIndex, &pEnumItem))
  1677. {
  1678. *ppidlOut2 = ILCombineBase(pidlReal2, pEnumItem->_pidlWrap);
  1679. if (!*ppidlOut2)
  1680. hres = E_OUTOFMEMORY;
  1681. }
  1682. }
  1683. }
  1684. break;
  1685. case SHCNE_CREATE:
  1686. case SHCNE_MKDIR:
  1687. {
  1688. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s", fFolder?
  1689. TEXT("SHCNE_MKDIR") : TEXT("SHCNE_CREATE"));
  1690. // Is there a thing of this name already?
  1691. if (S_OK == _SearchForPidl(psf1, pidlRealRel1, fFolder, &iIndex, &pEnumItem))
  1692. {
  1693. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s needs to be merged. Converting to Rename", pEnumItem->_pszDisplayName);
  1694. // Yes; Then we need to merge this new pidl into the wrapped pidl, and change this
  1695. // to a rename, passing the Old wrapped pidl as the first arg, and the new wrapped pidl
  1696. // as the second arg. I have to be careful about the freeing:
  1697. // Free *ppidlOut1
  1698. // Clone pEnumItem->_pidlWrap -> *ppidlOut1.
  1699. // Add pidl1 to pEnumItem->_pidlWrap.
  1700. // Clone new pEnumItem->_pidlWrap -> *ppidlOut2. ASSERT(*ppidlOut2 == NULL)
  1701. *ppidlOut1 = ILCombineBase(pidl1, pEnumItem->_pidlWrap);
  1702. if (*ppidlOut1)
  1703. {
  1704. AugMergeISF_WrapAddPidl(pidlRealRel1, iShellFolder1, &pEnumItem->_pidlWrap);
  1705. *ppidlOut2 = ILCombineBase(pidl1, pEnumItem->_pidlWrap);
  1706. if (!*ppidlOut2)
  1707. TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Failure. Was unable to create new pidl2");
  1708. *plEvent = fFolder? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM;
  1709. }
  1710. else
  1711. {
  1712. TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Failure. Was unable to create new pidl1");
  1713. }
  1714. }
  1715. else
  1716. {
  1717. LPITEMIDLIST pidlWrap;
  1718. CAugISFEnumItem* paugmEnum = new CAugISFEnumItem;
  1719. if (paugmEnum)
  1720. {
  1721. if (SUCCEEDED(AugMergeISF_CreateWrap(pidlRealRel1, (UINT)iShellFolder1, &pidlWrap)) &&
  1722. paugmEnum->InitWithWrappedToOwn(SAFECAST(this, IAugmentedShellFolder2*),
  1723. iShellFolder1, pidlWrap))
  1724. {
  1725. AUGMISFSEARCHFORPIDL AugMSearch;
  1726. AugMSearch.pszDisplayName = paugmEnum->_pszDisplayName;
  1727. AugMSearch.fFolder = fFolder;
  1728. int iInsertIndex = DPA_Search(_hdpaObjects, (LPVOID)&AugMSearch, 0,
  1729. AugMISFSearchForOnePidlByDisplayName, NULL, DPAS_SORTED | DPAS_INSERTAFTER);
  1730. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: Creating new unmerged %s at %d",
  1731. paugmEnum->_pszDisplayName, iInsertIndex);
  1732. if (iInsertIndex < 0)
  1733. iInsertIndex = DA_LAST;
  1734. if (DPA_InsertPtr(_hdpaObjects, iInsertIndex, paugmEnum) == -1)
  1735. {
  1736. TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Was unable to add %s for some reason. Bailing",
  1737. paugmEnum->_pszDisplayName);
  1738. DestroyObjectsProc(paugmEnum, NULL);
  1739. }
  1740. else
  1741. {
  1742. *ppidlOut1 = ILCombineBase(pidl1, paugmEnum->_pidlWrap);
  1743. }
  1744. }
  1745. else
  1746. DestroyObjectsProc(paugmEnum, NULL);
  1747. }
  1748. }
  1749. }
  1750. break;
  1751. case SHCNE_DELETE:
  1752. case SHCNE_RMDIR:
  1753. {
  1754. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s", fFolder?
  1755. TEXT("SHCNE_RMDIR") : TEXT("SHCNE_DELETE"));
  1756. int iDeleteIndex;
  1757. // Is there a folder of this name already?
  1758. if (S_OK == _SearchForPidl(psf1, pidlRealRel1,
  1759. fFolder, &iDeleteIndex, &pEnumItem))
  1760. {
  1761. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: Found %s checking merge state.", pEnumItem->_pszDisplayName);
  1762. // Yes; Then we need to unmerge this pidl from the wrapped pidl, and change this
  1763. // to a rename, passing the Old wrapped pidl as the first arg, and the new wrapped pidl
  1764. // as the second arg. I have to be careful about the freeing:
  1765. // Free *ppidlOut1
  1766. // Clone pEnumItem->_pidlWrap -> *ppidlOut1.
  1767. // Remove pidl1 from pEnumItem->_pidlWrap
  1768. // Convert to rename, pass new wrapped as second arg.
  1769. if (AugMergeISF_GetSourceCount( pEnumItem->_pidlWrap ) > 1 )
  1770. {
  1771. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s is Merged. Removing pidl, convert to rename", pEnumItem->_pszDisplayName);
  1772. *ppidlOut1 = ILCombineBase(pidl1, pEnumItem->_pidlWrap);
  1773. if (*ppidlOut1)
  1774. {
  1775. EVAL(SUCCEEDED(AugMergeISF_WrapRemovePidl(pEnumItem->_pidlWrap,
  1776. iShellFolder1, &pEnumItem->_pidlWrap)));
  1777. *ppidlOut2 = ILCombineBase(pidl1, pEnumItem->_pidlWrap);
  1778. if (!*ppidlOut2)
  1779. TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Failure. Was unable to create new pidl2");
  1780. *plEvent = fFolder? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM;
  1781. }
  1782. else
  1783. {
  1784. TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Failure. Was unable to create new pidl1");
  1785. }
  1786. }
  1787. else
  1788. {
  1789. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s is not Merged. deleteing", pEnumItem->_pszDisplayName);
  1790. pEnumItem = (CAugISFEnumItem*)DPA_DeletePtr(_hdpaObjects, iDeleteIndex);
  1791. if (EVAL(pEnumItem))
  1792. {
  1793. *ppidlOut1 = ILCombineBase(pidl1, pEnumItem->_pidlWrap);
  1794. DestroyObjectsProc(pEnumItem, NULL);
  1795. }
  1796. else
  1797. {
  1798. TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Failure. Was unable to get %d from DPA", iDeleteIndex);
  1799. }
  1800. }
  1801. }
  1802. }
  1803. break;
  1804. case SHCNE_RENAMEITEM:
  1805. case SHCNE_RENAMEFOLDER:
  1806. {
  1807. // BUGBUG (lamadio): When renaming an item in the menu, this code will split it into
  1808. // a Delete and a Create. We need to detect this situation and convert it to 1 rename. This
  1809. // will solve the problem of the lost order during a rename....
  1810. BOOL fEvent1Set = FALSE;
  1811. BOOL fFirstPidlInNamespace = FALSE;
  1812. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s", fFolder?
  1813. TEXT("SHCNE_RENAMEFOLDER") : TEXT("SHCNE_RENAMEITEM"));
  1814. // Is this item being renamed FROM the Folder?
  1815. if (iShellFolder1 != -1 && // Is this pidl a child of the Folder?
  1816. S_OK == _SearchForPidl(psf1, pidlRealRel1,
  1817. fFolder, &iIndex, &pEnumItem)) // Is it found?
  1818. {
  1819. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: Old pidl %s is in the Folder", pEnumItem->_pszDisplayName);
  1820. // Yes.
  1821. // Then we need to see if the item that it's being renamed from was Merged
  1822. // Need this for reentrancy
  1823. if (WrappedPidlContainsSrcID(pEnumItem->_pidlWrap, iShellFolder1))
  1824. {
  1825. // Was it merged?
  1826. if (AugMergeISF_GetSourceCount(pEnumItem->_pidlWrap) > 1) // Case 3)
  1827. {
  1828. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s is Merged. Removing pidl. Convert to rename for event 1",
  1829. pEnumItem->_pszDisplayName);
  1830. // Yes;
  1831. // Then we need to unmerge that item.
  1832. *ppidlOut1 = ILCombineBase(pidl1, pEnumItem->_pidlWrap);
  1833. if (*ppidlOut1)
  1834. {
  1835. // UnWrap
  1836. AugMergeISF_WrapRemovePidl(pEnumItem->_pidlWrap, iShellFolder1, &pEnumItem->_pidlWrap);
  1837. *ppidlOut2 = ILCombineBase(pidl1, pEnumItem->_pidlWrap);
  1838. if (!*ppidlOut2)
  1839. TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Failure. Was unable to create new pidl2");
  1840. // This We need to "Rename" the old wrapped pidl, to this new one
  1841. // that does not contain the old item.
  1842. fEvent1Set = TRUE;
  1843. }
  1844. else
  1845. {
  1846. TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Failure. Was unable to create new pidl1");
  1847. }
  1848. }
  1849. else
  1850. {
  1851. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s is not merged. Nuking item Convert to Delete for event 1.",
  1852. pEnumItem->_pszDisplayName);
  1853. // No, This was not a wrapped pidl. Then, convert to a delete:
  1854. pEnumItem = (CAugISFEnumItem*)DPA_DeletePtr(_hdpaObjects, iIndex);
  1855. if (EVAL(pEnumItem))
  1856. {
  1857. // If we're renaming from this folder, into this folder, Then the first event stays a rename.
  1858. if (iShellFolder2 == -1)
  1859. {
  1860. fEvent1Set = TRUE;
  1861. *plEvent = fFolder? SHCNE_RMDIR : SHCNE_DELETE;
  1862. }
  1863. else
  1864. {
  1865. fFirstPidlInNamespace = TRUE;
  1866. }
  1867. *ppidlOut1 = ILCombineBase(pidl1, pEnumItem->_pidlWrap);
  1868. DestroyObjectsProc(pEnumItem, NULL);
  1869. }
  1870. else
  1871. {
  1872. TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Failure. Was unable to find Item at %d", iIndex);
  1873. }
  1874. }
  1875. }
  1876. else
  1877. {
  1878. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: Skipping this because we already processed it."
  1879. "Dragging To Desktop?");
  1880. hres = E_FAIL;
  1881. }
  1882. }
  1883. // Is this item is being rename INTO the Start Menu?
  1884. if (iShellFolder2 != -1)
  1885. {
  1886. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: New pidl is in the Folder");
  1887. LPITEMIDLIST* ppidlNewWrapped1 = ppidlOut1;
  1888. LPITEMIDLIST* ppidlNewWrapped2 = ppidlOut2;
  1889. LONG* plNewEvent = plEvent;
  1890. if (fEvent1Set)
  1891. {
  1892. plNewEvent = plEvent2;
  1893. ppidlNewWrapped1 = ppidlOut1Event2;
  1894. ppidlNewWrapped2 = ppidlOut2Event2;
  1895. }
  1896. if (S_OK == _SearchForPidl(psf2, pidlRealRel2,
  1897. fFolder, &iIndex, &pEnumItem))
  1898. {
  1899. // If we're renaming from this folder, into this folder, Check to see if the destination has a
  1900. // conflict. If there is a confict (This case), then convert first event to a remove,
  1901. // and the second event to the rename.
  1902. if (fFirstPidlInNamespace)
  1903. {
  1904. fEvent1Set = TRUE;
  1905. *plEvent = fFolder? SHCNE_RMDIR : SHCNE_DELETE;
  1906. plNewEvent = plEvent2;
  1907. ppidlNewWrapped1 = ppidlOut1Event2;
  1908. ppidlNewWrapped2 = ppidlOut2Event2;
  1909. }
  1910. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s is in Folder", pEnumItem->_pszDisplayName);
  1911. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: Adding pidl to %s. Convert to Rename for event %s",
  1912. pEnumItem->_pszDisplayName, fEvent1Set? TEXT("2") : TEXT("1"));
  1913. // Then the destination needs to be merged.
  1914. *ppidlNewWrapped1 = ILCombineBase(pidl2, pEnumItem->_pidlWrap);
  1915. if (*ppidlNewWrapped1)
  1916. {
  1917. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: Successfully created out pidl1");
  1918. AugMergeISF_WrapAddPidl(pidlRealRel2, iShellFolder2, &pEnumItem->_pidlWrap);
  1919. *ppidlNewWrapped2 = ILCombineBase(pidl2, pEnumItem->_pidlWrap);
  1920. *plNewEvent = fFolder? SHCNE_RENAMEFOLDER : SHCNE_RENAMEITEM;
  1921. }
  1922. }
  1923. else
  1924. {
  1925. LPITEMIDLIST pidlWrap;
  1926. CAugISFEnumItem* paugmEnum = new CAugISFEnumItem;
  1927. if (paugmEnum)
  1928. {
  1929. if (SUCCEEDED(AugMergeISF_CreateWrap(pidlRealRel2, (UINT)iShellFolder2, &pidlWrap)) &&
  1930. paugmEnum->InitWithWrappedToOwn(SAFECAST(this, IAugmentedShellFolder2*),
  1931. iShellFolder2, pidlWrap))
  1932. {
  1933. AUGMISFSEARCHFORPIDL AugMSearch;
  1934. AugMSearch.pszDisplayName = paugmEnum->_pszDisplayName;
  1935. AugMSearch.fFolder = BOOLIFY(paugmEnum->_rgfAttrib & SFGAO_FOLDER);
  1936. int iInsertIndex = DPA_Search(_hdpaObjects, &AugMSearch, 0,
  1937. AugMISFSearchForOnePidlByDisplayName, NULL, DPAS_SORTED | DPAS_INSERTAFTER);
  1938. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: %s is a new item. Converting to Create",
  1939. paugmEnum->_pszDisplayName);
  1940. if (iInsertIndex < 0)
  1941. iInsertIndex = DA_LAST;
  1942. if (DPA_InsertPtr(_hdpaObjects, iInsertIndex, paugmEnum) == -1)
  1943. {
  1944. TraceMsg(TF_ERROR, "CAugMISF::TranslateIDs: Was unable to add %s for some reason. Bailing",
  1945. paugmEnum->_pszDisplayName);
  1946. DestroyObjectsProc(paugmEnum, NULL);
  1947. }
  1948. else
  1949. {
  1950. TraceMsg(TF_AUGM, "CAugMISF::TranslateIDs: Creating new item %s at %d for event %s",
  1951. paugmEnum->_pszDisplayName, iInsertIndex, fEvent1Set? TEXT("2") : TEXT("1"));
  1952. // If we're renaming from this folder, into this folder, Then the first event stays
  1953. // a rename.
  1954. if (!fFirstPidlInNamespace)
  1955. {
  1956. *plNewEvent = fFolder ? SHCNE_MKDIR : SHCNE_CREATE;
  1957. *ppidlNewWrapped1 = ILCombineBase(pidl2, pidlWrap);
  1958. *ppidlNewWrapped2 = NULL;
  1959. }
  1960. else
  1961. *ppidlOut2 = ILCombineBase(pidl2, pidlWrap);
  1962. }
  1963. }
  1964. else
  1965. DestroyObjectsProc(paugmEnum, NULL);
  1966. }
  1967. }
  1968. }
  1969. }
  1970. break;
  1971. default:
  1972. break;
  1973. }
  1974. Cleanup:
  1975. ILFree(pidlReal1);
  1976. ILFree(pidlReal2);
  1977. #ifdef DEBUG
  1978. DumpObjects();
  1979. _fInternalGDNO = FALSE;
  1980. #endif
  1981. return hres;
  1982. }
  1983. BOOL CAugmentedMergeISF::IsChildIDInternal(LPCITEMIDLIST pidlKid, BOOL fImmediate, int* piShellFolder)
  1984. {
  1985. // This is basically the same Method as the interface method, but returns the shell folder
  1986. // that it came from.
  1987. BOOL fChild = FALSE;
  1988. //At this point we should have a translated pidl
  1989. if (pidlKid)
  1990. {
  1991. if (SUCCEEDED(AugMergeISF_IsWrap(pidlKid)))
  1992. {
  1993. LPCITEMIDLIST pidlRelKid = ILFindLastID(pidlKid);
  1994. if (pidlRelKid)
  1995. {
  1996. UINT uiId;
  1997. LPITEMIDLIST pidl;
  1998. HANDLE hEnum = AugMergeISF_EnumFirstSrcPidl(pidlRelKid, &uiId, &pidl);
  1999. if (hEnum)
  2000. {
  2001. do
  2002. {
  2003. ILFree(pidl);
  2004. for (int i = 0; fChild == FALSE && i < DPA_GetPtrCount(_hdpaNamespaces); i++)
  2005. {
  2006. CNamespace * pns = (CNamespace *)DPA_GetPtr(_hdpaNamespaces, i);
  2007. // reuse pidl
  2008. if (pns && (pidl = pns->GetPidl()) != NULL)
  2009. {
  2010. if (ILIsParent(pidl, pidlKid, fImmediate) &&
  2011. !ILIsEqual(pidl, pidlKid))
  2012. {
  2013. fChild = TRUE;
  2014. if (piShellFolder)
  2015. *piShellFolder = i;
  2016. }
  2017. }
  2018. }
  2019. }
  2020. while (fChild == FALSE && AugMergeISF_EnumNextSrcPidl(hEnum, &uiId, &pidl));
  2021. AugMergeISF_EndEnumSrcPidls(hEnum);
  2022. }
  2023. }
  2024. }
  2025. else
  2026. {
  2027. int cSrcs = NamespaceCount();
  2028. for(int i = 0; fChild == FALSE && i < cSrcs ; i++)
  2029. {
  2030. CNamespace* pSrc = Namespace(i);
  2031. if (pSrc && ILIsParent(pSrc->GetPidl(), pidlKid, fImmediate) &&
  2032. !ILIsEqual(pSrc->GetPidl(), pidlKid))
  2033. {
  2034. fChild = TRUE;
  2035. if (piShellFolder)
  2036. *piShellFolder = i;
  2037. }
  2038. }
  2039. }
  2040. }
  2041. return fChild;
  2042. }
  2043. //-------------------------------------------------------------------------------------------------//
  2044. STDMETHODIMP CAugmentedMergeISF::IsChildID( LPCITEMIDLIST pidlKid, BOOL fImmediate)
  2045. {
  2046. return IsChildIDInternal(pidlKid, fImmediate, NULL) ? S_OK : S_FALSE;
  2047. }
  2048. //-------------------------------------------------------------------------------------------------//
  2049. STDMETHODIMP CAugmentedMergeISF::IsEqualID( LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2 )
  2050. {
  2051. // This used to return E_NOTIMPL. I'm kinda overloading the interface to mean:
  2052. // is this equal tp any of your namespaces.
  2053. HRESULT hres = S_FALSE;
  2054. int cSrcs = NamespaceCount();
  2055. for(int i = 0; hres == S_FALSE && i < cSrcs ; i++)
  2056. {
  2057. CNamespace* pSrc = Namespace(i);
  2058. if (pidl1)
  2059. {
  2060. if (pSrc && ILIsEqual(pSrc->GetPidl(), pidl1))
  2061. hres = S_OK;
  2062. }
  2063. else if (pidl2) // If you pass a pidl2 it means: Is pidl2 a parent of one of my namespaces?
  2064. {
  2065. if (pSrc && ILIsParent(pidl2, pSrc->GetPidl(), FALSE))
  2066. hres = S_OK;
  2067. }
  2068. }
  2069. return hres;
  2070. }
  2071. //-------------------------------------------------------------------------------------------------//
  2072. STDMETHODIMP CAugmentedMergeISF::Register(
  2073. HWND hwnd,
  2074. UINT uMsg,
  2075. long lEvents )
  2076. {
  2077. int i, cSrcs ;
  2078. if( 0 >= (cSrcs = NamespaceCount()) )
  2079. return E_FAIL ;
  2080. for( i = 0; i < cSrcs ; i++ )
  2081. {
  2082. CNamespace* pSrc ;
  2083. if( NULL != (pSrc = Namespace( i )) )
  2084. pSrc->RegisterNotify( hwnd, uMsg, lEvents ) ;
  2085. }
  2086. return S_OK ;
  2087. }
  2088. //-------------------------------------------------------------------------------------------------//
  2089. STDMETHODIMP CAugmentedMergeISF::Unregister ()
  2090. {
  2091. int i, cSrcs = NamespaceCount() ;
  2092. if( cSrcs <= 0 )
  2093. return E_FAIL ;
  2094. for( i = 0; i < cSrcs ; i++ )
  2095. {
  2096. CNamespace* pSrc ;
  2097. if( NULL != (pSrc = Namespace( i )) )
  2098. pSrc->UnregisterNotify() ;
  2099. }
  2100. return S_OK ;
  2101. }
  2102. // *** IDropTarget methods ***
  2103. #define HIDA_GetPIDLFolder(pida) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[0])
  2104. #define HIDA_GetPIDLItem(pida, i) (LPCITEMIDLIST)(((LPBYTE)pida)+(pida)->aoffset[i+1])
  2105. HRESULT CAugmentedMergeISF::DragEnter(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  2106. {
  2107. ASSERT(!_fCommon);
  2108. ASSERT(_pdt == NULL);
  2109. if (pDataObj)
  2110. {
  2111. InitClipboardFormats();
  2112. FORMATETC fmte = {g_cfHIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  2113. STGMEDIUM medium;
  2114. medium.pUnkForRelease = NULL;
  2115. medium.hGlobal = NULL;
  2116. if (SUCCEEDED(pDataObj->GetData(&fmte, &medium)))
  2117. {
  2118. LPIDA pida = (LPIDA)GlobalLock(medium.hGlobal);
  2119. if (pida)
  2120. {
  2121. LPCITEMIDLIST pidlItem = HIDA_GetPIDLFolder(pida);
  2122. _fCommon = BOOLIFY(_IsCommonPidl(pidlItem));
  2123. GlobalUnlock(medium.hGlobal);
  2124. }
  2125. ReleaseStgMedium(&medium);
  2126. }
  2127. CNamespace *pSrc = NULL;
  2128. ULONG gdnsAttribs = 0;
  2129. if (!_fCommon)
  2130. gdnsAttribs = ASFF_DEFNAMESPACE_ALL;
  2131. if (SUCCEEDED(GetDefNamespace(gdnsAttribs, (PVOID*)&pSrc, NULL, NULL)))
  2132. {
  2133. if (SUCCEEDED(pSrc->ShellFolder()->CreateViewObject(_hwnd, IID_IDropTarget, (void **)&_pdt)))
  2134. {
  2135. _pdt->DragEnter(pDataObj, grfKeyState, pt, pdwEffect);
  2136. }
  2137. }
  2138. }
  2139. _grfDragEnterKeyState = grfKeyState;
  2140. _dwDragEnterEffect = *pdwEffect;
  2141. return S_OK;
  2142. }
  2143. HRESULT CAugmentedMergeISF::DragOver(DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  2144. {
  2145. HRESULT hres = S_OK;
  2146. if (_pdt)
  2147. hres = _pdt->DragOver(grfKeyState, pt, pdwEffect);
  2148. return hres;
  2149. }
  2150. HRESULT CAugmentedMergeISF::DragLeave(void)
  2151. {
  2152. HRESULT hres = S_OK;
  2153. _fCommon = 0;
  2154. if (_pdt)
  2155. {
  2156. hres = _pdt->DragLeave();
  2157. ATOMICRELEASE(_pdt);
  2158. }
  2159. return hres;
  2160. }
  2161. HRESULT CAugmentedMergeISF::Drop(IDataObject *pDataObj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  2162. {
  2163. HRESULT hres = S_OK;
  2164. BOOL bNoUI = !_fCommon;
  2165. BOOL bConfirmed = !_fCommon;
  2166. if (!_pdt && pDataObj)
  2167. {
  2168. LPITEMIDLIST pidlParent = NULL,
  2169. pidlOther = NULL;
  2170. int csidl = _fCommon ? CSIDL_COMMON_STARTMENU : CSIDL_STARTMENU,
  2171. csidlOther = _fCommon ? CSIDL_STARTMENU : CSIDL_COMMON_STARTMENU;
  2172. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, csidl, &pidlParent)) &&
  2173. SUCCEEDED(SHGetSpecialFolderLocation(NULL, csidlOther, &pidlOther)))
  2174. {
  2175. FORMATETC fmte = {g_cfHIDA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  2176. STGMEDIUM medium;
  2177. medium.pUnkForRelease = NULL;
  2178. medium.hGlobal = NULL;
  2179. if (SUCCEEDED(pDataObj->GetData(&fmte, &medium)))
  2180. {
  2181. LPIDA pida = (LPIDA)GlobalLock(medium.hGlobal);
  2182. if (pida)
  2183. {
  2184. IShellFolder *psfParent = NULL,
  2185. *psfOther = NULL;
  2186. if (SUCCEEDED(IEBindToObject(pidlParent, &psfParent)) &&
  2187. SUCCEEDED(IEBindToObject(pidlOther, &psfOther)))
  2188. {
  2189. LPCITEMIDLIST pidlItem, pidl;
  2190. LPITEMIDLIST pidlRel;
  2191. pidlItem = HIDA_GetPIDLItem(pida, 0);
  2192. // we came here because we don't have pdt which means that
  2193. // there is only one folder in our namespace and that's not
  2194. // the one we have to drop IDataObj on.
  2195. CNamespace* pCNamespace = Namespace(0);
  2196. if (pCNamespace)
  2197. {
  2198. pidl = pCNamespace->GetPidl(); // don't need to free pidl.
  2199. if (pidl)
  2200. {
  2201. pidlRel = ILClone(ILFindChild(pidlOther, pidl));
  2202. if (pidlRel)
  2203. {
  2204. STRRET strret;
  2205. TCHAR szDir[MAX_PATH];
  2206. strret.uType = STRRET_CSTR;
  2207. if (SUCCEEDED(psfParent->GetDisplayNameOf(pidlRel, SHGDN_FORPARSING, &strret)) &&
  2208. SUCCEEDED(StrRetToBuf(&strret, pidlRel, szDir, ARRAYSIZE(szDir))))
  2209. {
  2210. if (_fCommon)
  2211. {
  2212. bConfirmed = AffectAllUsers(_hwnd);
  2213. bNoUI = TRUE;
  2214. }
  2215. if (bConfirmed)
  2216. {
  2217. BOOL bCreated = FALSE;
  2218. switch (SHCreateDirectory(_hwnd, szDir))
  2219. {
  2220. case ERROR_FILENAME_EXCED_RANGE:
  2221. case ERROR_FILE_EXISTS:
  2222. case ERROR_ALREADY_EXISTS:
  2223. case 0: // It was created successfully.
  2224. bCreated = TRUE;
  2225. }
  2226. if (bCreated)
  2227. {
  2228. IShellFolder *psf;
  2229. if (SUCCEEDED(psfParent->BindToObject(pidlRel, NULL, IID_IShellFolder, (void **)&psf)))
  2230. {
  2231. psf->CreateViewObject(_hwnd, IID_IDropTarget, (void **)&_pdt);
  2232. // we're going to call drop on it, call dragenter first
  2233. if (_pdt)
  2234. _pdt->DragEnter(pDataObj, _grfDragEnterKeyState, pt, &_dwDragEnterEffect);
  2235. psf->Release();
  2236. }
  2237. }
  2238. }
  2239. }
  2240. ILFree(pidlRel);
  2241. }
  2242. }
  2243. }
  2244. }
  2245. if (psfParent)
  2246. psfParent->Release();
  2247. if (psfOther)
  2248. psfOther->Release();
  2249. GlobalUnlock(medium.hGlobal);
  2250. }
  2251. ReleaseStgMedium(&medium);
  2252. }
  2253. }
  2254. ILFree(pidlParent);
  2255. ILFree(pidlOther);
  2256. }
  2257. if (_pdt)
  2258. {
  2259. hres = E_FAIL;
  2260. if ((bNoUI || (bConfirmed = AffectAllUsers(_hwnd))) && bConfirmed)
  2261. hres = _pdt->Drop(pDataObj, grfKeyState, pt, pdwEffect);
  2262. else
  2263. hres = _pdt->DragLeave();
  2264. ATOMICRELEASE(_pdt);
  2265. }
  2266. _fCommon = 0;
  2267. return hres;
  2268. }
  2269. //-------------------------------------------------------------------------------------------------//
  2270. LPITEMIDLIST CAugmentedMergeISF::GetNativePidl(LPCITEMIDLIST pidlWrap, LPARAM nSrcID /*int nID*/)
  2271. {
  2272. LPITEMIDLIST pidlRet = NULL;
  2273. if (SUCCEEDED(AugMergeISF_GetSrcPidl(pidlWrap, (UINT)nSrcID, &pidlRet)))
  2274. return pidlRet ;
  2275. // not wrapped by me.
  2276. return NULL;
  2277. }
  2278. BOOL AffectAllUsers(HWND hwnd)
  2279. {
  2280. TCHAR szMessage[255];
  2281. TCHAR szTitle[20];
  2282. BOOL bRet = FALSE;
  2283. if (MLLoadShellLangString(IDS_ALLUSER_WARNING, szMessage, ARRAYSIZE(szMessage)) > 0 &&
  2284. MLLoadShellLangString(IDS_ALLUSER_WARNING_TITLE, szTitle, ARRAYSIZE(szTitle)) > 0)
  2285. {
  2286. bRet = IDYES == MessageBox(hwnd, szMessage, szTitle, MB_YESNO | MB_ICONINFORMATION);
  2287. }
  2288. return bRet;
  2289. }
  2290. BOOL CAugmentedMergeISF::_IsCommonPidl(LPCITEMIDLIST pidlItem)
  2291. {
  2292. BOOL bRet = FALSE;
  2293. LPITEMIDLIST pidlCommon;
  2294. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_STARTMENU, &pidlCommon)))
  2295. {
  2296. bRet = ILIsParent(pidlCommon, pidlItem, FALSE);
  2297. ILFree(pidlCommon);
  2298. }
  2299. if (!bRet &&
  2300. SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_PROGRAMS, &pidlCommon)))
  2301. {
  2302. bRet = ILIsParent(pidlCommon, pidlItem, FALSE);
  2303. ILFree(pidlCommon);
  2304. }
  2305. if (!bRet &&
  2306. SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_COMMON_DESKTOPDIRECTORY, &pidlCommon)))
  2307. {
  2308. bRet = ILIsParent(pidlCommon, pidlItem, FALSE);
  2309. ILFree(pidlCommon);
  2310. }
  2311. return bRet;
  2312. }
  2313. HRESULT CAugmentedMergeISF::_SearchForPidl(IShellFolder* psf, LPCITEMIDLIST pidl, BOOL fFolder, int* piIndex, CAugISFEnumItem** ppEnumItem)
  2314. {
  2315. STRRET str;
  2316. TCHAR szDisplayName[MAX_PATH];
  2317. int iIndex = -1;
  2318. *ppEnumItem = NULL;
  2319. if (SUCCEEDED(psf->GetDisplayNameOf(pidl, SHGDN_FORPARSING | SHGDN_INFOLDER, &str)) &&
  2320. SUCCEEDED(StrRetToBuf(&str, pidl, szDisplayName, ARRAYSIZE(szDisplayName))))
  2321. {
  2322. AUGMISFSEARCHFORPIDL SearchFor;
  2323. SearchFor.pszDisplayName = szDisplayName;
  2324. SearchFor.fFolder = fFolder;
  2325. iIndex = DPA_Search(_hdpaObjects, (LPVOID)&SearchFor, 0,
  2326. AugMISFSearchForOnePidlByDisplayName, NULL, DPAS_SORTED);
  2327. if (iIndex >= 0)
  2328. {
  2329. *ppEnumItem = DPA_GETPTR( _hdpaObjects, iIndex, CAugISFEnumItem);
  2330. }
  2331. }
  2332. if (piIndex)
  2333. *piIndex = iIndex;
  2334. if (*ppEnumItem)
  2335. return S_OK;
  2336. return S_FALSE;
  2337. }
  2338. // given a wrapped pidl
  2339. // f-n returns common and user namespaces (if they are in wrapped pidl) -- note that they are not addrefed
  2340. // unwrapped pidl, and if the unwrapped pidl is folder or not
  2341. HRESULT CAugmentedMergeISF::_GetNamespaces(LPCITEMIDLIST pidlWrap,
  2342. CNamespace** ppnsCommon,
  2343. UINT* pnCommonID,
  2344. CNamespace** ppnsUser,
  2345. UINT* pnUserID,
  2346. LPITEMIDLIST* ppidl,
  2347. BOOL *pbIsFolder)
  2348. {
  2349. HRESULT hres;
  2350. UINT nSrcID;
  2351. CNamespace * pns;
  2352. int cWrapped;
  2353. HANDLE hEnum;
  2354. ASSERT(ppnsCommon && ppnsUser && ppidl);
  2355. *ppnsCommon = NULL;
  2356. *ppnsUser = NULL;
  2357. *ppidl = NULL;
  2358. ASSERT(SUCCEEDED(AugMergeISF_IsWrap(pidlWrap)));
  2359. cWrapped = AugMergeISF_GetSourceCount(pidlWrap);
  2360. if (NULL == _hdpaNamespaces || 0 >= cWrapped ||
  2361. NULL == (hEnum = AugMergeISF_EnumFirstSrcPidl(pidlWrap, &nSrcID, ppidl)))
  2362. return E_FAIL;
  2363. hres = QueryNameSpace(nSrcID, (void **)&pns);
  2364. if (EVAL(SUCCEEDED(hres)))
  2365. {
  2366. IShellFolder * psf;
  2367. ULONG rgf = SFGAO_FOLDER;
  2368. psf = pns->ShellFolder(); // no addref
  2369. ASSERT(psf);
  2370. if (SUCCEEDED(psf->GetAttributesOf(1, (LPCITEMIDLIST*)ppidl, &rgf)))
  2371. {
  2372. if (pbIsFolder)
  2373. *pbIsFolder = rgf & SFGAO_FOLDER;
  2374. LPITEMIDLIST pidlItem;
  2375. UINT nCommonID;
  2376. CNamespace* pnsCommonTemp;
  2377. // get common namespace (attribs = 0)
  2378. hres = GetDefNamespace(0, (void **)&pnsCommonTemp, &nCommonID, NULL);
  2379. ASSERT(NamespaceCount() == 2 && SUCCEEDED(hres) || NamespaceCount() == 1);
  2380. if (FAILED(hres))
  2381. nCommonID = 1;
  2382. if (nCommonID == nSrcID)
  2383. {
  2384. *ppnsCommon = pns;
  2385. if (pnCommonID)
  2386. *pnCommonID = nCommonID;
  2387. }
  2388. else
  2389. {
  2390. *ppnsUser = pns;
  2391. if (pnUserID)
  2392. *pnUserID = nSrcID;
  2393. }
  2394. if (AugMergeISF_EnumNextSrcPidl(hEnum, &nSrcID, &pidlItem))
  2395. {
  2396. ASSERT(ILIsEqual(*ppidl, pidlItem));
  2397. ILFree(pidlItem);
  2398. if (SUCCEEDED(QueryNameSpace(nSrcID, (void **)&pns)))
  2399. {
  2400. ASSERT(pns);
  2401. if (nCommonID == nSrcID)
  2402. {
  2403. *ppnsCommon = pns;
  2404. if (pnCommonID)
  2405. *pnCommonID = nCommonID;
  2406. }
  2407. else
  2408. {
  2409. *ppnsUser = pns;
  2410. if (pnUserID)
  2411. *pnUserID = nSrcID;
  2412. }
  2413. }
  2414. }
  2415. hres = S_OK;
  2416. }
  2417. }
  2418. AugMergeISF_EndEnumSrcPidls(hEnum);
  2419. return hres;
  2420. }
  2421. HRESULT CAugmentedMergeISF::_GetContextMenu(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl,
  2422. UINT * prgfInOut, void ** ppvOut)
  2423. {
  2424. HRESULT hres;
  2425. LPITEMIDLIST pidl;
  2426. BOOL bIsFolder;
  2427. CNamespace * pnsCommon;
  2428. CNamespace * pnsUser;
  2429. ASSERT(cidl == 1);
  2430. // psfCommon and psfUser are not addrefed
  2431. hres = _GetNamespaces(apidl[0], &pnsCommon, NULL, &pnsUser, NULL, &pidl, &bIsFolder);
  2432. if (SUCCEEDED(hres))
  2433. {
  2434. ASSERT(pnsCommon || pnsUser);
  2435. if (bIsFolder)
  2436. {
  2437. // folder? need our context menu
  2438. IShellFolder * psfCommon = NULL;
  2439. IShellFolder * psfUser = NULL;
  2440. LPCITEMIDLIST pidlCommon = NULL;
  2441. LPCITEMIDLIST pidlUser = NULL;
  2442. if (pnsCommon)
  2443. {
  2444. psfCommon = pnsCommon->ShellFolder();
  2445. pidlCommon = pnsCommon->GetPidl();
  2446. }
  2447. if (pnsUser)
  2448. {
  2449. psfUser = pnsUser->ShellFolder();
  2450. pidlUser = pnsUser->GetPidl();
  2451. }
  2452. CAugMergeISFContextMenu * pcm = CreateMergeISFContextMenu(psfCommon, pidlCommon,
  2453. psfUser, pidlUser,
  2454. pidl, hwnd, prgfInOut);
  2455. if (pcm)
  2456. {
  2457. hres = pcm->QueryInterface(IID_IContextMenu, ppvOut);
  2458. pcm->Release();
  2459. }
  2460. else
  2461. hres = E_OUTOFMEMORY;
  2462. }
  2463. else
  2464. { // it's not a folder
  2465. // delegate to the isf
  2466. IShellFolder * psf = pnsUser ? pnsUser->ShellFolder() : pnsCommon->ShellFolder();
  2467. hres = psf->GetUIObjectOf(hwnd, 1, (LPCITEMIDLIST*)&pidl, IID_IContextMenu, prgfInOut, ppvOut);
  2468. }
  2469. ILFree(pidl);
  2470. }
  2471. return hres;
  2472. }
  2473. //-------------------------------------------------------------------------//
  2474. STDMETHODIMP CAugmentedMergeISF::GetDefNamespace(
  2475. LPCITEMIDLIST pidlWrap,
  2476. ULONG dwAttrib,
  2477. OUT IShellFolder** ppsf,
  2478. OUT LPITEMIDLIST* ppidlItem )
  2479. {
  2480. HRESULT hr ;
  2481. LPITEMIDLIST pidl ;
  2482. CNamespace* pSrc ;
  2483. ULONG dwDefAttrib = dwAttrib & ASFF_DEFNAMESPACE_ALL ;
  2484. int cWrapped ;
  2485. UINT nSrcID ;
  2486. HANDLE hEnum ;
  2487. ASSERT( ppsf ) ;
  2488. *ppsf = NULL ;
  2489. if (ppidlItem)
  2490. *ppidlItem = NULL ;
  2491. if (FAILED((hr = AugMergeISF_IsWrap( pidlWrap ))))
  2492. return hr ;
  2493. cWrapped = AugMergeISF_GetSourceCount( pidlWrap ) ;
  2494. // No namespaces?
  2495. if (NULL == _hdpaNamespaces || 0 >= cWrapped ||
  2496. NULL == (hEnum = AugMergeISF_EnumFirstSrcPidl( pidlWrap, &nSrcID, &pidl)))
  2497. return E_FAIL ;
  2498. // Only one namespace in wrap? Give up the shell folder and item ID.
  2499. if (1 == cWrapped || 0==dwDefAttrib)
  2500. {
  2501. AugMergeISF_EndEnumSrcPidls( hEnum ) ; // no need to go further
  2502. // Retrieve the namespace object identified by nSrcID.
  2503. if( SUCCEEDED( (hr = QueryNameSpace( nSrcID, (PVOID*)&pSrc )) ) )
  2504. {
  2505. *ppsf = pSrc->ShellFolder() ;
  2506. if( ppidlItem )
  2507. *ppidlItem = pidl ;
  2508. return S_OK ;
  2509. }
  2510. ILFree( pidl ) ;
  2511. return hr ;
  2512. }
  2513. // More than one namespace in wrap?
  2514. if( cWrapped > 1 )
  2515. {
  2516. LPITEMIDLIST pidl0 = NULL ;
  2517. CNamespace* pSrc0 = NULL ; // get this below.
  2518. for (BOOL bEnum = TRUE ; bEnum ;
  2519. bEnum = AugMergeISF_EnumNextSrcPidl(hEnum, &nSrcID, &pidl))
  2520. {
  2521. if (SUCCEEDED((hr = QueryNameSpace(nSrcID, (PVOID*)&pSrc))))
  2522. {
  2523. if (dwDefAttrib & pSrc->Attrib())
  2524. {
  2525. // Matched attributes; we're done.
  2526. AugMergeISF_EndEnumSrcPidls(hEnum);
  2527. *ppsf = pSrc->ShellFolder() ;
  2528. if (ppidlItem)
  2529. *ppidlItem = pidl;
  2530. if(pidl0)
  2531. ILFree(pidl0);
  2532. return S_OK ;
  2533. }
  2534. // Stash first namespace object and item pidl.
  2535. // We'll default to these if
  2536. if( NULL == pSrc0 )
  2537. {
  2538. pSrc0 = pSrc ;
  2539. pidl0 = ILClone( pidl ) ;
  2540. }
  2541. }
  2542. ILFree( pidl ) ;
  2543. }
  2544. AugMergeISF_EndEnumSrcPidls( hEnum ) ;
  2545. // Default to first namespace
  2546. if( pSrc0 && pidl0 )
  2547. {
  2548. *ppsf = pSrc0->ShellFolder() ;
  2549. if( ppidlItem )
  2550. *ppidlItem = pidl0 ;
  2551. return S_OK ;
  2552. }
  2553. }
  2554. return E_UNEXPECTED ;
  2555. }
  2556. //-------------------------------------------------------------------------//
  2557. // Retrieves the default namespaces for the indicated attibutes.
  2558. // The dwAttrib arg must be initialized prior to function entry,
  2559. STDMETHODIMP CAugmentedMergeISF::GetDefNamespace(
  2560. ULONG dwAttrib,
  2561. OUT PVOID* ppSrc, UINT *pnSrcID, PVOID* ppSrc0 )
  2562. {
  2563. CNamespace* pSrc ;
  2564. ULONG dwDefAttrib = dwAttrib & ASFF_DEFNAMESPACE_ALL ;
  2565. // this is an internal helper so we better make sure we pass the correct params!
  2566. //if (NULL == ppSrc)
  2567. // return E_INVALIDARG ;
  2568. *ppSrc = NULL ;
  2569. if( ppSrc0 )
  2570. *ppSrc0 = NULL ;
  2571. for( int i = 0, cSrcs = NamespaceCount(); i < cSrcs ; i++ )
  2572. {
  2573. if( NULL != (pSrc = Namespace( i )) )
  2574. {
  2575. if( 0 == i && ppSrc0 )
  2576. *ppSrc0 = pSrc ;
  2577. if( dwDefAttrib & pSrc->Attrib() ||
  2578. dwDefAttrib == 0 && !(pSrc->Attrib() & ASFF_DEFNAMESPACE_ALL))
  2579. {
  2580. *ppSrc = pSrc;
  2581. if (NULL != pnSrcID)
  2582. *pnSrcID = i;
  2583. return S_OK ;
  2584. }
  2585. }
  2586. }
  2587. return E_FAIL ;
  2588. }
  2589. // BUGBUG(lamadio): Move this to a better location, This is a nice generic function
  2590. #ifdef DEBUG
  2591. BOOL DPA_VerifySorted(HDPA hdpa, PFNDPACOMPARE pfn, LPARAM lParam)
  2592. {
  2593. if (!EVAL(hdpa))
  2594. return FALSE;
  2595. for (int i = 0; i < DPA_GetPtrCount(hdpa) - 1; i++)
  2596. {
  2597. if (pfn(DPA_FastGetPtr(hdpa, i), DPA_FastGetPtr(hdpa, i + 1), lParam) > 0)
  2598. return FALSE;
  2599. }
  2600. return TRUE;
  2601. }
  2602. #else
  2603. #define DPA_VerifySorted(hdpa, pfn, lParam)
  2604. #endif
  2605. int CAugmentedMergeISF::AcquireObjects()
  2606. {
  2607. HDPA hdpa2 = NULL;
  2608. DEBUG_CODE(_fInternalGDNO = TRUE);
  2609. for (int i = 0; i < DPA_GETPTRCOUNT(_hdpaNamespaces); i++)
  2610. {
  2611. CNamespace * pns = DPA_GETPTR(_hdpaNamespaces, i, CNamespace);
  2612. IShellFolder * psf;
  2613. IEnumIDList * peid;
  2614. HDPA * phdpa;
  2615. ASSERT(pns);
  2616. psf = pns->ShellFolder(); // no addref here!
  2617. if (i == 0)
  2618. {
  2619. phdpa = &_hdpaObjects;
  2620. _hdpaObjects = DPA_Create(4); // We should always create the DPA
  2621. }
  2622. else
  2623. {
  2624. ASSERT(i == 1); // no support for more than 2 isf's
  2625. phdpa = &hdpa2;
  2626. }
  2627. HRESULT hres = psf->EnumObjects(NULL, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS | SHCONTF_INCLUDEHIDDEN, &peid);
  2628. if (SUCCEEDED(hres))
  2629. {
  2630. if (!*phdpa)
  2631. *phdpa = DPA_Create(4);
  2632. if (*phdpa)
  2633. {
  2634. LPITEMIDLIST pidl;
  2635. ULONG cEnum;
  2636. while (SUCCEEDED(peid->Next(1, &pidl, &cEnum)) && 1 == cEnum)
  2637. {
  2638. CAugISFEnumItem* paugmEnum = new CAugISFEnumItem;
  2639. if (paugmEnum)
  2640. {
  2641. if (paugmEnum->Init(SAFECAST(this, IAugmentedShellFolder2*), i, pidl))
  2642. {
  2643. if (DPA_AppendPtr(*phdpa, paugmEnum) == -1)
  2644. DestroyObjectsProc(paugmEnum, NULL);
  2645. }
  2646. else
  2647. delete paugmEnum;
  2648. }
  2649. ILFree(pidl);
  2650. }
  2651. }
  2652. peid->Release();
  2653. }
  2654. else
  2655. {
  2656. TraceMsg(TF_WARNING, "CAugMISF::AcquireObjects: Failed to get enumerator 0x%x", hres);
  2657. }
  2658. }
  2659. // now that we have both hdpa's (or one) let's merge them.
  2660. if (DPA_GETPTRCOUNT(_hdpaNamespaces) == 2 && hdpa2)
  2661. {
  2662. DPA_Merge(_hdpaObjects, hdpa2, DPAM_UNION, AugmEnumCompare, AugmEnumMerge, (LPARAM)0);
  2663. DPA_DESTROY(hdpa2, DestroyObjectsProc);
  2664. }
  2665. else
  2666. {
  2667. DPA_Sort(_hdpaObjects, AugmEnumCompare, 0);
  2668. }
  2669. ASSERT(DPA_VerifySorted(_hdpaObjects, AugmEnumCompare, 0));
  2670. DEBUG_CODE(_fInternalGDNO = FALSE);
  2671. #ifdef DEBUG
  2672. TraceMsg(TF_AUGM, "CAugMISF::AcquireObjects");
  2673. DumpObjects();
  2674. #endif
  2675. _count = DPA_GETPTRCOUNT(_hdpaObjects);
  2676. return _count;
  2677. }
  2678. //-------------------------------------------------------------------------//
  2679. void CAugmentedMergeISF::FreeObjects()
  2680. {
  2681. DPA_DESTROY( _hdpaObjects, DestroyObjectsProc ) ;
  2682. _hdpaObjects = NULL;
  2683. _count = 0 ;
  2684. }
  2685. //-------------------------------------------------------------------------//
  2686. int CAugmentedMergeISF::DestroyObjectsProc( LPVOID pv, LPVOID pvData )
  2687. {
  2688. CAugISFEnumItem* paugmEnum = (CAugISFEnumItem*)pv;
  2689. if (EVAL(NULL != paugmEnum))
  2690. {
  2691. delete paugmEnum;
  2692. }
  2693. return TRUE ;
  2694. }
  2695. //-------------------------------------------------------------------------//
  2696. void CAugmentedMergeISF::FreeNamespaces()
  2697. {
  2698. DPA_DESTROY( _hdpaNamespaces, DestroyNamespacesProc ) ;
  2699. }
  2700. //-------------------------------------------------------------------------//
  2701. int CAugmentedMergeISF::DestroyNamespacesProc( LPVOID pv, LPVOID pvData )
  2702. {
  2703. CNamespace* p ;
  2704. if( NULL != (p = (CNamespace*)pv) )
  2705. delete p ;
  2706. return TRUE ;
  2707. }
  2708. STDMETHODIMP CAugmentedMergeISF::GetPidl(int* piPos, DWORD grfEnumFlags, LPITEMIDLIST* ppidl)
  2709. {
  2710. *ppidl = NULL;
  2711. if (_hdpaObjects == NULL)
  2712. AcquireObjects();
  2713. if (_hdpaObjects == NULL)
  2714. return E_OUTOFMEMORY;
  2715. BOOL fWantFolders = 0 != (grfEnumFlags & SHCONTF_FOLDERS),
  2716. fWantNonFolders = 0 != (grfEnumFlags & SHCONTF_NONFOLDERS),
  2717. fWantHidden = 0 != (grfEnumFlags & SHCONTF_INCLUDEHIDDEN) ;
  2718. while (*piPos < _count)
  2719. {
  2720. CAugISFEnumItem* paugmEnum = DPA_GETPTR( _hdpaObjects, *piPos, CAugISFEnumItem);
  2721. if ( NULL != paugmEnum )
  2722. {
  2723. BOOL fFolder = 0 != (paugmEnum->_rgfAttrib & SFGAO_FOLDER),
  2724. fHidden = 0 != (paugmEnum->_rgfAttrib & SFGAO_HIDDEN);
  2725. if ((!fHidden || fWantHidden) &&
  2726. ((fFolder && fWantFolders) || (!fFolder && fWantNonFolders)))
  2727. {
  2728. // Copy out the pidl ;
  2729. *ppidl = ILClone(paugmEnum->_pidlWrap);
  2730. break;
  2731. }
  2732. else
  2733. {
  2734. (*piPos)++;
  2735. }
  2736. }
  2737. }
  2738. if (*ppidl)
  2739. return S_OK;
  2740. return S_FALSE;
  2741. }
  2742. //-------------------------------------------------------------------------//
  2743. CEnum::CEnum(IAugmentedMergedShellFolderInternal* psmsfi, DWORD grfEnumFlags, int iPos) :
  2744. _cRef(1),
  2745. _iPos(iPos),
  2746. _psmsfi(psmsfi),
  2747. _grfEnumFlags(grfEnumFlags)
  2748. {
  2749. _psmsfi->AddRef();
  2750. }
  2751. CEnum::~CEnum()
  2752. {
  2753. ATOMICRELEASE(_psmsfi);
  2754. }
  2755. //-------------------------------------------------------------------------//
  2756. // class CEnum - IUnknown methods
  2757. //-------------------------------------------------------------------------//
  2758. //-------------------------------------------------------------------------//
  2759. STDMETHODIMP CEnum::QueryInterface( REFIID riid, LPVOID * ppvObj )
  2760. {
  2761. static const QITAB qit[] = {
  2762. QITABENT(CEnum, IEnumIDList),
  2763. { 0 }
  2764. };
  2765. return QISearch(this, qit, riid, ppvObj);
  2766. }
  2767. //-------------------------------------------------------------------------//
  2768. STDMETHODIMP_(ULONG) CEnum::AddRef ()
  2769. {
  2770. return InterlockedIncrement(&_cRef);
  2771. }
  2772. //-------------------------------------------------------------------------//
  2773. STDMETHODIMP_(ULONG) CEnum::Release ()
  2774. {
  2775. ASSERT( 0 != _cRef );
  2776. ULONG cRef = InterlockedDecrement(&_cRef);
  2777. if ( 0 == cRef )
  2778. {
  2779. delete this;
  2780. }
  2781. return cRef;
  2782. }
  2783. //-------------------------------------------------------------------------//
  2784. // class CEnum - IEnumIDList methods
  2785. //-------------------------------------------------------------------------//
  2786. STDMETHODIMP CEnum::Next(
  2787. ULONG celt,
  2788. LPITEMIDLIST *rgelt,
  2789. ULONG *pceltFetched )
  2790. {
  2791. int iStart = _iPos;
  2792. int cFetched = 0;
  2793. HRESULT hres = S_OK;
  2794. if( !(celt > 0 && rgelt) || (NULL == pceltFetched && celt > 1 ) )
  2795. return E_INVALIDARG ;
  2796. *rgelt = 0;
  2797. while(hres == S_OK && (_iPos - iStart) < (int)celt)
  2798. {
  2799. LPITEMIDLIST pidl;
  2800. hres = _psmsfi->GetPidl(&_iPos, _grfEnumFlags, &pidl);
  2801. if (hres == S_OK)
  2802. {
  2803. rgelt[cFetched] = pidl;
  2804. cFetched++ ;
  2805. }
  2806. _iPos++;
  2807. }
  2808. if( pceltFetched )
  2809. *pceltFetched = cFetched ;
  2810. return celt == (ULONG)cFetched ? S_OK : S_FALSE ;
  2811. }
  2812. //-------------------------------------------------------------------------//
  2813. STDMETHODIMP CEnum::Skip(ULONG celt)
  2814. {
  2815. _iPos += celt;
  2816. return S_OK ;
  2817. }
  2818. //-------------------------------------------------------------------------//
  2819. STDMETHODIMP CEnum::Reset()
  2820. {
  2821. _iPos = 0;
  2822. return S_OK ;
  2823. }
  2824. //-------------------------------------------------------------------------//
  2825. // REVIEW: Can probably be E_NOTIMPL
  2826. STDMETHODIMP CEnum::Clone( IEnumIDList **ppenum )
  2827. {
  2828. if( NULL == (*ppenum = new CEnum( _psmsfi, _grfEnumFlags, _iPos )) )
  2829. return E_OUTOFMEMORY;
  2830. return S_OK;
  2831. }
  2832. BOOL CAugISFEnumItem::Init(IShellFolder* psf, int iShellFolder, LPCITEMIDLIST pidl)
  2833. {
  2834. // This is ok, the memory just gets written to twice.
  2835. if (SUCCEEDED(AugMergeISF_CreateWrap(pidl, iShellFolder, &_pidlWrap)))
  2836. {
  2837. // Takes ownership of passed in pidl.
  2838. return InitWithWrappedToOwn(psf, iShellFolder, _pidlWrap);
  2839. }
  2840. return FALSE;
  2841. }
  2842. BOOL CAugISFEnumItem::InitWithWrappedToOwn(IShellFolder* psf, int iShellFolder, LPITEMIDLIST pidl)
  2843. {
  2844. BOOL fRet = FALSE;
  2845. STRRET str;
  2846. TCHAR szDisplayName[MAX_PATH];
  2847. _pidlWrap = pidl;
  2848. _rgfAttrib = SFGAO_FOLDER | SFGAO_HIDDEN;
  2849. psf->GetAttributesOf(1, (LPCITEMIDLIST*)&pidl, &_rgfAttrib);
  2850. if (SUCCEEDED(psf->GetDisplayNameOf(pidl, SHGDN_FORPARSING | SHGDN_INFOLDER, &str)) &&
  2851. SUCCEEDED(StrRetToBuf(&str, pidl, szDisplayName, ARRAYSIZE(szDisplayName))))
  2852. {
  2853. SetDisplayName(szDisplayName);
  2854. fRet = TRUE;
  2855. }
  2856. return fRet;
  2857. }