histband.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 49k
Category:

Windows Kernel

Development Platform:

Visual C++

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