Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

716 lines
20 KiB

  1. /**************************************************************\
  2. FILE: NSCBand.cpp
  3. DESCRIPTION: implementation of CNSCBand. the class CNSCBand
  4. exists to support name space control bands. A name
  5. space control uses IShellFolder rooted in various
  6. namespaces including Favorites, history, Shell Name
  7. Space, etc. to depict a hierarchical UI
  8. representation of the given name space.
  9. AUTHOR: chrisny
  10. \**************************************************************/
  11. #include "priv.h"
  12. #include "sccls.h"
  13. #include "util.h"
  14. #include "resource.h"
  15. #include "dhuihand.h"
  16. #include "nscband.h"
  17. #include <varutil.h>
  18. #include <mluisupp.h>
  19. HRESULT CNSCBand::_Init(LPCITEMIDLIST pidl)
  20. {
  21. // further initialization happens in ShowDW
  22. _fInited = FALSE;
  23. _fVisible = FALSE;
  24. _fCanFocus = TRUE;
  25. _haccTree = LoadAccelerators(MLGetHinst(), MAKEINTRESOURCE(ACCEL_FAVBAR));
  26. // pidl can be real or a CSIDL_ constant
  27. if (HIWORD(pidl))
  28. _pidl = ILClone(pidl);
  29. else
  30. SHGetSpecialFolderLocation(NULL, LOWORD(pidl), &_pidl);
  31. return _pidl ? S_OK : E_FAIL;
  32. }
  33. CNSCBand::~CNSCBand()
  34. {
  35. if (_pidl)
  36. ILFree(_pidl);
  37. ATOMICRELEASE(_pns);
  38. ATOMICRELEASE(_pweh);
  39. if (_himlNormal)
  40. ImageList_Destroy(_himlNormal);
  41. if (_himlHot)
  42. ImageList_Destroy(_himlHot);
  43. }
  44. HRESULT CNSCBand::QueryInterface(REFIID riid, void **ppvObj)
  45. {
  46. static const QITAB qit[] = {
  47. QITABENT(CNSCBand, IContextMenu), // IID_IContextMenu
  48. QITABENT(CNSCBand, IWinEventHandler), // IID_IWinEventHandler
  49. QITABENT(CNSCBand, IBandNavigate), // IID_IBandNavigate
  50. QITABENT(CNSCBand, INamespaceProxy), // IID_INamespaceProxy
  51. { 0 },
  52. };
  53. HRESULT hres = QISearch(this, qit, riid, ppvObj);
  54. if (FAILED(hres))
  55. hres = CToolBand::QueryInterface(riid, ppvObj);
  56. return hres;
  57. }
  58. #ifndef ENABLE_CCHANNELBAND
  59. HRESULT CNSCBand_CreateInstanceEx(IUnknown *punkOuter, IUnknown **ppunk,
  60. LPCOBJECTINFO poi, LPCITEMIDLIST pidl)
  61. {
  62. // aggregation checking is handled in class factory
  63. HRESULT hres;
  64. CNSCBand * p = new CNSCBand();
  65. if (p)
  66. {
  67. hres = p->_Init(pidl);
  68. if (SUCCEEDED(hres))
  69. {
  70. p->_pns = CNscTree_CreateInstance();
  71. if (p->_pns)
  72. {
  73. p->_poi = poi;
  74. // if you change this cast, fix up CChannelBand_CreateInstance
  75. *ppunk = SAFECAST(p, IDeskBand *);
  76. IUnknown_SetSite(p->_pns, *ppunk);
  77. hres = S_OK;
  78. }
  79. }
  80. p->Release();
  81. }
  82. else
  83. hres = E_OUTOFMEMORY;
  84. return hres;
  85. }
  86. #endif
  87. #ifdef ENABLE_CHANNELS
  88. extern LPITEMIDLIST Channel_GetFolderPidl();
  89. HRESULT CChannelBand_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  90. {
  91. #ifndef ENABLE_CCHANNELBAND
  92. ASSERT(FALSE);
  93. return E_FAIL;
  94. #else
  95. HRESULT hres = CNSCBand_CreateInstanceEx(punkOuter, ppunk, poi, Channel_GetFolderPidl());
  96. if (*ppunk) {
  97. CNSCBand* p = (CNSCBand*)(IDeskBand*)*ppunk;
  98. p->_SetNscMode(MODE_CHANNELS);
  99. }
  100. return hres;
  101. #endif
  102. }
  103. #endif // ENABLE_CHANNELS
  104. extern HRESULT GetHistoryPIDL(LPITEMIDLIST *ppidlHistory);
  105. HRESULT CNSCBand::CloseDW(DWORD dw)
  106. {
  107. if (_fVisible)
  108. {
  109. _UnregisterBand();
  110. }
  111. if (_pns)
  112. {
  113. IUnknown_SetSite(_pns, NULL); // Break the ref-count cycle.
  114. }
  115. return CToolBand::CloseDW(dw);
  116. }
  117. void CNSCBand::_UnregisterBand()
  118. {
  119. IBrowserService *pswProxy;
  120. QueryService(SID_SProxyBrowser, IID_IBrowserService, (LPVOID*)&pswProxy);
  121. ASSERT(pswProxy);
  122. if (pswProxy)
  123. {
  124. IOleCommandTarget *poctProxy;
  125. if (SUCCEEDED(pswProxy->QueryInterface(IID_IOleCommandTarget, (void **)&poctProxy)))
  126. {
  127. VARIANT var;
  128. VariantInit(&var);
  129. // Register ourselves for SBCMDID_SELECTHISTPIDL,SBCMDID_INITFILECTXMENU
  130. var.vt = VT_UNKNOWN;
  131. QueryInterface(IID_IUnknown, (void **)&var.punkVal);
  132. poctProxy->Exec(&CGID_Explorer, SBCMDID_UNREGISTERNSCBAND, OLECMDEXECOPT_PROMPTUSER, &var, NULL);
  133. VariantClear(&var);
  134. poctProxy->Release();
  135. }
  136. pswProxy->Release();
  137. }
  138. }
  139. HRESULT CNSCBand::_InitializeNsc()
  140. {
  141. return _pns->Initialize(_pidl, _GetEnumFlags(), NSS_DROPTARGET | NSS_BROWSERSELECT);
  142. }
  143. HRESULT CNSCBand::ShowDW(BOOL fShow)
  144. {
  145. BOOL fIsHistory = IsEqualCLSID(*_poi->pclsid, CLSID_HistBand);
  146. if (fShow && _hwnd && !_fVisible)
  147. {
  148. IBrowserService *pswProxy;
  149. QueryService(SID_SProxyBrowser, IID_PPV_ARG(IBrowserService, &pswProxy));
  150. ASSERT(pswProxy);
  151. if (!_fInited)
  152. {
  153. _InitializeNsc();
  154. }
  155. else
  156. {
  157. _pns->ShowWindow(TRUE);
  158. }
  159. if (pswProxy)
  160. {
  161. IOleCommandTarget *poctProxy;
  162. if (SUCCEEDED(pswProxy->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &poctProxy))))
  163. {
  164. VARIANT var;
  165. VariantInit(&var);
  166. // Register ourselves for SBCMDID_SELECTHISTPIDL,SBCMDID_INITFILECTXMENU
  167. var.vt = VT_UNKNOWN;
  168. QueryInterface(IID_PPV_ARG(IUnknown, &var.punkVal));
  169. poctProxy->Exec(&CGID_Explorer, SBCMDID_REGISTERNSCBAND, OLECMDEXECOPT_PROMPTUSER, &var, NULL);
  170. //clear the variant cheaply
  171. var.vt = VT_EMPTY;
  172. Release();
  173. // do any special registration if necessary
  174. _OnRegisterBand(poctProxy);
  175. poctProxy->Release();
  176. }
  177. pswProxy->Release();
  178. }
  179. _fInited = TRUE;
  180. _fVisible = TRUE;
  181. }
  182. else if (!fShow && _fVisible)
  183. {
  184. _pns->ShowWindow(FALSE);
  185. _UnregisterBand();
  186. _fVisible = FALSE;
  187. }
  188. return CToolBand::ShowDW(fShow);
  189. }
  190. HRESULT CNSCBand::GetWindow(HWND *phwnd)
  191. {
  192. INSCTree2 *pns2;
  193. HRESULT hr = _pns->QueryInterface(IID_PPV_ARG(INSCTree2, &pns2));
  194. if (SUCCEEDED(hr))
  195. {
  196. pns2->CreateTree2(_hwndParent, _GetTVStyle(), _GetTVExStyle(), &_hwnd);
  197. hr = CToolBand::GetWindow(phwnd);
  198. pns2->Release();
  199. }
  200. return hr;
  201. }
  202. DWORD CNSCBand::_GetTVStyle()
  203. {
  204. DWORD dwFlags = TVS_FULLROWSELECT | TVS_TRACKSELECT | TVS_INFOTIP;
  205. DWORD dwValue;
  206. DWORD dwSize = SIZEOF(dwValue);
  207. BOOL fDefault = TRUE;
  208. SHRegGetUSValue(L"Software\\Microsoft\\Internet Explorer\\Main",
  209. L"NscSingleExpand", NULL, (LPBYTE)&dwValue, &dwSize, FALSE,
  210. (void *) &fDefault, SIZEOF(fDefault));
  211. if (dwValue)
  212. dwFlags |= TVS_SINGLEEXPAND;
  213. return dwFlags;
  214. }
  215. HRESULT CNSCBand::GetBandInfo(DWORD dwBandID, DWORD fViewMode,
  216. DESKBANDINFO* pdbi)
  217. {
  218. _dwBandID = dwBandID;
  219. pdbi->dwModeFlags = DBIMF_FIXEDBMP | DBIMF_VARIABLEHEIGHT;
  220. pdbi->ptMinSize.x = 16;
  221. pdbi->ptMinSize.y = 0;
  222. pdbi->ptMaxSize.x = 32000; // random
  223. pdbi->ptMaxSize.y = 32000; // random
  224. pdbi->ptActual.y = -1;
  225. pdbi->ptActual.x = -1;
  226. pdbi->ptIntegral.y = 1;
  227. if (_szTitle[0])
  228. {
  229. StrCpyNW(pdbi->wszTitle, _szTitle, ARRAYSIZE(pdbi->wszTitle));
  230. }
  231. else
  232. {
  233. CLSID clsid;
  234. UINT ids;
  235. GetClassID(&clsid);
  236. if (IsEqualIID(clsid, CLSID_FavBand))
  237. ids = IDS_BAND_FAVORITES;
  238. else if (IsEqualIID(clsid, CLSID_HistBand))
  239. ids = IDS_BAND_HISTORY;
  240. else if (IsEqualIID(clsid, CLSID_ExplorerBand))
  241. ids = IDS_BAND_EXPLORER;
  242. else
  243. {
  244. ASSERT(FALSE); // BOGUS BAND!!!
  245. return S_FALSE;
  246. }
  247. MLLoadStringW(ids, pdbi->wszTitle, ARRAYSIZE(pdbi->wszTitle));
  248. }
  249. return S_OK;
  250. }
  251. void _InitColors(BOOL fReinit);
  252. // *** IWinEventHandler methods ***
  253. HRESULT CNSCBand::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
  254. {
  255. HRESULT hr = E_FAIL;
  256. if (!_pweh && _pns)
  257. _pns->QueryInterface(IID_IWinEventHandler, (void **) &_pweh);
  258. // We need to tell the bandsite that we have become active if we're getting a
  259. // click focus or something
  260. if (uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->code == NM_SETFOCUS)
  261. {
  262. IUnknown_OnFocusChangeIS(_punkSite, SAFECAST(this, IInputObject*), TRUE);
  263. }
  264. if (_pweh)
  265. hr = _pweh->OnWinEvent(hwnd, uMsg, wParam, lParam, plres);
  266. return hr;
  267. }
  268. HRESULT CNSCBand::IsWindowOwner(HWND hwnd)
  269. {
  270. HRESULT hres;
  271. hres = SHIsChildOrSelf(_hwnd, hwnd);
  272. ASSERT(hwnd != NULL || hres == S_FALSE);
  273. ASSERT(_hwnd != NULL || hres == S_FALSE);
  274. return hres;
  275. }
  276. //*** CNSCBand::IPersistStream::* {
  277. HRESULT CNSCBand::GetClassID(CLSID *pClassID)
  278. {
  279. ASSERT(_poi->pclsid != NULL);
  280. *pClassID = *(_poi->pclsid);
  281. return S_OK;
  282. }
  283. HRESULT CNSCBand::Load(IStream *pstm)
  284. {
  285. return S_OK;
  286. }
  287. HRESULT CNSCBand::Save(IStream *pstm, BOOL fClearDirty)
  288. {
  289. return S_OK;
  290. }
  291. // }
  292. //*** CNSCBand::IContextMenu::* {
  293. HRESULT CNSCBand::QueryContextMenu(HMENU hmenu,
  294. UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
  295. {
  296. int i = 0;
  297. #if 0
  298. HMENU hmenuMe = LoadMenuPopup(MENU_IWBBAND);
  299. i += Shell_MergeMenus(hmenu, hmenuMe, indexMenu, idCmdFirst + i, idCmdLast, MM_ADDSEPARATOR) - (idCmdFirst + i);
  300. DestroyMenu(hmenuMe);
  301. #endif
  302. // aka (S_OK|i)
  303. return MAKE_HRESULT(ERROR_SUCCESS, FACILITY_NULL, i);
  304. }
  305. HRESULT CNSCBand::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
  306. {
  307. #if 0
  308. int idCmd = -1;
  309. if (!HIWORD(pici->lpVerb))
  310. idCmd = LOWORD(pici->lpVerb);
  311. switch (idCmd)
  312. {
  313. case default:
  314. TraceMsg(DM_ERROR, "cbb::ic cmd=%d not handled", idCmd);
  315. break;
  316. }
  317. #endif
  318. return S_OK;
  319. }
  320. HRESULT CNSCBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
  321. {
  322. if (pguidCmdGroup && IsEqualGUID(CGID_Explorer, *pguidCmdGroup))
  323. {
  324. for (UINT i=0; i < cCmds; i++)
  325. {
  326. rgCmds[i].cmdf = 0;
  327. switch (rgCmds[i].cmdID)
  328. {
  329. case SBCMDID_INITFILECTXMENU:
  330. if (_hwnd && _fVisible)
  331. {
  332. rgCmds->cmdf = 0;
  333. if (pcmdtext)
  334. pcmdtext->cmdtextf = 0;
  335. if (pcmdtext)
  336. {
  337. if (SUCCEEDED(_pns->GetSelectedItemName(pcmdtext->rgwz, pcmdtext->cwBuf)))
  338. {
  339. rgCmds->cmdf = OLECMDF_ENABLED;
  340. pcmdtext->cmdtextf = OLECMDTEXTF_NAME;
  341. pcmdtext->cwActual = lstrlenW(pcmdtext->rgwz) + 1;
  342. }
  343. }
  344. }
  345. break;
  346. case SBCMDID_FILERENAME:
  347. case SBCMDID_FILEDELETE:
  348. case SBCMDID_FILEPROPERTIES:
  349. {
  350. LPITEMIDLIST pidl;
  351. // get selected item can return NULL pidl and S_FALSE
  352. if (_pns->GetSelectedItem(&pidl, 0) == S_OK)
  353. {
  354. DWORD rgfAttrib = SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET; // CAN_LINK
  355. if (SUCCEEDED(IEGetAttributesOf(pidl, &rgfAttrib)))
  356. {
  357. DWORD nCmdID;
  358. static const DWORD tbtab[] = {
  359. SBCMDID_FILEDELETE, SBCMDID_FILEPROPERTIES, SBCMDID_FILERENAME };
  360. static const DWORD cttab[] = {
  361. SFGAO_CANDELETE, SFGAO_HASPROPSHEET, SFGAO_CANRENAME };
  362. nCmdID = SHSearchMapInt((int*)tbtab, (int*)cttab, ARRAYSIZE(tbtab), rgCmds[i].cmdID);
  363. if (nCmdID != -1 && (rgfAttrib & nCmdID))
  364. rgCmds[i].cmdf = OLECMDF_ENABLED;
  365. }
  366. ILFree(pidl);
  367. }
  368. break;
  369. }
  370. default:
  371. break;
  372. }
  373. }
  374. return S_OK;
  375. }
  376. return CToolBand::QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext);
  377. }
  378. HRESULT CNSCBand::_InvokeCommandOnItem(LPCTSTR pszVerb)
  379. {
  380. HRESULT hr;
  381. IContextMenu *pcm;
  382. hr = _QueryContextMenuSelection(&pcm);
  383. if (SUCCEEDED(hr))
  384. {
  385. CMINVOKECOMMANDINFOEX ici =
  386. {
  387. SIZEOF(CMINVOKECOMMANDINFOEX),
  388. 0L,
  389. _hwnd,
  390. NULL,
  391. NULL, NULL,
  392. SW_NORMAL,
  393. };
  394. #ifdef UNICODE
  395. CHAR szVerbAnsi[MAX_PATH];
  396. SHUnicodeToAnsi(pszVerb, szVerbAnsi, ARRAYSIZE(szVerbAnsi));
  397. ici.lpVerb = szVerbAnsi;
  398. ici.lpVerbW = pszVerb;
  399. ici.fMask |= CMIC_MASK_UNICODE;
  400. #else
  401. ici.lpVerb = pszVerb;
  402. #endif
  403. hr = pcm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
  404. pcm->Release();
  405. }
  406. return hr;
  407. }
  408. HRESULT CNSCBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  409. {
  410. if (pguidCmdGroup == NULL)
  411. {
  412. switch (nCmdID)
  413. {
  414. case OLECMDID_REFRESH:
  415. if (_pns)
  416. _pns->Refresh();
  417. return S_OK;
  418. }
  419. }
  420. else if (pguidCmdGroup && IsEqualGUID(CGID_Explorer, *pguidCmdGroup))
  421. {
  422. HRESULT hr = S_OK;
  423. switch (nCmdID)
  424. {
  425. case SBCMDID_SELECTHISTPIDL:
  426. if (IsEqualCLSID(*_poi->pclsid, CLSID_HistBand) && _hwnd && _fVisible)
  427. {
  428. // If you're not visible do nothing. On becoming visible
  429. // use Exec to proxy to get last pidlSelect that you would
  430. // have shown, had you been visible
  431. LPITEMIDLIST pidlSelect = VariantToIDList(pvarargIn);
  432. if (pidlSelect)
  433. {
  434. _pns->SetSelectedItem(pidlSelect, TRUE, FALSE, 0);
  435. ILFree(pidlSelect);
  436. }
  437. }
  438. break;
  439. case SBCMDID_INITFILECTXMENU:
  440. if (_hwnd && _fVisible)
  441. {
  442. if (pvarargOut)
  443. {
  444. VariantClearLazy(pvarargOut);
  445. HRESULT hres = _QueryContextMenuSelection((IContextMenu **)&(pvarargOut->punkVal));
  446. if (SUCCEEDED(hres))
  447. {
  448. pvarargOut->vt = VT_UNKNOWN;
  449. }
  450. }
  451. }
  452. break;
  453. case SBCMDID_FILERENAME:
  454. {
  455. IShellNameSpace *psfns;
  456. hr = _pns->QueryInterface(IID_PPV_ARG(IShellNameSpace, &psfns));
  457. if (SUCCEEDED(hr))
  458. {
  459. hr = psfns->InvokeContextMenuCommand(L"rename");
  460. psfns->Release();
  461. }
  462. break;
  463. }
  464. case SBCMDID_FILEDELETE:
  465. hr = _InvokeCommandOnItem(TEXT("delete"));
  466. break;
  467. case SBCMDID_FILEPROPERTIES:
  468. hr = _InvokeCommandOnItem(TEXT("properties"));
  469. break;
  470. default:
  471. hr = E_FAIL;
  472. break;
  473. }
  474. if (SUCCEEDED(hr))
  475. return hr;
  476. }
  477. return CToolBand::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  478. }
  479. HRESULT CNSCBand::_QueryContextMenuSelection(IContextMenu ** ppcm)
  480. {
  481. HRESULT hr = E_FAIL;
  482. LPITEMIDLIST pidlSelected;
  483. *ppcm = NULL;
  484. hr = _pns->GetSelectedItem(&pidlSelected, 0);
  485. if (SUCCEEDED(hr))
  486. {
  487. LPCITEMIDLIST pidlRelative;
  488. IShellFolder * psf;
  489. hr = IEBindToParentFolder(pidlSelected, &psf, &pidlRelative);
  490. if (SUCCEEDED(hr))
  491. {
  492. hr = psf->GetUIObjectOf(NULL, 1, &pidlRelative, IID_PPV_ARG_NULL(IContextMenu, ppcm));
  493. }
  494. ILFree(pidlSelected);
  495. }
  496. return hr;
  497. }
  498. HRESULT CNSCBand::Select(LPCITEMIDLIST pidl)
  499. {
  500. _pns->SetSelectedItem(pidl, TRUE, FALSE, 0);
  501. return S_OK;
  502. }
  503. // *** IInputObject Methods ***
  504. HRESULT CNSCBand::TranslateAcceleratorIO(LPMSG lpMsg)
  505. {
  506. HWND hwndFocus = GetFocus();
  507. if (_pns->InLabelEdit())
  508. return EditBox_TranslateAcceleratorST(lpMsg);
  509. else if ( lpMsg && lpMsg->hwnd && SendMessage(lpMsg->hwnd, TVM_TRANSLATEACCELERATOR, 0, (LPARAM)lpMsg))
  510. return S_OK;
  511. else if (hwndFocus == _hwnd && TranslateAcceleratorWrap(_hwnd, _haccTree, lpMsg))
  512. return S_OK;
  513. return S_FALSE;
  514. }
  515. void CNSCBand::_EnsureImageListsLoaded()
  516. {
  517. if (_himlNormal == NULL)
  518. _himlNormal = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_HISTORYANDFAVBANDSDEF), 18, 3, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
  519. if (_himlHot == NULL)
  520. _himlHot = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_HISTORYANDFAVBANDSHOT), 18, 3, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
  521. }
  522. HRESULT CNSCBand::_TranslatePidl(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidlTarget, ULONG *pulAttrib)
  523. {
  524. IShellFolder *psf;
  525. LPCITEMIDLIST pidlLast;
  526. HRESULT hr = SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast);
  527. if (SUCCEEDED(hr))
  528. {
  529. hr = SHGetNavigateTarget(psf, pidlLast, ppidlTarget, pulAttrib);
  530. psf->Release();
  531. }
  532. return hr;
  533. }
  534. // favorites, history and Explorer band should override this (they need not worry about channel band)
  535. BOOL CNSCBand::_ShouldNavigateToPidl(LPCITEMIDLIST pidl, ULONG ulAttrib)
  536. {
  537. BOOL bReturn = (ulAttrib & SFGAO_FOLDER);
  538. if (bReturn)
  539. {
  540. IShellFolder *psf;
  541. LPCITEMIDLIST pidlLast;
  542. HRESULT hr = SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast);
  543. if (SUCCEEDED(hr))
  544. {
  545. bReturn = IsExpandableChannelFolder(psf, pidlLast);
  546. psf->Release();
  547. }
  548. }
  549. return !bReturn;
  550. }
  551. HRESULT CNSCBand::GetNavigateTarget(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidlTarget, ULONG *pulAttrib)
  552. {
  553. HRESULT hr = _TranslatePidl(pidl, ppidlTarget, pulAttrib);
  554. if (SUCCEEDED(hr))
  555. {
  556. hr = _ShouldNavigateToPidl(pidl, *pulAttrib) ? S_OK : S_FALSE;
  557. if (hr == S_FALSE)
  558. {
  559. ILFree(*ppidlTarget);
  560. *ppidlTarget = NULL;
  561. }
  562. }
  563. return hr;
  564. }
  565. HRESULT CNSCBand::OnSelectionChanged(LPCITEMIDLIST pidl)
  566. {
  567. return S_OK;
  568. }
  569. HRESULT CNSCBand::Invoke(LPCITEMIDLIST pidl)
  570. {
  571. HRESULT hr = E_INVALIDARG;
  572. if (pidl)
  573. {
  574. IShellBrowser *psb;
  575. hr = IUnknown_QueryService(_punkSite, SID_SProxyBrowser, IID_PPV_ARG(IShellBrowser, &psb));
  576. if (SUCCEEDED(hr))
  577. {
  578. hr = _NavigateRightPane(psb, pidl);
  579. if (FAILED(hr))
  580. {
  581. IShellFolder *psf;
  582. LPCITEMIDLIST pidlChild;
  583. if (SUCCEEDED(SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild)))
  584. {
  585. DWORD dwAttributes = SFGAO_FOLDER;
  586. psf->GetAttributesOf(1, &pidlChild, &dwAttributes);
  587. if (!(dwAttributes & SFGAO_FOLDER))
  588. {
  589. hr = SHInvokeDefaultCommand(_hwnd, psf, pidlChild);
  590. }
  591. psf->Release();
  592. }
  593. }
  594. psb->Release();
  595. }
  596. }
  597. return hr;
  598. }
  599. HRESULT CNSCBand::_NavigateRightPane(IShellBrowser *psb, LPCITEMIDLIST pidl)
  600. {
  601. HRESULT hr = psb->BrowseObject(pidl, SBSP_SAMEBROWSER);
  602. if (SUCCEEDED(hr))
  603. UEMFireEvent(&UEMIID_BROWSER, UEME_INSTRBROWSER, UEMF_INSTRUMENT, UIBW_NAVIGATE, UIBL_NAVOTHER);
  604. return hr;
  605. }