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.

739 lines
24 KiB

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include "nscband.h"
  4. #include "resource.h"
  5. #include "uemapp.h" // KMTF: Included for instrumentation
  6. #include "shlguid.h"
  7. #include <dpa.h>
  8. #include <mluisupp.h>
  9. #include "varutil.h"
  10. #include "apithk.h"
  11. #define TF_EXPLORERBAND 0
  12. typedef struct
  13. {
  14. LPITEMIDLIST pidl;
  15. IShellFolder *psf;
  16. } SFCITEM;
  17. class CExplorerBand : public CNSCBand,
  18. public IDispatch
  19. {
  20. public:
  21. // *** IUnknown ***
  22. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  23. STDMETHODIMP_(ULONG) AddRef(void) { return CNSCBand::AddRef(); };
  24. STDMETHODIMP_(ULONG) Release(void) { return CNSCBand::Release(); };
  25. // *** IOleCommandTarget methods ***
  26. STDMETHODIMP QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext);
  27. STDMETHODIMP Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut);
  28. // *** IDockingWindow methods ***
  29. STDMETHODIMP CloseDW(DWORD dw);
  30. STDMETHODIMP ShowDW(BOOL fShow);
  31. // *** IObjectWithSite methods ***
  32. STDMETHODIMP SetSite(IUnknown* punkSite);
  33. // *** INamespaceProxy methods ***
  34. STDMETHODIMP Invoke(LPCITEMIDLIST pidl);
  35. STDMETHODIMP OnSelectionChanged(LPCITEMIDLIST pidl);
  36. STDMETHODIMP CacheItem(LPCITEMIDLIST pidl) {_MaybeAddToLegacySFC(pidl); return S_OK;}
  37. // *** IDispatch methods ***
  38. STDMETHODIMP GetTypeInfoCount(UINT *pctinfo) {return E_NOTIMPL;}
  39. STDMETHODIMP GetTypeInfo(UINT itinfo,LCID lcid,ITypeInfo **pptinfo) {return E_NOTIMPL;}
  40. STDMETHODIMP GetIDsOfNames(REFIID riid,OLECHAR **rgszNames,UINT cNames, LCID lcid, DISPID * rgdispid) {return E_NOTIMPL;}
  41. STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid, WORD wFlags,
  42. DISPPARAMS *pdispparams, VARIANT *pvarResult, EXCEPINFO *pexcepinfo, UINT *puArgErr);
  43. protected:
  44. CExplorerBand() : _fCanSelect(TRUE), _fIgnoreSelection(TRUE)
  45. {}
  46. virtual ~CExplorerBand();
  47. virtual HRESULT _TranslatePidl(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidlTarget, ULONG *pulAttrib);
  48. virtual BOOL _ShouldNavigateToPidl(LPCITEMIDLIST pidl, ULONG ulAttrib);
  49. virtual HRESULT _InitializeNsc();
  50. virtual DWORD _GetTVStyle();
  51. virtual DWORD _GetTVExStyle();
  52. virtual DWORD _GetEnumFlags();
  53. void _MaybeAddToLegacySFC(LPCITEMIDLIST pidl);
  54. void _AddToLegacySFC(LPCITEMIDLIST pidl, IShellFolder *psf);
  55. BOOL _IsInSFC(LPCITEMIDLIST pidl);
  56. BOOL _IsFloppy(LPCITEMIDLIST pidl);
  57. void _OnNavigate();
  58. HRESULT _ConnectToBrowser(BOOL fConnect);
  59. friend HRESULT CExplorerBand_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi);
  60. static void s_DVEnumReadyCallback(void *pvData);
  61. CDSA<SFCITEM> *_pdsaLegacySFC;
  62. DWORD _dwcpCookie;
  63. LPITEMIDLIST _pidlView; //pidl view is navigated to
  64. BOOL _fCanSelect;
  65. BOOL _fIgnoreSelection; //so we don't navigate away from the web page when user opens explorer pane
  66. BOOL _fFloppyRefresh;
  67. };
  68. HRESULT _UnwrapRootedPidl(LPCITEMIDLIST pidlRooted, BOOL bOnlyIfRooted, LPITEMIDLIST *ppidl)
  69. {
  70. HRESULT hr = E_FAIL;
  71. if (ILIsRooted(pidlRooted))
  72. {
  73. hr = SHILCombine(ILRootedFindIDList(pidlRooted), _ILNext(pidlRooted), ppidl);
  74. }
  75. else if (!bOnlyIfRooted)
  76. {
  77. hr = SHILClone(pidlRooted, ppidl);
  78. }
  79. return hr;
  80. }
  81. BOOL IsFTPPidl(LPCITEMIDLIST pidl)
  82. {
  83. BOOL fIsFTP = FALSE;
  84. IShellFolder * psf;
  85. if (pidl && SUCCEEDED(IEBindToObject(pidl, &psf)))
  86. {
  87. fIsFTP = IsFTPFolder(psf);
  88. psf->Release();
  89. }
  90. return fIsFTP;
  91. }
  92. void CExplorerBand::_OnNavigate()
  93. {
  94. IBrowserService* pbs;
  95. HRESULT hr = IUnknown_QueryService(_punkSite, SID_STopLevelBrowser, IID_PPV_ARG(IBrowserService, &pbs));
  96. if (SUCCEEDED(hr))
  97. {
  98. LPITEMIDLIST pidl;
  99. hr = pbs->GetPidl(&pidl);
  100. if (SUCCEEDED(hr))
  101. {
  102. LPITEMIDLIST pidlNew;
  103. hr = _UnwrapRootedPidl(pidl, FALSE, &pidlNew);
  104. if (SUCCEEDED(hr))
  105. {
  106. // We must go in this code path if the pidl is an FTP pidl. FTP pidls can contain
  107. // passwords so it needs to replace any existing pidl. Whistler #252206.
  108. if (!_pidlView || !ILIsEqual(pidlNew, _pidlView) || IsFTPPidl(pidlNew))
  109. {
  110. DWORD dwAttributes = SFGAO_FOLDER;
  111. // only let folders go through (to filter out Web pages)
  112. hr = IEGetAttributesOf(pidlNew, &dwAttributes);
  113. if (SUCCEEDED(hr) && (dwAttributes & SFGAO_FOLDER))
  114. {
  115. BOOL fExpand = (_pidlView == NULL); //the very first time we expand the folder the view is navigated to
  116. Pidl_Set(&_pidlView, pidlNew);
  117. _fIgnoreSelection = FALSE; //in the web page case we don't come here because the page does not have folder attribute
  118. if (_fCanSelect)
  119. {
  120. if (fExpand)
  121. {
  122. VARIANT var;
  123. hr = InitVariantFromIDList(&var, _pidlView);
  124. if (SUCCEEDED(hr))
  125. {
  126. IShellNameSpace *psns;
  127. hr = _pns->QueryInterface(IID_PPV_ARG(IShellNameSpace, &psns));
  128. if (SUCCEEDED(hr))
  129. {
  130. psns->Expand(var, 1);
  131. psns->Release();
  132. }
  133. VariantClear(&var);
  134. }
  135. }
  136. else
  137. {
  138. _pns->SetSelectedItem(_pidlView, TRUE, FALSE, 0);
  139. }
  140. }
  141. }
  142. }
  143. // view navigation is asynchronous so we don't know if it failed in OnSelectionChanged
  144. // but the view is getting navigated to the old pidl and _fCanSelect is false (which happens after we try
  145. // to navigate the view) so it is safe to assume that navigation failed.
  146. // we need to update the selection to match the view
  147. else if (ILIsEqual(pidlNew, _pidlView) && !_fCanSelect)
  148. {
  149. _pns->SetSelectedItem(_pidlView, TRUE, FALSE, 0);
  150. }
  151. _fCanSelect = TRUE;
  152. ILFree(pidlNew);
  153. }
  154. ILFree(pidl);
  155. }
  156. pbs->Release();
  157. }
  158. if (FAILED(hr))
  159. {
  160. Pidl_Set(&_pidlView, NULL);
  161. }
  162. }
  163. HRESULT CExplorerBand::Invoke(DISPID dispidMember, REFIID riid,LCID lcid, WORD wFlags,
  164. DISPPARAMS *pdispparams, VARIANT *pvarResult,
  165. EXCEPINFO *pexcepinfo, UINT *puArgErr)
  166. {
  167. HRESULT hr = S_OK;
  168. if (!pdispparams)
  169. return E_INVALIDARG;
  170. switch(dispidMember)
  171. {
  172. case DISPID_NAVIGATECOMPLETE2:
  173. case DISPID_DOCUMENTCOMPLETE:
  174. {
  175. BOOL fCallNavigateFinished = TRUE;
  176. IDVGetEnum *pdvge;
  177. if (SUCCEEDED(IUnknown_QueryService(_punkSite, SID_SFolderView, IID_PPV_ARG(IDVGetEnum, &pdvge))))
  178. {
  179. // callback will call it
  180. fCallNavigateFinished = FALSE;
  181. if (dispidMember == DISPID_NAVIGATECOMPLETE2)
  182. pdvge->SetEnumReadyCallback(s_DVEnumReadyCallback, this);
  183. pdvge->Release();
  184. }
  185. _OnNavigate();
  186. if (fCallNavigateFinished && DISPID_DOCUMENTCOMPLETE == dispidMember)
  187. {
  188. // need to let nsc know the navigation finished in case we navigated to a 3rd party namespace extension (w/ its own view impl)
  189. // because it does not implement IDVGetEnum, hence s_DVEnumReadyCallback will not get called
  190. LPITEMIDLIST pidlClone = ILClone(_pidlView);
  191. // should we unwrap this pidl if rooted?
  192. if (pidlClone)
  193. _pns->RightPaneNavigationFinished(pidlClone); // takes ownership
  194. }
  195. }
  196. break;
  197. default:
  198. hr = E_INVALIDARG;
  199. break;
  200. }
  201. return hr;
  202. }
  203. void CExplorerBand::s_DVEnumReadyCallback(void *pvData)
  204. {
  205. CExplorerBand *peb = (CExplorerBand *) pvData;
  206. IBrowserService* pbs;
  207. if (SUCCEEDED(IUnknown_QueryService(peb->_punkSite, SID_STopLevelBrowser, IID_PPV_ARG(IBrowserService, &pbs))))
  208. {
  209. LPITEMIDLIST pidlTemp;
  210. if (SUCCEEDED(pbs->GetPidl(&pidlTemp)))
  211. {
  212. LPITEMIDLIST pidl;
  213. if (SUCCEEDED(_UnwrapRootedPidl(pidlTemp, FALSE, &pidl)))
  214. {
  215. peb->_pns->RightPaneNavigationFinished(pidl); // takes ownership
  216. }
  217. ILFree(pidlTemp);
  218. }
  219. pbs->Release();
  220. }
  221. }
  222. const TCHAR c_szLink[] = TEXT("link");
  223. const TCHAR c_szRename[] = TEXT("rename");
  224. const TCHAR c_szMove[] = TEXT("cut");
  225. const TCHAR c_szPaste[] = TEXT("paste");
  226. const TCHAR c_szCopy[] = TEXT("copy");
  227. const TCHAR c_szDelete[] = TEXT("delete");
  228. const TCHAR c_szProperties[] = TEXT("properties");
  229. // IOleCommandTarget
  230. HRESULT CExplorerBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
  231. {
  232. if (pguidCmdGroup == NULL)
  233. {
  234. IContextMenu *pcm = NULL;
  235. HRESULT hr = _QueryContextMenuSelection(&pcm);
  236. if (SUCCEEDED(hr))
  237. {
  238. HMENU hmenu = CreatePopupMenu();
  239. if (hmenu)
  240. {
  241. hr = pcm->QueryContextMenu(hmenu, 0, 0, 255, 0);
  242. if (SUCCEEDED(hr))
  243. {
  244. UINT ilast = GetMenuItemCount(hmenu);
  245. for (UINT ipos=0; ipos < ilast; ipos++)
  246. {
  247. MENUITEMINFO mii = {0};
  248. TCHAR szVerb[40];
  249. UINT idCmd;
  250. mii.cbSize = SIZEOF(MENUITEMINFO);
  251. mii.fMask = MIIM_ID|MIIM_STATE;
  252. if (!GetMenuItemInfoWrap(hmenu, ipos, TRUE, &mii)) continue;
  253. if (0 != (mii.fState & (MF_GRAYED|MF_DISABLED))) continue;
  254. idCmd = mii.wID;
  255. hr = ContextMenu_GetCommandStringVerb(pcm, idCmd, szVerb, ARRAYSIZE(szVerb));
  256. if (SUCCEEDED(hr))
  257. {
  258. LPCTSTR szCmd = NULL;
  259. for (ULONG cItem = 0; cItem < cCmds; cItem++)
  260. {
  261. switch (rgCmds[cItem].cmdID)
  262. {
  263. case OLECMDID_CUT:
  264. szCmd = c_szMove;
  265. break;
  266. case OLECMDID_COPY:
  267. szCmd = c_szCopy;
  268. break;
  269. case OLECMDID_PASTE:
  270. szCmd = c_szPaste;
  271. break;
  272. case OLECMDID_DELETE:
  273. szCmd = c_szDelete;
  274. break;
  275. case OLECMDID_PROPERTIES:
  276. szCmd = c_szProperties;
  277. break;
  278. }
  279. if (StrCmpI(szVerb, szCmd)==0)
  280. {
  281. rgCmds[cItem].cmdf = OLECMDF_ENABLED;
  282. }
  283. }
  284. }
  285. }
  286. }
  287. DestroyMenu(hmenu);
  288. }
  289. else
  290. {
  291. hr = E_FAIL;
  292. }
  293. pcm->Release();
  294. }
  295. if (SUCCEEDED(hr))
  296. return hr;
  297. }
  298. return CNSCBand::QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext);
  299. }
  300. HRESULT CExplorerBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  301. {
  302. if (pguidCmdGroup == NULL)
  303. {
  304. HRESULT hr;
  305. switch(nCmdID)
  306. {
  307. case OLECMDID_CUT:
  308. hr = _InvokeCommandOnItem(c_szMove);
  309. break;
  310. case OLECMDID_COPY:
  311. hr = _InvokeCommandOnItem(c_szCopy);
  312. break;
  313. case OLECMDID_PASTE:
  314. hr = _InvokeCommandOnItem(c_szPaste);
  315. break;
  316. case OLECMDID_DELETE:
  317. hr = _InvokeCommandOnItem(c_szDelete);
  318. break;
  319. case OLECMDID_PROPERTIES:
  320. hr = _InvokeCommandOnItem(c_szProperties);
  321. break;
  322. default:
  323. hr = E_FAIL;
  324. break;
  325. }
  326. if (SUCCEEDED(hr))
  327. return hr;
  328. }
  329. return CNSCBand::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  330. }
  331. // IDockingWindow
  332. HRESULT CExplorerBand::CloseDW(DWORD dw)
  333. {
  334. _ConnectToBrowser(FALSE);
  335. return CNSCBand::CloseDW(dw);
  336. }
  337. HRESULT CExplorerBand::ShowDW(BOOL fShow)
  338. {
  339. return CNSCBand::ShowDW(fShow);
  340. }
  341. // IObjectWithSite
  342. HRESULT CExplorerBand::SetSite(IUnknown* punkSite)
  343. {
  344. HRESULT hr = CNSCBand::SetSite(punkSite);
  345. if (punkSite)
  346. _ConnectToBrowser(TRUE);
  347. return hr;
  348. }
  349. int _SFCDestroyCB(SFCITEM *psfcItem, void *pv)
  350. {
  351. psfcItem->psf->Release();
  352. ILFree(psfcItem->pidl);
  353. return 1;
  354. }
  355. CExplorerBand::~CExplorerBand()
  356. {
  357. ILFree(_pidlView);
  358. if (_pdsaLegacySFC)
  359. {
  360. _pdsaLegacySFC->DestroyCallback(_SFCDestroyCB, NULL);
  361. delete _pdsaLegacySFC;
  362. }
  363. }
  364. HRESULT CExplorerBand::QueryInterface(REFIID riid, void **ppvObj)
  365. {
  366. static const QITAB qit[] = {
  367. QITABENT(CExplorerBand, IDispatch),
  368. { 0 },
  369. };
  370. HRESULT hr = QISearch(this, qit, riid, ppvObj);
  371. if (FAILED(hr))
  372. hr = CNSCBand::QueryInterface(riid, ppvObj);
  373. return hr;
  374. }
  375. DWORD CExplorerBand::_GetEnumFlags()
  376. {
  377. DWORD dwFlags = SHCONTF_FOLDERS;
  378. SHELLSTATE ss = {0};
  379. SHGetSetSettings(&ss, SSF_SHOWALLOBJECTS, FALSE);
  380. if (ss.fShowAllObjects)
  381. dwFlags |= SHCONTF_INCLUDEHIDDEN;
  382. return dwFlags;
  383. }
  384. DWORD CExplorerBand::_GetTVExStyle()
  385. {
  386. DWORD dwExStyle = 0;
  387. if (IsOS(OS_WHISTLERORGREATER) &&
  388. SHRegGetBoolUSValue(TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"),
  389. TEXT("FriendlyTree"), FALSE, TRUE))
  390. {
  391. dwExStyle |= TVS_EX_NOSINGLECOLLAPSE;
  392. }
  393. return dwExStyle;
  394. }
  395. DWORD CExplorerBand::_GetTVStyle()
  396. {
  397. DWORD dwStyle = WS_CHILD | WS_CLIPSIBLINGS | WS_TABSTOP | WS_HSCROLL | TVS_EDITLABELS | TVS_SHOWSELALWAYS;
  398. if (SHRegGetBoolUSValue(TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"), TEXT("FriendlyTree"), FALSE, TRUE))
  399. {
  400. dwStyle |= TVS_HASBUTTONS | TVS_SINGLEEXPAND | TVS_TRACKSELECT;
  401. }
  402. else
  403. {
  404. dwStyle |= TVS_HASBUTTONS | TVS_HASLINES;
  405. }
  406. // If the parent window is mirrored then the treeview window will inheret the mirroring flag
  407. // And we need the reading order to be Left to right, which is the right to left in the mirrored mode.
  408. if (_hwndParent && IS_WINDOW_RTL_MIRRORED(_hwndParent))
  409. {
  410. // This means left to right reading order because this window will be mirrored.
  411. _dwStyle |= TVS_RTLREADING;
  412. }
  413. return dwStyle;
  414. }
  415. HRESULT CExplorerBand_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  416. {
  417. // aggregation checking is handled in class factory
  418. CExplorerBand * peb = new CExplorerBand();
  419. if (!peb)
  420. return E_OUTOFMEMORY;
  421. if (SUCCEEDED(peb->_Init((LPCITEMIDLIST)CSIDL_DESKTOP)))
  422. {
  423. peb->_pns = CNscTree_CreateInstance();
  424. if (peb->_pns)
  425. {
  426. ASSERT(poi);
  427. peb->_poi = poi;
  428. // if you change this cast, fix up CFavBand_CreateInstance
  429. *ppunk = SAFECAST(peb, IDeskBand *);
  430. IUnknown_SetSite(peb->_pns, *ppunk);
  431. peb->_SetNscMode(MODE_NORMAL);
  432. return S_OK;
  433. }
  434. }
  435. peb->Release();
  436. return E_FAIL;
  437. }
  438. HRESULT CExplorerBand::_ConnectToBrowser(BOOL fConnect)
  439. {
  440. IBrowserService* pbs;
  441. HRESULT hr = IUnknown_QueryService(_punkSite, SID_STopLevelBrowser, IID_PPV_ARG(IBrowserService, &pbs));
  442. if (SUCCEEDED(hr))
  443. {
  444. if (fConnect)
  445. {
  446. LPITEMIDLIST pidlTemp = NULL;
  447. // try to get the pidl the browser is navigated to
  448. // this usually fails if user just opened Explorer window because navigation is asynchronous
  449. // so we're not initialized yet
  450. if (FAILED(pbs->GetPidl(&pidlTemp)))
  451. {
  452. IBrowserService2 *pbs2;
  453. if (SUCCEEDED(pbs->QueryInterface(IID_PPV_ARG(IBrowserService2, &pbs2))))
  454. {
  455. LPCBASEBROWSERDATA pbbd;
  456. // our last hope is the pidl browser is navigating to...
  457. if (SUCCEEDED(pbs2->GetBaseBrowserData(&pbbd)) && pbbd->_pidlPending)
  458. {
  459. pidlTemp = ILClone(pbbd->_pidlPending);
  460. }
  461. pbs2->Release();
  462. }
  463. }
  464. if (pidlTemp)
  465. {
  466. LPITEMIDLIST pidl;
  467. // see if we're dealing with a rooted namespace
  468. if (SUCCEEDED(_UnwrapRootedPidl(pidlTemp, TRUE, &pidl)))
  469. {
  470. _Init(pidl); //if so, reinitialize ourself with the rooted pidl
  471. ILFree(pidl);
  472. }
  473. ILFree(pidlTemp);
  474. }
  475. }
  476. IConnectionPointContainer* pcpc;
  477. hr = IUnknown_QueryService(pbs, SID_SWebBrowserApp, IID_PPV_ARG(IConnectionPointContainer, &pcpc));
  478. // Let's now have the Browser Window give us notification when something happens.
  479. if (SUCCEEDED(hr))
  480. {
  481. hr = ConnectToConnectionPoint(SAFECAST(this, IDispatch*), DIID_DWebBrowserEvents2, fConnect,
  482. pcpc, &_dwcpCookie, NULL);
  483. pcpc->Release();
  484. }
  485. pbs->Release();
  486. }
  487. ASSERT(SUCCEEDED(hr));
  488. return hr;
  489. }
  490. HRESULT CExplorerBand::_InitializeNsc()
  491. {
  492. HRESULT hr = _pns->Initialize(_pidl, _GetEnumFlags(), NSS_DROPTARGET | NSS_BROWSERSELECT);
  493. if (SUCCEEDED(hr))
  494. _OnNavigate();
  495. return hr;
  496. }
  497. HRESULT CExplorerBand::_TranslatePidl(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidlTarget, ULONG *pulAttrib)
  498. {
  499. HRESULT hr = E_INVALIDARG;
  500. if (pidl && ppidlTarget && pulAttrib)
  501. {
  502. hr = IEGetAttributesOf(pidl, pulAttrib);
  503. if (SUCCEEDED(hr))
  504. {
  505. hr = SHILClone(pidl, ppidlTarget);
  506. }
  507. }
  508. return hr;
  509. }
  510. BOOL CExplorerBand::_ShouldNavigateToPidl(LPCITEMIDLIST pidl, ULONG ulAttrib)
  511. {
  512. return ulAttrib & SFGAO_FOLDER;
  513. }
  514. BOOL CExplorerBand::_IsFloppy(LPCITEMIDLIST pidl)
  515. {
  516. BOOL fRet = FALSE;
  517. WCHAR szPath[MAX_PATH];
  518. if (SUCCEEDED(SHGetNameAndFlags(pidl, SHGDN_FORPARSING, szPath, ARRAYSIZE(szPath), NULL)))
  519. {
  520. if (DRIVE_REMOVABLE == GetDriveType(szPath))
  521. {
  522. fRet = (L'A' == szPath[0] || L'B' == szPath[0] || L'a' == szPath[0] || L'b' == szPath[0]);
  523. }
  524. }
  525. return fRet;
  526. }
  527. HRESULT CExplorerBand::Invoke(LPCITEMIDLIST pidl)
  528. {
  529. HRESULT hr;
  530. // allow user to navigate to an already selected item if they opened Explorer band in Web browser
  531. // (because we put selection on the root node but don't navigate away from the web page, if they click
  532. // on the root we don't navigate there, because selection never changed)
  533. if (!_pidlView)
  534. {
  535. _fIgnoreSelection = FALSE;
  536. hr = OnSelectionChanged(pidl);
  537. }
  538. else if (ILIsEqual(pidl, _pidlView) && _IsFloppy(pidl))
  539. {
  540. // If the drive is a floppy and the user reselects the drive refresh the contents. This enables
  541. // a user to refresh when a floppy is replaced.
  542. _fFloppyRefresh = TRUE;
  543. hr = OnSelectionChanged(pidl);
  544. _fFloppyRefresh = FALSE;
  545. }
  546. else
  547. {
  548. hr = S_OK;
  549. }
  550. return hr;
  551. }
  552. HRESULT CExplorerBand::OnSelectionChanged(LPCITEMIDLIST pidl)
  553. {
  554. HRESULT hr = E_INVALIDARG;
  555. if (!_fIgnoreSelection)
  556. {
  557. if (pidl)
  558. {
  559. ULONG ulAttrib = SFGAO_FOLDER;
  560. LPITEMIDLIST pidlTarget;
  561. hr = GetNavigateTarget(pidl, &pidlTarget, &ulAttrib);
  562. if (hr == S_OK)
  563. {
  564. if (!_pidlView || _fFloppyRefresh || !ILIsEqual(pidlTarget, _pidlView))
  565. {
  566. hr = CNSCBand::Invoke(pidlTarget);
  567. if (SUCCEEDED(hr))
  568. _fCanSelect = FALSE;
  569. _pns->RightPaneNavigationStarted(pidlTarget);
  570. pidlTarget = NULL; // ownership passed
  571. }
  572. ILFree(pidlTarget);
  573. }
  574. #ifdef DEBUG
  575. else if (hr == S_FALSE)
  576. {
  577. ASSERT(pidlTarget == NULL);
  578. }
  579. #endif
  580. }
  581. }
  582. else
  583. {
  584. _fIgnoreSelection = FALSE; //we ignore only first selection
  585. }
  586. return hr;
  587. }
  588. void CExplorerBand::_MaybeAddToLegacySFC(LPCITEMIDLIST pidl)
  589. {
  590. IShellFolder *psf = NULL;
  591. if (pidl && SUCCEEDED(SHBindToObjectEx(NULL, pidl, NULL, IID_PPV_ARG(IShellFolder, &psf))))
  592. {
  593. //
  594. // APPCOMPAT LEGACY - Compatibility. needs the Shell folder cache, - ZekeL - 4-MAY-99
  595. // some apps, specifically WS_FTP and AECO Zip Pro,
  596. // rely on having a shellfolder existing in order for them to work.
  597. // we pulled the SFC because it wasnt any perf win.
  598. //
  599. if (OBJCOMPATF_OTNEEDSSFCACHE & SHGetObjectCompatFlags(psf, NULL))
  600. _AddToLegacySFC(pidl, psf);
  601. psf->Release();
  602. }
  603. }
  604. BOOL CExplorerBand::_IsInSFC(LPCITEMIDLIST pidl)
  605. {
  606. BOOL bReturn = FALSE;
  607. ASSERT(_pdsaLegacySFC);
  608. for (int i=0; i<_pdsaLegacySFC->GetItemCount(); i++)
  609. {
  610. SFCITEM *psfcItem = _pdsaLegacySFC->GetItemPtr(i);
  611. if (ILIsEqual(psfcItem->pidl, pidl))
  612. {
  613. bReturn = TRUE;
  614. break;
  615. }
  616. }
  617. return bReturn;
  618. }
  619. void CExplorerBand::_AddToLegacySFC(LPCITEMIDLIST pidl, IShellFolder *psf)
  620. {
  621. if (!_pdsaLegacySFC)
  622. {
  623. _pdsaLegacySFC = new CDSA<SFCITEM>;
  624. if (_pdsaLegacySFC && !_pdsaLegacySFC->Create(4))
  625. {
  626. delete _pdsaLegacySFC;
  627. _pdsaLegacySFC = NULL;
  628. }
  629. }
  630. if (_pdsaLegacySFC)
  631. {
  632. LPITEMIDLIST pidlCache;
  633. if (!_IsInSFC(pidl) && SUCCEEDED(SHILClone(pidl, &pidlCache)))
  634. {
  635. SFCITEM sfc = {pidlCache, psf};
  636. if (-1 != _pdsaLegacySFC->InsertItem(0, &sfc))
  637. psf->AddRef();
  638. else
  639. ILFree(pidlCache);
  640. }
  641. }
  642. }