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.

1379 lines
48 KiB

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include "nscband.h"
  4. #include "nsc.h"
  5. #include "resource.h"
  6. #include "dhuihand.h"
  7. #include <varutil.h>
  8. #include <mluisupp.h>
  9. #define DM_HISTBAND 0x0000000
  10. #define DM_GUIPAINS 0x40000000
  11. #define REGKEY_HISTORY_VIEW TEXT("HistoryViewType")
  12. #define REGKEY_DEFAULT_SIZE 0x10
  13. #define VIEWTYPE_MAX 0x4 // A "guess" at how many viewtypes thare will be
  14. #define VIEWTYPE_REALLOC 0x4 // How many to realloc at a time
  15. // these are temporary
  16. #define MENUID_SEARCH 0x4e4e
  17. // Distance between history search go and stop buttons
  18. #define HISTSRCH_BUTTONDIST 6
  19. extern HINSTANCE g_hinst;
  20. #define WM_SEARCH_STATE (WM_USER + 314)
  21. class CHistBand : public CNSCBand,
  22. public IShellFolderSearchableCallback
  23. {
  24. friend HRESULT CHistBand_CreateInstance(IUnknown *punkOuter,
  25. IUnknown **ppunk, LPCOBJECTINFO poi);
  26. public:
  27. // *** IUnknown methods ***
  28. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  29. STDMETHODIMP_(ULONG) AddRef (void) { return CNSCBand::AddRef(); };
  30. STDMETHODIMP_(ULONG) Release(void) { return CNSCBand::Release(); };
  31. // *** IOleCommandTarget methods ***
  32. STDMETHODIMP Exec(const GUID *pguidCmdGroup,
  33. DWORD nCmdID,
  34. DWORD nCmdexecopt,
  35. VARIANTARG *pvarargIn,
  36. VARIANTARG *pvarargOut);
  37. // *** IOleWindow methods ***
  38. // (overriding CNSCBand implementation
  39. STDMETHODIMP GetWindow(HWND *phwnd);
  40. // *** IInputObject methods ***
  41. // (overriding CNSCBand/CToolBand's implementation)
  42. STDMETHODIMP TranslateAcceleratorIO(LPMSG lpMsg);
  43. // *** IDockingWindow methods ***
  44. STDMETHODIMP ShowDW(BOOL fShow);
  45. // *** IShellFolderSearchableCallback methods ***
  46. STDMETHODIMP RunBegin(DWORD dwReserved);
  47. STDMETHODIMP RunEnd(DWORD dwReserved);
  48. protected:
  49. virtual void _AddButtons(BOOL fAdd);
  50. virtual HRESULT _OnRegisterBand(IOleCommandTarget *poctProxy);
  51. virtual BOOL _ShouldNavigateToPidl(LPCITEMIDLIST pidl, ULONG ulAttrib);
  52. virtual HRESULT _NavigateRightPane(IShellBrowser *psb, LPCITEMIDLIST pidl);
  53. ~CHistBand();
  54. HRESULT _InitViewPopup();
  55. HRESULT _DoViewPopup(int x, int y);
  56. HRESULT _ViewPopupSelect(UINT idCmd);
  57. #ifdef SPLIT_HISTORY_VIEW_BUTTON
  58. UINT _NextMenuItem();
  59. #endif
  60. HRESULT _ChangePidl(LPITEMIDLIST);
  61. HRESULT _SelectPidl(LPCITEMIDLIST pidlSelect, BOOL fCreate,
  62. LPCITEMIDLIST pidlViewType = NULL,
  63. BOOL fReinsert = FALSE);
  64. virtual HRESULT _InitializeNsc();
  65. LPITEMIDLIST _GetCurrentSelectPidl(IOleCommandTarget *poctProxy = NULL);
  66. HRESULT _SetRegistryPersistView(int iMenuID);
  67. int _GetRegistryPersistView();
  68. LPCITEMIDLIST _MenuIDToPIDL(UINT uMenuID);
  69. int _PIDLToMenuID(LPITEMIDLIST pidl);
  70. IShellFolderViewType* _GetViewTypeInfo();
  71. HRESULT _GetHistoryViews();
  72. HRESULT _FreeViewInfo();
  73. void _ResizeChildWindows(LONG width, LONG height, BOOL fRepaint);
  74. HRESULT _DoSearchUIStuff();
  75. HRESULT _ExecuteSearch(LPTSTR pszSearchString);
  76. HRESULT _ClearSearch();
  77. IShellFolderSearchable *_EnsureSearch();
  78. static LRESULT CALLBACK s_EditWndSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  79. static LRESULT CALLBACK s_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
  80. static BOOL_PTR CALLBACK s_HistSearchDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  81. BOOL _fStrsAdded; // Strings from resource have been added as buttons on the toolbar
  82. LONG_PTR _lStrOffset;
  83. HMENU _hViewMenu; // an instance var so we can cache it
  84. UINT _uViewCheckedItem; // which menuitem in the View menu is checked?
  85. LPITEMIDLIST *_ppidlViewTypes;
  86. LPTSTR *_ppszStrViewNames;
  87. UINT _nViews;
  88. int _iMaxMenuID;
  89. HWND _hwndNSC;
  90. HWND _hwndSearchDlg;
  91. LONG _lSearchDlgHeight;
  92. LPITEMIDLIST _pidlSearch; // current search
  93. IShellFolderSearchable *_psfSearch;
  94. LPITEMIDLIST _pidlHistory; // cache the history pidl from SHGetHistoryPIDL
  95. IShellFolder *_psfHistory; // cache the history shell folder
  96. IShellFolderViewType *_psfvtCache; // view type information
  97. LPITEMIDLIST _pidlLastSelect;
  98. };
  99. CHistBand::~CHistBand()
  100. {
  101. DestroyMenu(_hViewMenu);
  102. if (_pidlLastSelect)
  103. ILFree(_pidlLastSelect);
  104. if (_pidlHistory)
  105. ILFree(_pidlHistory);
  106. if (_psfHistory)
  107. _psfHistory->Release();
  108. if (_psfvtCache)
  109. _psfvtCache->Release();
  110. _ClearSearch(); // Frees _pidlSearch
  111. if (_psfSearch)
  112. _psfSearch->Release();
  113. _FreeViewInfo();
  114. }
  115. HRESULT CHistBand::QueryInterface(REFIID riid, void **ppvObj)
  116. {
  117. static const QITAB qit[] = {
  118. QITABENT(CHistBand, IShellFolderSearchableCallback), // IID_IShellFolderSearchableCallback
  119. { 0 },
  120. };
  121. HRESULT hr = QISearch(this, qit, riid, ppvObj);
  122. if (FAILED(hr))
  123. hr = CNSCBand::QueryInterface(riid, ppvObj);
  124. return hr;
  125. }
  126. // *** IOleCommandTarget methods ***
  127. HRESULT CHistBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
  128. DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
  129. {
  130. HRESULT hRes = S_OK;
  131. if (pguidCmdGroup)
  132. {
  133. if (IsEqualGUID(CLSID_HistBand, *pguidCmdGroup))
  134. {
  135. switch(nCmdID)
  136. {
  137. case FCIDM_HISTBAND_VIEW:
  138. if (pvarargIn && (pvarargIn->vt == VT_I4))
  139. {
  140. #ifdef SPLIT_HISTORY_VIEW_BUTTON
  141. if (nCmdexecopt == OLECMDEXECOPT_PROMPTUSER)
  142. hRes = _DoViewPopup(GET_X_LPARAM(pvarargIn->lVal), GET_Y_LPARAM(pvarargIn->lVal));
  143. else
  144. hRes = _ViewPopupSelect(_NextMenuItem());
  145. #else
  146. ASSERT(nCmdexecopt == OLECMDEXECOPT_PROMPTUSER);
  147. hRes = _DoViewPopup(GET_X_LPARAM(pvarargIn->lVal), GET_Y_LPARAM(pvarargIn->lVal));
  148. #endif
  149. }
  150. else
  151. ASSERT(0);
  152. break;
  153. case FCIDM_HISTBAND_SEARCH:
  154. _ViewPopupSelect(MENUID_SEARCH);
  155. break;
  156. }
  157. }
  158. else if ((IsEqualGUID(CGID_Explorer, *pguidCmdGroup)))
  159. {
  160. switch (nCmdID)
  161. {
  162. case SBCMDID_SELECTHISTPIDL:
  163. #ifdef ANNOYING_HISTORY_AUTOSELECT
  164. if (_uViewCheckedItem != MENUID_SEARCH)
  165. {
  166. LPCITEMIDLIST pidlSelect = VariantToIDList(pvarargIn);
  167. // Get the current view information
  168. LPCITEMIDLIST pidlView = _MenuIDToPIDL(_uViewCheckedItem);
  169. DWORD dwViewFlags = SFVTFLAG_NOTIFY_CREATE;
  170. IShellFolderViewType* psfvtInfo = _GetViewTypeInfo();
  171. if (psfvtInfo)
  172. {
  173. // query for view type properties -- this will tell us how to
  174. // select the item...
  175. hRes = psfvtInfo->GetViewTypeProperties(pidlView,
  176. &dwViewFlags);
  177. psfvtInfo->Release();
  178. }
  179. if (SUCCEEDED(hRes))
  180. {
  181. hRes = _SelectPidl(pidlSelect, dwViewFlags & SFVTFLAG_NOTIFY_CREATE,
  182. pidlView, dwViewFlags & SFVTFLAG_NOTIFY_RESORT);
  183. }
  184. ILFree(pidlSelect);
  185. }
  186. else //eat it, so that nsc doesn't get it
  187. hRes = S_OK;
  188. #endif //ANNOYING_HISTORY_AUTOSELECT
  189. hRes = S_OK;
  190. break;
  191. case SBCMDID_FILEDELETE:
  192. hRes = _InvokeCommandOnItem(TEXT("delete"));
  193. break;
  194. }
  195. }
  196. else
  197. hRes = CNSCBand::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  198. }
  199. else
  200. hRes = CNSCBand::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
  201. return hRes;
  202. }
  203. // *** IInputObject methods ***
  204. HRESULT CHistBand::TranslateAcceleratorIO(LPMSG pmsg)
  205. {
  206. #ifdef DEBUG
  207. if (pmsg->message == WM_KEYDOWN)
  208. TraceMsg(DM_GUIPAINS, "CHistBand -- TranslateAcceleratorIO called and _hwndSearchDlg is %x", _hwndSearchDlg);
  209. #endif
  210. HWND hwndFocus = GetFocus();
  211. // Translate accelerator messages for dialog
  212. if ( (_hwndSearchDlg) && (hwndFocus != _hwndNSC) && (!hwndFocus || !IsChild(_hwndNSC, hwndFocus)) )
  213. {
  214. if (pmsg->message == WM_KEYDOWN)
  215. {
  216. if (IsVK_TABCycler(pmsg))
  217. {
  218. BOOL fBackwards = (GetAsyncKeyState(VK_SHIFT) < 0);
  219. HWND hwndCur = pmsg->hwnd;
  220. if (GetParent(pmsg->hwnd) != _hwndSearchDlg)
  221. hwndCur = NULL;
  222. HWND hwndNext = GetNextDlgTabItem(_hwndSearchDlg, hwndCur, fBackwards);
  223. // Get the First dialog item in this searching order
  224. HWND hwndFirst;
  225. if (!fBackwards) {
  226. hwndFirst = GetNextDlgTabItem(_hwndSearchDlg, NULL, FALSE);
  227. }
  228. else
  229. // passing NULL for the 2nd parameter returned NULL with ERROR_SUCCESS,
  230. // so this is a workaround
  231. hwndFirst = GetNextDlgTabItem(_hwndSearchDlg,
  232. GetNextDlgTabItem(_hwndSearchDlg,
  233. NULL, FALSE), TRUE);
  234. // If the next dialog tabstop is the first dialog tabstop, then
  235. // let someone else get focus
  236. if ((!hwndCur) || (hwndNext != hwndFirst))
  237. {
  238. SetFocus(hwndNext);
  239. return S_OK;
  240. }
  241. else if (!fBackwards) {
  242. SetFocus(_hwndNSC);
  243. return S_OK;
  244. }
  245. }
  246. else if ( (pmsg->wParam == VK_RETURN) )
  247. SendMessage(_hwndSearchDlg, WM_COMMAND, MAKELONG(GetDlgCtrlID(pmsg->hwnd), 0), 0L);
  248. }
  249. // The History Search Edit Box is activated
  250. if (pmsg->hwnd == GetDlgItem(_hwndSearchDlg, IDC_EDITHISTSEARCH)) {
  251. // If the user pressed tab within the dialog
  252. return EditBox_TranslateAcceleratorST(pmsg);
  253. }
  254. }
  255. return CNSCBand::TranslateAcceleratorIO(pmsg);
  256. }
  257. // sends appropriate resize messages to our children windows
  258. void CHistBand::_ResizeChildWindows(LONG width, LONG height, BOOL fRepaint)
  259. {
  260. if (_hwndNSC)
  261. {
  262. int y1 = _hwndSearchDlg ? _lSearchDlgHeight : 0;
  263. int y2 = _hwndSearchDlg ? height - _lSearchDlgHeight : height;
  264. MoveWindow(_hwndNSC, 0, y1, width, y2, fRepaint);
  265. }
  266. if (_hwndSearchDlg)
  267. {
  268. MoveWindow(_hwndSearchDlg, 0, 0, width, _lSearchDlgHeight, fRepaint);
  269. }
  270. }
  271. HRESULT CHistBand::_DoSearchUIStuff()
  272. {
  273. HRESULT hr;
  274. // host the search dialog inside my window:
  275. _hwndSearchDlg = CreateDialogParam(MLGetHinst(), MAKEINTRESOURCE(DLG_HISTSEARCH2),
  276. _hwnd, s_HistSearchDlgProc, reinterpret_cast<LPARAM>(this));
  277. if (_hwndSearchDlg)
  278. {
  279. RECT rcSelf;
  280. GetClientRect(_hwnd, &rcSelf);
  281. RECT rcDlg;
  282. GetClientRect(_hwndSearchDlg, &rcDlg);
  283. _lSearchDlgHeight = rcDlg.bottom;
  284. _ResizeChildWindows(rcSelf.right, rcSelf.bottom, TRUE);
  285. ShowWindow(_hwndSearchDlg, SW_SHOWDEFAULT);
  286. hr = S_OK;
  287. }
  288. else
  289. {
  290. hr = E_FAIL;
  291. }
  292. return hr;
  293. }
  294. // WndProc for main window to go in rebar
  295. LRESULT CALLBACK CHistBand::s_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
  296. {
  297. CHistBand* phb = reinterpret_cast<CHistBand *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
  298. switch (msg)
  299. {
  300. case WM_SETFOCUS:
  301. {
  302. TraceMsg(DM_GUIPAINS, "Histband Parent -- SETFOCUS");
  303. // The only way this should be called is via a RB_CYCLEFOCUS->...->UIActivateIO->SetFocus
  304. // therefore, we can assume that we're being tabbed into or something with equally good.
  305. // If we tab into the outer dummy window, transfer the focus to
  306. // our appropriate child:
  307. BOOL fBackwards = (GetAsyncKeyState(VK_SHIFT) < 0);
  308. if (phb->_hwndSearchDlg) {
  309. // Select either the first or the last item in the dialog depending on
  310. // whether we're shifting in or shifting out
  311. SetFocus(GetNextDlgTabItem(phb->_hwndSearchDlg, (NULL), fBackwards));
  312. }
  313. else {
  314. TraceMsg(DM_GUIPAINS, "NSC is being given focus!");
  315. SetFocus(phb->_hwndNSC);
  316. }
  317. }
  318. return 0;
  319. case WM_CREATE:
  320. SetWindowLongPtr(hWnd, GWLP_USERDATA,
  321. (reinterpret_cast<LONG_PTR>((reinterpret_cast<CREATESTRUCT *>(lParam))->lpCreateParams)));
  322. return 0;
  323. case WM_SIZE:
  324. if (phb)
  325. phb->_ResizeChildWindows(LOWORD(lParam), HIWORD(lParam), TRUE);
  326. return 0;
  327. case WM_NCDESTROY:
  328. //make sure the search object gets freed when the view/window is destroyed, because it holds a ref to us
  329. phb->_ClearSearch();
  330. break;
  331. case WM_NOTIFY:
  332. {
  333. if (phb) {
  334. // We proxy the notification messages to our own parent who thinks that we
  335. // are the namespace control
  336. LPNMHDR pnmh = (LPNMHDR)lParam;
  337. // Notification message coming from NSC
  338. if (pnmh->hwndFrom == phb->_hwndNSC)
  339. return SendMessage(phb->_hwndParent, msg, wParam, lParam);
  340. }
  341. } // INTENTIONAL FALLTHROUGH
  342. }
  343. return DefWindowProc(hWnd, msg, wParam, lParam);
  344. }
  345. // *** IOleWindow methods ***
  346. HRESULT CHistBand::GetWindow(HWND *phwnd)
  347. {
  348. if (!_hwnd)
  349. {
  350. // we want to wrap a window around the namespace control so
  351. // that we can add siblings later
  352. // Get our parent's dimensions
  353. RECT rcParent;
  354. GetClientRect(_hwndParent, &rcParent);
  355. static LPTSTR pszClassName = TEXT("History Pane");
  356. WNDCLASSEX wndclass = { 0 };
  357. wndclass.cbSize = sizeof(wndclass);
  358. wndclass.style = CS_PARENTDC | CS_HREDRAW | CS_VREDRAW;
  359. wndclass.lpfnWndProc = s_WndProc;
  360. wndclass.hInstance = g_hinst;
  361. wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  362. wndclass.lpszClassName = pszClassName;
  363. RegisterClassEx(&wndclass);
  364. _hwnd = CreateWindow(pszClassName, TEXT("History Window"),
  365. WS_CHILD | WS_TABSTOP,
  366. 0, 0, rcParent.right, rcParent.bottom,
  367. _hwndParent, NULL, g_hinst, (LPVOID)this);
  368. }
  369. if (_hwnd) // Host NSC
  370. _pns->CreateTree(_hwnd, _GetTVStyle(), &_hwndNSC);
  371. return CToolBand::GetWindow(phwnd);
  372. }
  373. // *** IDockingWindow methods ***
  374. HRESULT CHistBand::ShowDW(BOOL fShow)
  375. {
  376. HRESULT hr = CNSCBand::ShowDW(fShow);
  377. _AddButtons(fShow);
  378. return hr;
  379. }
  380. static const TBBUTTON c_tbHistory[] =
  381. {
  382. { I_IMAGENONE, FCIDM_HISTBAND_VIEW, TBSTATE_ENABLED, BTNS_AUTOSIZE | BTNS_WHOLEDROPDOWN | BTNS_SHOWTEXT, {0,0}, 0, 0 },
  383. { 2, FCIDM_HISTBAND_SEARCH, TBSTATE_ENABLED, BTNS_AUTOSIZE | BTNS_SHOWTEXT, {0,0}, 0, 1 },
  384. };
  385. // Adds buttons from the above table to the Explorer
  386. void CHistBand::_AddButtons(BOOL fAdd)
  387. {
  388. // don't add button if we have no menu
  389. if (!_hViewMenu)
  390. return;
  391. IExplorerToolbar* piet;
  392. if (SUCCEEDED(_punkSite->QueryInterface(IID_IExplorerToolbar, (void**)&piet)))
  393. {
  394. if (fAdd)
  395. {
  396. piet->SetCommandTarget((IUnknown*)SAFECAST(this, IOleCommandTarget*), &CLSID_HistBand, 0);
  397. if (!_fStrsAdded)
  398. {
  399. piet->AddString(&CLSID_HistBand, MLGetHinst(), IDS_HIST_BAR_LABELS, &_lStrOffset);
  400. _fStrsAdded = TRUE;
  401. }
  402. _EnsureImageListsLoaded();
  403. piet->SetImageList(&CLSID_HistBand, _himlNormal, _himlHot, NULL);
  404. TBBUTTON tbHistory[ARRAYSIZE(c_tbHistory)];
  405. memcpy(tbHistory, c_tbHistory, SIZEOF(TBBUTTON) * ARRAYSIZE(c_tbHistory));
  406. for (int i = 0; i < ARRAYSIZE(c_tbHistory); i++)
  407. tbHistory[i].iString += (long) _lStrOffset;
  408. piet->AddButtons(&CLSID_HistBand, ARRAYSIZE(tbHistory), tbHistory);
  409. }
  410. else
  411. piet->SetCommandTarget(NULL, NULL, 0);
  412. piet->Release();
  413. }
  414. }
  415. // *** IShellFolderSearchableCallback methods ***
  416. // enable and disable cancel buttons
  417. HRESULT CHistBand::RunBegin(DWORD dwReserved)
  418. {
  419. HRESULT hr = E_FAIL;
  420. if (_hwndSearchDlg)
  421. {
  422. SendMessage(_hwndSearchDlg, WM_SEARCH_STATE, (WPARAM)TRUE, NULL);
  423. hr = S_OK;
  424. }
  425. return hr;
  426. }
  427. HRESULT CHistBand::RunEnd(DWORD dwReserved)
  428. {
  429. HRESULT hr = E_FAIL;
  430. if (_hwndSearchDlg)
  431. {
  432. SendMessage(_hwndSearchDlg, WM_SEARCH_STATE, (WPARAM)FALSE, NULL);
  433. hr = S_OK;
  434. }
  435. return hr;
  436. }
  437. // A utility function used in the WM_SIZE handling below...
  438. inline HWND _GetHwndAndRect(HWND hwndDlg, int item, BOOL fClient, RECT &rc) {
  439. HWND hwnd = GetDlgItem(hwndDlg, item);
  440. if (fClient)
  441. GetClientRect(hwnd, &rc);
  442. else {
  443. GetWindowRect(hwnd, &rc);
  444. MapWindowPoints(NULL, hwndDlg, ((LPPOINT)&rc), 2);
  445. }
  446. return hwnd;
  447. }
  448. LRESULT CALLBACK CHistBand::s_EditWndSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  449. {
  450. switch(uMsg) {
  451. case WM_KEYDOWN:
  452. if ((GetAsyncKeyState(VK_CONTROL) < 0) &&
  453. (wParam == TEXT('U'))) {
  454. uMsg = WM_SETTEXT;
  455. wParam = 0;
  456. lParam = ((LPARAM)(LPCTSTR)TEXT(""));
  457. }
  458. break;
  459. case WM_CHAR:
  460. if (wParam == VK_RETURN) {
  461. PostMessage(GetParent(hwnd), WM_COMMAND, MAKELONG(IDB_HISTSRCH_GO, 0), 0L);
  462. return 0L;
  463. }
  464. break;
  465. }
  466. return CallWindowProc((WNDPROC)(GetWindowLongPtr(hwnd, GWLP_USERDATA)), hwnd, uMsg, wParam, lParam);
  467. }
  468. // Please see note at top of file for explanation...
  469. INT_PTR CALLBACK CHistBand::s_HistSearchDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  470. {
  471. switch(uMsg) {
  472. case WM_PAINT:
  473. {
  474. // paint a little separator bar on the bottom
  475. PAINTSTRUCT ps;
  476. RECT rcSelf;
  477. HDC hdc = BeginPaint(hwndDlg, &ps);
  478. GetClientRect(hwndDlg, &rcSelf);
  479. RECT rcFill = { 0, rcSelf.bottom - 2, rcSelf.right, rcSelf.bottom };
  480. FillRect(hdc, &rcFill, GetSysColorBrush(COLOR_BTNFACE));
  481. EndPaint(hwndDlg, &ps);
  482. break;
  483. }
  484. // Supply child controls with correct bkgd color
  485. case WM_CTLCOLORSTATIC:
  486. if ((HWND)lParam == GetDlgItem(hwndDlg, IDD_HISTSRCH_ANIMATION)) {
  487. SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW));
  488. return (INT_PTR) GetSysColorBrush(COLOR_WINDOW);
  489. }
  490. else {
  491. SetBkMode((HDC)wParam, TRANSPARENT);
  492. return (INT_PTR) GetSysColorBrush(COLOR_WINDOW);
  493. }
  494. case WM_CTLCOLORDLG:
  495. //SetBkColor((HDC)HIWORD(lParam), GetSysColor(COLOR_WINDOW));
  496. return (INT_PTR) GetSysColorBrush(COLOR_WINDOW);
  497. case WM_INITDIALOG: {
  498. HWND hwndEdit = GetDlgItem(hwndDlg, IDC_EDITHISTSEARCH);
  499. WNDPROC pfnOldEditProc = (WNDPROC)(GetWindowLongPtr(hwndEdit, GWLP_WNDPROC));
  500. // subclass the editbox
  501. SetWindowLongPtr(hwndEdit, GWLP_USERDATA, (LPARAM)pfnOldEditProc);
  502. SetWindowLongPtr(hwndEdit, GWLP_WNDPROC, (LPARAM)s_EditWndSubclassProc);
  503. SetWindowLongPtr(hwndDlg, DWLP_USER, lParam);
  504. Animate_Open(GetDlgItem(hwndDlg, IDD_HISTSRCH_ANIMATION),
  505. MAKEINTRESOURCE(IDA_HISTSEARCHAVI));
  506. // limit the edit control to MAX_PATH-1 characters
  507. Edit_LimitText(hwndEdit, MAX_PATH-1);
  508. break;
  509. }
  510. case WM_DESTROY:
  511. Animate_Close(GetDlgItem(hwndDlg, IDD_HISTSRCH_ANIMATION));
  512. break;
  513. case WM_SIZE: {
  514. if (wParam == SIZE_RESTORED) {
  515. UINT uWidth = LOWORD(lParam);
  516. UINT uHeight = HIWORD(lParam);
  517. RECT rcAnimSize, rcCancel, rcSearch, rcEdit, rcStatic;
  518. HWND hwndAnim = _GetHwndAndRect(hwndDlg, IDD_HISTSRCH_ANIMATION, TRUE, rcAnimSize);
  519. HWND hwndCancel = _GetHwndAndRect(hwndDlg, IDCANCEL, FALSE, rcCancel);
  520. HWND hwndSearch = _GetHwndAndRect(hwndDlg, IDB_HISTSRCH_GO, FALSE, rcSearch);
  521. HWND hwndEdit = _GetHwndAndRect(hwndDlg, IDC_EDITHISTSEARCH, FALSE, rcEdit);
  522. // calculate the minimum tolerable width
  523. UINT uMinWidth = ((rcCancel.right - rcCancel.left) +
  524. (rcSearch.right - rcSearch.left) + HISTSRCH_BUTTONDIST +
  525. rcEdit.left +
  526. rcAnimSize.right + 1);
  527. if (uWidth < uMinWidth)
  528. uWidth = uMinWidth;
  529. HDWP hdwp = BeginDeferWindowPos(5);
  530. if (hdwp)
  531. {
  532. // align the animation box with the upper-right corner
  533. DeferWindowPos(hdwp, hwndAnim, HWND_TOP, uWidth - rcAnimSize.right, 0,
  534. rcAnimSize.right, rcAnimSize.bottom, SWP_NOZORDER);
  535. // stretch the textbox as wide as possible
  536. UINT uNewTextWidth = uWidth - rcAnimSize.right - 1 - rcEdit.left;
  537. DeferWindowPos(hdwp, hwndEdit, HWND_TOP, rcEdit.left, rcEdit.top, uNewTextWidth,
  538. rcEdit.bottom - rcEdit.top, SWP_NOZORDER);
  539. // static text should not be longer than edit textbox
  540. HWND hwndStatic = _GetHwndAndRect(hwndDlg, IDC_HISTSRCH_STATIC, FALSE, rcStatic);
  541. DeferWindowPos(hdwp, hwndStatic, HWND_TOP, rcEdit.left, rcStatic.top, uNewTextWidth,
  542. rcStatic.bottom - rcStatic.top, SWP_NOZORDER);
  543. // align the cancel button with the right of the edit box
  544. UINT uCancelLeft = uWidth - rcAnimSize.right - 1 - (rcCancel.right - rcCancel.left);
  545. DeferWindowPos(hdwp, hwndCancel, HWND_TOP, uCancelLeft, rcCancel.top,
  546. rcCancel.right - rcCancel.left, rcCancel.bottom - rcCancel.top, SWP_NOZORDER);
  547. // align the search button so that it ends six pixels (HISTSRCH_BUTTONDIST)
  548. // to the left of the cancel button
  549. DeferWindowPos(hdwp, hwndSearch, HWND_TOP,
  550. uCancelLeft - HISTSRCH_BUTTONDIST - (rcSearch.right - rcSearch.left),
  551. rcSearch.top, rcSearch.right - rcSearch.left, rcSearch.bottom - rcSearch.top, SWP_NOZORDER);
  552. EndDeferWindowPos(hdwp);
  553. }
  554. }
  555. else
  556. return FALSE;
  557. break;
  558. }
  559. case WM_COMMAND:
  560. {
  561. CHistBand *phb = reinterpret_cast<CHistBand *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
  562. switch (LOWORD(wParam))
  563. {
  564. case IDC_EDITHISTSEARCH:
  565. switch (HIWORD(wParam))
  566. {
  567. case EN_SETFOCUS:
  568. // This guy allows us to intercept TranslateAccelerator messages
  569. // like backspace. This is the same as calling UIActivateIO(TRUE), but
  570. // doesn't cause an infinite setfocus loop in Win95
  571. IUnknown_OnFocusChangeIS(phb->_punkSite, SAFECAST(phb, IInputObject*), TRUE);
  572. SetFocus((HWND)lParam);
  573. break;
  574. case EN_CHANGE:
  575. // Enable 'Go Fish' button iff there is text in the edit box
  576. EnableWindow(GetDlgItem(hwndDlg, IDB_HISTSRCH_GO),
  577. (bool) SendDlgItemMessage(hwndDlg, IDC_EDITHISTSEARCH, EM_LINELENGTH, 0, 0));
  578. break;
  579. }
  580. break;
  581. case IDB_HISTSRCH_GO:
  582. {
  583. TCHAR szSearchString[MAX_PATH];
  584. if (GetDlgItemText(hwndDlg, IDC_EDITHISTSEARCH, szSearchString, ARRAYSIZE(szSearchString)))
  585. {
  586. IServiceProvider *pServiceProvider;
  587. HRESULT hr = IUnknown_QueryService(phb->_punkSite,
  588. SID_SProxyBrowser,
  589. IID_IServiceProvider,
  590. (void **)&pServiceProvider);
  591. if (SUCCEEDED(hr))
  592. {
  593. IWebBrowser2 *pWebBrowser2;
  594. hr = pServiceProvider->QueryService(SID_SWebBrowserApp,
  595. IID_IWebBrowser2,
  596. (void **)&pWebBrowser2);
  597. if (SUCCEEDED(hr))
  598. {
  599. ::PutFindText(pWebBrowser2, szSearchString);
  600. pWebBrowser2->Release();
  601. }
  602. pServiceProvider->Release();
  603. }
  604. phb->_ExecuteSearch(szSearchString);
  605. }
  606. }
  607. break;
  608. case IDCANCEL:
  609. {
  610. if (phb->_EnsureSearch())
  611. {
  612. phb->_psfSearch->CancelAsyncSearch(phb->_pidlSearch, NULL);
  613. }
  614. break;
  615. }
  616. default:
  617. return FALSE;
  618. }
  619. }
  620. return FALSE;
  621. case WM_SEARCH_STATE:
  622. {
  623. BOOL fStart = (BOOL)wParam;
  624. if (fStart)
  625. Animate_Play(GetDlgItem(hwndDlg, IDD_HISTSRCH_ANIMATION), 0, -1, -1);
  626. else {
  627. HWND hwndAnim = GetDlgItem(hwndDlg, IDD_HISTSRCH_ANIMATION);
  628. Animate_Stop(hwndAnim);
  629. Animate_Seek(hwndAnim, 0); // reset the animation
  630. //HACK for IE5 ship
  631. //if there's only one item found in history search, the item doesn't display
  632. //because someone (comctl32?) set redraw to false.
  633. //so, manually force it to true when the search stops
  634. CHistBand *phb = reinterpret_cast<CHistBand *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
  635. if (phb)
  636. SendMessage(phb->_hwndNSC, WM_SETREDRAW, TRUE, 0);
  637. }
  638. HWND hwndFocus = GetFocus();
  639. EnableWindow(GetDlgItem(hwndDlg, IDC_EDITHISTSEARCH), !fStart);
  640. EnableWindow(GetDlgItem(hwndDlg, IDB_HISTSRCH_GO), !fStart);
  641. EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), fStart);
  642. //make sure the focus goes to the right place
  643. if ((NULL != hwndFocus) && (hwndFocus == GetDlgItem(hwndDlg, IDC_EDITHISTSEARCH) ||
  644. (hwndFocus == GetDlgItem(hwndDlg, IDCANCEL))))
  645. SetFocus(GetDlgItem(hwndDlg, fStart ? IDCANCEL : IDC_EDITHISTSEARCH));
  646. break;
  647. }
  648. default:
  649. return FALSE;
  650. }
  651. return TRUE;
  652. }
  653. IShellFolderSearchable *CHistBand::_EnsureSearch() {
  654. ASSERT(_psfHistory);
  655. if (!_pidlSearch) {
  656. _psfHistory->QueryInterface(IID_IShellFolderSearchable,
  657. (LPVOID *)&_psfSearch);
  658. }
  659. return _psfSearch;
  660. }
  661. HRESULT CHistBand::_ClearSearch() {
  662. HRESULT hr = S_FALSE;
  663. if (_pidlSearch) {
  664. if (_EnsureSearch())
  665. {
  666. EVAL(SUCCEEDED(_psfSearch->CancelAsyncSearch(_pidlSearch, NULL)));
  667. hr = _psfSearch->InvalidateSearch(_pidlSearch, NULL);
  668. }
  669. ILFree(_pidlSearch);
  670. _pidlSearch = NULL;
  671. }
  672. return hr;
  673. }
  674. HRESULT CHistBand::_ExecuteSearch(LPTSTR pszSearchString)
  675. {
  676. HRESULT hr = E_FAIL;
  677. if (_EnsureSearch())
  678. {
  679. _ClearSearch();
  680. hr = _psfSearch->FindString(pszSearchString,
  681. NULL,
  682. reinterpret_cast<IUnknown *>
  683. (static_cast<IShellFolderSearchableCallback *>
  684. (this)),
  685. &_pidlSearch);
  686. if (SUCCEEDED(hr))
  687. {
  688. _ChangePidl(ILCombine(_pidlHistory, _pidlSearch));
  689. }
  690. }
  691. return hr;
  692. }
  693. #ifdef SPLIT_HISTORY_VIEW_BUTTON
  694. UINT CHistBand::_NextMenuItem() {
  695. if (_uViewCheckedItem + 1 > _nViews)
  696. return 1;
  697. else
  698. return _uViewCheckedItem + 1;
  699. }
  700. #endif
  701. HRESULT CHistBand::_ViewPopupSelect(UINT idCmd)
  702. {
  703. HRESULT hr = E_FAIL;
  704. if (idCmd == MENUID_SEARCH)
  705. {
  706. if (_uViewCheckedItem != MENUID_SEARCH)
  707. {
  708. // display the dialog box
  709. if (SUCCEEDED(hr = _DoSearchUIStuff()))
  710. {
  711. _ChangePidl((LPITEMIDLIST)INVALID_HANDLE_VALUE); // blank out NSC
  712. _uViewCheckedItem = MENUID_SEARCH;
  713. CheckMenuRadioItem(_hViewMenu, 1, _iMaxMenuID, _uViewCheckedItem, MF_BYCOMMAND);
  714. }
  715. }
  716. if (_hwndSearchDlg)
  717. SetFocus(GetDlgItem(_hwndSearchDlg, IDC_EDITHISTSEARCH));
  718. }
  719. else
  720. {
  721. LPCITEMIDLIST pidlNewSelect = _MenuIDToPIDL(idCmd);
  722. if (pidlNewSelect) {
  723. if (ILIsEmpty(pidlNewSelect))
  724. hr = _ChangePidl(ILClone(_pidlHistory));
  725. else
  726. hr = _ChangePidl(ILCombine(_pidlHistory, pidlNewSelect));
  727. if (SUCCEEDED(hr))
  728. hr = _SelectPidl(NULL, TRUE, pidlNewSelect);
  729. // deleted "&& _uViewCheckedItem >= 0" from test below
  730. // because UINTs are by definition always >= 0
  731. if (SUCCEEDED(hr))
  732. {
  733. // get rid of search dialog -- its no longer needed
  734. if (_hwndSearchDlg) {
  735. EndDialog(_hwndSearchDlg, 0);
  736. DestroyWindow(_hwndSearchDlg);
  737. _hwndSearchDlg = NULL;
  738. // invalidate the previous search and prepare for the next
  739. _ClearSearch();
  740. RECT rcSelf;
  741. GetClientRect(_hwnd, &rcSelf);
  742. _ResizeChildWindows(rcSelf.right, rcSelf.bottom, TRUE);
  743. }
  744. _uViewCheckedItem = idCmd;
  745. CheckMenuRadioItem(_hViewMenu, 1, _iMaxMenuID,
  746. _uViewCheckedItem, MF_BYCOMMAND);
  747. // write out the new selection to registry
  748. EVAL(SUCCEEDED(_SetRegistryPersistView(_uViewCheckedItem)));
  749. hr = S_OK;
  750. }
  751. }
  752. }
  753. return hr;
  754. }
  755. HRESULT CHistBand::_DoViewPopup(int x, int y)
  756. {
  757. if (!_hViewMenu) return E_FAIL;
  758. HRESULT hr = E_FAIL;
  759. UINT idCmd = TrackPopupMenu(_hViewMenu, TPM_RETURNCMD, x, y, 0, _hwnd, NULL);
  760. // Currently, re-selecting the menu item will cause the item to be refreshed
  761. // This makes sense to me, but it can be prevented by
  762. // testing idCmd != _uViewCheckedItem
  763. if ( (idCmd > 0) )
  764. {
  765. return _ViewPopupSelect(idCmd);
  766. }
  767. else
  768. hr = S_FALSE;
  769. return hr;
  770. }
  771. // Change the current select NSC pidl
  772. // WARNING: The pidl passed in will be assimilated by us...
  773. // We will deallocate it.
  774. HRESULT CHistBand::_ChangePidl(LPITEMIDLIST pidl)
  775. {
  776. if (_pidl)
  777. ILFree(_pidl);
  778. _pidl = pidl;
  779. if ((LPITEMIDLIST)INVALID_HANDLE_VALUE == pidl)
  780. _pidl = NULL;
  781. _pns->Initialize(pidl, (SHCONTF_FOLDERS | SHCONTF_NONFOLDERS), (NSS_DROPTARGET | NSS_BROWSERSELECT));
  782. return S_OK;
  783. }
  784. // _SelectPidl - Have NSC change the current selected pidl
  785. //
  786. // passing NULL for pidlSelect will select the current select pidl
  787. HRESULT CHistBand::_SelectPidl(LPCITEMIDLIST pidlSelect, // <-Standard Hist-type pidl to select
  788. BOOL fCreate, // <-create NSC item if not there?
  789. LPCITEMIDLIST pidlView,/*=NULL*/ // <-special history view type or NULL
  790. BOOL fReinsert /*=0*/) // <-reinsert pidl into NSC and re-sort
  791. {
  792. HRESULT hRes = S_OK;
  793. BOOL fFreePidlSelect = FALSE;
  794. if ( (!pidlSelect) &&
  795. ((pidlSelect = _GetCurrentSelectPidl())) )
  796. fFreePidlSelect = TRUE;
  797. if (pidlSelect) {
  798. LPITEMIDLIST pidlNewSelect = NULL;
  799. // cache the last selected pidl
  800. if (_pidlLastSelect != pidlSelect) {
  801. if (_pidlLastSelect)
  802. ILFree(_pidlLastSelect);
  803. _pidlLastSelect = ILClone(pidlSelect);
  804. }
  805. if (pidlView && !ILIsEmpty(pidlView)) {
  806. IShellFolderViewType *psfvtInfo = _GetViewTypeInfo();
  807. if (psfvtInfo) {
  808. LPITEMIDLIST pidlFromRoot = ILFindChild(_pidlHistory,
  809. pidlSelect);
  810. if (pidlFromRoot && !ILIsEmpty(pidlFromRoot))
  811. {
  812. LPITEMIDLIST pidlNewFromRoot;
  813. if (SUCCEEDED(psfvtInfo->TranslateViewPidl(pidlFromRoot, pidlView,
  814. &pidlNewFromRoot)))
  815. {
  816. if (pidlNewFromRoot) {
  817. pidlNewSelect = ILCombine(_pidlHistory, pidlNewFromRoot);
  818. if (pidlNewSelect) {
  819. _pns->SetSelectedItem(pidlNewSelect, fCreate, fReinsert, 0);
  820. ILFree(pidlNewSelect);
  821. }
  822. ILFree(pidlNewFromRoot);
  823. }
  824. }
  825. }
  826. psfvtInfo->Release();
  827. }
  828. }
  829. else
  830. _pns->SetSelectedItem(pidlSelect, fCreate, fReinsert, 0);
  831. if (fFreePidlSelect)
  832. ILFree(const_cast<LPITEMIDLIST>(pidlSelect));
  833. }
  834. return hRes;
  835. }
  836. HRESULT CHistBand::_SetRegistryPersistView(int iMenuID)
  837. {
  838. LPCITEMIDLIST pidlReg = _MenuIDToPIDL(iMenuID);
  839. if (!pidlReg)
  840. return E_FAIL;
  841. LONG lRet = (SHRegSetUSValue(REGSTR_PATH_MAIN, REGKEY_HISTORY_VIEW,
  842. REG_BINARY, (LPVOID)pidlReg, ILGetSize(pidlReg),
  843. SHREGSET_HKCU | SHREGSET_FORCE_HKCU));
  844. return HRESULT_FROM_WIN32(lRet);
  845. }
  846. // Get the default view from the registry as a menu item
  847. int CHistBand::_GetRegistryPersistView()
  848. {
  849. int iRegMenu = -1;
  850. DWORD dwType = REG_BINARY;
  851. ITEMIDLIST pidlDefault = { 0 };
  852. // make a preliminary call to find out the size of the data
  853. DWORD cbData = 0;
  854. LONG error = SHRegGetUSValue(REGSTR_PATH_MAIN, REGKEY_HISTORY_VIEW, &dwType,
  855. NULL, &cbData, FALSE, &pidlDefault,
  856. sizeof(pidlDefault));
  857. if (cbData)
  858. {
  859. LPITEMIDLIST pidlReg = ((LPITEMIDLIST)SHAlloc(cbData));
  860. if (pidlReg)
  861. {
  862. error = SHRegGetUSValue(REGSTR_PATH_MAIN, REGKEY_HISTORY_VIEW, &dwType,
  863. (LPVOID)pidlReg, &cbData, FALSE, &pidlDefault,
  864. sizeof(pidlDefault));
  865. if (error == ERROR_SUCCESS)
  866. iRegMenu = _PIDLToMenuID(pidlReg);
  867. SHFree(pidlReg);
  868. }
  869. }
  870. return iRegMenu;
  871. }
  872. LPCITEMIDLIST CHistBand::_MenuIDToPIDL(UINT uMenuID)
  873. {
  874. ASSERT(_ppidlViewTypes);
  875. if ((uMenuID > 0) && (uMenuID <= _nViews))
  876. return _ppidlViewTypes[uMenuID - 1];
  877. return NULL;
  878. }
  879. int CHistBand::_PIDLToMenuID(LPITEMIDLIST pidl)
  880. {
  881. ASSERT(_psfHistory && _ppidlViewTypes);
  882. int iMenuID = -1;
  883. // handle the empty pidl, which designates the
  884. // default view, separately
  885. if (ILIsEmpty(pidl))
  886. iMenuID = 1;
  887. else
  888. {
  889. for (UINT u = 0; u < _nViews; ++u)
  890. {
  891. if (_psfHistory->CompareIDs(0, pidl, _ppidlViewTypes[u]) == 0)
  892. iMenuID = u + 1;
  893. }
  894. }
  895. return iMenuID;
  896. }
  897. // remember to release return value
  898. IShellFolderViewType* CHistBand::_GetViewTypeInfo()
  899. {
  900. IShellFolderViewType* psfvRet = NULL;
  901. if (_psfvtCache)
  902. {
  903. _psfvtCache->AddRef();
  904. psfvRet = _psfvtCache;
  905. }
  906. else if (_psfHistory)
  907. {
  908. // QI For the views
  909. // We set the pointer because of a bad QI somewhere...
  910. if (SUCCEEDED(_psfHistory->QueryInterface(IID_IShellFolderViewType,
  911. ((void**)&psfvRet))))
  912. {
  913. _psfvtCache = psfvRet;
  914. psfvRet->AddRef(); // one released in destructor, another by caller
  915. }
  916. else
  917. psfvRet = NULL;
  918. }
  919. return psfvRet;
  920. }
  921. HRESULT CHistBand::_FreeViewInfo()
  922. {
  923. if (_ppidlViewTypes)
  924. {
  925. // the first pidl in this list is NULL, the default view
  926. for (UINT u = 0; u < _nViews; ++u)
  927. if (EVAL(_ppidlViewTypes[u]))
  928. ILFree(_ppidlViewTypes[u]);
  929. LocalFree(_ppidlViewTypes);
  930. _ppidlViewTypes = NULL;
  931. }
  932. if (_ppszStrViewNames)
  933. {
  934. for (UINT u = 0; u < _nViews; ++u)
  935. if (EVAL(_ppszStrViewNames[u]))
  936. CoTaskMemFree(_ppszStrViewNames[u]);
  937. LocalFree(_ppszStrViewNames);
  938. _ppszStrViewNames = NULL;
  939. }
  940. return S_OK;
  941. }
  942. // Load the popup menu (if there are views to be had)
  943. HRESULT CHistBand::_InitViewPopup()
  944. {
  945. HRESULT hRes = E_FAIL;
  946. _iMaxMenuID = 0;
  947. if (SUCCEEDED((hRes = _GetHistoryViews())))
  948. {
  949. if ((_hViewMenu = CreatePopupMenu()))
  950. {
  951. // the IDCMD for the view menu will always be
  952. // one more than the index into the view tables
  953. for (UINT u = 0; u < _nViews; ++u)
  954. {
  955. int iMenuID = _PIDLToMenuID(_ppidlViewTypes[u]);
  956. if (iMenuID >= 0)
  957. AppendMenu(_hViewMenu, MF_STRING, iMenuID,
  958. _ppszStrViewNames[u]);
  959. if (iMenuID > _iMaxMenuID)
  960. _iMaxMenuID = iMenuID;
  961. }
  962. // retrieve the persisted view information
  963. // and check the corresponding menu item
  964. int iSelectMenuID = _GetRegistryPersistView();
  965. if (iSelectMenuID < 0 || ((UINT)iSelectMenuID) > _nViews)
  966. iSelectMenuID = 1; //bogus menuid
  967. _uViewCheckedItem = iSelectMenuID;
  968. CheckMenuRadioItem(_hViewMenu, 1, _nViews, _uViewCheckedItem, MF_BYCOMMAND);
  969. }
  970. }
  971. #ifdef HISTORY_VIEWSEARCHMENU
  972. // if this is a searchable shell folder, then add the search menu item
  973. if (_EnsureSearch())
  974. {
  975. hRes = S_OK;
  976. // only add separator if there is a menu already!
  977. if (!_hViewMenu)
  978. _hViewMenu = CreatePopupMenu();
  979. else
  980. AppendMenu(_hViewMenu, MF_SEPARATOR, 0, NULL);
  981. if (_hViewMenu)
  982. {
  983. TCHAR szSearchMenuText[MAX_PATH];
  984. LoadString(MLGetHinst(), IDS_SEARCH_MENUOPT,
  985. szSearchMenuText, ARRAYSIZE(szSearchMenuText));
  986. AppendMenu(_hViewMenu, MF_STRING, MENUID_SEARCH, szSearchMenuText);
  987. _iMaxMenuID = MENUID_SEARCH;
  988. }
  989. else
  990. hRes = E_FAIL;
  991. }
  992. #endif
  993. return hRes;
  994. }
  995. // This guy calls the enumerator
  996. HRESULT CHistBand::_GetHistoryViews()
  997. {
  998. ASSERT(_psfHistory);
  999. HRESULT hRes = E_FAIL;
  1000. UINT cbViews; // how many views are allocated
  1001. ASSERT(VIEWTYPE_MAX > 0);
  1002. EVAL(SUCCEEDED(_FreeViewInfo()));
  1003. IShellFolderViewType *psfViewType = _GetViewTypeInfo();
  1004. if (psfViewType)
  1005. {
  1006. // allocate buffers to store the view information
  1007. _ppidlViewTypes = ((LPITEMIDLIST *)LocalAlloc(LPTR, VIEWTYPE_MAX * sizeof(LPITEMIDLIST)));
  1008. if (_ppidlViewTypes) {
  1009. _ppszStrViewNames = ((LPTSTR *)LocalAlloc(LPTR, VIEWTYPE_MAX * sizeof(LPTSTR)));
  1010. if (_ppszStrViewNames) {
  1011. IEnumIDList *penum = NULL;
  1012. cbViews = VIEWTYPE_MAX;
  1013. _nViews = 1;
  1014. // get the default view information
  1015. _ppidlViewTypes[0] = IEILCreate(sizeof(ITEMIDLIST));
  1016. if (_ppidlViewTypes[0] &&
  1017. SUCCEEDED((hRes = psfViewType->GetDefaultViewName(0, &(_ppszStrViewNames[0])))))
  1018. {
  1019. // empty pidl will be the default
  1020. ASSERT(ILIsEmpty(_ppidlViewTypes[0]));
  1021. // get the iterator for the other views
  1022. if (SUCCEEDED((hRes = psfViewType->EnumViews(0, &penum)))) {
  1023. ULONG cFetched = 0;
  1024. // iterate to get other view information
  1025. while(SUCCEEDED(hRes) &&
  1026. SUCCEEDED(penum->Next(1, &(_ppidlViewTypes[_nViews]), &cFetched)) &&
  1027. cFetched)
  1028. {
  1029. // get the name of this view
  1030. if (SUCCEEDED(DisplayNameOfAsOLESTR(_psfHistory, _ppidlViewTypes[_nViews], 0, &(_ppszStrViewNames[_nViews]))))
  1031. {
  1032. // prepare for next iteration by reallocating the buffer if necessary
  1033. if (_nViews > cbViews - 1)
  1034. {
  1035. LPITEMIDLIST *ppidlViewTypes = ((LPITEMIDLIST *)LocalReAlloc(_ppidlViewTypes,
  1036. (cbViews + VIEWTYPE_REALLOC) * sizeof(LPITEMIDLIST),
  1037. LMEM_MOVEABLE | LMEM_ZEROINIT));
  1038. if (ppidlViewTypes)
  1039. {
  1040. _ppidlViewTypes = ppidlViewTypes;
  1041. LPTSTR * ppszStrViewNames = ((LPTSTR *)LocalReAlloc(_ppszStrViewNames,
  1042. (cbViews + VIEWTYPE_REALLOC) * sizeof(LPTSTR),
  1043. LMEM_MOVEABLE | LMEM_ZEROINIT));
  1044. if (ppszStrViewNames)
  1045. {
  1046. _ppszStrViewNames = ppszStrViewNames;
  1047. cbViews += VIEWTYPE_REALLOC;
  1048. }
  1049. else
  1050. {
  1051. hRes = E_OUTOFMEMORY;
  1052. break;
  1053. }
  1054. }
  1055. else
  1056. {
  1057. hRes = E_OUTOFMEMORY;
  1058. break;
  1059. }
  1060. }
  1061. ++_nViews;
  1062. }
  1063. }
  1064. penum->Release();
  1065. }
  1066. }
  1067. }
  1068. }
  1069. psfViewType->Release();
  1070. }
  1071. return hRes;
  1072. }
  1073. HRESULT CHistBand_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  1074. {
  1075. // aggregation checking is handled in class factory
  1076. CHistBand * phb = new CHistBand();
  1077. if (!phb)
  1078. return E_OUTOFMEMORY;
  1079. ASSERT(phb->_pidlHistory == NULL &&
  1080. phb->_pidlLastSelect == NULL &&
  1081. phb->_pidl == NULL &&
  1082. phb->_psfvtCache == NULL);
  1083. if (SUCCEEDED(SHGetHistoryPIDL(&(phb->_pidlHistory))) &&
  1084. SUCCEEDED(IEBindToObject(phb->_pidlHistory,
  1085. &(phb->_psfHistory))))
  1086. {
  1087. HRESULT hResLocal = E_FAIL;
  1088. // if we can get different views, then init with the persisted
  1089. // view type, otherwise, init with the top-level history type
  1090. if (SUCCEEDED(phb->_InitViewPopup())) {
  1091. LPCITEMIDLIST pidlInit = phb->_MenuIDToPIDL(phb->_uViewCheckedItem);
  1092. if (pidlInit) {
  1093. LPITEMIDLIST pidlFullInit = ILCombine(phb->_pidlHistory, pidlInit);
  1094. if (pidlFullInit) {
  1095. hResLocal = phb->_Init(pidlFullInit);
  1096. ILFree(pidlFullInit);
  1097. }
  1098. }
  1099. }
  1100. else
  1101. hResLocal = phb->_Init(phb->_pidlHistory);
  1102. // From old favband code: // if (SUCCEEDED(phb->_Init((LPCITEMIDLIST)CSIDL_FAVORITES)))
  1103. if (SUCCEEDED(hResLocal))
  1104. {
  1105. phb->_pns = CNscTree_CreateInstance();
  1106. if (phb->_pns)
  1107. {
  1108. ASSERT(poi);
  1109. phb->_poi = poi;
  1110. // if you change this cast, fix up CChannelBand_CreateInstance
  1111. *ppunk = SAFECAST(phb, IDeskBand *);
  1112. IUnknown_SetSite(phb->_pns, *ppunk);
  1113. phb->_SetNscMode(MODE_HISTORY);
  1114. return S_OK;
  1115. }
  1116. }
  1117. }
  1118. phb->Release();
  1119. return E_FAIL;
  1120. }
  1121. // Ask the powers that be which pidl is selected...
  1122. LPITEMIDLIST CHistBand::_GetCurrentSelectPidl(IOleCommandTarget *poctProxy/* = NULL*/)
  1123. {
  1124. LPITEMIDLIST pidlRet = NULL;
  1125. VARIANT var;
  1126. BOOL fReleaseProxy = FALSE;
  1127. VariantInit(&var);
  1128. var.vt = VT_EMPTY;
  1129. if (poctProxy == NULL)
  1130. {
  1131. IBrowserService *pswProxy;
  1132. if (SUCCEEDED(QueryService(SID_SProxyBrowser, IID_PPV_ARG(IBrowserService, &pswProxy))))
  1133. {
  1134. ASSERT(pswProxy);
  1135. if (FAILED(pswProxy->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &poctProxy))))
  1136. {
  1137. pswProxy->Release();
  1138. return NULL;
  1139. }
  1140. else
  1141. fReleaseProxy = TRUE;
  1142. pswProxy->Release();
  1143. }
  1144. }
  1145. // Inquire the current select pidl
  1146. if ((SUCCEEDED(poctProxy->Exec(&CGID_Explorer, SBCMDID_GETHISTPIDL,
  1147. OLECMDEXECOPT_PROMPTUSER, NULL, &var))) &&
  1148. (var.vt != VT_EMPTY))
  1149. {
  1150. pidlRet = VariantToIDList(&var);
  1151. VariantClearLazy(&var);
  1152. }
  1153. if (fReleaseProxy)
  1154. poctProxy->Release();
  1155. return pidlRet;
  1156. }
  1157. // gets called by CNSCBand::ShowDW every time history band is shown
  1158. HRESULT CHistBand::_OnRegisterBand(IOleCommandTarget *poctProxy)
  1159. {
  1160. HRESULT hRes = E_FAIL;
  1161. if (_uViewCheckedItem != MENUID_SEARCH)
  1162. {
  1163. LPITEMIDLIST pidlSelect = _GetCurrentSelectPidl(poctProxy);
  1164. if (pidlSelect)
  1165. {
  1166. _SelectPidl(pidlSelect, TRUE);
  1167. ILFree(pidlSelect);
  1168. hRes = S_OK;
  1169. }
  1170. }
  1171. return hRes;
  1172. }
  1173. HRESULT CHistBand::_InitializeNsc()
  1174. {
  1175. return _pns->Initialize(_pidl, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, NSS_NOHISTSELECT | NSS_DROPTARGET | NSS_BROWSERSELECT);
  1176. }
  1177. BOOL CHistBand::_ShouldNavigateToPidl(LPCITEMIDLIST pidl, ULONG ulAttrib)
  1178. {
  1179. return !(ulAttrib & SFGAO_FOLDER);
  1180. }
  1181. HRESULT CHistBand::_NavigateRightPane(IShellBrowser *psb, LPCITEMIDLIST pidl)
  1182. {
  1183. HRESULT hr = psb->BrowseObject(pidl, SBSP_SAMEBROWSER | SBSP_NOAUTOSELECT);
  1184. if (SUCCEEDED(hr))
  1185. {
  1186. IOleCommandTarget *poctProxy;
  1187. if (SUCCEEDED(QueryService(SID_SProxyBrowser, IID_PPV_ARG(IOleCommandTarget, &poctProxy))))
  1188. {
  1189. VARIANTARG var;
  1190. InitVariantFromIDList(&var, pidl);
  1191. poctProxy->Exec(&CGID_Explorer, SBCMDID_SELECTHISTPIDL, OLECMDEXECOPT_PROMPTUSER, &var, NULL);
  1192. VariantClear(&var);
  1193. poctProxy->Release();
  1194. }
  1195. UEMFireEvent(&UEMIID_BROWSER, UEME_INSTRBROWSER, UEMF_INSTRUMENT, UIBW_NAVIGATE, UIBL_NAVHIST);
  1196. }
  1197. return hr;
  1198. }