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.

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