#include "priv.h"
#include "sccls.h"
#include "nscband.h"
#include "nsc.h"
#include "resource.h"
#include "dhuihand.h"
#include <varutil.h>

#include <mluisupp.h>

#define DM_HISTBAND     0x0000000
#define DM_GUIPAINS     0x40000000

#define REGKEY_HISTORY_VIEW TEXT("HistoryViewType")
#define REGKEY_DEFAULT_SIZE 0x10

#define VIEWTYPE_MAX        0x4  // A "guess" at how many viewtypes thare will be
#define VIEWTYPE_REALLOC    0x4  // How many to realloc at a time

// these are temporary
#define MENUID_SEARCH       0x4e4e

// Distance between history search go and stop buttons
#define HISTSRCH_BUTTONDIST 6 

extern HINSTANCE     g_hinst;

#define WM_SEARCH_STATE (WM_USER + 314)

class CHistBand : public CNSCBand,
                  public IShellFolderSearchableCallback
{
    friend HRESULT CHistBand_CreateInstance(IUnknown *punkOuter,
                                            IUnknown **ppunk, LPCOBJECTINFO poi);
public:
    // *** IUnknown methods ***
    STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
    STDMETHODIMP_(ULONG) AddRef (void) { return CNSCBand::AddRef();  };
    STDMETHODIMP_(ULONG) Release(void) { return CNSCBand::Release(); };
    
    // *** IOleCommandTarget methods ***
    STDMETHODIMP Exec(const GUID *pguidCmdGroup,
                  DWORD nCmdID,
                  DWORD nCmdexecopt,
                  VARIANTARG *pvarargIn,
                  VARIANTARG *pvarargOut);

    // *** IOleWindow methods ***
    //  (overriding CNSCBand implementation
    STDMETHODIMP GetWindow(HWND *phwnd);

    // *** IInputObject methods ***
    //  (overriding CNSCBand/CToolBand's implementation)
    STDMETHODIMP TranslateAcceleratorIO(LPMSG lpMsg);

    // *** IDockingWindow methods ***
    STDMETHODIMP ShowDW(BOOL fShow);

    // *** IShellFolderSearchableCallback methods ***
    STDMETHODIMP RunBegin(DWORD dwReserved);
    STDMETHODIMP RunEnd(DWORD dwReserved);
    
protected:
    virtual void    _AddButtons(BOOL fAdd);
    virtual HRESULT _OnRegisterBand(IOleCommandTarget *poctProxy);
    virtual BOOL _ShouldNavigateToPidl(LPCITEMIDLIST pidl, ULONG ulAttrib);
    virtual HRESULT _NavigateRightPane(IShellBrowser *psb, LPCITEMIDLIST pidl);

    ~CHistBand();

    HRESULT       _InitViewPopup();
    HRESULT       _DoViewPopup(int x, int y);
    HRESULT       _ViewPopupSelect(UINT idCmd);

#ifdef SPLIT_HISTORY_VIEW_BUTTON
    UINT          _NextMenuItem();
#endif

    HRESULT       _ChangePidl(LPITEMIDLIST);
    HRESULT       _SelectPidl(LPCITEMIDLIST pidlSelect, BOOL fCreate,
                              LPCITEMIDLIST pidlViewType = NULL,
                              BOOL fReinsert = FALSE);

    virtual HRESULT _InitializeNsc();
    LPITEMIDLIST  _GetCurrentSelectPidl(IOleCommandTarget *poctProxy = NULL);
    HRESULT       _SetRegistryPersistView(int iMenuID);
    int           _GetRegistryPersistView();
    LPCITEMIDLIST _MenuIDToPIDL(UINT uMenuID);
    int           _PIDLToMenuID(LPITEMIDLIST pidl);
    IShellFolderViewType*  _GetViewTypeInfo();
    HRESULT       _GetHistoryViews();
    HRESULT       _FreeViewInfo();

    void          _ResizeChildWindows(LONG width, LONG height, BOOL fRepaint);
    HRESULT       _DoSearchUIStuff();
    HRESULT       _ExecuteSearch(LPTSTR pszSearchString);
    HRESULT       _ClearSearch();
    IShellFolderSearchable *_EnsureSearch();
    static LRESULT CALLBACK s_EditWndSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
    static LRESULT CALLBACK s_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
    static BOOL_PTR    CALLBACK s_HistSearchDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
    
    BOOL  _fStrsAdded;  // Strings from resource have been added as buttons on the toolbar
    LONG_PTR  _lStrOffset;

    HMENU _hViewMenu;          // an instance var so we can cache it
    UINT  _uViewCheckedItem;   // which menuitem in the View menu is checked?

    LPITEMIDLIST *_ppidlViewTypes;
    LPTSTR       *_ppszStrViewNames;
    UINT          _nViews;
    int           _iMaxMenuID;

    HWND          _hwndNSC;
    HWND          _hwndSearchDlg;
    LONG          _lSearchDlgHeight;
    LPITEMIDLIST  _pidlSearch;  // current search
    IShellFolderSearchable *_psfSearch;
    
    LPITEMIDLIST  _pidlHistory; // cache the history pidl from SHGetHistoryPIDL
    IShellFolder *_psfHistory;  // cache the history shell folder
    IShellFolderViewType  *_psfvtCache;  // view type information

    LPITEMIDLIST  _pidlLastSelect;
};

CHistBand::~CHistBand() 
{
    DestroyMenu(_hViewMenu);
    if (_pidlLastSelect)
        ILFree(_pidlLastSelect);
    if (_pidlHistory)
        ILFree(_pidlHistory);
    if (_psfHistory)
        _psfHistory->Release();
    if (_psfvtCache)
        _psfvtCache->Release();
   
    _ClearSearch(); // Frees _pidlSearch 
    if (_psfSearch)
        _psfSearch->Release();
    
    _FreeViewInfo();
}

HRESULT CHistBand::QueryInterface(REFIID riid, void **ppvObj)
{
    static const QITAB qit[] = {
        QITABENT(CHistBand, IShellFolderSearchableCallback),  // IID_IShellFolderSearchableCallback
        { 0 },
    };
    HRESULT hr = QISearch(this, qit, riid, ppvObj);
    if (FAILED(hr))
        hr = CNSCBand::QueryInterface(riid, ppvObj);
    return hr;
}

// *** IOleCommandTarget methods ***
HRESULT CHistBand::Exec(const GUID *pguidCmdGroup, DWORD nCmdID,
                        DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
{
    HRESULT hRes = S_OK;
    if (pguidCmdGroup)
    {
        if (IsEqualGUID(CLSID_HistBand, *pguidCmdGroup))
        {
            switch(nCmdID)
            {
            case FCIDM_HISTBAND_VIEW:
                if (pvarargIn && (pvarargIn->vt == VT_I4))
                {
#ifdef SPLIT_HISTORY_VIEW_BUTTON
                    if (nCmdexecopt == OLECMDEXECOPT_PROMPTUSER)
                        hRes = _DoViewPopup(GET_X_LPARAM(pvarargIn->lVal), GET_Y_LPARAM(pvarargIn->lVal));
                    else
                        hRes = _ViewPopupSelect(_NextMenuItem());
#else
                    ASSERT(nCmdexecopt == OLECMDEXECOPT_PROMPTUSER);
                    hRes = _DoViewPopup(GET_X_LPARAM(pvarargIn->lVal), GET_Y_LPARAM(pvarargIn->lVal));
#endif
                }
                else
                    ASSERT(0);
                break;
                
            case FCIDM_HISTBAND_SEARCH:
                _ViewPopupSelect(MENUID_SEARCH);
                break;
            }
        }
        else if ((IsEqualGUID(CGID_Explorer, *pguidCmdGroup)))
        {
            switch (nCmdID)
            {
            case SBCMDID_SELECTHISTPIDL:
#ifdef ANNOYING_HISTORY_AUTOSELECT
                if (_uViewCheckedItem != MENUID_SEARCH)
                {
                    LPCITEMIDLIST pidlSelect = VariantToIDList(pvarargIn);

                    // Get the current view information
                    LPCITEMIDLIST pidlView = _MenuIDToPIDL(_uViewCheckedItem);
                    DWORD dwViewFlags = SFVTFLAG_NOTIFY_CREATE;
                    IShellFolderViewType* psfvtInfo = _GetViewTypeInfo();

                    if (psfvtInfo)
                    {
                        // query for view type properties -- this will tell us how to
                        //   select the item...
                        hRes = psfvtInfo->GetViewTypeProperties(pidlView,
                                                                &dwViewFlags);
                        psfvtInfo->Release();
                    }
                    if (SUCCEEDED(hRes))
                    {
                        hRes = _SelectPidl(pidlSelect, dwViewFlags & SFVTFLAG_NOTIFY_CREATE,
                                           pidlView,   dwViewFlags & SFVTFLAG_NOTIFY_RESORT);
                    }
                    ILFree(pidlSelect);
                }
                else //eat it, so that nsc doesn't get it
                    hRes = S_OK;
#endif //ANNOYING_HISTORY_AUTOSELECT
                hRes = S_OK;
                break;
                
            case SBCMDID_FILEDELETE:
                hRes = _InvokeCommandOnItem(TEXT("delete"));
                break;
            }
        }
        else
            hRes = CNSCBand::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
    }
    else
        hRes =  CNSCBand::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
    return hRes;
}

// *** IInputObject methods ***
HRESULT CHistBand::TranslateAcceleratorIO(LPMSG pmsg)
{
#ifdef DEBUG
    if (pmsg->message == WM_KEYDOWN)
        TraceMsg(DM_GUIPAINS, "CHistBand -- TranslateAcceleratorIO called and _hwndSearchDlg is %x", _hwndSearchDlg);
#endif

    HWND hwndFocus = GetFocus();
    
    // Translate accelerator messages for dialog
    if ( (_hwndSearchDlg) && (hwndFocus != _hwndNSC) && (!hwndFocus || !IsChild(_hwndNSC, hwndFocus)) )
    {
        if (pmsg->message == WM_KEYDOWN)
        {
            if (IsVK_TABCycler(pmsg))
            {
                BOOL fBackwards = (GetAsyncKeyState(VK_SHIFT) < 0);
                HWND hwndCur = pmsg->hwnd;
                if (GetParent(pmsg->hwnd) != _hwndSearchDlg)
                    hwndCur = NULL;
                
                HWND hwndNext  = GetNextDlgTabItem(_hwndSearchDlg, hwndCur, fBackwards);
                
                // Get the First dialog item in this searching order
                HWND hwndFirst;
                if (!fBackwards) {
                    hwndFirst = GetNextDlgTabItem(_hwndSearchDlg, NULL, FALSE);
                }
                else
                    // passing NULL for the 2nd parameter returned NULL with ERROR_SUCCESS,
                    //  so this is a workaround
                    hwndFirst = GetNextDlgTabItem(_hwndSearchDlg,
                                                  GetNextDlgTabItem(_hwndSearchDlg,
                                                                    NULL, FALSE), TRUE);
                
                // If the next dialog tabstop is the first dialog tabstop, then
                //   let someone else get focus
                if ((!hwndCur) || (hwndNext != hwndFirst))
                {
                    SetFocus(hwndNext);
                    return S_OK;
                }
                else if (!fBackwards) {
                    SetFocus(_hwndNSC);
                    return S_OK;
                }
            }
            else if ( (pmsg->wParam == VK_RETURN) )
                SendMessage(_hwndSearchDlg, WM_COMMAND, MAKELONG(GetDlgCtrlID(pmsg->hwnd), 0), 0L);
        }
        // The History Search Edit Box is activated
        if (pmsg->hwnd == GetDlgItem(_hwndSearchDlg, IDC_EDITHISTSEARCH)) {
            // If the user pressed tab within the dialog
            return EditBox_TranslateAcceleratorST(pmsg);
        }
    }
    return CNSCBand::TranslateAcceleratorIO(pmsg);
}

// sends appropriate resize messages to our children windows
void CHistBand::_ResizeChildWindows(LONG width, LONG height, BOOL fRepaint)
{
    if (_hwndNSC)
    {
        int y1 = _hwndSearchDlg ? _lSearchDlgHeight : 0;
        int y2 = _hwndSearchDlg ? height - _lSearchDlgHeight : height;

        MoveWindow(_hwndNSC, 0, y1, width, y2, fRepaint);
    }

    if (_hwndSearchDlg)
    {
        MoveWindow(_hwndSearchDlg, 0, 0, width, _lSearchDlgHeight, fRepaint);
    }
}

HRESULT CHistBand::_DoSearchUIStuff()
{
    HRESULT hr;

    // host the search dialog inside my window:
    _hwndSearchDlg = CreateDialogParam(MLGetHinst(), MAKEINTRESOURCE(DLG_HISTSEARCH2),
                                       _hwnd, s_HistSearchDlgProc, reinterpret_cast<LPARAM>(this));

    if (_hwndSearchDlg)
    {
        RECT rcSelf;
        GetClientRect(_hwnd, &rcSelf);
    
        RECT rcDlg;
        GetClientRect(_hwndSearchDlg, &rcDlg);

        _lSearchDlgHeight = rcDlg.bottom;

        _ResizeChildWindows(rcSelf.right, rcSelf.bottom, TRUE);
        ShowWindow(_hwndSearchDlg, SW_SHOWDEFAULT);

        hr = S_OK;
    }
    else
    {
        hr = E_FAIL;
    }

    return hr;
}

// WndProc for main window to go in rebar
LRESULT CALLBACK CHistBand::s_WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    CHistBand* phb = reinterpret_cast<CHistBand *>(GetWindowLongPtr(hWnd, GWLP_USERDATA));

    switch (msg)
    {
    case WM_SETFOCUS:
        {
            TraceMsg(DM_GUIPAINS, "Histband Parent -- SETFOCUS");
            // The only way this should be called is via a RB_CYCLEFOCUS->...->UIActivateIO->SetFocus
            //  therefore, we can assume that we're being tabbed into or something with equally good.
            // If we tab into the outer dummy window, transfer the focus to
            //  our appropriate child:
            BOOL fBackwards = (GetAsyncKeyState(VK_SHIFT) < 0);
            if (phb->_hwndSearchDlg) {
                // Select either the first or the last item in the dialog depending on
                //  whether we're shifting in or shifting out
                SetFocus(GetNextDlgTabItem(phb->_hwndSearchDlg, (NULL), fBackwards));
            }
            else {
                TraceMsg(DM_GUIPAINS, "NSC is being given focus!");
                SetFocus(phb->_hwndNSC);
            }
        }
        return 0;
    case WM_CREATE:
        SetWindowLongPtr(hWnd, GWLP_USERDATA,
                      (reinterpret_cast<LONG_PTR>((reinterpret_cast<CREATESTRUCT *>(lParam))->lpCreateParams)));
        return 0;
    case WM_SIZE:
        if (phb)
            phb->_ResizeChildWindows(LOWORD(lParam), HIWORD(lParam), TRUE);
        return 0;
    case WM_NCDESTROY:
        //make sure the search object gets freed when the view/window is destroyed, because it holds a ref to us
        phb->_ClearSearch();
        break;
        
    case WM_NOTIFY:
        {
            if (phb) {
                // We proxy the notification messages to our own parent who thinks that we
                //  are the namespace control
                LPNMHDR pnmh = (LPNMHDR)lParam;
                
                // Notification message coming from NSC
                if (pnmh->hwndFrom == phb->_hwndNSC)
                    return SendMessage(phb->_hwndParent, msg, wParam, lParam);
            }
        } // INTENTIONAL FALLTHROUGH
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}

// *** IOleWindow methods ***
HRESULT CHistBand::GetWindow(HWND *phwnd)
{
    if (!_hwnd)
    {
        // we want to wrap a window around the namespace control so
        //  that we can add siblings later
        
        // Get our parent's dimensions
        RECT rcParent;
        GetClientRect(_hwndParent, &rcParent);

        static LPTSTR pszClassName = TEXT("History Pane");

        WNDCLASSEX wndclass    = { 0 };
        wndclass.cbSize        = sizeof(wndclass);
        wndclass.style         = CS_PARENTDC | CS_HREDRAW | CS_VREDRAW;
        wndclass.lpfnWndProc   = s_WndProc;
        wndclass.hInstance     = g_hinst;
        wndclass.hCursor       = LoadCursor(NULL, IDC_ARROW);
        wndclass.lpszClassName = pszClassName;

        RegisterClassEx(&wndclass);
    
        _hwnd = CreateWindow(pszClassName, TEXT("History Window"),
                             WS_CHILD | WS_TABSTOP,
                             0, 0, rcParent.right, rcParent.bottom,
                             _hwndParent, NULL, g_hinst, (LPVOID)this);
    }
    
    if (_hwnd)   // Host NSC
        _pns->CreateTree(_hwnd, _GetTVStyle(), &_hwndNSC);

    return CToolBand::GetWindow(phwnd);
}

// *** IDockingWindow methods ***
HRESULT CHistBand::ShowDW(BOOL fShow)
{
    HRESULT hr = CNSCBand::ShowDW(fShow);
    _AddButtons(fShow);
    return hr;
}

static const TBBUTTON c_tbHistory[] =
{
    { I_IMAGENONE, FCIDM_HISTBAND_VIEW,   TBSTATE_ENABLED, BTNS_AUTOSIZE | BTNS_WHOLEDROPDOWN | BTNS_SHOWTEXT,  {0,0}, 0, 0 },
    {           2, FCIDM_HISTBAND_SEARCH, TBSTATE_ENABLED, BTNS_AUTOSIZE | BTNS_SHOWTEXT,                       {0,0}, 0, 1 },
};

// Adds buttons from the above table to the Explorer
void CHistBand::_AddButtons(BOOL fAdd)
{
    // don't add button if we have no menu
    if (!_hViewMenu)
        return;

    IExplorerToolbar* piet;

    if (SUCCEEDED(_punkSite->QueryInterface(IID_IExplorerToolbar, (void**)&piet)))
    {
        if (fAdd)
        {
            piet->SetCommandTarget((IUnknown*)SAFECAST(this, IOleCommandTarget*), &CLSID_HistBand, 0);

            if (!_fStrsAdded)
            {
                piet->AddString(&CLSID_HistBand, MLGetHinst(), IDS_HIST_BAR_LABELS, &_lStrOffset);
                _fStrsAdded = TRUE;
            }

            _EnsureImageListsLoaded();
            piet->SetImageList(&CLSID_HistBand, _himlNormal, _himlHot, NULL);

            TBBUTTON tbHistory[ARRAYSIZE(c_tbHistory)];
            memcpy(tbHistory, c_tbHistory, SIZEOF(TBBUTTON) * ARRAYSIZE(c_tbHistory));
            for (int i = 0; i < ARRAYSIZE(c_tbHistory); i++)
                tbHistory[i].iString += (long) _lStrOffset;

            piet->AddButtons(&CLSID_HistBand, ARRAYSIZE(tbHistory), tbHistory);
        }
        else
            piet->SetCommandTarget(NULL, NULL, 0);

        piet->Release();
    }
}

// *** IShellFolderSearchableCallback methods ***
// enable and disable cancel buttons 
HRESULT CHistBand::RunBegin(DWORD dwReserved)
{
    HRESULT hr = E_FAIL;
    if (_hwndSearchDlg)
    {
        SendMessage(_hwndSearchDlg, WM_SEARCH_STATE, (WPARAM)TRUE, NULL);
        hr = S_OK;
    }
    return hr;
}

HRESULT CHistBand::RunEnd(DWORD dwReserved)
{
    HRESULT hr = E_FAIL;
    if (_hwndSearchDlg)
    {
        SendMessage(_hwndSearchDlg, WM_SEARCH_STATE, (WPARAM)FALSE, NULL);
        hr = S_OK;
    }
    return hr;
}

// A utility function used in the WM_SIZE handling below...
inline HWND _GetHwndAndRect(HWND hwndDlg, int item, BOOL fClient, RECT &rc) {
    HWND hwnd = GetDlgItem(hwndDlg, item);
    if (fClient)
        GetClientRect(hwnd, &rc);
    else {
        GetWindowRect(hwnd, &rc);
        MapWindowPoints(NULL, hwndDlg, ((LPPOINT)&rc), 2);
    }
    return hwnd;
}

LRESULT CALLBACK CHistBand::s_EditWndSubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg) {
    case WM_KEYDOWN:
        if ((GetAsyncKeyState(VK_CONTROL) < 0) &&
            (wParam == TEXT('U'))) {
            uMsg   = WM_SETTEXT;
            wParam = 0;
            lParam = ((LPARAM)(LPCTSTR)TEXT(""));
        }
        break;

    case WM_CHAR:
        if (wParam == VK_RETURN) {
            PostMessage(GetParent(hwnd), WM_COMMAND, MAKELONG(IDB_HISTSRCH_GO, 0), 0L);
            return 0L;
        }
        break;
    }
    return CallWindowProc((WNDPROC)(GetWindowLongPtr(hwnd, GWLP_USERDATA)), hwnd, uMsg, wParam, lParam);
}


// Please see note at top of file for explanation...
INT_PTR CALLBACK CHistBand::s_HistSearchDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg) {
    case WM_PAINT:
        {
            // paint a little separator bar on the bottom
            PAINTSTRUCT ps;
            RECT        rcSelf;
            HDC         hdc = BeginPaint(hwndDlg, &ps);
            GetClientRect(hwndDlg, &rcSelf);
            RECT        rcFill = { 0, rcSelf.bottom - 2, rcSelf.right, rcSelf.bottom };
            FillRect(hdc, &rcFill, GetSysColorBrush(COLOR_BTNFACE));
            EndPaint(hwndDlg, &ps);
            break;
        }

    // Supply child controls with correct bkgd color
    case WM_CTLCOLORSTATIC:
        if ((HWND)lParam == GetDlgItem(hwndDlg, IDD_HISTSRCH_ANIMATION)) {
            SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW));
            return (INT_PTR) GetSysColorBrush(COLOR_WINDOW);
        }
        else {
            SetBkMode((HDC)wParam, TRANSPARENT);
            return (INT_PTR) GetSysColorBrush(COLOR_WINDOW);
        }
    case WM_CTLCOLORDLG:
        //SetBkColor((HDC)HIWORD(lParam), GetSysColor(COLOR_WINDOW));
        return (INT_PTR) GetSysColorBrush(COLOR_WINDOW);
    case WM_INITDIALOG: {
        HWND    hwndEdit       = GetDlgItem(hwndDlg, IDC_EDITHISTSEARCH);
        WNDPROC pfnOldEditProc = (WNDPROC)(GetWindowLongPtr(hwndEdit, GWLP_WNDPROC));

        // subclass the editbox
        SetWindowLongPtr(hwndEdit, GWLP_USERDATA, (LPARAM)pfnOldEditProc);
        SetWindowLongPtr(hwndEdit, GWLP_WNDPROC,  (LPARAM)s_EditWndSubclassProc);
        
        SetWindowLongPtr(hwndDlg, DWLP_USER, lParam);
        Animate_Open(GetDlgItem(hwndDlg, IDD_HISTSRCH_ANIMATION),
                     MAKEINTRESOURCE(IDA_HISTSEARCHAVI));

        // limit the edit control to MAX_PATH-1 characters
        Edit_LimitText(hwndEdit, MAX_PATH-1);

        break;
    }
    case WM_DESTROY:
        Animate_Close(GetDlgItem(hwndDlg, IDD_HISTSRCH_ANIMATION));
        break;
    case WM_SIZE: {
        if (wParam == SIZE_RESTORED) {
            UINT uWidth  = LOWORD(lParam);
            UINT uHeight = HIWORD(lParam);

            RECT rcAnimSize, rcCancel, rcSearch, rcEdit, rcStatic;
            HWND hwndAnim   = _GetHwndAndRect(hwndDlg, IDD_HISTSRCH_ANIMATION, TRUE,  rcAnimSize);
            HWND hwndCancel = _GetHwndAndRect(hwndDlg, IDCANCEL,               FALSE, rcCancel);
            HWND hwndSearch = _GetHwndAndRect(hwndDlg, IDB_HISTSRCH_GO,        FALSE, rcSearch);
            HWND hwndEdit   = _GetHwndAndRect(hwndDlg, IDC_EDITHISTSEARCH,     FALSE, rcEdit);
            
            // calculate the minimum tolerable width
            UINT uMinWidth  = ((rcCancel.right - rcCancel.left) +
                               (rcSearch.right - rcSearch.left) + HISTSRCH_BUTTONDIST +
                               rcEdit.left +
                               rcAnimSize.right + 1);

            if (uWidth < uMinWidth)
                uWidth = uMinWidth;

            HDWP hdwp = BeginDeferWindowPos(5);

            if (hdwp)
            {
                // align the animation box with the upper-right corner
                DeferWindowPos(hdwp, hwndAnim, HWND_TOP, uWidth - rcAnimSize.right, 0,
                               rcAnimSize.right, rcAnimSize.bottom, SWP_NOZORDER);
                
                // stretch the textbox as wide as possible
                UINT uNewTextWidth = uWidth - rcAnimSize.right - 1 - rcEdit.left;
                DeferWindowPos(hdwp, hwndEdit, HWND_TOP, rcEdit.left, rcEdit.top, uNewTextWidth,
                               rcEdit.bottom - rcEdit.top, SWP_NOZORDER);
                
                // static text should not be longer than edit textbox
                HWND hwndStatic = _GetHwndAndRect(hwndDlg, IDC_HISTSRCH_STATIC, FALSE, rcStatic);
                DeferWindowPos(hdwp, hwndStatic, HWND_TOP, rcEdit.left, rcStatic.top, uNewTextWidth,
                               rcStatic.bottom - rcStatic.top, SWP_NOZORDER);
                
                // align the cancel button with the right of the edit box
                UINT uCancelLeft = uWidth - rcAnimSize.right - 1 - (rcCancel.right - rcCancel.left);
                DeferWindowPos(hdwp, hwndCancel, HWND_TOP, uCancelLeft, rcCancel.top,
                               rcCancel.right - rcCancel.left, rcCancel.bottom - rcCancel.top, SWP_NOZORDER);
                
                // align the search button so that it ends six pixels (HISTSRCH_BUTTONDIST)
                //   to the left of the cancel button
                DeferWindowPos(hdwp, hwndSearch, HWND_TOP,
                               uCancelLeft - HISTSRCH_BUTTONDIST - (rcSearch.right - rcSearch.left),
                               rcSearch.top, rcSearch.right - rcSearch.left, rcSearch.bottom - rcSearch.top, SWP_NOZORDER);

                EndDeferWindowPos(hdwp);
            }
        }
        else
            return FALSE;
        break;
    }
    case WM_COMMAND:
        {
            CHistBand *phb = reinterpret_cast<CHistBand *>(GetWindowLongPtr(hwndDlg, DWLP_USER));

            switch (LOWORD(wParam))
            {
            case IDC_EDITHISTSEARCH:
                switch (HIWORD(wParam))
                {
                case EN_SETFOCUS:
                    // This guy allows us to intercept TranslateAccelerator messages
                    //  like backspace.  This is the same as calling UIActivateIO(TRUE), but
                    //  doesn't cause an infinite setfocus loop in Win95
                    IUnknown_OnFocusChangeIS(phb->_punkSite, SAFECAST(phb, IInputObject*), TRUE);
                    SetFocus((HWND)lParam);
                    break;
                case EN_CHANGE:
                    // Enable 'Go Fish' button iff there is text in the edit box
                    EnableWindow(GetDlgItem(hwndDlg, IDB_HISTSRCH_GO),
                                 (bool) SendDlgItemMessage(hwndDlg, IDC_EDITHISTSEARCH, EM_LINELENGTH, 0, 0));
                    break;
                }
                break;
            case IDB_HISTSRCH_GO:
                {
                    TCHAR szSearchString[MAX_PATH];
                    if (GetDlgItemText(hwndDlg, IDC_EDITHISTSEARCH, szSearchString, ARRAYSIZE(szSearchString)))
                    {
                        IServiceProvider *pServiceProvider;
                        
                        HRESULT hr = IUnknown_QueryService(phb->_punkSite, 
                                                           SID_SProxyBrowser, 
                                                           IID_IServiceProvider, 
                                                           (void **)&pServiceProvider);

                        if (SUCCEEDED(hr))
                        {
                            IWebBrowser2 *pWebBrowser2;
                            hr = pServiceProvider->QueryService(SID_SWebBrowserApp, 
                                                                IID_IWebBrowser2, 
                                                                (void **)&pWebBrowser2);
                            if (SUCCEEDED(hr))
                            {
                                ::PutFindText(pWebBrowser2, szSearchString);
                                pWebBrowser2->Release();
                            }

                            pServiceProvider->Release();
                        }

                        phb->_ExecuteSearch(szSearchString);
                    }
                }
                break;
            case IDCANCEL:
                {
                    if (phb->_EnsureSearch())
                    {
                        phb->_psfSearch->CancelAsyncSearch(phb->_pidlSearch, NULL);
                    }
                    break;
                }
            default:
                return FALSE;
            }
        }
        return FALSE;

    case WM_SEARCH_STATE:
        {
            BOOL fStart = (BOOL)wParam;
            if (fStart)
                Animate_Play(GetDlgItem(hwndDlg, IDD_HISTSRCH_ANIMATION), 0, -1, -1);
            else {
                HWND hwndAnim = GetDlgItem(hwndDlg, IDD_HISTSRCH_ANIMATION);
                Animate_Stop(hwndAnim);
                Animate_Seek(hwndAnim, 0); // reset the animation

                //HACK for IE5 ship
                //if there's only one item found in history search, the item doesn't display
                //because someone (comctl32?) set redraw to false.
                //so, manually force it to true when the search stops
                CHistBand *phb = reinterpret_cast<CHistBand *>(GetWindowLongPtr(hwndDlg, DWLP_USER));
                if (phb)
                    SendMessage(phb->_hwndNSC, WM_SETREDRAW, TRUE, 0);
            }
            HWND hwndFocus = GetFocus();

            EnableWindow(GetDlgItem(hwndDlg, IDC_EDITHISTSEARCH), !fStart);
            EnableWindow(GetDlgItem(hwndDlg, IDB_HISTSRCH_GO), !fStart);            
            EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), fStart);

            //make sure the focus goes to the right place
            if ((NULL != hwndFocus) && (hwndFocus == GetDlgItem(hwndDlg, IDC_EDITHISTSEARCH) ||
                                       (hwndFocus == GetDlgItem(hwndDlg, IDCANCEL))))
                SetFocus(GetDlgItem(hwndDlg, fStart ? IDCANCEL : IDC_EDITHISTSEARCH));
            break;
        }

    default:
        return FALSE;
    }
    return TRUE;
}

IShellFolderSearchable *CHistBand::_EnsureSearch() {
    ASSERT(_psfHistory);
    if (!_pidlSearch) {
        _psfHistory->QueryInterface(IID_IShellFolderSearchable,
                                    (LPVOID *)&_psfSearch);
    }
    return _psfSearch;
}

HRESULT CHistBand::_ClearSearch() {
    HRESULT hr = S_FALSE;

    if (_pidlSearch) {
        if (_EnsureSearch())
        {
            EVAL(SUCCEEDED(_psfSearch->CancelAsyncSearch(_pidlSearch, NULL)));
            hr = _psfSearch->InvalidateSearch(_pidlSearch, NULL);
        }
        ILFree(_pidlSearch);
        _pidlSearch = NULL;
    }
    return hr;
}
    
HRESULT CHistBand::_ExecuteSearch(LPTSTR pszSearchString)
{
    HRESULT hr = E_FAIL;
    
    if (_EnsureSearch())
    {
        _ClearSearch();
        hr = _psfSearch->FindString(pszSearchString,
                                                     NULL,
                                                     reinterpret_cast<IUnknown *>
                                                     (static_cast<IShellFolderSearchableCallback *>
                                                      (this)),
                                                     &_pidlSearch);
        if (SUCCEEDED(hr))
        {
            _ChangePidl(ILCombine(_pidlHistory, _pidlSearch));
        }
    }
    return hr;
}

#ifdef SPLIT_HISTORY_VIEW_BUTTON
UINT CHistBand::_NextMenuItem() {
    if (_uViewCheckedItem + 1 > _nViews)
        return 1;
    else
        return _uViewCheckedItem + 1;
}
#endif

HRESULT CHistBand::_ViewPopupSelect(UINT idCmd) 
{
    HRESULT hr = E_FAIL;

    if (idCmd == MENUID_SEARCH)
    {
        if (_uViewCheckedItem != MENUID_SEARCH)
        {
            // display the dialog box
            if (SUCCEEDED(hr = _DoSearchUIStuff()))
            {
                _ChangePidl((LPITEMIDLIST)INVALID_HANDLE_VALUE); // blank out NSC
                _uViewCheckedItem = MENUID_SEARCH;
                CheckMenuRadioItem(_hViewMenu, 1, _iMaxMenuID, _uViewCheckedItem, MF_BYCOMMAND);
            }
        }
        if (_hwndSearchDlg)
            SetFocus(GetDlgItem(_hwndSearchDlg, IDC_EDITHISTSEARCH));
    }
    else
    {
        LPCITEMIDLIST pidlNewSelect = _MenuIDToPIDL(idCmd);
        if (pidlNewSelect) {
            if (ILIsEmpty(pidlNewSelect))
                hr = _ChangePidl(ILClone(_pidlHistory));
            else
                hr = _ChangePidl(ILCombine(_pidlHistory, pidlNewSelect));

            if (SUCCEEDED(hr))
                hr = _SelectPidl(NULL, TRUE, pidlNewSelect);

            // deleted "&& _uViewCheckedItem >= 0" from test below
            // because UINTs are by definition always >= 0
            if (SUCCEEDED(hr))
            {
                // get rid of search dialog -- its no longer needed
                if (_hwndSearchDlg) {
                    EndDialog(_hwndSearchDlg, 0);
                    DestroyWindow(_hwndSearchDlg);
                    _hwndSearchDlg = NULL;
                    // invalidate the previous search and prepare for the next
                    _ClearSearch();
                    RECT rcSelf;
                    GetClientRect(_hwnd, &rcSelf);
                    _ResizeChildWindows(rcSelf.right, rcSelf.bottom, TRUE);
                }
                
                _uViewCheckedItem = idCmd;
                CheckMenuRadioItem(_hViewMenu, 1, _iMaxMenuID,
                                   _uViewCheckedItem, MF_BYCOMMAND);
                // write out the new selection to registry
                EVAL(SUCCEEDED(_SetRegistryPersistView(_uViewCheckedItem)));
                hr = S_OK;
            }
        }
    }
    return hr;
}

HRESULT CHistBand::_DoViewPopup(int x, int y)
{
    if (!_hViewMenu) return E_FAIL;

    HRESULT hr = E_FAIL;

    UINT idCmd = TrackPopupMenu(_hViewMenu, TPM_RETURNCMD, x, y, 0, _hwnd, NULL);
    // Currently, re-selecting the menu item will cause the item to be refreshed
    //  This makes sense to me, but it can be prevented by
    //  testing idCmd != _uViewCheckedItem
    if ( (idCmd > 0) )
    {
        return _ViewPopupSelect(idCmd);
    }
    else
        hr = S_FALSE;

    return hr;
}

// Change the current select NSC pidl
// WARNING: The pidl passed in will be assimilated by us...
//          We will deallocate it.
HRESULT CHistBand::_ChangePidl(LPITEMIDLIST pidl) 
{
    if (_pidl)
        ILFree(_pidl);

    _pidl = pidl;
    if ((LPITEMIDLIST)INVALID_HANDLE_VALUE == pidl)
        _pidl = NULL;
    _pns->Initialize(pidl, (SHCONTF_FOLDERS | SHCONTF_NONFOLDERS), (NSS_DROPTARGET | NSS_BROWSERSELECT));
    return S_OK;
}

// _SelectPidl - Have NSC change the current selected pidl
//
// passing NULL for pidlSelect will select the current select pidl
HRESULT CHistBand::_SelectPidl(LPCITEMIDLIST pidlSelect,        // <-Standard Hist-type pidl to select
                               BOOL fCreate,                    // <-create NSC item if not there?
                               LPCITEMIDLIST pidlView,/*=NULL*/ // <-special history view type or NULL
                               BOOL fReinsert /*=0*/)           // <-reinsert pidl into NSC and re-sort
{
    HRESULT hRes = S_OK;
    BOOL    fFreePidlSelect = FALSE;

    if ( (!pidlSelect) &&
         ((pidlSelect = _GetCurrentSelectPidl())) )
        fFreePidlSelect = TRUE;

    if (pidlSelect) {
        LPITEMIDLIST pidlNewSelect = NULL;

        // cache the last selected pidl
        if (_pidlLastSelect != pidlSelect) {
            if (_pidlLastSelect)
                ILFree(_pidlLastSelect);
            _pidlLastSelect = ILClone(pidlSelect);
        }

        if (pidlView && !ILIsEmpty(pidlView)) {
            IShellFolderViewType *psfvtInfo = _GetViewTypeInfo();

            if (psfvtInfo) {
                LPITEMIDLIST pidlFromRoot = ILFindChild(_pidlHistory,
                                                        pidlSelect);
                if (pidlFromRoot && !ILIsEmpty(pidlFromRoot))
                {
                    LPITEMIDLIST pidlNewFromRoot;
                    if (SUCCEEDED(psfvtInfo->TranslateViewPidl(pidlFromRoot, pidlView,
                                                               &pidlNewFromRoot)))
                    {
                        if (pidlNewFromRoot) {
                            pidlNewSelect = ILCombine(_pidlHistory, pidlNewFromRoot);
                            if (pidlNewSelect) {
                                _pns->SetSelectedItem(pidlNewSelect, fCreate, fReinsert, 0);
                                ILFree(pidlNewSelect);
                            }
                            ILFree(pidlNewFromRoot);
                        }
                    }
                }
                psfvtInfo->Release();
            }
        }
        else
            _pns->SetSelectedItem(pidlSelect, fCreate, fReinsert, 0);

        if (fFreePidlSelect)
            ILFree(const_cast<LPITEMIDLIST>(pidlSelect));
    }
    return hRes;
}

HRESULT CHistBand::_SetRegistryPersistView(int iMenuID) 
{
    LPCITEMIDLIST pidlReg = _MenuIDToPIDL(iMenuID);

    if (!pidlReg)
        return E_FAIL;

    LONG lRet = (SHRegSetUSValue(REGSTR_PATH_MAIN, REGKEY_HISTORY_VIEW,
                         REG_BINARY, (LPVOID)pidlReg, ILGetSize(pidlReg),
                         SHREGSET_HKCU | SHREGSET_FORCE_HKCU));
    return HRESULT_FROM_WIN32(lRet);
}

// Get the default view from the registry as a menu item
int CHistBand::_GetRegistryPersistView() 
{
    int          iRegMenu = -1;
    DWORD        dwType = REG_BINARY;

    ITEMIDLIST   pidlDefault = { 0 };

    // make a preliminary call to find out the size of the data
    DWORD cbData = 0;
    LONG error   = SHRegGetUSValue(REGSTR_PATH_MAIN, REGKEY_HISTORY_VIEW, &dwType,
                                   NULL, &cbData, FALSE, &pidlDefault,
                                   sizeof(pidlDefault));
    if (cbData)
    {
        LPITEMIDLIST pidlReg = ((LPITEMIDLIST)SHAlloc(cbData));

        if (pidlReg)
        {
            error = SHRegGetUSValue(REGSTR_PATH_MAIN, REGKEY_HISTORY_VIEW, &dwType,
                                    (LPVOID)pidlReg, &cbData, FALSE, &pidlDefault,
                                    sizeof(pidlDefault));

            if (error == ERROR_SUCCESS)
                iRegMenu = _PIDLToMenuID(pidlReg);

            SHFree(pidlReg);
        }
    }

    return iRegMenu;
}

LPCITEMIDLIST CHistBand::_MenuIDToPIDL(UINT uMenuID) 
{
    ASSERT(_ppidlViewTypes);
    if ((uMenuID > 0) && (uMenuID <= _nViews))
        return _ppidlViewTypes[uMenuID - 1];
    return NULL;
}

int CHistBand::_PIDLToMenuID(LPITEMIDLIST pidl) 
{
    ASSERT(_psfHistory && _ppidlViewTypes);

    int iMenuID = -1;

    // handle the empty pidl, which designates the
    //  default view, separately
    if (ILIsEmpty(pidl))
        iMenuID = 1;
    else 
    {
        for (UINT u = 0; u < _nViews; ++u) 
        {
            if (_psfHistory->CompareIDs(0, pidl, _ppidlViewTypes[u]) == 0)
                iMenuID = u + 1;
        }
    }
    return iMenuID;
}

// remember to release return value
IShellFolderViewType* CHistBand::_GetViewTypeInfo() 
{
    IShellFolderViewType* psfvRet = NULL;

    if (_psfvtCache)
    {
        _psfvtCache->AddRef();
        psfvRet = _psfvtCache;
    }
    else if (_psfHistory)
    {
        // QI For the views
        // We set the pointer because of a bad QI somewhere...
        if (SUCCEEDED(_psfHistory->QueryInterface(IID_IShellFolderViewType,
                                                  ((void**)&psfvRet))))
        {
            _psfvtCache = psfvRet;
            psfvRet->AddRef(); // one released in destructor, another by caller
        }
        else
            psfvRet = NULL;
    }
    return psfvRet;
}

HRESULT CHistBand::_FreeViewInfo() 
{
    if (_ppidlViewTypes) 
    {
        // the first pidl in this list is NULL, the default view
        for (UINT u = 0; u < _nViews; ++u)
            if (EVAL(_ppidlViewTypes[u]))
                ILFree(_ppidlViewTypes[u]);
        LocalFree(_ppidlViewTypes);
        _ppidlViewTypes = NULL;
    }
    if (_ppszStrViewNames) 
    {
        for (UINT u = 0; u < _nViews; ++u)
            if (EVAL(_ppszStrViewNames[u]))
                CoTaskMemFree(_ppszStrViewNames[u]);
        LocalFree(_ppszStrViewNames);
        _ppszStrViewNames = NULL;
    }
    return S_OK;
}

// Load the popup menu (if there are views to be had)
HRESULT CHistBand::_InitViewPopup() 
{
    HRESULT hRes = E_FAIL;

    _iMaxMenuID = 0;

    if (SUCCEEDED((hRes = _GetHistoryViews()))) 
    {
        if ((_hViewMenu = CreatePopupMenu()))
        {
            // the IDCMD for the view menu will always be
            //   one more than the index into the view tables
            for (UINT u = 0; u < _nViews; ++u) 
            {
                int iMenuID = _PIDLToMenuID(_ppidlViewTypes[u]);
                if (iMenuID >= 0)
                    AppendMenu(_hViewMenu, MF_STRING, iMenuID,
                               _ppszStrViewNames[u]);
                if (iMenuID > _iMaxMenuID)
                    _iMaxMenuID = iMenuID;
            }

            // retrieve the persisted view information
            //  and check the corresponding menu item
            int iSelectMenuID = _GetRegistryPersistView();
            if (iSelectMenuID < 0 || ((UINT)iSelectMenuID) > _nViews)
                iSelectMenuID = 1; //bogus menuid
            _uViewCheckedItem = iSelectMenuID;
            CheckMenuRadioItem(_hViewMenu, 1, _nViews, _uViewCheckedItem, MF_BYCOMMAND);
        }
    }

#ifdef HISTORY_VIEWSEARCHMENU
    // if this is a searchable shell folder, then add the search menu item
    if (_EnsureSearch())
    {
        hRes = S_OK;

        // only add separator if there is a menu already!
        if (!_hViewMenu)
            _hViewMenu = CreatePopupMenu();
        else
            AppendMenu(_hViewMenu, MF_SEPARATOR, 0, NULL);

        if (_hViewMenu)
        {
            TCHAR szSearchMenuText[MAX_PATH];
            LoadString(MLGetHinst(), IDS_SEARCH_MENUOPT,
                       szSearchMenuText, ARRAYSIZE(szSearchMenuText));
            AppendMenu(_hViewMenu, MF_STRING, MENUID_SEARCH, szSearchMenuText);
            _iMaxMenuID = MENUID_SEARCH;
        }
        else
            hRes = E_FAIL;
    }
#endif
    return hRes;
}

// This guy calls the enumerator
HRESULT CHistBand::_GetHistoryViews() 
{
    ASSERT(_psfHistory);
    HRESULT hRes = E_FAIL;

    UINT cbViews; // how many views are allocated

    ASSERT(VIEWTYPE_MAX > 0);

    EVAL(SUCCEEDED(_FreeViewInfo()));

    IShellFolderViewType *psfViewType = _GetViewTypeInfo();

    if (psfViewType)
    {
        // allocate buffers to store the view information
        _ppidlViewTypes = ((LPITEMIDLIST *)LocalAlloc(LPTR, VIEWTYPE_MAX * sizeof(LPITEMIDLIST)));
        if (_ppidlViewTypes) {
            _ppszStrViewNames = ((LPTSTR *)LocalAlloc(LPTR, VIEWTYPE_MAX * sizeof(LPTSTR)));
            if (_ppszStrViewNames) {
                IEnumIDList *penum = NULL;
                cbViews  = VIEWTYPE_MAX;
                _nViews  = 1;
                // get the default view information
                _ppidlViewTypes[0]   = IEILCreate(sizeof(ITEMIDLIST));
                if (_ppidlViewTypes[0] &&
                    SUCCEEDED((hRes = psfViewType->GetDefaultViewName(0, &(_ppszStrViewNames[0])))))
                {
                    // empty pidl will be the default
                    ASSERT(ILIsEmpty(_ppidlViewTypes[0]));
                    // get the iterator for the other views
                    if (SUCCEEDED((hRes = psfViewType->EnumViews(0, &penum)))) {
                        ULONG cFetched = 0;
                        // iterate to get other view information
                        while(SUCCEEDED(hRes)                                                   &&
                              SUCCEEDED(penum->Next(1, &(_ppidlViewTypes[_nViews]), &cFetched)) &&
                              cFetched)
                        {
                            // get the name of this view
                            if (SUCCEEDED(DisplayNameOfAsOLESTR(_psfHistory, _ppidlViewTypes[_nViews], 0, &(_ppszStrViewNames[_nViews]))))
                            {
                                // prepare for next iteration by reallocating the buffer if necessary
                                if (_nViews > cbViews - 1)
                                {
                                    LPITEMIDLIST *ppidlViewTypes = ((LPITEMIDLIST *)LocalReAlloc(_ppidlViewTypes,
                                                                                       (cbViews + VIEWTYPE_REALLOC) * sizeof(LPITEMIDLIST),
                                                                                       LMEM_MOVEABLE | LMEM_ZEROINIT));
                                    if (ppidlViewTypes)
                                    {
                                        _ppidlViewTypes = ppidlViewTypes;
                                        LPTSTR * ppszStrViewNames = ((LPTSTR *)LocalReAlloc(_ppszStrViewNames,
                                                                                   (cbViews + VIEWTYPE_REALLOC) * sizeof(LPTSTR),
                                                                                   LMEM_MOVEABLE | LMEM_ZEROINIT));
                                        if (ppszStrViewNames)
                                        {
                                            _ppszStrViewNames = ppszStrViewNames;
                                            cbViews += VIEWTYPE_REALLOC;
                                        }
                                        else
                                        {
                                            hRes = E_OUTOFMEMORY;
                                            break;
                                        }
                                    }
                                    else
                                    {
                                        hRes = E_OUTOFMEMORY;
                                        break;
                                    }
                                }
                                ++_nViews;
                            }
                        }
                        penum->Release();
                    }
                }
            }
        }
        psfViewType->Release();
    }
    return hRes;
}

HRESULT CHistBand_CreateInstance(IUnknown *punkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
{
    // aggregation checking is handled in class factory
    CHistBand * phb = new CHistBand();

    if (!phb)
        return E_OUTOFMEMORY;

    ASSERT(phb->_pidlHistory    == NULL &&
           phb->_pidlLastSelect == NULL &&
           phb->_pidl           == NULL &&
           phb->_psfvtCache     == NULL);


    if (SUCCEEDED(SHGetHistoryPIDL(&(phb->_pidlHistory))) &&
        SUCCEEDED(IEBindToObject(phb->_pidlHistory,
                                 &(phb->_psfHistory))))
    {
        HRESULT hResLocal = E_FAIL;

        // if we can get different views, then init with the persisted
        //   view type, otherwise, init with the top-level history type
        if (SUCCEEDED(phb->_InitViewPopup())) {
            LPCITEMIDLIST pidlInit = phb->_MenuIDToPIDL(phb->_uViewCheckedItem);
            if (pidlInit) {
                LPITEMIDLIST pidlFullInit = ILCombine(phb->_pidlHistory, pidlInit);
                if (pidlFullInit) {
                    hResLocal = phb->_Init(pidlFullInit);
                    ILFree(pidlFullInit);
                }
            }
        }
        else
            hResLocal = phb->_Init(phb->_pidlHistory);

        // From old favband code: // if (SUCCEEDED(phb->_Init((LPCITEMIDLIST)CSIDL_FAVORITES)))
        if (SUCCEEDED(hResLocal))
        {
            phb->_pns = CNscTree_CreateInstance();
            if (phb->_pns)
            {
                ASSERT(poi);
                phb->_poi = poi;
                // if you change this cast, fix up CChannelBand_CreateInstance
                *ppunk = SAFECAST(phb, IDeskBand *);

                IUnknown_SetSite(phb->_pns, *ppunk);
                phb->_SetNscMode(MODE_HISTORY);
                return S_OK;
            }
        }
    }

    phb->Release();

    return E_FAIL;
}

// Ask the powers that be which pidl is selected...
LPITEMIDLIST CHistBand::_GetCurrentSelectPidl(IOleCommandTarget *poctProxy/* = NULL*/) 
{
    LPITEMIDLIST pidlRet = NULL;
    VARIANT var;
    BOOL    fReleaseProxy = FALSE;
    VariantInit(&var);
    var.vt = VT_EMPTY;

    if (poctProxy == NULL) 
    {
        IBrowserService *pswProxy;
        if (SUCCEEDED(QueryService(SID_SProxyBrowser, IID_PPV_ARG(IBrowserService, &pswProxy))))
        {
            ASSERT(pswProxy);
            if (FAILED(pswProxy->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &poctProxy))))
            {
                pswProxy->Release();
                return NULL;
            }
            else
                fReleaseProxy = TRUE;

            pswProxy->Release();
        }
    }

    //  Inquire the current select pidl
    if ((SUCCEEDED(poctProxy->Exec(&CGID_Explorer, SBCMDID_GETHISTPIDL,
                                   OLECMDEXECOPT_PROMPTUSER, NULL, &var))) &&
        (var.vt != VT_EMPTY))
    {
        pidlRet = VariantToIDList(&var);
        VariantClearLazy(&var);
    }
    if (fReleaseProxy)
        poctProxy->Release();
    return pidlRet;
}

// gets called by CNSCBand::ShowDW every time history band is shown
HRESULT CHistBand::_OnRegisterBand(IOleCommandTarget *poctProxy) 
{
    HRESULT hRes = E_FAIL;
    if (_uViewCheckedItem != MENUID_SEARCH)
    {
        LPITEMIDLIST pidlSelect = _GetCurrentSelectPidl(poctProxy);
        if (pidlSelect)
        {
            _SelectPidl(pidlSelect, TRUE);
            ILFree(pidlSelect);
            hRes = S_OK;
        }
    }
    return hRes;
}

HRESULT CHistBand::_InitializeNsc()
{
    return _pns->Initialize(_pidl, SHCONTF_FOLDERS | SHCONTF_NONFOLDERS, NSS_NOHISTSELECT | NSS_DROPTARGET | NSS_BROWSERSELECT);
}

BOOL CHistBand::_ShouldNavigateToPidl(LPCITEMIDLIST pidl, ULONG ulAttrib)
{
    return !(ulAttrib & SFGAO_FOLDER);
}

HRESULT CHistBand::_NavigateRightPane(IShellBrowser *psb, LPCITEMIDLIST pidl)
{
    HRESULT hr = psb->BrowseObject(pidl, SBSP_SAMEBROWSER | SBSP_NOAUTOSELECT);
    if (SUCCEEDED(hr))
    {
        IOleCommandTarget *poctProxy;
        if (SUCCEEDED(QueryService(SID_SProxyBrowser, IID_PPV_ARG(IOleCommandTarget, &poctProxy))))
        {
            VARIANTARG var;
            
            InitVariantFromIDList(&var, pidl);
            poctProxy->Exec(&CGID_Explorer, SBCMDID_SELECTHISTPIDL, OLECMDEXECOPT_PROMPTUSER, &var, NULL);
            VariantClear(&var);
            poctProxy->Release();
        }
        UEMFireEvent(&UEMIID_BROWSER, UEME_INSTRBROWSER, UEMF_INSTRUMENT, UIBW_NAVIGATE, UIBL_NAVHIST);
    }
    return hr;
}

