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.

635 lines
18 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. extern HRESULT GetHistoryPIDL(LPITEMIDLIST *ppidlHistory);
  59. HRESULT CNSCBand::CloseDW(DWORD dw)
  60. {
  61. if (_fVisible)
  62. {
  63. _UnregisterBand();
  64. }
  65. if (_pns)
  66. {
  67. IUnknown_SetSite(_pns, NULL); // Break the ref-count cycle.
  68. }
  69. return CToolBand::CloseDW(dw);
  70. }
  71. void CNSCBand::_UnregisterBand()
  72. {
  73. IBrowserService *pswProxy;
  74. QueryService(SID_SProxyBrowser, IID_PPV_ARG(IBrowserService, &pswProxy));
  75. ASSERT(pswProxy);
  76. if (pswProxy)
  77. {
  78. IOleCommandTarget *poctProxy;
  79. if (SUCCEEDED(pswProxy->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &poctProxy))))
  80. {
  81. VARIANT var;
  82. VariantInit(&var);
  83. // Register ourselves for SBCMDID_SELECTHISTPIDL,SBCMDID_INITFILECTXMENU
  84. var.vt = VT_UNKNOWN;
  85. QueryInterface(IID_PPV_ARG(IUnknown, &var.punkVal));
  86. poctProxy->Exec(&CGID_Explorer, SBCMDID_UNREGISTERNSCBAND, OLECMDEXECOPT_PROMPTUSER, &var, NULL);
  87. VariantClear(&var);
  88. poctProxy->Release();
  89. }
  90. pswProxy->Release();
  91. }
  92. }
  93. HRESULT CNSCBand::_InitializeNsc()
  94. {
  95. return _pns->Initialize(_pidl, _GetEnumFlags(), NSS_DROPTARGET | NSS_BROWSERSELECT);
  96. }
  97. HRESULT CNSCBand::ShowDW(BOOL fShow)
  98. {
  99. BOOL fIsHistory = IsEqualCLSID(*_poi->pclsid, CLSID_HistBand);
  100. if (fShow && _hwnd && !_fVisible)
  101. {
  102. IBrowserService *pswProxy;
  103. QueryService(SID_SProxyBrowser, IID_PPV_ARG(IBrowserService, &pswProxy));
  104. ASSERT(pswProxy);
  105. if (!_fInited)
  106. {
  107. _InitializeNsc();
  108. }
  109. else
  110. {
  111. _pns->ShowWindow(TRUE);
  112. }
  113. if (pswProxy)
  114. {
  115. IOleCommandTarget *poctProxy;
  116. if (SUCCEEDED(pswProxy->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &poctProxy))))
  117. {
  118. VARIANT var;
  119. VariantInit(&var);
  120. // Register ourselves for SBCMDID_SELECTHISTPIDL,SBCMDID_INITFILECTXMENU
  121. var.vt = VT_UNKNOWN;
  122. QueryInterface(IID_PPV_ARG(IUnknown, &var.punkVal));
  123. poctProxy->Exec(&CGID_Explorer, SBCMDID_REGISTERNSCBAND, OLECMDEXECOPT_PROMPTUSER, &var, NULL);
  124. //clear the variant cheaply
  125. var.vt = VT_EMPTY;
  126. Release();
  127. // do any special registration if necessary
  128. _OnRegisterBand(poctProxy);
  129. poctProxy->Release();
  130. }
  131. pswProxy->Release();
  132. }
  133. _fInited = TRUE;
  134. _fVisible = TRUE;
  135. }
  136. else if (!fShow && _fVisible)
  137. {
  138. _pns->ShowWindow(FALSE);
  139. _UnregisterBand();
  140. _fVisible = FALSE;
  141. }
  142. return CToolBand::ShowDW(fShow);
  143. }
  144. HRESULT CNSCBand::GetWindow(HWND *phwnd)
  145. {
  146. INSCTree2 *pns2;
  147. HRESULT hr = _pns->QueryInterface(IID_PPV_ARG(INSCTree2, &pns2));
  148. if (SUCCEEDED(hr))
  149. {
  150. pns2->CreateTree2(_hwndParent, _GetTVStyle(), _GetTVExStyle(), &_hwnd);
  151. hr = CToolBand::GetWindow(phwnd);
  152. pns2->Release();
  153. }
  154. return hr;
  155. }
  156. DWORD CNSCBand::_GetTVStyle()
  157. {
  158. DWORD dwFlags = TVS_FULLROWSELECT | TVS_TRACKSELECT | TVS_INFOTIP;
  159. DWORD dwValue;
  160. DWORD dwSize = SIZEOF(dwValue);
  161. BOOL fDefault = TRUE;
  162. SHRegGetUSValue(L"Software\\Microsoft\\Internet Explorer\\Main",
  163. L"NscSingleExpand", NULL, (LPBYTE)&dwValue, &dwSize, FALSE,
  164. (void *) &fDefault, sizeof(fDefault));
  165. if (dwValue)
  166. dwFlags |= TVS_SINGLEEXPAND;
  167. return dwFlags;
  168. }
  169. HRESULT CNSCBand::GetBandInfo(DWORD dwBandID, DWORD fViewMode,
  170. DESKBANDINFO* pdbi)
  171. {
  172. _dwBandID = dwBandID;
  173. pdbi->dwModeFlags = DBIMF_FIXEDBMP | DBIMF_VARIABLEHEIGHT;
  174. pdbi->ptMinSize.x = 16;
  175. pdbi->ptMinSize.y = 0;
  176. pdbi->ptMaxSize.x = 32000; // random
  177. pdbi->ptMaxSize.y = 32000; // random
  178. pdbi->ptActual.y = -1;
  179. pdbi->ptActual.x = -1;
  180. pdbi->ptIntegral.y = 1;
  181. if (_szTitle[0])
  182. {
  183. StrCpyNW(pdbi->wszTitle, _szTitle, ARRAYSIZE(pdbi->wszTitle));
  184. }
  185. else
  186. {
  187. CLSID clsid;
  188. UINT ids;
  189. GetClassID(&clsid);
  190. if (IsEqualIID(clsid, CLSID_FavBand))
  191. ids = IDS_BAND_FAVORITES;
  192. else if (IsEqualIID(clsid, CLSID_HistBand))
  193. ids = IDS_BAND_HISTORY;
  194. else if (IsEqualIID(clsid, CLSID_ExplorerBand))
  195. ids = IDS_BAND_EXPLORER;
  196. else
  197. {
  198. ASSERT(FALSE); // BOGUS BAND!!!
  199. return S_FALSE;
  200. }
  201. MLLoadStringW(ids, pdbi->wszTitle, ARRAYSIZE(pdbi->wszTitle));
  202. }
  203. return S_OK;
  204. }
  205. void _InitColors(BOOL fReinit);
  206. // *** IWinEventHandler methods ***
  207. HRESULT CNSCBand::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
  208. {
  209. HRESULT hr = E_FAIL;
  210. if (!_pweh && _pns)
  211. _pns->QueryInterface(IID_PPV_ARG(IWinEventHandler, &_pweh));
  212. // We need to tell the bandsite that we have become active if we're getting a
  213. // click focus or something
  214. if (uMsg == WM_NOTIFY && ((LPNMHDR)lParam)->code == NM_SETFOCUS)
  215. {
  216. IUnknown_OnFocusChangeIS(_punkSite, SAFECAST(this, IInputObject*), TRUE);
  217. }
  218. if (_pweh)
  219. hr = _pweh->OnWinEvent(hwnd, uMsg, wParam, lParam, plres);
  220. return hr;
  221. }
  222. HRESULT CNSCBand::IsWindowOwner(HWND hwnd)
  223. {
  224. HRESULT hr = SHIsChildOrSelf(_hwnd, hwnd);
  225. ASSERT(hwnd != NULL || hr == S_FALSE);
  226. ASSERT(_hwnd != NULL || hr == S_FALSE);
  227. return hr;
  228. }
  229. //*** CNSCBand::IPersistStream::* {
  230. HRESULT CNSCBand::GetClassID(CLSID *pClassID)
  231. {
  232. ASSERT(_poi->pclsid != NULL);
  233. *pClassID = *(_poi->pclsid);
  234. return S_OK;
  235. }
  236. HRESULT CNSCBand::Load(IStream *pstm)
  237. {
  238. return S_OK;
  239. }
  240. HRESULT CNSCBand::Save(IStream *pstm, BOOL fClearDirty)
  241. {
  242. return S_OK;
  243. }
  244. // }
  245. //*** CNSCBand::IContextMenu::* {
  246. HRESULT CNSCBand::QueryContextMenu(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
  247. {
  248. // aka (S_OK|i)
  249. return MAKE_HRESULT(ERROR_SUCCESS, FACILITY_NULL, 0);
  250. }
  251. HRESULT CNSCBand::InvokeCommand(LPCMINVOKECOMMANDINFO pici)
  252. {
  253. return S_OK;
  254. }
  255. HRESULT CNSCBand::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD rgCmds[], OLECMDTEXT *pcmdtext)
  256. {
  257. if (pguidCmdGroup && IsEqualGUID(CGID_Explorer, *pguidCmdGroup))
  258. {
  259. for (UINT i=0; i < cCmds; i++)
  260. {
  261. rgCmds[i].cmdf = 0;
  262. switch (rgCmds[i].cmdID)
  263. {
  264. case SBCMDID_INITFILECTXMENU:
  265. if (_hwnd && _fVisible)
  266. {
  267. rgCmds->cmdf = 0;
  268. if (pcmdtext)
  269. pcmdtext->cmdtextf = 0;
  270. if (pcmdtext)
  271. {
  272. if (SUCCEEDED(_pns->GetSelectedItemName(pcmdtext->rgwz, pcmdtext->cwBuf)))
  273. {
  274. rgCmds->cmdf = OLECMDF_ENABLED;
  275. pcmdtext->cmdtextf = OLECMDTEXTF_NAME;
  276. pcmdtext->cwActual = lstrlenW(pcmdtext->rgwz) + 1;
  277. }
  278. }
  279. }
  280. break;
  281. case SBCMDID_FILERENAME:
  282. case SBCMDID_FILEDELETE:
  283. case SBCMDID_FILEPROPERTIES:
  284. {
  285. LPITEMIDLIST pidl;
  286. // get selected item can return NULL pidl and S_FALSE
  287. if (_pns->GetSelectedItem(&pidl, 0) == S_OK)
  288. {
  289. DWORD rgfAttrib = SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET; // CAN_LINK
  290. if (SUCCEEDED(IEGetAttributesOf(pidl, &rgfAttrib)))
  291. {
  292. DWORD nCmdID;
  293. static const DWORD tbtab[] = {
  294. SBCMDID_FILEDELETE, SBCMDID_FILEPROPERTIES, SBCMDID_FILERENAME };
  295. static const DWORD cttab[] = {
  296. SFGAO_CANDELETE, SFGAO_HASPROPSHEET, SFGAO_CANRENAME };
  297. nCmdID = SHSearchMapInt((int*)tbtab, (int*)cttab, ARRAYSIZE(tbtab), rgCmds[i].cmdID);
  298. if (nCmdID != -1 && (rgfAttrib & nCmdID))
  299. rgCmds[i].cmdf = OLECMDF_ENABLED;
  300. }
  301. ILFree(pidl);
  302. }
  303. break;
  304. }
  305. default:
  306. break;
  307. }
  308. }
  309. return S_OK;
  310. }
  311. return CToolBand::QueryStatus(pguidCmdGroup, cCmds, rgCmds, pcmdtext);
  312. }
  313. HRESULT CNSCBand::_InvokeCommandOnItem(LPCTSTR pszVerb)
  314. {
  315. HRESULT hr;
  316. IContextMenu *pcm;
  317. hr = _QueryContextMenuSelection(&pcm);
  318. if (SUCCEEDED(hr))
  319. {
  320. CMINVOKECOMMANDINFOEX ici =
  321. {
  322. SIZEOF(CMINVOKECOMMANDINFOEX),
  323. 0L,
  324. _hwnd,
  325. NULL,
  326. NULL, NULL,
  327. SW_NORMAL,
  328. };
  329. CHAR szVerbAnsi[MAX_PATH];
  330. SHUnicodeToAnsi(pszVerb, szVerbAnsi, ARRAYSIZE(szVerbAnsi));
  331. ici.lpVerb = szVerbAnsi;
  332. ici.lpVerbW = pszVerb;
  333. ici.fMask |= CMIC_MASK_UNICODE;
  334. hr = pcm->InvokeCommand((LPCMINVOKECOMMANDINFO)&ici);
  335. pcm->Release();
  336. }
  337. return hr;
  338. }
  339. HRESULT CNSCBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  340. {
  341. if (pguidCmdGroup == NULL)
  342. {
  343. switch (nCmdID)
  344. {
  345. case OLECMDID_REFRESH:
  346. if (_pns)
  347. _pns->Refresh();
  348. return S_OK;
  349. }
  350. }
  351. else if (pguidCmdGroup && IsEqualGUID(CGID_Explorer, *pguidCmdGroup))
  352. {
  353. HRESULT hr = S_OK;
  354. switch (nCmdID)
  355. {
  356. case SBCMDID_SELECTHISTPIDL:
  357. if (IsEqualCLSID(*_poi->pclsid, CLSID_HistBand) && _hwnd && _fVisible)
  358. {
  359. // If you're not visible do nothing. On becoming visible
  360. // use Exec to proxy to get last pidlSelect that you would
  361. // have shown, had you been visible
  362. LPITEMIDLIST pidlSelect = VariantToIDList(pvarargIn);
  363. if (pidlSelect)
  364. {
  365. ASSERT(_pns);
  366. _pns->SetSelectedItem(pidlSelect, TRUE, FALSE, 0);
  367. ILFree(pidlSelect);
  368. }
  369. }
  370. break;
  371. case SBCMDID_INITFILECTXMENU:
  372. if (_hwnd && _fVisible)
  373. {
  374. if (pvarargOut)
  375. {
  376. VariantClearLazy(pvarargOut);
  377. hr = _QueryContextMenuSelection((IContextMenu **)&(pvarargOut->punkVal));
  378. if (SUCCEEDED(hr))
  379. {
  380. pvarargOut->vt = VT_UNKNOWN;
  381. }
  382. }
  383. }
  384. break;
  385. case SBCMDID_FILERENAME:
  386. {
  387. IShellNameSpace *psfns;
  388. hr = _pns->QueryInterface(IID_PPV_ARG(IShellNameSpace, &psfns));
  389. if (SUCCEEDED(hr))
  390. {
  391. hr = psfns->InvokeContextMenuCommand(L"rename");
  392. psfns->Release();
  393. }
  394. break;
  395. }
  396. case SBCMDID_FILEDELETE:
  397. hr = _InvokeCommandOnItem(TEXT("delete"));
  398. break;
  399. case SBCMDID_FILEPROPERTIES:
  400. hr = _InvokeCommandOnItem(TEXT("properties"));
  401. break;
  402. default:
  403. hr = E_FAIL;
  404. break;
  405. }
  406. if (SUCCEEDED(hr))
  407. return hr;
  408. }
  409. return CToolBand::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  410. }
  411. HRESULT CNSCBand::_QueryContextMenuSelection(IContextMenu ** ppcm)
  412. {
  413. *ppcm = NULL;
  414. LPITEMIDLIST pidlSelected;
  415. HRESULT hr = _pns->GetSelectedItem(&pidlSelected, 0);
  416. if (SUCCEEDED(hr))
  417. {
  418. LPCITEMIDLIST pidlRelative;
  419. IShellFolder * psf;
  420. hr = IEBindToParentFolder(pidlSelected, &psf, &pidlRelative);
  421. if (SUCCEEDED(hr))
  422. {
  423. hr = psf->GetUIObjectOf(NULL, 1, &pidlRelative, IID_PPV_ARG_NULL(IContextMenu, ppcm));
  424. psf->Release();
  425. }
  426. ILFree(pidlSelected);
  427. }
  428. return hr;
  429. }
  430. HRESULT CNSCBand::Select(LPCITEMIDLIST pidl)
  431. {
  432. _pns->SetSelectedItem(pidl, TRUE, FALSE, 0);
  433. return S_OK;
  434. }
  435. // *** IInputObject Methods ***
  436. HRESULT CNSCBand::TranslateAcceleratorIO(LPMSG lpMsg)
  437. {
  438. HWND hwndFocus = GetFocus();
  439. if (_pns->InLabelEdit())
  440. return EditBox_TranslateAcceleratorST(lpMsg);
  441. else if (lpMsg && lpMsg->hwnd && SendMessage(lpMsg->hwnd, TVM_TRANSLATEACCELERATOR, 0, (LPARAM)lpMsg))
  442. return S_OK;
  443. else if (hwndFocus == _hwnd && TranslateAcceleratorWrap(_hwnd, _haccTree, lpMsg))
  444. return S_OK;
  445. return S_FALSE;
  446. }
  447. void CNSCBand::_EnsureImageListsLoaded()
  448. {
  449. if (_himlNormal == NULL)
  450. _himlNormal = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_HISTORYANDFAVBANDSDEF), 18, 3, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
  451. if (_himlHot == NULL)
  452. _himlHot = ImageList_LoadImage(HINST_THISDLL, MAKEINTRESOURCE(IDB_HISTORYANDFAVBANDSHOT), 18, 3, RGB(255, 0, 255), IMAGE_BITMAP, LR_CREATEDIBSECTION);
  453. }
  454. HRESULT CNSCBand::_TranslatePidl(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidlTarget, ULONG *pulAttrib)
  455. {
  456. IShellFolder *psf;
  457. LPCITEMIDLIST pidlLast;
  458. HRESULT hr = SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast);
  459. if (SUCCEEDED(hr))
  460. {
  461. hr = SHGetNavigateTarget(psf, pidlLast, ppidlTarget, pulAttrib);
  462. psf->Release();
  463. }
  464. return hr;
  465. }
  466. // favorites, history and Explorer band should override this (they need not worry about channel band)
  467. BOOL CNSCBand::_ShouldNavigateToPidl(LPCITEMIDLIST pidl, ULONG ulAttrib)
  468. {
  469. BOOL bReturn = (ulAttrib & SFGAO_FOLDER);
  470. if (bReturn)
  471. {
  472. IShellFolder *psf;
  473. LPCITEMIDLIST pidlLast;
  474. HRESULT hr = SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlLast);
  475. if (SUCCEEDED(hr))
  476. {
  477. bReturn = IsExpandableChannelFolder(psf, pidlLast);
  478. psf->Release();
  479. }
  480. }
  481. return !bReturn;
  482. }
  483. HRESULT CNSCBand::GetNavigateTarget(LPCITEMIDLIST pidl, LPITEMIDLIST *ppidlTarget, ULONG *pulAttrib)
  484. {
  485. HRESULT hr = _TranslatePidl(pidl, ppidlTarget, pulAttrib);
  486. if (SUCCEEDED(hr))
  487. {
  488. hr = _ShouldNavigateToPidl(pidl, *pulAttrib) ? S_OK : S_FALSE;
  489. if (hr == S_FALSE)
  490. {
  491. ILFree(*ppidlTarget);
  492. *ppidlTarget = NULL;
  493. }
  494. }
  495. return hr;
  496. }
  497. HRESULT CNSCBand::OnSelectionChanged(LPCITEMIDLIST pidl)
  498. {
  499. return S_OK;
  500. }
  501. HRESULT CNSCBand::Invoke(LPCITEMIDLIST pidl)
  502. {
  503. HRESULT hr = E_INVALIDARG;
  504. if (pidl)
  505. {
  506. IShellBrowser *psb;
  507. hr = IUnknown_QueryService(_punkSite, SID_SProxyBrowser, IID_PPV_ARG(IShellBrowser, &psb));
  508. if (SUCCEEDED(hr))
  509. {
  510. hr = _NavigateRightPane(psb, pidl);
  511. if (FAILED(hr))
  512. {
  513. IShellFolder *psf;
  514. LPCITEMIDLIST pidlChild;
  515. if (SUCCEEDED(SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild)))
  516. {
  517. if (!SHGetAttributes(psf, pidlChild, SFGAO_FOLDER))
  518. {
  519. hr = SHInvokeDefaultCommand(_hwnd, psf, pidlChild);
  520. }
  521. psf->Release();
  522. }
  523. }
  524. psb->Release();
  525. }
  526. }
  527. return hr;
  528. }
  529. HRESULT CNSCBand::_NavigateRightPane(IShellBrowser *psb, LPCITEMIDLIST pidl)
  530. {
  531. HRESULT hr = psb->BrowseObject(pidl, SBSP_SAMEBROWSER);
  532. if (SUCCEEDED(hr))
  533. UEMFireEvent(&UEMIID_BROWSER, UEME_INSTRBROWSER, UEMF_INSTRUMENT, UIBW_NAVIGATE, UIBL_NAVOTHER);
  534. return hr;
  535. }